Merge "Added validation for protocol field while adding flow"
authorGiovanni Meo <gmeo@cisco.com>
Thu, 19 Sep 2013 15:21:04 +0000 (15:21 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 19 Sep 2013 15:21:04 +0000 (15:21 +0000)
148 files changed:
opendaylight/archetypes/odl-model-project/src/main/resources/archetype-resources/pom.xml
opendaylight/clustering/integrationtest/pom.xml
opendaylight/clustering/services_implementation/pom.xml
opendaylight/clustering/services_implementation/src/main/java/org/opendaylight/controller/clustering/services_implementation/internal/ClusterManagerCommon.java
opendaylight/clustering/stub/src/main/java/org/opendaylight/controller/clustering/stub/internal/ClusterManagerCommon.java
opendaylight/commons/opendaylight/pom.xml
opendaylight/connectionmanager/api/src/main/java/org/opendaylight/controller/connectionmanager/ConnectionLocality.java [new file with mode: 0644]
opendaylight/connectionmanager/api/src/main/java/org/opendaylight/controller/connectionmanager/IConnectionManager.java
opendaylight/connectionmanager/implementation/src/main/java/org/opendaylight/controller/connectionmanager/internal/ConnectionManager.java
opendaylight/connectionmanager/implementation/src/main/java/org/opendaylight/controller/connectionmanager/scheme/AbstractScheme.java
opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/ContainerConfig.java
opendaylight/containermanager/it.implementation/src/main/java/org/opendaylight/controller/containermanager/internal/ContainerManager.java
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/FlowEntryInstall.java
opendaylight/forwardingrulesmanager/implementation/pom.xml
opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/implementation/data/FlowEntryDistributionOrder.java
opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java
opendaylight/forwardingrulesmanager/integrationtest/pom.xml
opendaylight/hosttracker/implementation/pom.xml
opendaylight/hosttracker/integrationtest/pom.xml
opendaylight/hosttracker_new/implementation/pom.xml
opendaylight/md-sal/sal-compability/pom.xml [new file with mode: 0644]
opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalConversionsUtils.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/api/pom.xml [new file with mode: 0644]
opendaylight/northbound/bundlescanner/api/src/main/java/org/opendaylight/controller/northbound/bundlescanner/IBundleScanService.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/pom.xml [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/main/java/org/opendaylight/controller/northbound/bundlescanner/internal/Activator.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/main/java/org/opendaylight/controller/northbound/bundlescanner/internal/BundleInfo.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/main/java/org/opendaylight/controller/northbound/bundlescanner/internal/BundleScanServiceImpl.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/main/java/org/opendaylight/controller/northbound/bundlescanner/internal/BundleScanner.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/Animal.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/BasePerson.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/Mammal.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/NoAnnotation.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/NonRelevantAnnotation.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/Person.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_misc/Misc.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub1/NoAnnotation.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub1/Zoo.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub2/Agent.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub2/Customer.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub2/NoAnnotation.java [new file with mode: 0644]
opendaylight/northbound/bundlescanner/implementation/src/test/java/org/opendaylight/controller/northbound/bundlescanner/internal/BundleScannerTest.java [new file with mode: 0644]
opendaylight/northbound/commons/pom.xml
opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/JacksonJsonProcessingExceptionMapper.java [new file with mode: 0644]
opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/NorthboundApplication.java [new file with mode: 0644]
opendaylight/northbound/containermanager/pom.xml
opendaylight/northbound/flowprogrammer/pom.xml
opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowProgrammerNorthboundRSApplication.java [deleted file]
opendaylight/northbound/flowprogrammer/src/main/resources/WEB-INF/web.xml
opendaylight/northbound/hosttracker/pom.xml
opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthboundRSApplication.java [deleted file]
opendaylight/northbound/hosttracker/src/main/resources/WEB-INF/web.xml
opendaylight/northbound/integrationtest/pom.xml
opendaylight/northbound/integrationtest/src/test/java/org/opendaylight/controller/northbound/integrationtest/NorthboundIT.java
opendaylight/northbound/networkconfiguration/bridgedomain/pom.xml
opendaylight/northbound/networkconfiguration/bridgedomain/src/main/java/org/opendaylight/controller/networkconfig/bridgedomain/northbound/BridgeDomainNorthboundApplication.java [deleted file]
opendaylight/northbound/networkconfiguration/bridgedomain/src/main/resources/WEB-INF/web.xml
opendaylight/northbound/staticrouting/pom.xml
opendaylight/northbound/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/northbound/StaticRoutingNorthboundRSApplication.java [deleted file]
opendaylight/northbound/staticrouting/src/main/resources/WEB-INF/web.xml
opendaylight/northbound/statistics/pom.xml
opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthboundRSApplication.java [deleted file]
opendaylight/northbound/statistics/src/main/resources/WEB-INF/web.xml
opendaylight/northbound/subnets/pom.xml
opendaylight/northbound/subnets/src/main/java/org/opendaylight/controller/subnets/northbound/SubnetsNorthboundRSApplication.java [deleted file]
opendaylight/northbound/subnets/src/main/resources/WEB-INF/web.xml
opendaylight/northbound/switchmanager/pom.xml
opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/SwitchNorthboundRSApplication.java [deleted file]
opendaylight/northbound/switchmanager/src/main/resources/WEB-INF/web.xml
opendaylight/northbound/topology/pom.xml
opendaylight/northbound/topology/src/main/java/org/opendaylight/controller/topology/northbound/TopologyNorthboundRSApplication.java [deleted file]
opendaylight/northbound/topology/src/main/resources/WEB-INF/web.xml
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/ISwitch.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SwitchHandler.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowStatisticsConverter.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryServiceShim.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/authorization/AppRoleLevel.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Node.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/NodeConnector.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/NodeTable.java
opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/FlowProgrammerService.java
opendaylight/sal/yang-prototype/pom.xml
opendaylight/sal/yang-prototype/sal/model/model-flow-base/src/main/yang/group-types.yang [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/model/model-flow-base/src/main/yang/match-types.yang
opendaylight/sal/yang-prototype/sal/model/model-flow-service/src/main/yang/group-service.yang [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/pom.xml
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/pom.xml
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeSpecification.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/YangtoolsMappingHelper.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/JavassistUtils.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RoutingPair.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataProviderContext.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiProviderContext.xtend
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/_DataBrokerImpl.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/Constants.xtend [moved from opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/Constants.xtend with 84% similarity]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/PropertiesUtils.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/package-info.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/GeneratorUtils.xtend [deleted file]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/PropertiesUtils.xtend [deleted file]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/package-info.java [deleted file]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/test/org/opendaylight/controller/sal/binding/test/GenerationTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/BarUpdate.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooListener.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooUpdate.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/Grouping.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/InheritedContextInput.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObject.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObjectKey.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/SimpleInput.java [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/pom.xml
opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/LoadBalancerNorthboundRSApplication.java [deleted file]
opendaylight/samples/northbound/loadbalancer/src/main/resources/WEB-INF/web.xml
opendaylight/statisticsmanager/implementation/pom.xml
opendaylight/statisticsmanager/integrationtest/pom.xml
opendaylight/switchmanager/api/pom.xml
opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/SpanConfig.java
opendaylight/switchmanager/implementation/pom.xml
opendaylight/switchmanager/integrationtest/pom.xml
opendaylight/topologymanager/implementation/pom.xml [moved from opendaylight/topologymanager/pom.xml with 97% similarity]
opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManager.java [moved from opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManager.java with 100% similarity]
opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManagerAware.java [moved from opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManagerAware.java with 100% similarity]
opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManagerClusterWideAware.java [moved from opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManagerClusterWideAware.java with 100% similarity]
opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/TopologyUserLinkConfig.java [moved from opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/TopologyUserLinkConfig.java with 100% similarity]
opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/internal/Activator.java [moved from opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/internal/Activator.java with 100% similarity]
opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImpl.java [moved from opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImpl.java with 100% similarity]
opendaylight/topologymanager/implementation/src/test/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImplTest.java [moved from opendaylight/topologymanager/src/test/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImplTest.java with 100% similarity]
opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java
opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthorizationUserConfigTest.java
opendaylight/usermanager/implementation/src/main/java/org/opendaylight/controller/usermanager/internal/Activator.java
opendaylight/usermanager/implementation/src/main/java/org/opendaylight/controller/usermanager/internal/UserManager.java
opendaylight/web/devices/pom.xml
opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/Devices.java
opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/SpanPortJsonBean.java [new file with mode: 0644]
opendaylight/web/devices/src/main/resources/js/page.js
opendaylight/web/root/src/main/java/org/opendaylight/controller/web/DaylightWebAdmin.java
opendaylight/web/root/src/main/resources/WEB-INF/jsp/main.jsp
opendaylight/web/root/src/main/resources/js/open.js
opendaylight/web/topology/src/main/java/org/opendaylight/controller/topology/web/Topology.java
third-party/openflowj/src/main/java/org/openflow/protocol/OFType.java

index b84346514f17c85a3b4d24c2f1f1878747bcd623..ecc08d011db9db0063711104dfb205d3ddca0e02 100644 (file)
@@ -9,7 +9,7 @@
   <properties>\r
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\r
     <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>\r
-    <yang.version>0.5.7-SNAPSHOT</yang.version>\r
+    <yang.version>0.5.8-SNAPSHOT</yang.version>\r
     <maven.bundle.version>2.4.0</maven.bundle.version>\r
   </properties>\r
 \r
@@ -56,7 +56,7 @@
       <plugin>\r
         <groupId>org.opendaylight.yangtools</groupId>\r
         <artifactId>yang-maven-plugin</artifactId>\r
-        <version>0.5.7-SNAPSHOT</version>\r
+        <version>${yang.version}</version>\r
         <executions>\r
           <execution>\r
             <goals>\r
@@ -79,7 +79,7 @@
           <dependency>\r
             <groupId>org.opendaylight.yangtools</groupId>\r
             <artifactId>maven-sal-api-gen-plugin</artifactId>\r
-            <version>0.5.7-SNAPSHOT</version>\r
+            <version>${yang.version}</version>\r
             <type>jar</type>\r
           </dependency>\r
         </dependencies>\r
   </build>\r
   <pluginRepositories>\r
     <pluginRepository>\r
-      <id>central2</id>\r
-      <name>central2</name>\r
-      <url>http://repo2.maven.org/maven2</url>\r
+      <id>central</id>\r
+      <name>maven repo1</name>\r
+      <url>http://repo1.maven.org/maven2</url>\r
        <snapshots>\r
         <enabled>false</enabled>\r
       </snapshots>\r
       <name>ebr-bundles-external</name>\r
       <url>${nexusproxy}/repositories/ebr-bundles-external/</url>\r
     </repository>\r
-    <repository>\r
-      <id>central2</id>\r
-      <name>central2</name>\r
-      <url>http://repo2.maven.org/maven2</url>\r
-      <snapshots>\r
-        <enabled>false</enabled>\r
-      </snapshots>\r
-      <releases>\r
-        <enabled>true</enabled>\r
-      </releases>\r
-    </repository>\r
     <repository>\r
       <id>central</id>\r
       <name>central</name>\r
index 0fadb128901cd16749511f32c58e2ea71973fc75..63ef24d3b161bb98947540c3e1c64f00071672b8 100644 (file)
@@ -52,7 +52,7 @@
     <!-- Sonar jacoco plugin to get integration test coverage info -->
     <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
     <sonar.jacoco.reportPath>../implementation/target/jacoco.exec</sonar.jacoco.reportPath>
-    <sonar.jacoco.itReportPath>../implementaiton/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+    <sonar.jacoco.itReportPath>../implementation/target/jacoco-it.exec</sonar.jacoco.itReportPath>
     <sonar.language>java</sonar.language>
   </properties>
   <build>
@@ -69,7 +69,7 @@
       <plugin>
         <groupId>org.jacoco</groupId>
         <artifactId>jacoco-maven-plugin</artifactId>
-        <version>0.5.3.201107060350</version>
+        <version>${jacoco.version}</version>
         <configuration>
           <destFile>../implementation/target/jacoco-it.exec</destFile>
           <includes>org.opendaylight.controller.*</includes>
index c0a8064493d6d303ba24fb75466751f8f8c75aa0..d6bd287434a499c19b1aa1576b0aa11ee303344d 100644 (file)
@@ -30,7 +30,7 @@
         <plugin>
           <groupId>org.jacoco</groupId>
           <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.5.3.201107060350</version>
+          <version>${jacoco.version}</version>
         </plugin>
       </plugins>
     </pluginManagement>
index fabf3e9f1d704413346d97b98c561e8d2adc8a16..90299e5ac960dcbd34c63df4cd8418c5b57ddf5f 100644 (file)
@@ -39,7 +39,7 @@ import org.opendaylight.controller.clustering.services.ListenRoleChangeAddExcept
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-abstract public class ClusterManagerCommon implements IClusterServicesCommon {
+public abstract class ClusterManagerCommon implements IClusterServicesCommon {
     protected String containerName = null;
     private IClusterServices clusterService = null;
     protected static final Logger logger = LoggerFactory
index 035b0d3433e413b928e4ce753f9bea1d034e0218..975f97c8e5104a75ef56080ca5d59717098cb38c 100644 (file)
@@ -45,7 +45,7 @@ import org.apache.felix.dm.Component;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-abstract public class ClusterManagerCommon implements IClusterServicesCommon {
+public abstract class ClusterManagerCommon implements IClusterServicesCommon {
     protected String containerName = "";
     protected static final Logger logger = LoggerFactory
             .getLogger(ClusterManagerCommon.class);
index 075ccb1bfa58bff729814c4ccd65eaa2dbb17458..31dd741cfdb0d7cfa8328e26cc639c94769f208b 100644 (file)
     <sample-toaster.version>1.0-SNAPSHOT</sample-toaster.version>
     <releaseplugin.version>2.3.2</releaseplugin.version>
     <commons.lang.version>3.1</commons.lang.version>
+    <jacoco.version>0.5.3.201107060350</jacoco.version>
   </properties>
 
   <pluginRepositories>
     <pluginRepository>
-      <id>central2</id>
-      <name>central2</name>
-      <url>http://repo2.maven.org/maven2</url>
+      <id>central</id>
+      <name>maven repo1</name>
+      <url>http://repo1.maven.org/maven2</url>
     </pluginRepository>
   </pluginRepositories>
 
       <name>ebr-bundles-external</name>
       <url>${nexusproxy}/repositories/ebr-bundles-external/</url>
     </repository>
-    <repository>
-      <id>central2</id>
-      <name>central2</name>
-      <url>http://repo2.maven.org/maven2</url>
-      <snapshots>
-        <enabled>false</enabled>
-      </snapshots>
-      <releases>
-          <enabled>true</enabled>
-      </releases>
-    </repository>
     <repository>
       <id>central</id>
       <name>central</name>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
         <version>${surefire.version}</version>
-        <configuration>
-          <argLine>${testvm.argLine}</argLine>
-        </configuration>
       </plugin>
     </plugins>
     <pluginManagement>
       <artifactId>jersey-json</artifactId>
       <version>${jersey.version}</version>
     </dependency>
+    <dependency>
+        <groupId>org.ow2.asm</groupId>
+        <artifactId>asm-all</artifactId>
+        <version>4.1</version>
+    </dependency>
   </dependencies>
 </project>
diff --git a/opendaylight/connectionmanager/api/src/main/java/org/opendaylight/controller/connectionmanager/ConnectionLocality.java b/opendaylight/connectionmanager/api/src/main/java/org/opendaylight/controller/connectionmanager/ConnectionLocality.java
new file mode 100644 (file)
index 0000000..347ca07
--- /dev/null
@@ -0,0 +1,28 @@
+package org.opendaylight.controller.connectionmanager;
+
+public enum ConnectionLocality {
+    /**
+     * This controller is the (or one of the) master for a given node
+     */
+    LOCAL("This controller is the (or one of the) master for a given node"),
+
+    /**
+     * This controller is not the master for a given node
+     */
+    NOT_LOCAL("This controller is not the master for a given node"),
+
+    /**
+     * The given node is not connected to any of the controllers in the cluster
+     */
+    NOT_CONNECTED("The given node is not connected to any of the controllers in the cluster");
+
+    private ConnectionLocality(String description) {
+        this.description = description;
+    }
+
+    private String description;
+
+    public String toString() {
+        return description;
+    }
+}
index 12b196989e4a0c4fa1f608cd7a479d224064555c..788af16248ccd62c8cc0760dbcb20134983b3cac 100644 (file)
@@ -54,12 +54,27 @@ public interface IConnectionManager {
     public Set<Node> getLocalNodes();
 
     /**
+     * @deprecated Use getLocalityStatus(Node node) instead.
+     *
      * Method to test if a node is local to a controller.
      *
-     * @return true if node is local to this controller. false otherwise.
+     * @param node The node for which the locality is being tested
+     * @return true if node is local to this controller.<br>
+     *         false if either node is not connected to this controller or
+     *         not connected to any other controllers in the cluster.
      */
     public boolean isLocal(Node node);
 
+    /**
+     * getLocalityStatus provides the tri-state connectivity status as opposed to the
+     * binary status returned by isLocal.
+     * ConnectionLocality enum that is returned by this method also includes the case of
+     * a Node not connected to any of the controllers in the cluster.
+     * @param node The node for which the locality is being verified
+     * @return ConnectionLocality
+     */
+    public ConnectionLocality getLocalityStatus(Node node);
+
     /**
      * Disconnect a Node from the controller.
      *
index bd377190f2d2f2911f3ae9b43edda2b2b0c39bc2..df5175083b1870ef99b29443d42003eb2bb179c5 100644 (file)
@@ -37,6 +37,7 @@ import org.eclipse.osgi.framework.console.CommandProvider;
 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
 import org.opendaylight.controller.clustering.services.ICoordinatorChangeAware;
+import org.opendaylight.controller.connectionmanager.ConnectionLocality;
 import org.opendaylight.controller.connectionmanager.ConnectionMgmtScheme;
 import org.opendaylight.controller.connectionmanager.IConnectionManager;
 import org.opendaylight.controller.connectionmanager.scheme.AbstractScheme;
@@ -185,6 +186,13 @@ public class ConnectionManager implements IConnectionManager, IConnectionListene
         return scheme.isLocal(node);
     }
 
+    @Override
+    public ConnectionLocality getLocalityStatus(Node node) {
+        AbstractScheme scheme = schemes.get(activeScheme);
+        if (scheme == null) return ConnectionLocality.NOT_CONNECTED;
+        return scheme.getLocalityStatus(node);
+    }
+
     @Override
     public void updateNode(Node node, UpdateType type, Set<Property> props) {
         logger.debug("updateNode: {} type {} props {}", node, type, props);
index 06b72219f7fbddc5b5b17357f421f003691a36f7..78f274c717585993d13a3deeb86812a32ad4ad5a 100644 (file)
@@ -14,6 +14,7 @@ import org.opendaylight.controller.clustering.services.CacheConfigException;
 import org.opendaylight.controller.clustering.services.CacheExistException;
 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
 import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.connectionmanager.ConnectionLocality;
 import org.opendaylight.controller.connectionmanager.ConnectionMgmtScheme;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.utils.Status;
@@ -146,6 +147,15 @@ public abstract class AbstractScheme {
         return (controllers != null && controllers.contains(myController));
     }
 
+    public ConnectionLocality getLocalityStatus(Node node) {
+        if (nodeConnections == null) return ConnectionLocality.NOT_CONNECTED;
+        Set<InetAddress> controllers = nodeConnections.get(node);
+        if (controllers == null || controllers.size() == 0) return ConnectionLocality.NOT_CONNECTED;
+        InetAddress myController = clusterServices.getMyAddress();
+        return controllers.contains(myController) ? ConnectionLocality.LOCAL:
+                                                    ConnectionLocality.NOT_LOCAL;
+    }
+
     public Status removeNode (Node node) {
         return removeNodeFromController(node, clusterServices.getMyAddress());
     }
index 01715cc1bf1e98960266f1832460aec1b74942e2..89bf424e67a4465c885c82b2ec3206d559709064 100644 (file)
@@ -223,7 +223,7 @@ public class ContainerConfig implements Serializable {
      */
     private Status validateName() {
         // No Container configuration allowed to container default
-        return (container.matches(regexName) && !container.equalsIgnoreCase(GlobalConstants.DEFAULT.toString())) ?
+        return ((container != null) && container.matches(regexName) && !container.equalsIgnoreCase(GlobalConstants.DEFAULT.toString())) ?
                 new Status(StatusCode.SUCCESS) : new Status(StatusCode.BADREQUEST, "Invalid container name");
     }
 
@@ -386,11 +386,38 @@ public class ContainerConfig implements Serializable {
                             config.getName()));
                 }
             }
+        } else {
+            // Check for conflicting names with existing cFlows
+            List<String> conflicting = new ArrayList<String>(existingNames);
+            conflicting.retainAll(proposedNames);
+            if (!conflicting.isEmpty()) {
+                return new Status(StatusCode.CONFLICT,
+                        "Invalid Flow Spec configuration: flow spec name(s) conflict with existing flow specs: "
+                                + conflicting.toString());
+            }
+
+            /*
+             * Check for conflicting flow spec match (we only check for strict
+             * equality). Remove this in case (*) is reintroduced
+             */
+            if (this.containerFlows != null && !this.containerFlows.isEmpty()) {
+                Set<Match> existingMatches = new HashSet<Match>();
+                for (ContainerFlowConfig existing : this.containerFlows) {
+                    existingMatches.addAll(existing.getMatches());
+                }
+                for (ContainerFlowConfig proposed : cFlowConfigs) {
+                    if (existingMatches.removeAll(proposed.getMatches())) {
+                        return new Status(StatusCode.CONFLICT, String.format(
+                                "Invalid Flow Spec configuration: %s conflicts with existing flow spec",
+                                proposed.getName()));
+                    }
+                }
+            }
         }
+
         /*
          * Revisit the following flow-spec confict validation later based on more testing.
-         */
-         /*
+         * (*)
         if (!delete) {
             // Check for overlapping container flows in the request
             int size = cFlowConfigs.size();
index b5624af6afc8e916572bad446ab1e1438a166b3a..24ef0c08ef9d78a4f3410ded6f998af0281065d3 100644 (file)
@@ -192,8 +192,7 @@ public class ContainerManager implements IContainerManager {
 
     @Override
     public boolean doesContainerExist(String ContainerId) {
-        // TODO Auto-generated method stub
-        return false;
+        return GlobalConstants.DEFAULT.toString().equalsIgnoreCase(ContainerId);
     }
 
     @Override
index 56ca0c951be5a0c2a0664a70e7f6ac5aa4ada061..3efd97e2aa3857fa549e752ae16d1aa6990ab0f3 100644 (file)
@@ -74,7 +74,7 @@
     <module>../../statisticsmanager/api</module>
     <module>../../statisticsmanager/implementation</module>
     <module>../../statisticsmanager/integrationtest</module>
-    <module>../../topologymanager</module>
+    <module>../../topologymanager/implementation</module>
     <module>../../usermanager/api</module>
     <module>../../usermanager/implementation</module>
     <module>../../connectionmanager/api</module>
 
     <!-- Northbound bundles -->
     <module>../../northbound/commons</module>
+    <module>../../northbound/bundlescanner/api</module>
+    <module>../../northbound/bundlescanner/implementation</module>
     <module>../../northbound/topology</module>
     <module>../../northbound/staticrouting</module>
     <module>../../northbound/statistics</module>
index 970929f794b93d2e329ddbfa7b5684b51fbf043a..12f18ff6452b1cbec6f9a6d4bec1c6949b1d2836 100644 (file)
@@ -94,3 +94,6 @@ controllerKeyStore=
 controllerKeyStorePassword=
 controllerTrustStore=
 controllerTrustStorePassword=
+
+# User Manager configurations
+enableStrongPasswordCheck = false
index ee2113db8287066f7337a147ade4e7d9048bf2ea..1318c97ce22e40016fb113a4d1c46d524eba7c1b 100644 (file)
@@ -28,8 +28,8 @@ public class FlowEntryInstall implements Serializable {
     private final FlowEntry original;
     private final ContainerFlow cFlow;
     private final FlowEntry install;
-    transient private long requestId; // async request id
-    transient private boolean deletePending;
+    private transient long requestId; // async request id
+    private transient boolean deletePending;
 
     public FlowEntryInstall(FlowEntry original, ContainerFlow cFlow) {
         this.original = original;
index ea55ac8b08951f14191cbcd900a6309c7154fcfc..d146eead6f0168e7e25cdd290459fb5ff20be7d2 100644 (file)
@@ -33,7 +33,7 @@
         <plugin>
           <groupId>org.jacoco</groupId>
           <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.5.3.201107060350</version>
+          <version>${jacoco.version}</version>
         </plugin>
       </plugins>
     </pluginManagement>
index 5220428199c41920b50d2fcbc676e98ea52f3959..672a290a2427f6bb1676ab31f3b72e21ffaa922e 100644 (file)
@@ -27,9 +27,9 @@ public final class FlowEntryDistributionOrder implements Serializable {
      * Serialization UID
      */
     private static final long serialVersionUID = 416280377113255147L;
-    final private FlowEntryInstall entry;
-    final private UpdateType upType;
-    final private InetAddress requestorController;
+    private final FlowEntryInstall entry;
+    private final UpdateType upType;
+    private final InetAddress requestorController;
 
     /**
      * @return the entry
index 7feb7018ae65ee28ee3c4a0f769fb5660d4694f2..6e3e6b6633b0fc6098ee6795dac661df71a20fed 100644 (file)
@@ -39,6 +39,7 @@ import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
 import org.opendaylight.controller.clustering.services.IClusterServices;
 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
+import org.opendaylight.controller.connectionmanager.ConnectionLocality;
 import org.opendaylight.controller.connectionmanager.IConnectionManager;
 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
 import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
@@ -273,7 +274,7 @@ public class ForwardingRulesManager implements
         }
 
         Node n = e.getNode();
-        if (!connectionManager.isLocal(n)) {
+        if (connectionManager.getLocalityStatus(n) == ConnectionLocality.NOT_LOCAL) {
             Callable<Future<Status>> worker = new DistributeOrderCallable(e, u, t);
             if (worker != null) {
                 Future<Future<Status>> workerRes = this.executor.submit(worker);
@@ -291,7 +292,7 @@ public class ForwardingRulesManager implements
             }
         }
 
-        logsync.trace("LOCAL Node {} so processing Entry:{} UpdateType:{}", n, e, t);
+        logsync.trace("Node {} could be local. so processing Entry:{} UpdateType:{}", n, e, t);
         return null;
     }
 
@@ -2100,51 +2101,78 @@ public class ForwardingRulesManager implements
         addStaticFlowInternal(allowARP, true); // skip validation on internal static flow name
     }
 
+    /**
+     * (non-Javadoc)
+     *
+     * @see org.opendaylight.controller.switchmanager.ISwitchManagerAware#modeChangeNotify(org.opendaylight.controller.sal.core.Node,
+     *      boolean)
+     *
+     *      This method can be called from within the OSGi framework context,
+     *      given the programming operation can take sometime, it not good
+     *      pratice to have in it's context operations that can take time,
+     *      hence moving off to a different thread for async processing.
+     */
     @Override
-    public void modeChangeNotify(Node node, boolean proactive) {
-        List<FlowConfig> defaultConfigs = new ArrayList<FlowConfig>();
-
-        List<String> puntAction = new ArrayList<String>();
-        puntAction.add(ActionType.CONTROLLER.toString());
-
-        FlowConfig allowARP = new FlowConfig();
-        allowARP.setInstallInHw(true);
-        allowARP.setName(FlowConfig.INTERNALSTATICFLOWBEGIN + "Punt ARP" + FlowConfig.INTERNALSTATICFLOWEND);
-        allowARP.setPriority("1");
-        allowARP.setNode(node);
-        allowARP.setEtherType("0x" + Integer.toHexString(EtherTypes.ARP.intValue()).toUpperCase());
-        allowARP.setActions(puntAction);
-        defaultConfigs.add(allowARP);
-
-        FlowConfig allowLLDP = new FlowConfig();
-        allowLLDP.setInstallInHw(true);
-        allowLLDP.setName(FlowConfig.INTERNALSTATICFLOWBEGIN + "Punt LLDP" + FlowConfig.INTERNALSTATICFLOWEND);
-        allowLLDP.setPriority("1");
-        allowLLDP.setNode(node);
-        allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue()).toUpperCase());
-        allowLLDP.setActions(puntAction);
-        defaultConfigs.add(allowLLDP);
-
-        List<String> dropAction = new ArrayList<String>();
-        dropAction.add(ActionType.DROP.toString());
-
-        FlowConfig dropAllConfig = new FlowConfig();
-        dropAllConfig.setInstallInHw(true);
-        dropAllConfig.setName(FlowConfig.INTERNALSTATICFLOWBEGIN + "Catch-All Drop" + FlowConfig.INTERNALSTATICFLOWEND);
-        dropAllConfig.setPriority("0");
-        dropAllConfig.setNode(node);
-        dropAllConfig.setActions(dropAction);
-        defaultConfigs.add(dropAllConfig);
-
-        log.info("Forwarding mode for node {} set to {}", node, (proactive ? "proactive" : "reactive"));
-        for (FlowConfig fc : defaultConfigs) {
-            Status status = (proactive) ? addStaticFlowInternal(fc, false) : removeStaticFlow(fc);
-            if (status.isSuccess()) {
-                log.info("{} Proactive Static flow: {}", (proactive ? "Installed" : "Removed"), fc.getName());
-            } else {
-                log.warn("Failed to {} Proactive Static flow: {}", (proactive ? "install" : "remove"), fc.getName());
+    public void modeChangeNotify(final Node node, final boolean proactive) {
+        Callable<Status> modeChangeCallable = new Callable<Status>() {
+            @Override
+            public Status call() throws Exception {
+                List<FlowConfig> defaultConfigs = new ArrayList<FlowConfig>();
+
+                List<String> puntAction = new ArrayList<String>();
+                puntAction.add(ActionType.CONTROLLER.toString());
+
+                FlowConfig allowARP = new FlowConfig();
+                allowARP.setInstallInHw(true);
+                allowARP.setName(FlowConfig.INTERNALSTATICFLOWBEGIN + "Punt ARP" + FlowConfig.INTERNALSTATICFLOWEND);
+                allowARP.setPriority("1");
+                allowARP.setNode(node);
+                allowARP.setEtherType("0x" + Integer.toHexString(EtherTypes.ARP.intValue())
+                        .toUpperCase());
+                allowARP.setActions(puntAction);
+                defaultConfigs.add(allowARP);
+
+                FlowConfig allowLLDP = new FlowConfig();
+                allowLLDP.setInstallInHw(true);
+                allowLLDP.setName(FlowConfig.INTERNALSTATICFLOWBEGIN + "Punt LLDP" + FlowConfig.INTERNALSTATICFLOWEND);
+                allowLLDP.setPriority("1");
+                allowLLDP.setNode(node);
+                allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue())
+                        .toUpperCase());
+                allowLLDP.setActions(puntAction);
+                defaultConfigs.add(allowLLDP);
+
+                List<String> dropAction = new ArrayList<String>();
+                dropAction.add(ActionType.DROP.toString());
+
+                FlowConfig dropAllConfig = new FlowConfig();
+                dropAllConfig.setInstallInHw(true);
+                dropAllConfig.setName(FlowConfig.INTERNALSTATICFLOWBEGIN + "Catch-All Drop"
+                        + FlowConfig.INTERNALSTATICFLOWEND);
+                dropAllConfig.setPriority("0");
+                dropAllConfig.setNode(node);
+                dropAllConfig.setActions(dropAction);
+                defaultConfigs.add(dropAllConfig);
+
+                log.info("Forwarding mode for node {} set to {}", node, (proactive ? "proactive" : "reactive"));
+                for (FlowConfig fc : defaultConfigs) {
+                    Status status = (proactive) ? addStaticFlowInternal(fc, false) : removeStaticFlow(fc);
+                    if (status.isSuccess()) {
+                        log.info("{} Proactive Static flow: {}", (proactive ? "Installed" : "Removed"), fc.getName());
+                    } else {
+                        log.warn("Failed to {} Proactive Static flow: {}", (proactive ? "install" : "remove"),
+                                fc.getName());
+                    }
+                }
+                return new Status(StatusCode.SUCCESS);
             }
-        }
+        };
+
+        /*
+         * Execute the work outside the caller context, this could be an
+         * expensive operation and we don't want to block the caller for it.
+         */
+        this.executor.submit(modeChangeCallable);
     }
 
     /**
@@ -3082,7 +3110,7 @@ public class ForwardingRulesManager implements
                 return;
             }
             Node n = fei.getNode();
-            if (connectionManager.isLocal(n)) {
+            if (connectionManager.getLocalityStatus(n) == ConnectionLocality.LOCAL) {
                 logsync.trace("workOrder for fe {} processed locally", fe);
                 // I'm the controller in charge for the request, queue it for
                 // processing
index 77792435991ce414a6edf14590b7f9fe071a9b56..32cae25dba5aec22aa4b67a070f7b5848ce31014 100644 (file)
     <!-- Sonar jacoco plugin to get integration test coverage info -->
     <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
     <sonar.jacoco.reportPath>../implementation/target/jacoco.exec</sonar.jacoco.reportPath>
-    <sonar.jacoco.itReportPath>../implementaiton/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+    <sonar.jacoco.itReportPath>../implementation/target/jacoco-it.exec</sonar.jacoco.itReportPath>
     <sonar.language>java</sonar.language>
   </properties>
   <build>
       <plugin>
         <groupId>org.jacoco</groupId>
         <artifactId>jacoco-maven-plugin</artifactId>
-        <version>0.5.3.201107060350</version>
+        <version>${jacoco.version}</version>
         <configuration>
           <destFile>../implementation/target/jacoco-it.exec</destFile>
           <includes>org.opendaylight.controller.*</includes>
index 268dd4f67f6039f9bde419b8a726d4fe23063ac7..e93559b42ccae19ac461607d5680b4a3db1e0ec6 100644 (file)
@@ -33,7 +33,7 @@
         <plugin>
           <groupId>org.jacoco</groupId>
           <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.5.3.201107060350</version>
+          <version>${jacoco.version}</version>
         </plugin>
       </plugins>
     </pluginManagement>
index 81551650c34fe2a0eb49d0afeb2405ec75de4549..f2fefcdabcc05e7265ba811dbb9acd90fc14e4e1 100644 (file)
       <plugin>\r
         <groupId>org.jacoco</groupId>\r
         <artifactId>jacoco-maven-plugin</artifactId>\r
-        <version>0.5.3.201107060350</version>\r
+        <version>${jacoco.version}</version>\r
         <configuration>\r
           <destFile>../implementation/target/jacoco-it.exec</destFile>\r
           <includes>org.opendaylight.controller.*</includes>\r
index af2ea7b3475970cde2db15dfd660e13cdf177144..dfc2955cfd9679f8c7f3eca2ca4fb60fcf5ef2c5 100644 (file)
@@ -22,7 +22,7 @@
     <!-- Sonar properties using jacoco to retrieve integration test results -->
     <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
     <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
-    <sonar.jacoco.Reportpath>target/jacoco.exec</sonar.jacoco.Reportpath>
+    <sonar.jacoco.reportpath>target/jacoco.exec</sonar.jacoco.reportpath>
     <sonar.jacoco.itReportPath>target/jacoco-it.exec</sonar.jacoco.itReportPath>
     <sonar.language>java</sonar.language>
   </properties>
@@ -33,7 +33,7 @@
         <plugin>
           <groupId>org.jacoco</groupId>
           <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.5.3.201107060350</version>
+          <version>${jacoco.version}</version>
         </plugin>
       </plugins>
     </pluginManagement>
diff --git a/opendaylight/md-sal/sal-compability/pom.xml b/opendaylight/md-sal/sal-compability/pom.xml
new file mode 100644 (file)
index 0000000..e3d8c58
--- /dev/null
@@ -0,0 +1,45 @@
+<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>
+               <groupId>org.opendaylight.controller</groupId>
+               <artifactId>sal-parent</artifactId>
+               <version>1.0-SNAPSHOT</version>
+               <relativePath>../../sal/yang-prototype/sal/pom.xml</relativePath>
+       </parent>
+       <artifactId>sal-compability</artifactId>
+
+       <dependencies>
+               <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>sal</artifactId>
+                       <version>0.5.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller.model</groupId>
+                       <artifactId>model-flow-service</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller.model</groupId>
+                       <artifactId>model-flow-statistics</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>sal-binding-api</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>sal-common-util</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>com.google.guava</groupId>
+                       <artifactId>guava</artifactId>
+                       <type>bundle</type>
+                       <version>14.0.1</version>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalConversionsUtils.java b/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalConversionsUtils.java
new file mode 100644 (file)
index 0000000..c113cd8
--- /dev/null
@@ -0,0 +1,349 @@
+package org.opendaylight.controller.sal.compability;
+
+import static org.opendaylight.controller.sal.match.MatchType.DL_DST;
+import static org.opendaylight.controller.sal.match.MatchType.DL_SRC;
+import static org.opendaylight.controller.sal.match.MatchType.DL_TYPE;
+import static org.opendaylight.controller.sal.match.MatchType.DL_VLAN;
+import static org.opendaylight.controller.sal.match.MatchType.DL_VLAN_PR;
+import static org.opendaylight.controller.sal.match.MatchType.NW_DST;
+import static org.opendaylight.controller.sal.match.MatchType.NW_PROTO;
+import static org.opendaylight.controller.sal.match.MatchType.NW_SRC;
+import static org.opendaylight.controller.sal.match.MatchType.NW_TOS;
+import static org.opendaylight.controller.sal.match.MatchType.TP_DST;
+import static org.opendaylight.controller.sal.match.MatchType.TP_SRC;
+
+import java.net.InetAddress;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.action.Controller;
+import org.opendaylight.controller.sal.action.Output;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.match.Match;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Dscp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.action.action.ControllerAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.action.action.OutputAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.action.action.PopMplsAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.action.action.PushMplsAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.action.action.PushPbbAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.action.action.PushVlanAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.action.action.SetMplsTtlAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.action.action.SetNwTtlAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.action.action.SetQueueAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.flow.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanPcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.MacAddressFilter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.ethernet.match.fields.EthernetType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.match.EthernetMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.match.IpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.match.Layer3Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.match.Layer4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.match.VlanMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.match.layer._3.match.ArpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.match.layer._3.match.Ipv4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.match.layer._3.match.Ipv6Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.match.layer._4.match.SctpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.match.layer._4.match.TcpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.match.layer._4.match.UdpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev130819.vlan.match.fields.VlanId;
+
+import com.google.common.net.InetAddresses;
+
+public class ToSalConversionsUtils {
+
+    private ToSalConversionsUtils() {
+
+    }
+
+    public static Flow flowFrom(NodeFlow source) {
+        final Flow target = new Flow();
+
+        Integer hardTimeout = source.getHardTimeout();
+        if (hardTimeout != null) {
+            target.setHardTimeout(hardTimeout.shortValue());
+        }
+
+        Integer idleTimeout = source.getIdleTimeout();
+        if (idleTimeout != null) {
+            target.setIdleTimeout(idleTimeout.shortValue());
+        }
+
+        Integer priority = source.getPriority();
+        if (priority != null) {
+            target.setPriority(priority.shortValue());
+        }
+
+        target.setMatch(matchFrom(source.getMatch()));
+
+        List<Action> actions = source.getAction();
+        if (actions != null) {
+            for (Action sourceAction : actions) {
+                Set<org.opendaylight.controller.sal.action.Action> targetActions = actionFrom(sourceAction);
+                for (org.opendaylight.controller.sal.action.Action targetAction : targetActions) {
+                    target.addAction(targetAction);
+                }
+            }
+        }
+
+        target.setId(source.getCookie().longValue());
+        return target;
+    }
+
+    public static Set<org.opendaylight.controller.sal.action.Action> actionFrom(Action source) {
+        org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.action.Action sourceAction = source
+                .getAction();
+        Set<org.opendaylight.controller.sal.action.Action> targetAction = new HashSet<>();
+        if (sourceAction instanceof ControllerAction) {
+            targetAction.add(new Controller());
+        } else if (sourceAction instanceof OutputAction) {
+
+            List<Uri> nodeConnectors = ((OutputAction) sourceAction).getOutputNodeConnector();
+            for (Uri uri : nodeConnectors) {
+                targetAction.add(new Output(fromNodeConnectorRef(uri)));
+            }
+        } else if (sourceAction instanceof PopMplsAction) {
+            // TODO: define maping
+        } else if (sourceAction instanceof PushMplsAction) {
+            // TODO: define maping
+        } else if (sourceAction instanceof PushPbbAction) {
+            // TODO: define maping
+        } else if (sourceAction instanceof PushVlanAction) {
+            // TODO: define maping
+            // PushVlanAction vlanAction = (PushVlanAction) sourceAction;
+            // targetAction.add(new PushVlan(vlanAction., pcp, cfi, vlanId);
+        } else if (sourceAction instanceof SetMplsTtlAction) {
+            // TODO: define maping
+            // targetAction = //no action to map
+        } else if (sourceAction instanceof SetNwTtlAction) {
+            // TODO: define maping
+        } else if (sourceAction instanceof SetQueueAction) {
+            // TODO: define maping
+            // targetAction = //no action to map
+        }
+
+        return targetAction;
+    }
+
+    private static NodeConnector fromNodeConnectorRef(Uri uri) {
+        // TODO: Define mapping
+        return null;
+    }
+
+    public static Match matchFrom(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.flow.Match source) {
+        Match target = new Match();
+        if (source != null) {
+            fillFrom(target, source.getVlanMatch());
+            fillFrom(target, source.getEthernetMatch());
+            fillFrom(target, source.getLayer3Match());
+            fillFrom(target, source.getLayer4Match());
+            fillFrom(target, source.getIpMatch());
+        }
+
+        return target;
+    }
+
+    private static void fillFrom(Match target, VlanMatch vlanMatch) {
+        if (vlanMatch != null) {
+            VlanId vlanId = vlanMatch.getVlanId();
+            if (vlanId != null) {
+                org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId vlanIdInner = vlanId
+                        .getVlanId();
+                if (vlanIdInner != null) {
+                    Integer vlanValue = vlanIdInner.getValue();
+                    if (vlanValue != null) {
+                        target.setField(DL_VLAN, vlanValue.shortValue());
+                    }
+                }
+            }
+            VlanPcp vlanPcp = vlanMatch.getVlanPcp();
+            if (vlanPcp != null) {
+                Short vlanPcpValue = vlanPcp.getValue();
+                if (vlanPcpValue != null) {
+                    target.setField(DL_VLAN_PR, vlanPcpValue.byteValue());
+                }
+            }
+        }
+    }
+
+    private static void fillFrom(Match target, IpMatch ipMatch) {
+        if (ipMatch != null) {
+            Short ipProtocol = ipMatch.getIpProtocol();
+            if (ipProtocol != null) {
+                target.setField(NW_PROTO, ipProtocol.byteValue());
+            }
+            Dscp dscp = ipMatch.getIpDscp();
+            if (dscp != null) {
+                Short dscpValue = dscp.getValue();
+                if (dscpValue != null) {
+                    target.setField(NW_TOS, dscpValue.byteValue());
+                }
+            }
+        }
+    }
+
+    private static void fillFrom(Match target, Layer4Match layer4Match) {
+        if (layer4Match == null) {
+            return;
+        }
+        if (layer4Match instanceof SctpMatch) {
+            fillTransportLayer(target, (SctpMatch) layer4Match);
+        } else if (layer4Match instanceof TcpMatch) {
+            fillTransportLayer(target, (TcpMatch) layer4Match);
+        } else if (layer4Match instanceof UdpMatch) {
+            fillTransportLayer(target, (UdpMatch) layer4Match);
+        }
+    }
+
+    private static void fillTransportLayer(Match target, UdpMatch source) {
+        PortNumber udpSourcePort = source.getUdpSourcePort();
+        if (udpSourcePort != null) {
+            Integer udpSourcePortValue = udpSourcePort.getValue();
+            if (udpSourcePortValue != null) {
+                target.setField(TP_SRC, udpSourcePortValue.shortValue());
+            }
+        }
+
+        PortNumber udpDestPort = source.getUdpDestinationPort();
+        if (udpDestPort != null) {
+            Integer udpDestPortValue = udpDestPort.getValue();
+            if (udpDestPortValue != null) {
+                target.setField(TP_DST, udpDestPortValue.shortValue());
+            }
+        }
+    }
+
+    private static void fillTransportLayer(Match target, TcpMatch source) {
+        PortNumber tcpSourcePort = source.getTcpSourcePort();
+        if (tcpSourcePort != null) {
+            Integer tcpSourcePortValue = tcpSourcePort.getValue();
+            if (tcpSourcePortValue != null) {
+                target.setField(TP_SRC, tcpSourcePortValue.shortValue());
+            }
+        }
+
+        PortNumber tcpDestPort = source.getTcpDestinationPort();
+        if (tcpDestPort != null) {
+            Integer tcpDestPortValue = tcpDestPort.getValue();
+            if (tcpDestPortValue != null) {
+                target.setField(TP_DST, tcpDestPortValue.shortValue());
+            }
+        }
+    }
+
+    private static void fillTransportLayer(Match target, SctpMatch source) {
+        PortNumber sctpSourcePort = source.getSctpSourcePort();
+        if (sctpSourcePort != null) {
+            Integer sctpSourcePortValue = sctpSourcePort.getValue();
+            if (sctpSourcePortValue != null) {
+                target.setField(TP_SRC, sctpSourcePortValue.shortValue());
+            }
+        }
+        PortNumber sctpDestPort = source.getSctpDestinationPort();
+        if (sctpDestPort != null) {
+            Integer sctpDestPortValue = sctpDestPort.getValue();
+            if (sctpDestPortValue != null) {
+                target.setField(TP_DST, sctpDestPortValue.shortValue());
+            }
+        }
+    }
+
+    private static void fillFrom(Match target, Layer3Match source) {
+        if (source == null)
+            return;
+        if (source instanceof Ipv4Match) {
+            fillFromIpv4(target, (Ipv4Match) source);
+        } else if (source instanceof Ipv6Match) {
+            fillFromIpv6(target, (Ipv6Match) source);
+        } else if (source instanceof ArpMatch) {
+            fillFromArp(target, (ArpMatch) source);
+        }
+    }
+
+    private static void fillFromArp(Match target, ArpMatch source) {
+        Ipv4Prefix sourceAddress = source.getArpSourceTransportAddress();
+        if (sourceAddress != null) {
+            target.setField(NW_SRC, (InetAddress) inetAddressFrom(sourceAddress), null);
+        }
+        Ipv4Prefix destAddress = source.getArpSourceTransportAddress();
+        if (destAddress != null) {
+            target.setField(NW_DST, (InetAddress) inetAddressFrom(destAddress), null);
+        }
+    }
+
+    private static void fillFromIpv6(Match target, Ipv6Match source) {
+        Ipv6Prefix sourceAddress = source.getIpv6Source();
+        if (sourceAddress != null) {
+            target.setField(NW_SRC, (InetAddress) inetAddressFrom(sourceAddress), null);
+        }
+        Ipv6Prefix destAddress = source.getIpv6Source();
+        if (destAddress != null) {
+            target.setField(NW_DST, (InetAddress) inetAddressFrom(destAddress), null);
+        }
+    }
+
+    private static void fillFromIpv4(Match target, Ipv4Match source) {
+        Ipv4Prefix sourceAddress = source.getIpv4Source();
+        if (sourceAddress != null) {
+            target.setField(NW_SRC, (InetAddress) inetAddressFrom(sourceAddress), null);
+        }
+        Ipv4Prefix destAddress = source.getIpv4Source();
+        if (destAddress != null) {
+            target.setField(NW_DST, (InetAddress) inetAddressFrom(destAddress), null);
+        }
+    }
+
+    private static InetAddress inetAddressFrom(Ipv4Prefix source) {
+        if (source != null) {
+            String[] parts = source.getValue().split("/");
+            return InetAddresses.forString(parts[0]);
+        }
+        return null;
+    }
+
+    private static InetAddress inetAddressFrom(Ipv6Prefix source) {
+        if (source != null) {
+            String[] parts = source.getValue().split("/");
+            return InetAddresses.forString(parts[0]);
+        }
+        return null;
+    }
+
+    private static void fillFrom(Match target, EthernetMatch source) {
+        if (source == null)
+            return;
+        EthernetType ethType = source.getEthernetType();
+        if (ethType != null) {
+            EtherType ethInnerType = ethType.getType();
+            if (ethInnerType != null) {
+                Long value = ethInnerType.getValue();
+                target.setField(DL_TYPE, value.shortValue());
+            }
+        }
+
+        MacAddressFilter ethSource = source.getEthernetSource();
+        if (ethSource != null) {
+            target.setField(DL_SRC, bytesFrom(ethSource.getAddress()));
+        }
+
+        MacAddressFilter ethDest = source.getEthernetDestination();
+        if (ethDest != null) {
+            target.setField(DL_DST, bytesFrom(ethDest.getAddress()));
+        }
+    }
+
+    private static byte[] bytesFrom(MacAddress address) {
+        if (address != null) {
+            return address.getValue().getBytes();
+        }
+        return null;
+    }
+}
diff --git a/opendaylight/northbound/bundlescanner/api/pom.xml b/opendaylight/northbound/bundlescanner/api/pom.xml
new file mode 100644 (file)
index 0000000..2c96ec2
--- /dev/null
@@ -0,0 +1,46 @@
+<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>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+    <relativePath>../../../commons/opendaylight</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>
+  </scm>
+
+  <artifactId>bundlescanner</artifactId>
+  <version>0.4.0-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>
+            <Import-Package>
+              org.osgi.framework,
+              org.slf4j,
+              javax.ws.rs,
+              javax.ws.rs.core,
+              javax.xml.bind.annotation,
+              javax.xml.bind,
+            </Import-Package>
+            <Export-Package>
+                org.opendaylight.controller.northbound.bundlescanner
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/opendaylight/northbound/bundlescanner/api/src/main/java/org/opendaylight/controller/northbound/bundlescanner/IBundleScanService.java b/opendaylight/northbound/bundlescanner/api/src/main/java/org/opendaylight/controller/northbound/bundlescanner/IBundleScanService.java
new file mode 100644 (file)
index 0000000..5cb0b63
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * 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.northbound.bundlescanner;
+
+import java.util.List;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * The bundle scan service provides services which allow introspection of
+ * bundle classes for detecting annotated classes. The scanning is performed
+ * when a bundle is RESOLVED.
+ */
+public interface IBundleScanService {
+    /**
+     * The list of annotations to be scanned
+     */
+    public final String[] ANNOTATIONS_TO_SCAN = {
+        "javax.xml.bind.annotation.*", // JAXB annotatinos
+        "javax.ws.rs.*"                // JAX-RS annotatinos
+    };
+
+
+    public List<Class<?>> getAnnotatedClasses(
+            BundleContext context,
+            String[] annotations,
+            boolean includeDependentBundleClasses);
+}
diff --git a/opendaylight/northbound/bundlescanner/implementation/pom.xml b/opendaylight/northbound/bundlescanner/implementation/pom.xml
new file mode 100644 (file)
index 0000000..ceea28e
--- /dev/null
@@ -0,0 +1,73 @@
+<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>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+    <relativePath>../../../commons/opendaylight</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>
+  </scm>
+
+  <artifactId>bundlescanner.implementation</artifactId>
+  <version>0.4.0-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>
+            <Import-Package>
+              org.apache.felix.dm,
+              org.objectweb.asm,
+              org.opendaylight.controller.sal.core,
+              org.opendaylight.controller.northbound.bundlescanner,
+              org.osgi.framework,
+              org.slf4j,
+              javax.ws.rs,
+              javax.ws.rs.core,
+              javax.xml.bind.annotation,
+              javax.xml.bind,
+            </Import-Package>
+            <Bundle-Activator>
+                org.opendaylight.controller.northbound.bundlescanner.internal.Activator
+            </Bundle-Activator>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+      <dependency>
+          <groupId>org.ow2.asm</groupId>
+          <artifactId>asm-all</artifactId>
+          <version>4.1</version>
+      </dependency>
+      <dependency>
+        <groupId>org.springframework.osgi</groupId>
+        <artifactId>spring-osgi-mock</artifactId>
+        <version>1.2.1</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>bundlescanner</artifactId>
+        <version>0.4.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal</artifactId>
+        <version>0.5.0-SNAPSHOT</version>
+      </dependency>
+  </dependencies>
+</project>
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/main/java/org/opendaylight/controller/northbound/bundlescanner/internal/Activator.java b/opendaylight/northbound/bundlescanner/implementation/src/main/java/org/opendaylight/controller/northbound/bundlescanner/internal/Activator.java
new file mode 100644 (file)
index 0000000..6b0718c
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * 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.northbound.bundlescanner.internal;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.northbound.bundlescanner.IBundleScanService;
+import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+
+/**
+ * The activator registers the BundleScanner.
+ */
+public class Activator extends ComponentActivatorAbstractBase {
+
+    @Override
+    protected void init() {
+    }
+
+    @Override
+    protected void destroy() {
+    }
+
+    @Override
+    protected Object[] getGlobalImplementations() {
+        return new Object[] { BundleScanServiceImpl.class };
+    }
+
+    @Override
+    protected void configureGlobalInstance(Component c, Object imp) {
+        if (!imp.equals(BundleScanServiceImpl.class)) return;
+        // export service
+        c.setInterface(
+                new String[] { IBundleScanService.class.getName() },
+                null);
+    }
+
+}
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/main/java/org/opendaylight/controller/northbound/bundlescanner/internal/BundleInfo.java b/opendaylight/northbound/bundlescanner/implementation/src/main/java/org/opendaylight/controller/northbound/bundlescanner/internal/BundleInfo.java
new file mode 100644 (file)
index 0000000..a108931
--- /dev/null
@@ -0,0 +1,162 @@
+/**
+ * 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.northbound.bundlescanner.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * BundleInfo holds information related to the bundle obtained during the
+ * bundle scan process.
+ */
+/*package*/ class BundleInfo {
+    private static final Logger LOGGER = LoggerFactory.getLogger(BundleInfo.class);
+
+    private final Bundle bundle;
+    private final Map<String, Set<String>> annotatedClasses;
+    private final Set<String> exportPkgs;
+    private final Set<String> importPkgs;
+
+    public BundleInfo(Bundle bundle, Map<String, Set<String>> classes) {
+        this.bundle = bundle;
+        this.annotatedClasses = classes;
+        Dictionary<String, String> dict = bundle.getHeaders();
+        this.importPkgs = parsePackages(dict.get(Constants.IMPORT_PACKAGE));
+        this.exportPkgs = parsePackages(dict.get(Constants.EXPORT_PACKAGE));
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(super.toString());
+        sb.append("{name:").append(bundle.getSymbolicName())
+          .append(" id:").append(getId())
+          .append(" annotated-classes:").append(annotatedClasses)
+          .append(" imports:").append(importPkgs)
+          .append(" exports:").append(exportPkgs).append("}");
+        return sb.toString();
+    }
+
+    public Bundle getBundle() {
+        return bundle;
+    }
+
+    public long getId() {
+        return bundle.getBundleId();
+    }
+
+    public List<Class<?>> getAnnotatedClasses(Pattern pattern) {
+        List<String> result = new ArrayList<String>();
+        for (Map.Entry<String, Set<String>> entry : annotatedClasses.entrySet()) {
+            if (matches(pattern, entry.getValue())) {
+                result.add(entry.getKey());
+            }
+        }
+        return BundleScanner.loadClasses(bundle, result);
+    }
+
+    private boolean matches(Pattern pattern, Set<String> values) {
+        if (pattern == null) return true;
+        //LOGGER.debug("Matching: {} {}", pattern.toString(), values);
+        for (String s : values) {
+            if (pattern.matcher(s).find()) return true;
+        }
+        return false;
+    }
+
+    public List<Class<?>> getAnnotatedClasses(
+            Collection<BundleInfo> allbundles,
+            Pattern pattern)
+    {
+        List<Class<?>> classes = getAnnotatedClasses(pattern);
+        processAnnotatedClassesInternal(this, allbundles, pattern,
+                new HashSet<BundleInfo>(), classes);
+        return classes;
+    }
+
+    private List<String> getExportedAnnotatedClasses(Pattern pattern) {
+        List<String> classes = new ArrayList<String>();
+        for (Map.Entry<String, Set<String>> entry : annotatedClasses.entrySet()) {
+            String cls = entry.getKey();
+            int idx = cls.lastIndexOf(".");
+            String pkg = (idx == -1 ? "" : cls.substring(0, idx));
+            // for a class to match, the package has to be exported and
+            // annotations should match the given pattern
+            if (exportPkgs.contains(pkg) && matches(pattern, entry.getValue())) {
+                classes.add(cls);
+            }
+        }
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("Found in bundle:{} exported classes:[{}]",
+                    getBundle().getSymbolicName(), classes);
+        }
+        return classes;
+    }
+
+    private static void processAnnotatedClassesInternal(
+            BundleInfo target,
+            Collection<BundleInfo> bundlesToScan,
+            Pattern pattern,
+            Collection<BundleInfo> visited,
+            List<Class<?>> classes)
+    {
+        for (BundleInfo other : bundlesToScan) {
+            if (other.getId() == target.getId()) continue;
+            if (target.isDependantOn(other)) {
+                if (!visited.contains(other)) {
+                    classes.addAll(BundleScanner.loadClasses(other.getBundle(),
+                            other.getExportedAnnotatedClasses(pattern)));
+                    visited.add(other);
+                    processAnnotatedClassesInternal(other, bundlesToScan,
+                            pattern, visited, classes);
+                }
+            }
+        }
+    }
+
+    private boolean isDependantOn(BundleInfo other) {
+        for (String pkg : importPkgs) {
+            if (other.exportPkgs.contains(pkg)) return true;
+        }
+        return false;
+    }
+
+    public List<BundleInfo> getDependencies(Collection<BundleInfo> bundles) {
+        List<BundleInfo> result = new ArrayList<BundleInfo>();
+        for(BundleInfo bundle : bundles) {
+            if (isDependantOn(bundle)) result.add(bundle);
+        }
+        return result;
+    }
+
+
+    private static Set<String> parsePackages(String packageString) {
+        if (packageString == null) return Collections.emptySet();
+        String[] packages = packageString.split(",");
+        Set<String> result = new HashSet<String>();
+        for (int i=0; i<packages.length; i++) {
+            String[] nameAndAttrs = packages[i].split(";");
+            String packageName = nameAndAttrs[0].trim();
+            result.add(packageName);
+        }
+        return result;
+    }
+
+}
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/main/java/org/opendaylight/controller/northbound/bundlescanner/internal/BundleScanServiceImpl.java b/opendaylight/northbound/bundlescanner/implementation/src/main/java/org/opendaylight/controller/northbound/bundlescanner/internal/BundleScanServiceImpl.java
new file mode 100644 (file)
index 0000000..ad6d8e9
--- /dev/null
@@ -0,0 +1,22 @@
+package org.opendaylight.controller.northbound.bundlescanner.internal;
+
+import java.util.List;
+
+import org.opendaylight.controller.northbound.bundlescanner.IBundleScanService;
+import org.osgi.framework.BundleContext;
+
+public class BundleScanServiceImpl implements IBundleScanService {
+
+    public BundleScanServiceImpl() {}
+
+
+    @Override
+    public List<Class<?>> getAnnotatedClasses(BundleContext context,
+            String[] annotations,
+            boolean includeDependentBundleClasses)
+    {
+        return BundleScanner.getInstance().getAnnotatedClasses(
+                context, annotations, includeDependentBundleClasses);
+    }
+
+}
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/main/java/org/opendaylight/controller/northbound/bundlescanner/internal/BundleScanner.java b/opendaylight/northbound/bundlescanner/implementation/src/main/java/org/opendaylight/controller/northbound/bundlescanner/internal/BundleScanner.java
new file mode 100644 (file)
index 0000000..3e517e9
--- /dev/null
@@ -0,0 +1,277 @@
+/**
+ * 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.northbound.bundlescanner.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+import org.opendaylight.controller.northbound.bundlescanner.IBundleScanService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.SynchronousBundleListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The custom bundle scanner scans annotations on bundles and is used for
+ * constructing JAXBContext instances. It listens for bundle events and updates
+ * the metadata in realtime.
+ */
+/*package*/ class BundleScanner implements SynchronousBundleListener {
+    private static final Logger LOGGER = LoggerFactory.getLogger(BundleScanner.class);
+    private static BundleScanner INSTANCE; // singleton
+
+    private final Pattern annotationPattern;
+    private final Map<Long,BundleInfo> bundleAnnotations =
+            new HashMap<Long, BundleInfo>();
+
+    public static synchronized BundleScanner getInstance() {
+        if (INSTANCE == null) {
+            INSTANCE = new BundleScanner();
+        }
+        return INSTANCE;
+    }
+
+    /*package*/ BundleScanner(Bundle[] bundles) {
+        annotationPattern = mergePatterns(IBundleScanService.ANNOTATIONS_TO_SCAN, true);
+        init(bundles);
+    }
+
+    /*package*/ BundleScanner() {
+        this(FrameworkUtil.getBundle(BundleScanner.class).getBundleContext().getBundles());
+    }
+
+    public List<Class<?>> getAnnotatedClasses(BundleContext context,
+            String[] annotations,
+            boolean includeDependentBundleClasses)
+    {
+        BundleInfo info = bundleAnnotations.get(context.getBundle().getBundleId());
+        if (info == null) return Collections.emptyList();
+        Pattern pattern = mergePatterns(annotations, false);
+        List<Class<?>> result = null;
+        if (includeDependentBundleClasses) {
+            result = info.getAnnotatedClasses(bundleAnnotations.values(), pattern);
+        } else {
+            result = info.getAnnotatedClasses(pattern);
+        }
+        LOGGER.debug("Annotated classes detected: {} matching: {}", result, pattern);
+        return result;
+    }
+
+    ////////////////////////////////////////////////////////////////
+    // SynchronousBundleListener implementation
+    ////////////////////////////////////////////////////////////////
+
+    @Override
+    public void bundleChanged(BundleEvent event) {
+        Bundle bundle = event.getBundle();
+        long id = bundle.getBundleId();
+        switch(event.getType()) {
+            case BundleEvent.RESOLVED :
+                scan(bundle);
+                return;
+            case BundleEvent.UNRESOLVED :
+            case BundleEvent.UNINSTALLED :
+                bundleAnnotations.remove(id);
+                return;
+        }
+    }
+
+
+    ////////////////////////////////////////////////////////////////
+    //  ClassVisitor implementation
+    ////////////////////////////////////////////////////////////////
+
+    private static class AnnotationDetector extends ClassVisitor {
+        private final Map<String, Set<String>> matchedClasses =
+                new HashMap<String, Set<String>>();
+
+        private final Pattern annotationsPattern;
+        private Set<String> annotations;
+        private String className;
+        private boolean accessible;
+        private boolean matchedAnnotation;
+
+        public AnnotationDetector(Pattern pattern) {
+            super(Opcodes.ASM4);
+            this.annotationsPattern = pattern;
+        }
+
+        public Map<String, Set<String>> getMatchedClasses() {
+            return new HashMap<String, Set<String>>(matchedClasses);
+        }
+
+        @Override
+        public void visit(int version, int access, String name, String signature,
+                String superName, String[] interfaces)
+        {
+            //LOGGER.debug("Visiting class:" + name);
+            className = name;
+            accessible = ((access & Opcodes.ACC_PUBLIC) == Opcodes.ACC_PUBLIC);
+            matchedAnnotation = false;
+            annotations = new HashSet<String>();
+        }
+
+        @Override
+        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+            //LOGGER.debug("Visiting annotation:" + desc);
+            annotations.add(signature2class(desc));
+            if (!matchedAnnotation) {
+                matchedAnnotation = (annotationsPattern == null ||
+                        annotationsPattern.matcher(desc).find());
+            }
+            return null;
+        }
+
+        @Override
+        public void visitEnd() {
+            if (matchedAnnotation && accessible) {
+                className = path2class(className);
+                matchedClasses.put(className, new HashSet<String>(annotations));
+            }
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////
+    // Helpers
+    ////////////////////////////////////////////////////////////////
+
+    private synchronized void init(Bundle[] bundles) {
+        for (Bundle bundle : bundles) {
+            int state = bundle.getState();
+            if (state == Bundle.RESOLVED ||
+                state == Bundle.STARTING ||
+                state == Bundle.ACTIVE)
+            {
+                scan(bundle);
+            }
+        }
+    }
+
+    private static String path2class(String path) {
+        return path.replace(".class", "").replaceAll("/", ".");
+    }
+
+    private static String class2path(String clz) {
+        return clz.replaceAll("\\.", "/");
+    }
+
+    @SuppressWarnings("unused")
+    private static String class2signature(String clz) {
+        return "L" + class2path(clz) + ";";
+    }
+
+    private static String signature2class(String sig) {
+        if (sig.startsWith("L") && sig.endsWith(";")) {
+            sig = sig.substring(1, sig.length()-1);
+        }
+        return path2class(sig);
+    }
+
+   private static List<URL> getBundleClasses(Bundle bundle, String[] pkgs) {
+        List<URL> result = new ArrayList<URL>();
+        boolean recurse = false;
+        if (pkgs == null) {
+            recurse = true;
+            pkgs = new String[] { "/" } ;
+        }
+        for (String pkg : pkgs) {
+            pkg = class2path(pkg);
+            final Enumeration<URL> e = bundle.findEntries(pkg, "*.class", recurse);
+            if (e != null) {
+                while (e.hasMoreElements()) {
+                    URL url = e.nextElement();
+                    result.add(url);
+                }
+            }
+        }
+        return result;
+    }
+
+    private synchronized void scan(Bundle bundle) {
+        AnnotationDetector detector = new AnnotationDetector(annotationPattern);
+        try {
+            for (URL u : getBundleClasses(bundle, null)) {
+                InputStream is = u.openStream();
+                new ClassReader(is).accept(detector, 0);
+                is.close();
+            }
+        } catch (IOException ioe) {
+            LOGGER.error("Error scanning classes in bundle: {}", bundle.getSymbolicName(), ioe);
+        }
+        Map<String, Set<String>> classes = detector.getMatchedClasses();
+        if (classes != null && classes.size() > 0) {
+            BundleInfo info = new BundleInfo(bundle, classes);
+            bundleAnnotations.put(bundle.getBundleId(),info);
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("bindings found in bundle: {}[{}] " +
+                        "dependencies {} classes {}", bundle.getSymbolicName(),
+                        bundle.getBundleId(),
+                        info.getDependencies(bundleAnnotations.values()),
+                        classes);
+            }
+        }
+        // find bundle dependencies
+    }
+
+    public static List<Class<?>> loadClasses(Bundle bundle,
+            Collection<String> annotatedClasses)
+    {
+        List<Class<?>> result = new ArrayList<Class<?>>();
+        for (String name : annotatedClasses) {
+            try {
+                result.add(bundle.loadClass(name));
+            } catch (Exception e) {
+                LOGGER.error("Unable to load class: {}", name, e);
+            }
+        }
+        return result;
+    }
+
+    public static Pattern mergePatterns(String[] patterns, boolean convert2signature) {
+        if (patterns == null || patterns.length == 0) {
+            return null;
+        }
+        StringBuilder regex = new StringBuilder();
+        for (String c : patterns) {
+            if (c.endsWith("*")) {
+                c = c.substring(0, c.length() - 1);
+            }
+            if (regex.length() > 0) regex.append("|");
+            regex.append("^");
+            if (convert2signature) {
+                regex.append("L").append(c.replaceAll("\\.", "/"));
+            } else {
+                regex.append(c);
+            }
+        }
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("Merged regex: [{}]", regex.toString());
+        }
+        return Pattern.compile(regex.toString());
+    }
+
+}
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/Animal.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/Animal.java
new file mode 100644 (file)
index 0000000..e9fb31f
--- /dev/null
@@ -0,0 +1,6 @@
+package bundle_base;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public abstract class Animal { }
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/BasePerson.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/BasePerson.java
new file mode 100644 (file)
index 0000000..831d66b
--- /dev/null
@@ -0,0 +1,10 @@
+package bundle_base;
+
+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 javax.xml.bind.annotation.XmlSeeAlso;
+
+@XmlRootElement
+public class BasePerson { }
\ No newline at end of file
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/Mammal.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/Mammal.java
new file mode 100644 (file)
index 0000000..53ab14d
--- /dev/null
@@ -0,0 +1,6 @@
+package bundle_base;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class Mammal extends Animal { }
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/NoAnnotation.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/NoAnnotation.java
new file mode 100644 (file)
index 0000000..b8f3d10
--- /dev/null
@@ -0,0 +1,3 @@
+package bundle_base;
+
+public class NoAnnotation { }
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/NonRelevantAnnotation.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/NonRelevantAnnotation.java
new file mode 100644 (file)
index 0000000..9429345
--- /dev/null
@@ -0,0 +1,6 @@
+package bundle_base;
+
+@Deprecated
+public class NonRelevantAnnotation {
+
+}
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/Person.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_base/Person.java
new file mode 100644 (file)
index 0000000..9a6acc0
--- /dev/null
@@ -0,0 +1,27 @@
+package bundle_base;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+@XmlTransient
+@Deprecated
+public class Person extends BasePerson {
+
+    @XmlElement
+    protected String name;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @XmlRootElement
+    public static class Info { }
+
+    @XmlRootElement
+    private static class PrivateInfo { }
+}
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_misc/Misc.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_misc/Misc.java
new file mode 100644 (file)
index 0000000..cb33ce9
--- /dev/null
@@ -0,0 +1,7 @@
+package bundle_misc;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class Misc {
+
+}
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub1/NoAnnotation.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub1/NoAnnotation.java
new file mode 100644 (file)
index 0000000..9a08fc9
--- /dev/null
@@ -0,0 +1,5 @@
+package bundle_sub1;
+
+public class NoAnnotation {
+
+}
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub1/Zoo.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub1/Zoo.java
new file mode 100644 (file)
index 0000000..1eadad6
--- /dev/null
@@ -0,0 +1,26 @@
+package bundle_sub1;
+
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import bundle_base.Animal;
+import bundle_base.Mammal;
+
+
+@XmlRootElement
+public class Zoo {
+    private Animal creature;
+
+    @XmlElementRef
+    public Animal getCreature() {
+        return creature;
+    }
+
+    public void setCreature(Animal creature) {
+        this.creature = creature;
+    }
+
+    public Zoo() {
+        creature = new Mammal();
+    }
+}
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub2/Agent.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub2/Agent.java
new file mode 100644 (file)
index 0000000..2b98270
--- /dev/null
@@ -0,0 +1,11 @@
+package bundle_sub2;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import bundle_base.Person;
+
+
+@XmlRootElement
+public class Agent extends Person {
+
+}
\ No newline at end of file
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub2/Customer.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub2/Customer.java
new file mode 100644 (file)
index 0000000..a3f5dca
--- /dev/null
@@ -0,0 +1,56 @@
+package bundle_sub2;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import bundle_base.BasePerson;
+import bundle_base.Person;
+
+
+@XmlRootElement
+public class Customer extends Person {
+
+    private String password;
+    private List<String> phoneNumbers;
+    @XmlElementRef
+    @XmlElementWrapper
+    private final List<BasePerson> agents = new ArrayList<BasePerson>();
+
+    @XmlTransient
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    @XmlElement(name = "phone-number")
+    public List<String> getPhoneNumbers() {
+        return phoneNumbers;
+    }
+
+    public void setPhoneNumbers(List<String> phoneNumbers) {
+        this.phoneNumbers = phoneNumbers;
+    }
+
+    public void addAgent(Person mgr) {
+        this.agents.add(mgr);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(super.toString());
+        sb.append(" password:").append(password);
+        sb.append(" phoneNumbers:").append(phoneNumbers);
+        sb.append(" agents:").append(agents);
+        return sb.toString();
+    }
+}
+
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub2/NoAnnotation.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/bundle_sub2/NoAnnotation.java
new file mode 100644 (file)
index 0000000..430f10b
--- /dev/null
@@ -0,0 +1,5 @@
+package bundle_sub2;
+
+public class NoAnnotation {
+
+}
diff --git a/opendaylight/northbound/bundlescanner/implementation/src/test/java/org/opendaylight/controller/northbound/bundlescanner/internal/BundleScannerTest.java b/opendaylight/northbound/bundlescanner/implementation/src/test/java/org/opendaylight/controller/northbound/bundlescanner/internal/BundleScannerTest.java
new file mode 100644 (file)
index 0000000..0d7d7da
--- /dev/null
@@ -0,0 +1,212 @@
+package org.opendaylight.controller.northbound.bundlescanner.internal;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.xml.bind.JAXBException;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.opendaylight.controller.northbound.bundlescanner.IBundleScanService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Constants;
+import org.springframework.osgi.mock.MockBundle;
+import org.springframework.osgi.mock.MockBundleContext;
+import org.springframework.osgi.mock.MockFrameworkUtil;
+
+public class BundleScannerTest {
+
+    private static BundleScanner bundleScanner;
+    private static List<Bundle> bundles;
+    @Rule
+    public final TestName testName = new TestName();
+
+    @BeforeClass
+    public static void init() throws Exception {
+        bundles = makeMockBundles();
+        bundleScanner = new BundleScanner(bundles.toArray(new Bundle[bundles.size()]));
+    }
+
+    @AfterClass
+    public static void destroy() throws Exception {
+    }
+
+    @Before
+    public void setup() {
+        System.out.println("==== " + testName.getMethodName());
+    }
+
+    @Test
+    public void testValidateBundles() {
+        assertNotNull(bundleScanner);
+        BundleContext context = bundles.get(0).getBundleContext();
+        assertNotNull(context.getBundle());
+        assertNotNull(context.getBundles());
+        assertNotNull(context.getBundles().length >= 4);
+    }
+
+    @Test
+    public void testBundleEvents() throws Exception {
+        MockBundle newBundle = new TestMockBundle("misc", "", "bundle_misc");
+        assertTrue(bundleScanner.getAnnotatedClasses(
+                newBundle.getBundleContext(), null, false).size() == 0);
+        BundleEvent event = new BundleEvent(BundleEvent.RESOLVED, newBundle);
+        bundleScanner.bundleChanged(event);
+        assertTrue(bundleScanner.getAnnotatedClasses(
+                newBundle.getBundleContext(), null, false).size() == 1);
+    }
+
+    @Test
+    public void testAnnotatedClassesWithDependencies() throws Exception {
+        for (Bundle bundle : bundles) {
+            List<Class<?>> classes = bundleScanner.getAnnotatedClasses(
+                    bundle.getBundleContext(), null, true);
+            String name = bundle.getSymbolicName();
+            System.out.println("name:" + name + " classes:" + classes.size());
+            if ("misc".equals(name)) {
+                assertTrue(classes.size() == 1);
+            } else if ("base".equals(name)) {
+                assertTrue(classes.size() == 5);
+            } else if ("sub1".equals(name)) {
+                assertTrue(classes.size() == 6);
+            } else if ("sub2".equals(name)) {
+                assertTrue(classes.size() == 7);
+            }
+        }
+    }
+
+    @Test
+    public void testExactFiltering() {
+        Bundle bundle = findBundle("sub1");
+        String[] annos = { "javax.xml.bind.annotation.XmlTransient" };
+        List<Class<?>> classes = bundleScanner.getAnnotatedClasses(
+                bundle.getBundleContext(), annos, true);
+        assertTrue(classes.size() == 1);
+    }
+
+    @Test
+    public void testNonExactFiltering() {
+        Bundle bundle = findBundle("sub1");
+        String[] annos = { "javax.xml.bind.annotation.*" };
+        List<Class<?>> classes = bundleScanner.getAnnotatedClasses(
+                bundle.getBundleContext(), annos, true);
+        assertTrue(classes.size() == 6);
+    }
+
+    @Test
+    public void testFilteringUnmatched() {
+        Bundle bundle = findBundle("sub1");
+        String[] annos = { "non.existent.pkg" };
+        List<Class<?>> classes = bundleScanner.getAnnotatedClasses(
+                bundle.getBundleContext(), annos, true);
+        assertTrue(classes.size() == 0);
+    }
+
+    @Test
+    public void testRegexMerge() {
+        Pattern pattern = BundleScanner.mergePatterns(
+                new String[] {
+                        "javax.xml.bind.annotation.*",
+                        "javax.ws.rs.Path"
+                    },
+                true
+            );
+        assertTrue(pattern.matcher("Ljavax/xml/bind/annotation/FOO;").find());
+        assertFalse(pattern.matcher("Ljavax/servlet/FOO;").find());
+    }
+
+    private static Bundle findBundle(String symName) {
+        for (Bundle bundle : bundles) {
+            if (bundle.getSymbolicName().equals(symName)) return bundle;
+        }
+        return null;
+    }
+
+    private static List<Bundle> makeMockBundles() throws Exception {
+        List<Bundle> result = new ArrayList<Bundle>();
+        result.add(new MockBundle());
+        result.add(new TestMockBundle("base", "", "bundle_base"));
+        result.add(new TestMockBundle("sub1", "bundle_base", "bundle_sub1"));
+        result.add(new TestMockBundle("sub2", "bundle_base", "bundle_sub2"));
+        return result;
+    }
+
+    private static List<URL> findClasses(String pkg) throws URISyntaxException {
+        if (pkg == null) return Collections.EMPTY_LIST;
+        String npkg = pkg.replaceAll("\\.", "/");
+        URL dirUrl = BundleScannerTest.class.getClassLoader().getResource(npkg);
+        final List<URL> result = new ArrayList<URL>();
+        File dir = new File(dirUrl.toURI());
+        dir.listFiles(new FileFilter() {
+
+            @Override
+            public boolean accept(File file) {
+                if (file.isFile() && file.getName().endsWith(".class")) {
+                    try {
+                        result.add(file.toURI().toURL());
+                    } catch (MalformedURLException e) {
+                        throw new IllegalStateException(e);
+                    }
+                }
+                return false;
+            }
+
+        });
+        return result;
+    }
+
+    public static class TestMockBundle extends MockBundle {
+        List<URL> classes;
+        public TestMockBundle(String name, String imports, String exports) throws Exception {
+            super(name, makeHeaders(name, imports, exports), new MockBundleContext() {
+                @Override
+                public Bundle[] getBundles() {
+                    return bundles.toArray(new Bundle[bundles.size()]);
+                }
+            });
+            MockBundleContext ctx = (MockBundleContext) this.getBundleContext();
+            ctx.setBundle(this);
+            this.classes = findClasses(exports);
+        }
+
+        private static Dictionary<String,String> makeHeaders(
+                String name, String imports, String exports)
+        {
+            Dictionary<String,String> headers = new Hashtable<String,String>();
+            headers.put(Constants.IMPORT_PACKAGE, imports);
+            headers.put(Constants.EXPORT_PACKAGE, exports);
+            headers.put(Constants.BUNDLE_SYMBOLICNAME, name);
+            return headers;
+        }
+
+        @Override
+        public Enumeration findEntries(String path, String filePattern, boolean recurse) {
+            return Collections.enumeration(classes);
+        }
+
+        @Override
+        public long getBundleId() {
+            return hashCode();
+        }
+    }
+}
index b88375ffdc9390c8dba9801f65fd69076f68a588..972bece91fd2ce9e0400bf2500397e76a2d19691 100644 (file)
             </Export-Package>
             <Import-Package>
               javax.ws.rs,
+              javax.ws.rs.ext,
               javax.ws.rs.core,
+              javax.xml.bind,
               javax.xml.bind.annotation,
+              org.objectweb.asm,
               org.opendaylight.controller.sal.utils,
               org.opendaylight.controller.sal.authorization,
               org.opendaylight.controller.containermanager,
               org.opendaylight.controller.usermanager,
+              org.opendaylight.controller.northbound.bundlescanner,
+              org.osgi.framework,
+              org.osgi.service.packageadmin,
+              org.osgi.util.tracker,
               javax.servlet.http,
+              org.codehaus.jackson,
+              org.codehaus.jackson.jaxrs,
+              org.codehaus.jackson.map,
               org.slf4j
             </Import-Package>
           </instructions>
       <artifactId>usermanager</artifactId>
       <version>0.4.0-SNAPSHOT</version>
     </dependency>
+    <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>bundlescanner</artifactId>
+        <version>0.4.0-SNAPSHOT</version>
+    </dependency>
   </dependencies>
 </project>
diff --git a/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/JacksonJsonProcessingExceptionMapper.java b/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/JacksonJsonProcessingExceptionMapper.java
new file mode 100644 (file)
index 0000000..ca0d1b7
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * 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.northbound.commons;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.codehaus.jackson.JsonProcessingException;
+
+/**
+ * A custom exception mapper for handling Jackson JsonProcessingException types
+ */
+@Provider
+@Consumes({MediaType.APPLICATION_JSON, "text/json"})
+public class JacksonJsonProcessingExceptionMapper
+    implements ExceptionMapper<JsonProcessingException>
+{
+
+    @Override
+    public Response toResponse(JsonProcessingException exception) {
+        GenericEntity<String> entity =
+                new GenericEntity<String>(exception.getMessage()) {};
+        return Response.status(Response.Status.BAD_REQUEST).entity(entity).build();
+    }
+}
+
diff --git a/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/NorthboundApplication.java b/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/NorthboundApplication.java
new file mode 100644 (file)
index 0000000..5b82191
--- /dev/null
@@ -0,0 +1,157 @@
+/**
+ * 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.northbound.commons;
+
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.core.Application;
+import javax.ws.rs.ext.ContextResolver;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
+import org.codehaus.jackson.map.DeserializationConfig;
+import org.opendaylight.controller.northbound.bundlescanner.IBundleScanService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleReference;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceException;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Instance of javax.ws.rs.core.Application used to return the classes
+ * that will be instantiated for JAXRS processing. This hooks onto the
+ * bundle scanner service to provide JAXB classes to JAX-RS for prorcessing.
+ */
+@SuppressWarnings("unchecked")
+public class NorthboundApplication extends Application {
+    public static final String JAXRS_RESOURCES_MANIFEST_NAME = "Jaxrs-Resources";
+    private static final Logger LOGGER = LoggerFactory.getLogger(NorthboundApplication.class);
+
+    ////////////////////////////////////////////////////////////////
+    //  Application overrides
+    ////////////////////////////////////////////////////////////////
+
+    @Override
+    public Set<Object> getSingletons() {
+        Set<Object> singletons = new HashSet<Object>();
+        singletons.add(new ContextResolver<JAXBContext>() {
+            @Override
+            public JAXBContext getContext(Class<?> type) {
+                return newJAXBContext();
+            }
+
+        } );
+        singletons.add(getJsonProvider());
+        singletons.add(new JacksonJsonProcessingExceptionMapper());
+        return singletons;
+    }
+
+    @Override
+    public Set<Class<?>> getClasses() {
+        Set<Class<?>> result = new HashSet<Class<?>>();
+        result.addAll(findJAXRSResourceClasses());
+        return result;
+    }
+
+    private static final JacksonJaxbJsonProvider getJsonProvider() {
+        JacksonJaxbJsonProvider jsonProvider = new JacksonJaxbJsonProvider();
+        jsonProvider.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES,
+                false);
+        return jsonProvider;
+    }
+
+    private BundleContext getBundleContext() {
+        ClassLoader tlcl = Thread.currentThread().getContextClassLoader();
+        Bundle bundle = null;
+
+        if (tlcl instanceof BundleReference) {
+            bundle = ((BundleReference) tlcl).getBundle();
+        } else {
+            LOGGER.warn("Unable to determine the bundle context based on " +
+                        "thread context classloader.");
+            bundle = FrameworkUtil.getBundle(this.getClass());
+        }
+        return (bundle == null ? null : bundle.getBundleContext());
+    }
+
+    private static final IBundleScanService lookupBundleScanner(BundleContext ctx) {
+        ServiceReference svcRef = ctx.getServiceReference(IBundleScanService.class);
+        if (svcRef == null) {
+            throw new ServiceException("Unable to lookup IBundleScanService");
+        }
+        return IBundleScanService.class.cast(ctx.getService(svcRef));
+    }
+
+    private final JAXBContext newJAXBContext() {
+        BundleContext ctx = getBundleContext();
+        IBundleScanService svc = lookupBundleScanner(ctx);
+        try {
+            List<Class<?>> cls = svc.getAnnotatedClasses(ctx,
+                    new String[] { XmlRootElement.class.getPackage().getName() },
+                    true);
+            return JAXBContext.newInstance(cls.toArray(new Class[cls.size()]));
+        } catch (JAXBException je) {
+            LOGGER.error("Error creating JAXBContext", je);
+            return null;
+        }
+    }
+
+    private final Set<Class<?>> findJAXRSResourceClasses() {
+        BundleContext ctx = getBundleContext();
+        String bundleName = ctx.getBundle().getSymbolicName();
+        Set<Class<?>> result = new HashSet<Class<?>>();
+        ServiceException recordException = null;
+        try {
+            IBundleScanService svc = lookupBundleScanner(ctx);
+            result.addAll(svc.getAnnotatedClasses(ctx,
+                    new String[] { javax.ws.rs.Path.class.getName() }, false));
+        } catch (ServiceException se) {
+            recordException = se;
+            LOGGER.debug("Error finding JAXRS resource annotated classes in " +
+                    "bundle: {} error: {}.", bundleName, se.getMessage());
+            // the bundle scan service cannot be lookedup. Lets attempt to
+            // lookup the resources from the bundle manifest header
+            Dictionary<String,String> headers = ctx.getBundle().getHeaders();
+            String header = headers.get(JAXRS_RESOURCES_MANIFEST_NAME);
+            if (header != null) {
+                for (String s : header.split(",")) {
+                    s = s.trim();
+                    if (s.length() > 0) {
+                        try {
+                            result.add(ctx.getBundle().loadClass(s));
+                        } catch (ClassNotFoundException cnfe) {
+                            LOGGER.error("Cannot load class: {} in bundle: {} " +
+                                    "defined as MANIFEST JAX-RS resource", s, bundleName, cnfe);
+                        }
+                    }
+                }
+            }
+
+        }
+
+        if (result.size() == 0) {
+            if (recordException != null) {
+                throw recordException;
+            } else {
+                throw new ServiceException("No resource classes found in bundle:" +
+                        ctx.getBundle().getSymbolicName());
+            }
+        }
+        return result;
+    }
+
+}
index 067e5f19b92a09a1ad5764e3e87cc661c22be1c2..75341a6fdf6317390f80f757402a09c8b952f35d 100644 (file)
@@ -49,6 +49,7 @@
               !org.codehaus.enunciate.jaxrs
             </Import-Package>
             <Web-ContextPath>/controller/nb/v2/containermanager</Web-ContextPath>
+            <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
           </instructions>
         </configuration>
       </plugin>
index 2c729ba115d2ae0477d1158388f82a104316255c..addf857aa10d5af113b3a41be643eebb92fa5784 100644 (file)
@@ -61,6 +61,7 @@
             <Export-Package>
             </Export-Package>
             <Web-ContextPath>/controller/nb/v2/flowprogrammer</Web-ContextPath>
+            <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
           </instructions>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
diff --git a/opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowProgrammerNorthboundRSApplication.java b/opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowProgrammerNorthboundRSApplication.java
deleted file mode 100644 (file)
index 68c0ec1..0000000
+++ /dev/null
@@ -1,33 +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.flowprogrammer.northbound;
-
-import java.util.HashSet;
-import java.util.Set;
-import javax.ws.rs.core.Application;
-
-import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
-
-/**
- * Instance of javax.ws.rs.core.Application used to return the classes
- * that will be instantiated for JAXRS processing, this is necessary
- * because the package scanning in jersey doesn't yet work in OSGi
- * environment.
- *
- */
-public class FlowProgrammerNorthboundRSApplication extends Application {
-    @Override
-    public Set<Class<?>> getClasses() {
-        Set<Class<?>> classes = new HashSet<Class<?>>();
-        classes.add(FlowProgrammerNorthbound.class);
-        classes.add(JacksonJaxbJsonProvider.class);
-        return classes;
-    }
-}
index 5b3cec2292163b1a4ca7836dae4ea35d9e26f630..f5c1ae5f9234afd435928bb9f2b8e0e1770af4d2 100644 (file)
@@ -8,7 +8,7 @@
           <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
           <init-param>
             <param-name>javax.ws.rs.Application</param-name>
-            <param-value>org.opendaylight.controller.flowprogrammer.northbound.FlowProgrammerNorthboundRSApplication</param-value>
+            <param-value>org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
           </init-param>
           <load-on-startup>1</load-on-startup>
         </servlet>
index c1f6598a8a5b5e977cbede6bf750b1911bee6303..e0315fb1ee2bb743c7788a98795bca7102a8139b 100644 (file)
@@ -62,6 +62,7 @@
               !org.codehaus.enunciate.jaxrs
             </Import-Package>
             <Web-ContextPath>/controller/nb/v2/hosttracker</Web-ContextPath>
+            <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
           </instructions>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
diff --git a/opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthboundRSApplication.java b/opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthboundRSApplication.java
deleted file mode 100644 (file)
index 5d50dbf..0000000
+++ /dev/null
@@ -1,33 +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.hosttracker.northbound;
-
-import java.util.HashSet;
-import java.util.Set;
-import javax.ws.rs.core.Application;
-
-import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
-
-/**
- * This class is an instance of javax.ws.rs.core.Application used to return the classes
- * that will be instantiated for JAXRS processing, this is necessary
- * because the package scanning in jersey doesn't yet work in OSGi
- * environment.
- *
- */
-public class HostTrackerNorthboundRSApplication extends Application {
-    @Override
-    public Set<Class<?>> getClasses() {
-        Set<Class<?>> classes = new HashSet<Class<?>>();
-        classes.add(HostTrackerNorthbound.class);
-        classes.add(JacksonJaxbJsonProvider.class);
-        return classes;
-    }
-}
index 01b8fedce125301acaf2bc3b1c8adf2bbea9d3fa..d4ace8d89d8fb4fb0372e12ae5023702c0ed2835 100644 (file)
@@ -7,7 +7,7 @@
     <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
     <init-param>
       <param-name>javax.ws.rs.Application</param-name>
-      <param-value>org.opendaylight.controller.hosttracker.northbound.HostTrackerNorthboundRSApplication</param-value>
+      <param-value>org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
   </servlet>
index f0c04ae5e2bde9d3264dbb3a256b834239a70d16..3f2585e0c2f215e343f567c1ecb9331ca6555307 100644 (file)
@@ -20,9 +20,9 @@
   <version>0.4.0-SNAPSHOT</version>
   <pluginRepositories>
     <pluginRepository>
-      <id>central2</id>
-      <name>central2</name>
-      <url>http://repo2.maven.org/maven2</url>
+      <id>central</id>
+      <name>maven repo1</name>
+      <url>http://repo1.maven.org/maven2</url>
       <snapshots>
         <enabled>false</enabled>
       </snapshots>
       <version>0.4.0-SNAPSHOT</version>
     </dependency>
 
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>bundlescanner</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>bundlescanner.implementation</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
 
     <dependency>
       <groupId>org.codehaus.enunciate</groupId>
       <version>${url.version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.ow2.asm</groupId>
+      <artifactId>asm-all</artifactId>
+      <version>4.1</version>
+    </dependency>
     <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>org.springframework.asm</artifactId>
index b0a5f201b25739c819c7f64d1034b90cb0f669ca..e7ca7f57822a438e4243a29115fd38f854dce5ed 100644 (file)
@@ -428,6 +428,11 @@ public class NorthboundIT {
         // Test GET deleted subnet1
         result = getJsonResult(baseURL + "default/subnet/" + name1);
         Assert.assertEquals(404, httpResponseCode.intValue());
+
+        // TEST PUT bad subnet, expect 400, validate JSON exception mapper
+        JSONObject joBad = new JSONObject().put("foo", "bar");
+        result = getJsonResult(baseURL + "default/subnet/foo", "PUT", joBad.toString());
+        Assert.assertEquals(400, httpResponseCode.intValue());
   }
 
     @Test
@@ -1426,6 +1431,8 @@ public class NorthboundIT {
                 mavenBundle("org.opendaylight.controller", "logging.bridge").versionAsInProject(),
 //                mavenBundle("org.opendaylight.controller", "clustering.test").versionAsInProject(),
                 mavenBundle("org.opendaylight.controller", "forwarding.staticrouting").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "bundlescanner").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "bundlescanner.implementation").versionAsInProject(),
 
                 // Northbound bundles
                 mavenBundle("org.opendaylight.controller", "commons.northbound").versionAsInProject(),
@@ -1508,6 +1515,8 @@ public class NorthboundIT {
                 mavenBundle("org.ops4j.pax.exam", "pax-exam-link-mvn").versionAsInProject(),
                 mavenBundle("org.ops4j.pax.url", "pax-url-aether").versionAsInProject(),
 
+                mavenBundle("org.ow2.asm", "asm-all").versionAsInProject(),
+
                 mavenBundle("org.springframework", "org.springframework.asm").versionAsInProject(),
                 mavenBundle("org.springframework", "org.springframework.aop").versionAsInProject(),
                 mavenBundle("org.springframework", "org.springframework.context").versionAsInProject(),
index a8d81a73673786f8bb7083ff0c01676cead8f1f3..c1eb56aa29d1f14bdf003083b974229510f41633 100644 (file)
@@ -64,6 +64,7 @@
             <Export-Package>
             </Export-Package>
             <Web-ContextPath>/controller/nb/v2/networkconfig/bridgedomain</Web-ContextPath>
+            <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
           </instructions>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
diff --git a/opendaylight/northbound/networkconfiguration/bridgedomain/src/main/java/org/opendaylight/controller/networkconfig/bridgedomain/northbound/BridgeDomainNorthboundApplication.java b/opendaylight/northbound/networkconfiguration/bridgedomain/src/main/java/org/opendaylight/controller/networkconfig/bridgedomain/northbound/BridgeDomainNorthboundApplication.java
deleted file mode 100644 (file)
index 0d98d22..0000000
+++ /dev/null
@@ -1,33 +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.networkconfig.bridgedomain.northbound;
-
-import java.util.HashSet;
-import java.util.Set;
-import javax.ws.rs.core.Application;
-
-import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
-
-/**
- * Instance of javax.ws.rs.core.Application used to return the classes
- * that will be instantiated for JAXRS processing, this is necessary
- * because the package scanning in jersey doesn't yet work in OSGi
- * environment.
- *
- */
-public class BridgeDomainNorthboundApplication extends Application {
-    @Override
-    public Set<Class<?>> getClasses() {
-        Set<Class<?>> classes = new HashSet<Class<?>>();
-        classes.add(BridgeDomainNorthbound.class);
-        classes.add(JacksonJaxbJsonProvider.class);
-        return classes;
-    }
-}
index f4de222acc0f33140565c98dec2420ff2f11c9a4..bb871a1a77a0f725f1f7510f7095b7ec65131474 100644 (file)
@@ -7,7 +7,7 @@
     <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
     <init-param>
       <param-name>javax.ws.rs.Application</param-name>
-      <param-value>org.opendaylight.controller.networkconfig.bridgedomain.northbound.BridgeDomainNorthboundApplication</param-value>
+      <param-value>org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
   </servlet>
index eb285f2e818805179b6253cb8db4f5ea8f384e27..1028ca59abbd045b61aeb768bcb6cb1b33496416 100644 (file)
@@ -62,6 +62,7 @@
             <Export-Package>
             </Export-Package>
             <Web-ContextPath>/controller/nb/v2/staticroute</Web-ContextPath>
+            <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
           </instructions>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
diff --git a/opendaylight/northbound/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/northbound/StaticRoutingNorthboundRSApplication.java b/opendaylight/northbound/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/northbound/StaticRoutingNorthboundRSApplication.java
deleted file mode 100644 (file)
index a98a124..0000000
+++ /dev/null
@@ -1,33 +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.forwarding.staticrouting.northbound;
-
-import java.util.HashSet;
-import java.util.Set;
-import javax.ws.rs.core.Application;
-
-import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
-
-/**
- * Instance of javax.ws.rs.core.Application used to return the classes
- * that will be instantiated for JAXRS processing, this is necessary
- * because the package scanning in jersey doesn't yet work in OSGi
- * environment.
- *
- */
-public class StaticRoutingNorthboundRSApplication extends Application {
-    @Override
-    public Set<Class<?>> getClasses() {
-        Set<Class<?>> classes = new HashSet<Class<?>>();
-        classes.add(StaticRoutingNorthbound.class);
-        classes.add(JacksonJaxbJsonProvider.class);
-        return classes;
-    }
-}
index 0bf186b50e0c6616504c896219252d0f6ef4d52c..9f7c21a8b0cc9ef0a03e4645396df30089931cda 100644 (file)
@@ -7,7 +7,7 @@
     <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
     <init-param>
       <param-name>javax.ws.rs.Application</param-name>
-      <param-value>org.opendaylight.controller.forwarding.staticrouting.northbound.StaticRoutingNorthboundRSApplication</param-value>
+      <param-value>org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
   </servlet>
index 76129f4cb141eece18d37abb0c7c5bd66a4f1b98..74f64c2457189905db3cd215070f0cb032b39c9e 100644 (file)
@@ -70,6 +70,7 @@
             <Export-Package>
             </Export-Package>
             <Web-ContextPath>/controller/nb/v2/statistics</Web-ContextPath>
+            <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
           </instructions>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
diff --git a/opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthboundRSApplication.java b/opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthboundRSApplication.java
deleted file mode 100644 (file)
index 2b6dccc..0000000
+++ /dev/null
@@ -1,32 +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.statistics.northbound;
-
-import java.util.HashSet;
-import java.util.Set;
-import javax.ws.rs.core.Application;
-
-import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
-
-/**
- * Instance of javax.ws.rs.core.Application used to return the classes
- * that will be instantiated for JAXRS processing, this is necessary
- * because the package scanning in jersey doesn't yet work in OSGi
- * environment.
- *
- */
-public class StatisticsNorthboundRSApplication extends Application {
-    @Override
-    public Set<Class<?>> getClasses() {
-        Set<Class<?>> classes = new HashSet<Class<?>>();
-        classes.add(StatisticsNorthbound.class);
-        classes.add(JacksonJaxbJsonProvider.class);
-        return classes;
-    }
-}
index db0460ba56db2c4b2541cbecaa94d45df3fe4158..179db608adffdfb043002cfba7b60a78867fe0cc 100644 (file)
@@ -7,7 +7,7 @@
     <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
     <init-param>
       <param-name>javax.ws.rs.Application</param-name>
-      <param-value>org.opendaylight.controller.statistics.northbound.StatisticsNorthboundRSApplication</param-value>
+      <param-value>org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
   </servlet>
index c3ad783773c34f040b48eab10a73d8ec3402fa00..ba58e06ecbdc6f5841769e398b44fe1f103179c1 100644 (file)
@@ -77,6 +77,7 @@
             <Export-Package>
             </Export-Package>
             <Web-ContextPath>/controller/nb/v2/subnetservice</Web-ContextPath>
+            <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
           </instructions>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
diff --git a/opendaylight/northbound/subnets/src/main/java/org/opendaylight/controller/subnets/northbound/SubnetsNorthboundRSApplication.java b/opendaylight/northbound/subnets/src/main/java/org/opendaylight/controller/subnets/northbound/SubnetsNorthboundRSApplication.java
deleted file mode 100644 (file)
index e03cac6..0000000
+++ /dev/null
@@ -1,32 +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.subnets.northbound;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.ws.rs.core.Application;
-
-import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
-
-/**
- * Instance of javax.ws.rs.core.Application used to return the classes
- * that will be instantiated for JAXRS processing, this is necessary
- * because the package scanning in jersey doesn't yet work in OSGi
- * environment.
- *
- */
-public class SubnetsNorthboundRSApplication extends Application {
-    @Override
-    public Set<Class<?>> getClasses() {
-        Set<Class<?>> classes = new HashSet<Class<?>>();
-        classes.add(SubnetsNorthbound.class);
-        classes.add(JacksonJaxbJsonProvider.class);
-        return classes;
-    }
-}
index a5c70ee9d82bc232a9b0578a88bd76f37973fb5f..2300b8da400d6f15f46812f868c3e262b30b32df 100644 (file)
@@ -7,7 +7,7 @@
     <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
     <init-param>
       <param-name>javax.ws.rs.Application</param-name>
-      <param-value>org.opendaylight.controller.subnets.northbound.SubnetsNorthboundRSApplication</param-value>
+      <param-value> org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
   </servlet>
index a416414d06607208b430b2d14932e986937b847b..d46b17e4f7e2d27bebf7bfb401be64bd038b6806 100644 (file)
@@ -61,6 +61,7 @@
               !org.codehaus.enunciate.jaxrs
             </Import-Package>
             <Web-ContextPath>/controller/nb/v2/switchmanager</Web-ContextPath>
+            <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
           </instructions>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
diff --git a/opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/SwitchNorthboundRSApplication.java b/opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/SwitchNorthboundRSApplication.java
deleted file mode 100644 (file)
index 1cdfd31..0000000
+++ /dev/null
@@ -1,33 +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.switchmanager.northbound;
-
-import java.util.HashSet;
-import java.util.Set;
-import javax.ws.rs.core.Application;
-
-import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
-
-/**
- * Instance of javax.ws.rs.core.Application used to return the classes
- * that will be instantiated for JAXRS processing, this is necessary
- * because the package scanning in jersey doesn't yet work in OSGi
- * environment.
- *
- */
-public class SwitchNorthboundRSApplication extends Application {
-    @Override
-    public Set<Class<?>> getClasses() {
-        Set<Class<?>> classes = new HashSet<Class<?>>();
-        classes.add(SwitchNorthbound.class);
-        classes.add(JacksonJaxbJsonProvider.class);
-        return classes;
-    }
-}
index ea6fcc99b2ab475cec28d4d93ee4d778bd36b1ea..cce0dfb259bc8f0d30f6e99f8b41fc9867735e77 100644 (file)
@@ -7,7 +7,7 @@
     <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
     <init-param>
       <param-name>javax.ws.rs.Application</param-name>
-      <param-value>org.opendaylight.controller.switchmanager.northbound.SwitchNorthboundRSApplication</param-value>
+      <param-value>org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
   </servlet>
index 803a28079e47939a2b09bdf62db76769e4855349..ec3489aca2855b6da48f82364c9b175dda8ff6de 100644 (file)
@@ -64,6 +64,7 @@
               !org.codehaus.enunciate.jaxrs
             </Import-Package>
             <Web-ContextPath>/controller/nb/v2/topology</Web-ContextPath>
+            <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
           </instructions>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
diff --git a/opendaylight/northbound/topology/src/main/java/org/opendaylight/controller/topology/northbound/TopologyNorthboundRSApplication.java b/opendaylight/northbound/topology/src/main/java/org/opendaylight/controller/topology/northbound/TopologyNorthboundRSApplication.java
deleted file mode 100644 (file)
index 992cf6a..0000000
+++ /dev/null
@@ -1,33 +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.topology.northbound;
-
-import java.util.HashSet;
-import java.util.Set;
-import javax.ws.rs.core.Application;
-
-import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
-
-/**
- * Instance of javax.ws.rs.core.Application used to return the classes
- * that will be instantiated for JAXRS processing, this is necessary
- * because the package scanning in jersey doesn't yet work in OSGi
- * environment.
- *
- */
-public class TopologyNorthboundRSApplication extends Application {
-    @Override
-    public Set<Class<?>> getClasses() {
-        Set<Class<?>> classes = new HashSet<Class<?>>();
-        classes.add(TopologyNorthboundJAXRS.class);
-        classes.add(JacksonJaxbJsonProvider.class);
-        return classes;
-    }
-}
index bc818c8c6d46e1a3d86d46f162a9bd628e51e8a5..29f2049c2715f95b2fdc99ea287617f1d061ea7f 100644 (file)
@@ -7,7 +7,7 @@
     <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
     <init-param>
       <param-name>javax.ws.rs.Application</param-name>
-      <param-value>org.opendaylight.controller.topology.northbound.TopologyNorthboundRSApplication</param-value>
+      <param-value>org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
   </servlet>
index af3641823c874e485c01e19f627b2963ff9bf953..d924b66a0991d50edd74b925e14a7e1809a7e321 100644 (file)
@@ -232,4 +232,9 @@ public interface ISwitch {
      * until the Barrier reply arrives.
      */
     public Object asyncSendBarrierMessage();
+
+    /**
+     * Send a FLOW_MOD message with a wildcard match and action=DELETE.
+     */
+    public void deleteAllFlows();
 }
index 91909d20f53a5bde5adea2b7020c38a78406f080..6e000022df12909e1f4facdcbcf4236d20d3fd69 100644 (file)
@@ -372,12 +372,6 @@ public class SwitchHandler implements ISwitch {
                 // send feature request
                 OFMessage featureRequest = factory.getMessage(OFType.FEATURES_REQUEST);
                 asyncFastSend(featureRequest);
-                // delete all pre-existing flows
-                OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
-                OFFlowMod flowMod = (OFFlowMod) factory.getMessage(OFType.FLOW_MOD);
-                flowMod.setMatch(match).setCommand(OFFlowMod.OFPFC_DELETE).setOutPort(OFPort.OFPP_NONE)
-                        .setLength((short) OFFlowMod.MINIMUM_LENGTH);
-                asyncFastSend(flowMod);
                 this.state = SwitchState.WAIT_FEATURES_REPLY;
                 startSwitchTimer();
                 break;
@@ -925,4 +919,14 @@ public class SwitchHandler implements ISwitch {
             return result;
         }
     }
+
+    @Override
+    public void deleteAllFlows() {
+        logger.trace("deleteAllFlows on switch {}", HexString.toHexString(this.sid));
+        OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
+        OFFlowMod flowMod = (OFFlowMod) factory.getMessage(OFType.FLOW_MOD);
+        flowMod.setMatch(match).setCommand(OFFlowMod.OFPFC_DELETE).setOutPort(OFPort.OFPP_NONE)
+                .setLength((short) OFFlowMod.MINIMUM_LENGTH);
+        asyncFastSend(flowMod);
+    }
 }
index 82dbf670a9517ee1b998442f2d524f37628f5815..6873b528a2631f2d01480387f46be430e58b57c0 100644 (file)
@@ -59,6 +59,7 @@ public class FlowStatisticsConverter {
                     flow.setPriority(ofFlowStat.getPriority());
                     flow.setIdleTimeout(ofFlowStat.getIdleTimeout());
                     flow.setHardTimeout(ofFlowStat.getHardTimeout());
+                    flow.setId(ofFlowStat.getCookie());
                     flowOnNode = new FlowOnNode(flow);
                     flowOnNode.setByteCount(ofFlowStat.getByteCount());
                     flowOnNode.setPacketCount(ofFlowStat.getPacketCount());
@@ -74,6 +75,7 @@ public class FlowStatisticsConverter {
                     flow.setPriority(v6StatsReply.getPriority());
                     flow.setIdleTimeout(v6StatsReply.getIdleTimeout());
                     flow.setHardTimeout(v6StatsReply.getHardTimeout());
+                    flow.setId(v6StatsReply.getCookie());
                     flowOnNode = new FlowOnNode(flow);
                     flowOnNode.setByteCount(v6StatsReply.getByteCount());
                     flowOnNode.setPacketCount(v6StatsReply.getPacketCount());
index 8db83f0fc7e2449b99079aadf5dfc709204f2f35..15bba670d2a7b9e4387317e91f12e50e18cb5e29 100644 (file)
@@ -239,6 +239,11 @@ public class InventoryServiceShim implements IContainerListener,
         if (sw == null) {
             return;
         }
+        Node node = NodeCreator.createOFNode(sw.getId());
+        if ((nodeProps.get(node) != null)  && (connectionOutService.isLocal(node))) {
+            logger.debug("Ignore switchAdded {}", sw);
+            return;
+        }
 
         // Add all the nodeConnectors of this switch
         Map<NodeConnector, Set<Property>> ncProps = InventoryServiceHelper
@@ -437,7 +442,6 @@ public class InventoryServiceShim implements IContainerListener,
             for (String container : containers) {
                 notifyInventoryShimInternalListener(container, node, type, props);
             }
-
             // Notify external listener
             notifyInventoryShimExternalListener(node, type, props);
 
@@ -511,6 +515,11 @@ public class InventoryServiceShim implements IContainerListener,
             props.add(b);
         }
 
+        if ((nodeProps.get(node) == null) &&  (connectionOutService.isLocal(node)))  {
+            // The switch is connected for the first time, flush all flows
+            // that may exist on this switch
+            sw.deleteAllFlows();
+       }
         nodeProps.put(node, props);
         // Notify all internal and external listeners
         notifyInventoryShimListener(node, type, props);
index 7e73dd414f4e18dd927b3085b074bd02af56f762..124b495147db61d99b53b24138bf47e5dda4083c 100644 (file)
@@ -45,9 +45,9 @@ public enum AppRoleLevel implements Serializable {
     }
 
     public static AppRoleLevel fromString(String levelString) {
-        for (AppRoleLevel level : AppRoleLevel.values()) {
-                if (level.toString().equals(levelString)) {
-                        return level;
+        for (AppRoleLevel rolelevel : AppRoleLevel.values()) {
+                if (rolelevel.toString().equals(levelString)) {
+                        return rolelevel;
                 }
         }
         return null;
index d21a147506dfd8e2f546ddd5210df33b1fc29c20..0ea04c32065e7746518504901abc454f4d5e6281 100644 (file)
@@ -323,10 +323,10 @@ public class Node implements Serializable {
     @Override
     public String toString() {
         if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
-            return this.nodeType.toString() + "|"
+            return this.nodeType + "|"
                 + HexEncode.longToHexString((Long) this.nodeID);
         } else {
-            return this.nodeType.toString() + "|" + this.nodeID.toString();
+            return this.nodeType + "|" + this.nodeID.toString();
         }
     }
 
index 50ccf69b4090ad220aebb5b97b35559f978efd56..46c5a9dae933baee49c47e98476a37dd9222dae5 100644 (file)
@@ -464,9 +464,9 @@ public class NodeConnector implements Serializable {
             .equals(NodeConnectorIDType.SWSTACK) ||
             this.nodeConnectorType
             .equals(NodeConnectorIDType.HWPATH)) {
-            return this.nodeConnectorType.toString();
+            return this.nodeConnectorType;
         } else {
-            return this.nodeConnectorType.toString() + "|"
+            return this.nodeConnectorType + "|"
                     + this.nodeConnectorID.toString();
         }
     }
index 7b7f1ccaeaf22f29dc4fa2a9c35b75854086b46f..9e763eb241a273375edf7c27a6ed40871a9b0a0a 100644 (file)
@@ -292,7 +292,7 @@ public class NodeTable implements Serializable {
     }
 
     public String getNodeTableIdAsString() {
-        return this.nodeTableType.toString() + "|"
+        return this.nodeTableType + "|"
                 + this.nodeTableID.toString();
     }
 
index a7bdb9da8bf32072b73b45a3128b412b9f18f88a..854125b3567a196b940556363ed56c82e99d50c0 100644 (file)
@@ -432,6 +432,7 @@ public class FlowProgrammerService implements IFlowProgrammerService,
         Flow flow = new Flow(match, actions);
         flow.setPriority((short) 100);
         flow.setHardTimeout((short) 360);
+        flow.setId(1234L);
 
         return flow;
     }
@@ -489,6 +490,7 @@ public class FlowProgrammerService implements IFlowProgrammerService,
         Flow flow = new Flow(match, actions);
         flow.setPriority((short) 300);
         flow.setHardTimeout((short) 240);
+        flow.setId(65536L);
 
         return flow;
     }
index b1107594f50fb3d60390f71b081e2b495dc89f8c..3f84ff09a47b875a63bf18873a3d06e9b09cd80f 100644 (file)
@@ -43,9 +43,9 @@
 
     <pluginRepositories>
         <pluginRepository>
-          <id>central2</id>
-          <name>central2</name>
-          <url>http://repo2.maven.org/maven2</url>
+          <id>central</id>
+          <name>maven repo1</name>
+          <url>http://repo1.maven.org/maven2</url>
           <snapshots>
              <enabled>false</enabled>
           </snapshots>
             <name>ebr-bundles-external</name>
             <url>${nexusproxy}/repositories/ebr-bundles-external/</url>
         </repository>
-        <repository>
-          <id>central2</id>
-          <name>central2</name>
-          <url>http://repo2.maven.org/maven2</url>
-          <snapshots>
-            <enabled>false</enabled>
-          </snapshots>
-          <releases>
-            <enabled>true</enabled>
-          </releases>
-        </repository>
         <repository>
           <id>central</id>
           <name>central</name>
diff --git a/opendaylight/sal/yang-prototype/sal/model/model-flow-base/src/main/yang/group-types.yang b/opendaylight/sal/yang-prototype/sal/model/model-flow-base/src/main/yang/group-types.yang
new file mode 100644 (file)
index 0000000..626eabd
--- /dev/null
@@ -0,0 +1,175 @@
+module opendaylight-group-types {
+    namespace "urn:opendaylight:group:types";
+    prefix group;
+
+    import ietf-inet-types {prefix inet;}
+    import ietf-yang-types {prefix yang;}
+       import opendaylight-flow-types {prefix flow-types;}
+
+    revision "2013-09-17" {
+        description "Initial revision of group service";
+    }
+
+       typedef group-ref {
+               type instance-identifier;
+       }
+       
+       grouping group-types {
+               leaf group-type {
+                       type enumeration {
+                               enum group-all;
+                               enum group_select;
+                               enum group_indirect;
+                               enum group_ff;
+                       }
+               }
+       }
+       
+       grouping group {
+        
+        uses group-types;       
+               
+               leaf group-id {
+            type group-ref;
+        }
+               
+               container buckets {
+                       list bucket {
+                               key "order";
+                               leaf order {
+                                       type int32;
+                               }
+                               
+                               leaf weight {
+                                       type uint16;
+                               }
+                               
+                               leaf watch_port {
+                                       type uint32;
+                               }
+                               
+                               leaf watch_group {
+                                       type uint32;
+                               }
+                               
+                               container actions {
+                                       list action {
+                                               key "action-order";
+                                               leaf action-order {
+                                                       type int32;
+                                               }
+            
+                                               uses flow-types:action;
+                                       }
+                               }
+                       }
+               }
+    }
+       
+       grouping group-statistics-request {
+               list group-stats {
+                       key "group-id";                 
+                       
+                       leaf group-id {
+                               type int32;
+                       }                       
+               }
+       }
+       
+       grouping group-statistics {
+                       
+               leaf group-id {
+            type int32;
+               }
+               
+           leaf ref-count {
+            type yang:counter32;
+               }
+               
+               leaf packet-count {
+            type yang:counter64;
+        } 
+               
+        leaf byte-count {
+            type yang:counter64;
+        }
+
+        container duration {
+            leaf second {
+                type yang:counter32;
+            }
+            leaf nanosecond {
+                type yang:counter32;
+            }
+        }
+               
+               container buckets {
+                       list bucket-counter {
+                               key "order";
+                               leaf order {
+                                       type int32;
+                               }
+                               
+                               leaf packet-count {
+                                       type yang:counter64;
+                               } 
+               
+                               leaf byte-count {
+                                       type yang:counter64;
+                               }
+                       }
+               }               
+    }
+
+       grouping group-statistics-reply {
+               list group-stats {
+                       key "group-stats-order";
+                       leaf group-stats-order {
+                               type int32;
+                       }
+                       
+                       uses group-statistics;
+               }
+       }
+       
+       grouping group-desc-stats {
+               list group-desc-stats {
+                       key "order-id";                 
+                       
+                       leaf order-id {
+                               type int32;
+                       }
+                       
+                       uses group;
+               }
+       }
+       
+    grouping group-features {
+               list group-features {
+                       key "order";
+                       leaf order {
+                               type int32;
+                       }
+                       
+                       uses group-types;
+                       type capabilities {
+                               enum select-weight;
+                               enum select-liveness;
+                               enum chaining;
+                               enum chaining-checks;
+                       }       
+
+                       leaf-list max-groups {
+                               type uint32;
+                               description "Maximum number of groups for each type";
+                               max-elements 4;
+                       }
+                       
+                       leaf-list actions {
+                               type uint32;
+                               description "Bitmap number OFPAT_* that are supported";
+                               max-elements 4;
+                       }
+               }
+       }    
+}
\ No newline at end of file
index 54b46d5587af0e0c65841d03546d80aa7f58d5bb..757686c662ab747baced122af0d5218a170f061a 100644 (file)
@@ -68,16 +68,16 @@ module opendaylight-match-types {
     grouping "ip-match-fields" {
         leaf ip-protocol {
                 description "IP protocol.";
-                type uint8; // TODO define IP protocol number
+                type uint8; 
         }
 
         leaf ip-dscp {
             description "IP DSCP (6 bits in ToS field).";
-            type inet:dscp; // TODO: Define DSCP type
+            type inet:dscp; 
         }
         leaf ip-ecn {
             description "IP ECN (2 bits in ToS field).";
-            type uint8; // TODO define ECN
+            type uint8; 
         }
     }
 
@@ -130,7 +130,7 @@ module opendaylight-match-types {
             description "SCTP source port.";
             type inet:port-number;
         }
-        leaf sctp-destination-dst {
+        leaf sctp-destination-port {
             description "SCTP destination port.";
             type inet:port-number;
         }
diff --git a/opendaylight/sal/yang-prototype/sal/model/model-flow-service/src/main/yang/group-service.yang b/opendaylight/sal/yang-prototype/sal/model/model-flow-service/src/main/yang/group-service.yang
new file mode 100644 (file)
index 0000000..1ea2d34
--- /dev/null
@@ -0,0 +1,49 @@
+module sal-group {
+    namespace "urn:opendaylight:group:service";
+    prefix group;
+
+    import yang-ext {prefix ext;}
+    import opendaylight-inventory {prefix inv;}
+    import ietf-inet-types {prefix inet;}
+    import opendaylight-group-types {prefix group-type;}
+
+    revision "2013-09-17" {
+        description "Initial revision of group service";
+    }        
+       
+    grouping node-group {
+        leaf node {
+            type inv:node-ref;
+        }
+        
+        uses group-type:group;
+    }
+
+    /** Base configuration structure **/
+    grouping group-update {
+        container original-group {
+            uses group-type:group;
+        }
+        container updated-group {
+            uses group-type:group;
+        }
+    }
+
+    rpc add-group {
+        input {
+            uses node-group;
+        }
+    }
+
+    rpc remove-group {
+        input {
+            uses node-group;
+        }
+    }
+
+    rpc update-group {
+        input {
+            uses node-group;
+        }
+    }     
+}
\ No newline at end of file
index 0442e8f9b2646d8f9b4d159fdfff7ea1e47d0287..d70338e4e0d1623e385ba1d72b1e4976aa8e4c4e 100644 (file)
@@ -25,7 +25,7 @@
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <slf4j.version>1.7.2</slf4j.version>
                <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
-               <yang.version>0.5.7-SNAPSHOT</yang.version>
+               <yang.version>0.5.8-SNAPSHOT</yang.version>
                <maven.bundle.version>2.4.0</maven.bundle.version>
         <releaseplugin.version>2.3.2</releaseplugin.version>
         <guava.version>14.0.1</guava.version>
@@ -33,9 +33,9 @@
 
     <pluginRepositories>
         <pluginRepository>
-          <id>central2</id>
-          <name>central2</name>
-          <url>http://repo2.maven.org/maven2</url>
+          <id>central</id>
+          <name>maven repo1</name>
+          <url>http://repo1.maven.org/maven2</url>
           <snapshots>
               <enabled>false</enabled>
           </snapshots>
 
 
        <repositories>
-      <repository>
-        <id>central2</id>
-        <name>central2</name>
-        <url>http://repo2.maven.org/maven2</url>
-        <snapshots>
-            <enabled>false</enabled>
-        </snapshots>
-        <releases>
-            <enabled>true</enabled>
-        </releases>
-      </repository>
       <repository>
         <id>central</id>
         <name>central</name>
index 549e427d82e816fb4374d3b80b3b44e2b9aeee1d..96a16dcd5772d6000421f680259b3373d4f978c3 100644 (file)
 <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>
-               <groupId>org.opendaylight.controller</groupId>
-               <artifactId>sal-parent</artifactId>
-               <version>1.0-SNAPSHOT</version>
-       </parent>
-       <artifactId>sal-binding-broker-impl</artifactId>
-       <packaging>bundle</packaging>
+    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>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>sal-binding-broker-impl</artifactId>
+    <packaging>bundle</packaging>
     <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:MD-SAL</url>
+        <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:MD-SAL</url>
     </scm>
 
-       <build>
-               <plugins>
-                       <plugin>
-                               <groupId>org.apache.felix</groupId>
-                               <artifactId>maven-bundle-plugin</artifactId>
-                               <version>${maven.bundle.version}</version>
-                               <extensions>true</extensions>
-                               <configuration>
-                                       <instructions>
-                                               <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
-                                               <Bundle-Activator>org.opendaylight.controller.sal.binding.impl.BrokerActivator</Bundle-Activator>
-                                               <Private-Package>
-                                                       org.opendaylight.controller.sal.binding.impl,
-                                                       org.opendaylight.controller.sal.binding.impl.utils,
-                                                       org.eclipse.xtend2.lib,
-                                                       org.eclipse.xtext.xbase.*
-                                               </Private-Package>
-                                       </instructions>
-                               </configuration>
-                       </plugin>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${maven.bundle.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                        <Bundle-Activator>org.opendaylight.controller.sal.binding.impl.BrokerActivator</Bundle-Activator>
+                        <Private-Package>
+                            org.opendaylight.controller.sal.binding.impl,
+                            org.opendaylight.controller.sal.binding.impl.*,
+                            org.opendaylight.controller.sal.binding.codegen.*,
+                            org.eclipse.xtend2.lib,
+                            org.eclipse.xtend.lib,
+                            org.eclipse.xtext.xbase.*
+                        </Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
 
-                       <plugin>
-                               <groupId>org.eclipse.xtend</groupId>
-                               <artifactId>xtend-maven-plugin</artifactId>
-                               <version>2.4.2</version>
-                               <executions>
-                                       <execution>
-                                               <goals>
-                                                       <goal>compile</goal>
-                                               </goals>
-                                               <configuration>
-                                                       <outputDirectory>${basedir}/src/main/xtend-gen</outputDirectory>
-                                               </configuration>
-                                       </execution>
-                               </executions>
-                       </plugin>
-                       <plugin>
-                               <artifactId>maven-clean-plugin</artifactId>
-                               <version>2.4.1</version>
-                               <configuration>
-                                       <filesets>
-                                               <fileset>
-                                                       <directory>${basedir}/src/main/xtend-gen</directory>
-                                                       <includes>
-                                                               <include>**</include>
-                                                       </includes>
-                                               </fileset>
-                                       </filesets>
-                               </configuration>
-                       </plugin>
-               </plugins>
-       </build>
+            <plugin>
+                <groupId>org.eclipse.xtend</groupId>
+                <artifactId>xtend-maven-plugin</artifactId>
+                <version>2.4.2</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>compile</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${basedir}/src/main/xtend-gen</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-clean-plugin</artifactId>
+                <version>2.4.1</version>
+                <configuration>
+                    <filesets>
+                        <fileset>
+                            <directory>${basedir}/src/main/xtend-gen</directory>
+                            <includes>
+                                <include>**</include>
+                            </includes>
+                        </fileset>
+                    </filesets>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 
-       <dependencies>
-               <dependency>
-                       <groupId>org.opendaylight.controller</groupId>
-                       <artifactId>sal-common-util</artifactId>
-                       <version>1.0-SNAPSHOT</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.opendaylight.controller</groupId>
-                       <artifactId>sal-binding-api</artifactId>
-                       <version>1.0-SNAPSHOT</version>
-               </dependency>
-               <!-- >dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-core-api</artifactId> 
-                       <version>1.0-SNAPSHOT</version> </dependency -->
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common-util</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <!-- >dependency> <groupId>org.opendaylight.controller</groupId> 
+            <artifactId>sal-core-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency -->
 
-               <dependency>
-                       <groupId>org.slf4j</groupId>
-                       <artifactId>slf4j-api</artifactId>
-               </dependency>
-               <dependency>
-                       <groupId>org.osgi</groupId>
-                       <artifactId>org.osgi.core</artifactId>
-                       <version>5.0.0</version>
-               </dependency>
-               <dependency>
-                       <groupId>com.google.guava</groupId>
-                       <artifactId>guava</artifactId>
-               </dependency>
-               <dependency>
-                       <groupId>org.reflections</groupId>
-                       <artifactId>reflections</artifactId>
-                       <version>0.9.9-RC1</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.javassist</groupId>
-                       <artifactId>javassist</artifactId>
-                       <version>3.17.1-GA</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.eclipse.xtend</groupId>
-                       <artifactId>org.eclipse.xtend.lib</artifactId>
-                       <version>2.4.2</version>
-               </dependency>
-       </dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>5.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.reflections</groupId>
+            <artifactId>reflections</artifactId>
+            <version>0.9.9-RC1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.javassist</groupId>
+            <artifactId>javassist</artifactId>
+            <version>3.17.1-GA</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.xtend</groupId>
+            <artifactId>org.eclipse.xtend.lib</artifactId>
+            <version>2.4.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.9.5</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
 </project>
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend
new file mode 100644 (file)
index 0000000..6bdb3c8
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.binding.codegen
+
+import java.util.Map
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
+import org.opendaylight.yangtools.yang.binding.RpcService
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+
+import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
+
+class RuntimeCodeHelper {
+    /**
+     * Helper method to return delegate from ManagedDirectedProxy with use of reflection.
+     * 
+     * Note: This method uses reflection, but access to delegate field should be 
+     * avoided and called only if neccessary.
+     * 
+     */
+    public static def <T extends RpcService> getDelegate(RpcService proxy) {
+        val field = proxy.class.getField(DELEGATE_FIELD)
+        if (field == null) throw new UnsupportedOperationException("Unable to get delegate from proxy");
+        return field.get(proxy) as T
+    }
+
+    /**
+     * Helper method to set delegate to ManagedDirectedProxy with use of reflection.
+     * 
+     * Note: This method uses reflection, but setting delegate field should not occur too much
+     * to introduce any significant performance hits.
+     * 
+     */
+    public static def void setDelegate(RpcService proxy, RpcService delegate) {
+        val field = proxy.class.getField(DELEGATE_FIELD)
+        if (field == null) throw new UnsupportedOperationException("Unable to set delegate to proxy");
+        if (field.type.isAssignableFrom(delegate.class)) {
+            field.set(proxy, delegate)
+        } else
+            throw new IllegalArgumentException("delegate class is not assignable to proxy");
+    }
+
+    public static def Map<InstanceIdentifier, ? extends RpcService> getRoutingTable(RpcService target,
+        Class<? extends BaseIdentity> tableClass) {
+        val field = target.class.getField(tableClass.routingTableField)
+        if (field == null) throw new UnsupportedOperationException(
+            "Unable to get routing table. Table field does not exists");
+        return field.get(target) as Map<InstanceIdentifier, ? extends RpcService>;
+    }
+
+    public static def void setRoutingTable(RpcService target, Class<? extends BaseIdentity> tableClass,
+        Map<InstanceIdentifier, ? extends RpcService> routingTable) {
+         val field = target.class.getField(tableClass.routingTableField)
+        if (field == null) throw new UnsupportedOperationException(
+            "Unable to set routing table. Table field does not exists");
+        field.set(target,routingTable);
+        
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeSpecification.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeSpecification.xtend
new file mode 100644 (file)
index 0000000..c6e76c2
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.binding.codegen
+
+import org.opendaylight.yangtools.yang.binding.RpcService
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
+import org.opendaylight.yangtools.yang.binding.NotificationListener
+
+/**
+ * 
+ * 
+ */
+class RuntimeCodeSpecification {
+
+    public static val PACKAGE_PREFIX = "_gen.";
+
+    public static val DIRECT_PROXY_SUFFIX = "DirectProxy";
+    public static val ROUTER_SUFFIX = "Router";
+    public static val INVOKER_SUFFIX = "Invoker";
+
+    public static val DELEGATE_FIELD = "_delegate"
+    public static val ROUTING_TABLE_FIELD_PREFIX = "_routes_"
+
+    public static def getInvokerName(Class<? extends NotificationListener> listener) {
+        getGeneratedName(listener, INVOKER_SUFFIX);
+    }
+
+    /**
+     * Returns a name for DirectProxy implementation
+     * 
+     * 
+     */
+    public static def getDirectProxyName(Class<? extends RpcService> base) {
+        getGeneratedName(base, DIRECT_PROXY_SUFFIX);
+    }
+
+    /**
+     * Returns a name for Router implementation
+     * 
+     */
+    public static def getRouterName(Class<? extends RpcService> base) {
+        getGeneratedName(base, ROUTER_SUFFIX);
+    }
+
+    /**
+     * Returns a name for generated interface
+     * 
+     */
+    public static def getGeneratedName(Class<?> cls, String suffix) {
+        '''«PACKAGE_PREFIX»«cls.package.name».«cls.simpleName»$«suffix»'''.toString()
+    }
+
+    /**
+     * Returns a field name for specified routing context
+     * 
+     */
+    public static def getRoutingTableField(Class<? extends BaseIdentity> routingContext) {
+        return '''_routes_«routingContext.simpleName»'''.toString;
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/YangtoolsMappingHelper.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/YangtoolsMappingHelper.xtend
new file mode 100644 (file)
index 0000000..18d3e26
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * 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.binding.codegen
+
+import java.lang.reflect.Method
+import org.opendaylight.yangtools.yang.binding.Notification
+
+public static class YangtoolsMappingHelper {
+
+    public static def boolean isNotificationCallback(Method it) {
+        return name.startsWith("on") && parameterTypes.size === 1 &&
+            Notification.isAssignableFrom(parameterTypes.get(0))
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/JavassistUtils.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/JavassistUtils.java
new file mode 100644 (file)
index 0000000..c6be284
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.binding.codegen.impl;
+
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+
+public class JavassistUtils {
+
+    public static interface ClassGenerator {
+        void process(CtClass cls);
+    }
+
+    public static interface MethodGenerator {
+        void process(CtMethod method);
+    }
+
+    public static interface FieldGenerator {
+        void process(CtField field);
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RoutingPair.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RoutingPair.xtend
new file mode 100644 (file)
index 0000000..4324b4e
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * 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.binding.codegen.impl
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
+import javassist.CtMethod
+import java.lang.reflect.Method
+
+@Data
+class RoutingPair {
+
+    @Property
+    val Class<? extends BaseIdentity> context;
+    @Property
+    val CtMethod getter;
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend
new file mode 100644 (file)
index 0000000..3b3f419
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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.binding.codegen.impl
+
+import javassist.ClassPool
+import org.opendaylight.yangtools.yang.binding.RpcService
+
+import javassist.CtClass
+import static com.google.common.base.Preconditions.*
+
+import javassist.CtField
+import javassist.Modifier
+import javassist.CtMethod
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
+
+import java.util.Map
+import java.util.HashMap
+import javassist.NotFoundException
+import javassist.LoaderClassPath
+import org.opendaylight.controller.sal.binding.codegen.impl.JavassistUtils.MethodGenerator
+import org.opendaylight.controller.sal.binding.codegen.impl.JavassistUtils.ClassGenerator
+import org.opendaylight.yangtools.yang.binding.NotificationListener
+import org.opendaylight.yangtools.yang.binding.Notification
+import java.util.Arrays
+
+import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.*
+import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
+
+class RuntimeCodeGenerator {
+
+    val ClassPool classPool;
+
+    public new(ClassPool pool) {
+        classPool = pool;
+    }
+
+    def <T extends RpcService> Class<? extends T> generateDirectProxy(Class<T> iface) {
+        val supertype = iface.asCtClass
+        val targetCls = createClass(iface.directProxyName, supertype) [
+            field(DELEGATE_FIELD, iface);
+            implementMethodsFrom(supertype) [
+                body = '''return ($r) Â«DELEGATE_FIELD».«it.name»($$);'''
+            ]
+        ]
+        return targetCls.toClass(iface.classLoader)
+    }
+
+    def <T extends RpcService> Class<? extends T> generateRouter(Class<T> iface) {
+        val supertype = iface.asCtClass
+        val targetCls = createClass(iface.routerName, supertype) [
+            //field(ROUTING_TABLE_FIELD,Map)
+            field(DELEGATE_FIELD, iface)
+            val contexts = new HashMap<String, Class<? extends BaseIdentity>>();
+            // We search for routing pairs and add fields
+            supertype.methods.filter[declaringClass == supertype && parameterTypes.size === 1].forEach [ method |
+                val routingPair = method.routingContextInput;
+                if (routingPair !== null)
+                    contexts.put(routingPair.context.routingTableField, routingPair.context);
+            ]
+            for (ctx : contexts.entrySet) {
+                field(ctx.key, Map)
+            }
+            implementMethodsFrom(supertype) [
+                if (parameterTypes.size === 1) {
+                    val routingPair = routingContextInput;
+                    val bodyTmp = '''
+                    {
+                        final Â«InstanceIdentifier.name» identifier = $1.«routingPair.getter.name»();
+                        Â«supertype.name» instance = («supertype.name») Â«routingPair.context.routingTableField».get(identifier);
+                        if(instance == null) {
+                           instance = Â«DELEGATE_FIELD»;
+                        }
+                        return ($r) instance.«it.name»($$);
+                    }'''
+                    body = bodyTmp
+                } else if (parameterTypes.size === 0) {
+                    body = '''return ($r) Â«DELEGATE_FIELD».«it.name»($$);'''
+                }
+            ]
+        ]
+        return targetCls.toClass(iface.classLoader)
+    }
+
+    def Class<?> generateListenerInvoker(Class<? extends NotificationListener> iface) {
+        val targetCls = createClass(iface.invokerName) [
+            field(DELEGATE_FIELD, iface)
+            it.method(Void, "invoke", Notification) [
+                val callbacks = iface.methods.filter[notificationCallback]
+                body = '''
+                    {
+                        Â«FOR callback : callbacks SEPARATOR " else "»
+                            if($1 instanceof Â«val cls = callback.parameterTypes.get(0).name») {
+                                Â«DELEGATE_FIELD».«callback.name»((«cls») $1);
+                                return;
+                            }
+                        Â«ENDFOR»
+                    }
+                '''
+            ]
+        ]
+        return targetCls.toClass(iface.classLoader);
+    }
+
+    def void method(CtClass it, Class<?> returnType, String name, Class<?> parameter, MethodGenerator function1) {
+        val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it);
+        function1.process(method);
+        it.addMethod(method);
+    }
+
+    private def routingContextInput(CtMethod method) {
+        val inputClass = method.parameterTypes.get(0);
+        return inputClass.contextInstance;
+    }
+
+    private def RoutingPair getContextInstance(CtClass dataClass) {
+        for (method : dataClass.methods) {
+            if (method.parameterTypes.size === 0 && method.name.startsWith("get")) {
+                for (annotation : method.availableAnnotations) {
+                    if (annotation instanceof RoutingContext) {
+                        return new RoutingPair((annotation as RoutingContext).value, method)
+                    }
+                }
+            }
+        }
+        for (iface : dataClass.interfaces) {
+            val ret = getContextInstance(iface);
+            if (ret != null) return ret;
+        }
+        return null;
+    }
+
+    private def void implementMethodsFrom(CtClass target, CtClass source, MethodGenerator function1) {
+        for (method : source.methods) {
+            if (method.declaringClass == source) {
+                val redeclaredMethod = new CtMethod(method, target, null);
+                function1.process(redeclaredMethod);
+                target.addMethod(redeclaredMethod);
+            }
+        }
+    }
+
+    private def CtClass createClass(String fqn, ClassGenerator cls) {
+        val target = classPool.makeClass(fqn);
+        cls.process(target);
+        return target;
+    }
+
+    private def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) {
+        val target = classPool.makeClass(fqn);
+        target.implementsType(superInterface);
+        cls.process(target);
+        return target;
+    }
+
+    private def void implementsType(CtClass it, CtClass supertype) {
+        checkArgument(supertype.interface, "Supertype must be interface");
+        addInterface(supertype);
+    }
+
+    private def asCtClass(Class<?> class1) {
+        classPool.get(class1);
+    }
+
+    private def CtField field(CtClass it, String name, Class<?> returnValue) {
+        val field = new CtField(returnValue.asCtClass, name, it);
+        field.modifiers = Modifier.PUBLIC
+        addField(field);
+        return field;
+    }
+
+    def get(ClassPool pool, Class<?> cls) {
+        try {
+            return pool.get(cls.name)
+        } catch (NotFoundException e) {
+            pool.appendClassPath(new LoaderClassPath(cls.classLoader));
+            return pool.get(cls.name)
+        }
+    }
+}
index 2953466b2928a419eb0a2c3a09f4d74b771b7ab9..298a74ece5f71982ae7bcbb48f205e4039c44046 100644 (file)
@@ -11,30 +11,29 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider
 import org.opendaylight.yangtools.yang.binding.RpcService
 import javassist.ClassPool
-import javassist.CtMethod
-import javassist.CtField
 import org.osgi.framework.BundleContext
 import java.util.Map
 import java.util.HashMap
 import javassist.LoaderClassPath
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker
 import java.util.Hashtable
+import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*
 
-import static extension org.opendaylight.controller.sal.binding.impl.utils.PropertiesUtils.*
-import static extension org.opendaylight.controller.sal.binding.impl.utils.GeneratorUtils.*
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService
 import org.osgi.framework.ServiceRegistration
-import org.opendaylight.controller.sal.binding.impl.utils.PropertiesUtils
+import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*
+import static extension org.opendaylight.controller.sal.binding.impl.osgi.PropertiesUtils.*
 import org.opendaylight.controller.sal.binding.api.NotificationService
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
-import javassist.Modifier
+
 import org.slf4j.LoggerFactory
+import org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator
 
 class BindingAwareBrokerImpl implements BindingAwareBroker {
-    private static val DELEGATE_FIELD = "_delegate"
     private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl)
     
     private val clsPool = ClassPool.getDefault()
+    private var RuntimeCodeGenerator generator;
     private Map<Class<? extends RpcService>, RpcProxyContext> managedProxies = new HashMap();
     private var NotificationBrokerImpl notifyBroker
     private var ServiceRegistration<NotificationProviderService> notifyBrokerRegistration
@@ -47,7 +46,7 @@ class BindingAwareBrokerImpl implements BindingAwareBroker {
 
         // Initialization of notificationBroker
         notifyBroker = new NotificationBrokerImpl(null);
-        val brokerProperties = PropertiesUtils.newProperties();
+        val brokerProperties = newProperties();
         notifyBrokerRegistration = brokerBundleContext.registerService(NotificationProviderService, notifyBroker,
             brokerProperties)
         brokerBundleContext.registerService(NotificationService, notifyBroker, brokerProperties)
@@ -56,7 +55,8 @@ class BindingAwareBrokerImpl implements BindingAwareBroker {
     def initGenerator() {
 
         // YANG Binding Class Loader
-        clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader))
+        clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader));
+        generator = new RuntimeCodeGenerator(clsPool);
     }
 
     override registerConsumer(BindingAwareConsumer consumer, BundleContext bundleCtx) {
@@ -97,35 +97,16 @@ class BindingAwareBrokerImpl implements BindingAwareBroker {
         if ((existing = managedProxies.get(service)) != null) {
             return existing.proxy
         }
-        val proxyClass = service.generateDirectProxy()
+        val proxyClass = generator.generateDirectProxy(service)
         val rpcProxyCtx = new RpcProxyContext(proxyClass)
         val properties = new Hashtable<String, String>()
         rpcProxyCtx.proxy = proxyClass.newInstance as RpcService
 
-        properties.salServiceType = Constants.SAL_SERVICE_TYPE_CONSUMER_PROXY
+        properties.salServiceType = SAL_SERVICE_TYPE_CONSUMER_PROXY
         rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties)
         managedProxies.put(service, rpcProxyCtx)
         return rpcProxyCtx.proxy
     }
-
-    protected def generateDirectProxy(Class<? extends RpcService> delegate) {
-        val targetFqn = delegate.generatedName(Constants.PROXY_DIRECT_SUFFIX)
-        log.debug("Generating DirectProxy for {} Proxy name: {}",delegate,targetFqn);
-        val objCls = clsPool.get(Object)
-        val delegateCls = clsPool.get(delegate)
-        val proxyCls = clsPool.makeClass(targetFqn)
-        proxyCls.addInterface(delegateCls)
-        val delField = new CtField(delegateCls, DELEGATE_FIELD, proxyCls);
-        delField.modifiers = Modifier.PUBLIC
-        proxyCls.addField(delField)
-        delegateCls.methods.filter[it.declaringClass != objCls].forEach [
-            val proxyMethod = new CtMethod(it, proxyCls, null);
-            proxyMethod.body = '''return ($r) Â«DELEGATE_FIELD».«it.name»($$);'''
-            proxyCls.addMethod(proxyMethod)
-        ]
-        return proxyCls.toClass(delegate.classLoader)
-    }
-
     /**
      * Registers RPC Implementation
      * 
@@ -140,34 +121,4 @@ class BindingAwareBrokerImpl implements BindingAwareBroker {
         proxy.delegate = service;
         return new RpcServiceRegistrationImpl<T>(type, service, osgiReg);
     }
-    
-    /**
-     * Helper method to return delegate from ManagedDirectedProxy with use of reflection.
-     * 
-     * Note: This method uses reflection, but access to delegate field should be 
-     * avoided and called only if neccessary.
-     * 
-     */
-    def <T extends RpcService> getDelegate(RpcService proxy) {
-        val field = proxy.class.getField(DELEGATE_FIELD)
-        if(field == null) throw new UnsupportedOperationException("Unable to get delegate from proxy");
-        return field.get(proxy) as T
-    }
-    
-        /**
-     * Helper method to set delegate to ManagedDirectedProxy with use of reflection.
-     * 
-     * Note: This method uses reflection, but setting delegate field should not occur too much
-     * to introduce any significant performance hits.
-     * 
-     */
-    def void setDelegate(RpcService proxy, RpcService delegate) {
-        val field = proxy.class.getField(DELEGATE_FIELD)
-        if(field == null) throw new UnsupportedOperationException("Unable to set delegate to proxy");
-        if (field.type.isAssignableFrom(delegate.class)) {
-            field.set(proxy,delegate)
-        } else throw new IllegalArgumentException("delegate class is not assignable to proxy");
-    }
-    
-    
 }
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataProviderContext.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataProviderContext.xtend
new file mode 100644 (file)
index 0000000..398a219
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * 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.binding.impl
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier
+import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider
+
+class DataProviderContext {
+
+    @Property
+    var DataStoreIdentifier identifier;
+    @Property
+    var RuntimeDataProvider provider;
+}
index da1ba79997d16a910ccafe023076e72db460ae7c..22db73526e2e2e386636cc8b45320b3c246f24ad 100644 (file)
@@ -45,6 +45,7 @@ class NotificationBrokerImpl implements NotificationProviderService {
         notification.class.interfaces.filter[it != Notification && Notification.isAssignableFrom(it)]
     }
 
+    @SuppressWarnings("unchecked")
     def notifyAll(Collection<NotificationListener<?>> listeners, Notification notification) {
         listeners.forEach[(it as NotificationListener).onNotification(notification)]
     }
index a87fa0642a4eec5b33eca03630e2122f9d01ba61..a9031240c777961e9fdb5ad5bcb642b70c311f0a 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * 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.binding.impl;
 
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
@@ -7,47 +14,45 @@ import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.LoggerFactory
+import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*
 
 class OsgiConsumerContext implements ConsumerContext {
 
-       static val log = LoggerFactory.getLogger(OsgiConsumerContext)
-       protected val BundleContext bundleContext;
-       protected val BindingAwareBrokerImpl broker;
-       
-       new(BundleContext ctx,BindingAwareBrokerImpl broker) {
-               this.bundleContext = ctx;
-               this.broker = broker;
-       }
-
-       
-       override def <T extends BindingAwareService> getSALService(Class<T> service) {
-               // SAL Services are global
-               var ref =  bundleContext.getServiceReference(service);
-               return bundleContext.getService(ref) as T;
-       }
-       
-       
-
-       override def <T extends RpcService> T getRpcService(Class<T> module) {
-               try {
-                       
-                       val services = bundleContext.getServiceReferences(module, getProxyFilter());
-                       
-                       // Proxy service found / using first implementation
-                       // FIXME: Add advanced logic to retrieve service with right set of models
-                       if(false == services.empty) {
-                               val ref = services.iterator().next() as ServiceReference<T>;
-                               return bundleContext.getService(ref) as T;
-                       } 
-               } catch (InvalidSyntaxException e) {
-                       log.error("Created filter was invalid:", e.message,e)
-               }
-               return null;
-               
-
-       }
-
-       private def getProxyFilter() {
-               return '''(«Constants.SAL_SERVICE_TYPE»=«Constants.SAL_SERVICE_TYPE_CONSUMER_PROXY»)'''
-       }
+    static val log = LoggerFactory.getLogger(OsgiConsumerContext)
+    protected val BundleContext bundleContext;
+    protected val BindingAwareBrokerImpl broker;
+
+    new(BundleContext ctx, BindingAwareBrokerImpl broker) {
+        this.bundleContext = ctx;
+        this.broker = broker;
+    }
+
+    override def <T extends BindingAwareService> getSALService(Class<T> service) {
+
+        // SAL Services are global
+        var ref = bundleContext.getServiceReference(service);
+        return bundleContext.getService(ref) as T;
+    }
+
+    override def <T extends RpcService> T getRpcService(Class<T> module) {
+        try {
+
+            val services = bundleContext.getServiceReferences(module, getProxyFilter());
+
+            // Proxy service found / using first implementation
+            // FIXME: Add advanced logic to retrieve service with right set of models
+            if (false == services.empty) {
+                val ref = services.iterator().next() as ServiceReference<T>;
+                return bundleContext.getService(ref) as T;
+            }
+        } catch (InvalidSyntaxException e) {
+            log.error("Created filter was invalid:", e.message, e)
+        }
+        return null;
+
+    }
+
+    private def getProxyFilter() {
+        return '''(«SAL_SERVICE_TYPE»=«SAL_SERVICE_TYPE_CONSUMER_PROXY»)'''
+    }
 }
index 195fa8b9597ba19b5784e68e15d8d2fc563eef42..c769ca1ee38509fa3dbebd52948f81735fddf59c 100644 (file)
@@ -16,7 +16,8 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcService
 import org.opendaylight.yangtools.yang.binding.RpcService;
 import org.osgi.framework.BundleContext;
 
-import static extension org.opendaylight.controller.sal.binding.impl.utils.PropertiesUtils.*;
+import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*;
+import static extension org.opendaylight.controller.sal.binding.impl.osgi.PropertiesUtils.*;
 
 class OsgiProviderContext extends OsgiConsumerContext implements ProviderContext {
 
@@ -32,7 +33,7 @@ class OsgiProviderContext extends OsgiConsumerContext implements ProviderContext
 
         // TODO Auto-generated method stub
         val properties = new Hashtable<String, String>();
-        properties.salServiceType = Constants.SAL_SERVICE_TYPE_PROVIDER
+        properties.salServiceType = SAL_SERVICE_TYPE_PROVIDER
 
         // Fill requirements
         val salReg = broker.registerRpcImplementation(type, implementation, this, properties)
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/_DataBrokerImpl.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/_DataBrokerImpl.xtend
new file mode 100644 (file)
index 0000000..b278df5
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.binding.impl
+
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
+import org.opendaylight.controller.sal.common.DataStoreIdentifier
+import org.opendaylight.yangtools.yang.binding.DataRoot
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService
+import org.opendaylight.controller.sal.binding.api.data.DataCommitHandler
+import org.opendaylight.controller.sal.binding.api.data.DataRefresher
+import org.opendaylight.controller.sal.binding.api.data.DataValidator
+import org.opendaylight.yangtools.yang.common.RpcResult
+import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider
+import java.util.Map
+
+class _DataBrokerImpl implements DataProviderService {
+
+    Map<DataStoreIdentifier, DataProviderContext> dataProviders;
+    var DataProviderContext defaultDataProvider;
+
+    override <T extends DataRoot> getData(DataStoreIdentifier store, Class<T> rootType) {
+        val dataStore = resolveProvider(store, rootType);
+        return dataStore.provider.getData(store, rootType);
+    }
+
+    override <T extends DataRoot> getData(DataStoreIdentifier store, T filter) {
+    }
+
+    override <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub");
+    }
+
+    override <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub");
+    }
+
+    override commit(DataStoreIdentifier store) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    override editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    override addCommitHandler(DataStoreIdentifier store, DataCommitHandler provider) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    override addRefresher(DataStoreIdentifier store, DataRefresher refresher) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    override addValidator(DataStoreIdentifier store, DataValidator validator) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    override removeRefresher(DataStoreIdentifier store, DataRefresher refresher) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    override removeCommitHandler(DataStoreIdentifier store, DataCommitHandler provider) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+
+    }
+
+    override removeValidator(DataStoreIdentifier store, DataValidator validator) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    def DataProviderContext resolveProvider(DataStoreIdentifier store, Class<? extends DataRoot> root) {
+    }
+
+}
@@ -5,7 +5,7 @@
  * 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.binding.impl
+package org.opendaylight.controller.sal.binding.impl.osgi
 
 class Constants {
 
@@ -16,6 +16,4 @@ class Constants {
     public static val SAL_SERVICE_TYPE_CONSUMER_PROXY = "consumerProxy"
     public static val SAL_SERVICE_TYPE_PROVIDER = "provider"
     public static val SAL_SERVICE_TYPE_CONNECTOR = "connector"
-
-    public static val PROXY_DIRECT_SUFFIX = "DirectProxy";
 }
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/PropertiesUtils.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/PropertiesUtils.xtend
new file mode 100644 (file)
index 0000000..d04ca7f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.binding.impl.osgi
+
+import java.util.Hashtable
+import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*
+
+class PropertiesUtils {
+
+    private new() {
+    }
+
+    static def setSalServiceType(Hashtable<String, String> properties, String value) {
+        properties.put(SAL_SERVICE_TYPE, value)
+        return properties
+    }
+
+    static def getSalServiceType(Hashtable<String, String> properties) {
+        return properties.get(SAL_SERVICE_TYPE)
+    }
+
+    static def newProperties() {
+        new Hashtable<String, String>()
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/package-info.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/package-info.java
new file mode 100644 (file)
index 0000000..d788ccf
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * 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.binding.impl.osgi;
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/GeneratorUtils.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/GeneratorUtils.xtend
deleted file mode 100644 (file)
index c888121..0000000
+++ /dev/null
@@ -1,30 +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.binding.impl.utils
-
-import javassist.ClassPool
-import javassist.NotFoundException
-import javassist.LoaderClassPath
-
-class GeneratorUtils {
-
-    static val PREFIX = "_gen.";
-
-    public static def generatedName(Class<?> cls, String suffix) {
-        '''«PREFIX»«cls.package.name».«cls.simpleName»$«suffix»'''.toString()
-    }
-
-    public static def get(ClassPool pool, Class<?> cls) {
-        try {
-            return pool.get(cls.name)
-        } catch (NotFoundException e) {
-            pool.appendClassPath(new LoaderClassPath(cls.classLoader));
-            return pool.get(cls.name)
-        }
-    }
-}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/PropertiesUtils.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/PropertiesUtils.xtend
deleted file mode 100644 (file)
index 7ba62f5..0000000
+++ /dev/null
@@ -1,30 +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.binding.impl.utils
-
-import java.util.Hashtable
-import org.opendaylight.controller.sal.binding.impl.Constants
-
-class PropertiesUtils {
-       
-       private new() {}
-       
-       static def setSalServiceType(Hashtable<String,String> properties, String value) {
-               properties.put(Constants.SAL_SERVICE_TYPE,value)
-               return properties
-       }
-       
-       static def getSalServiceType(Hashtable<String,String> properties) {
-               return properties.get(Constants.SAL_SERVICE_TYPE)
-       }
-       
-       static def newProperties() {
-               new Hashtable<String,String>()
-       }
-       
-}
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/package-info.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/package-info.java
deleted file mode 100644 (file)
index 5110238..0000000
+++ /dev/null
@@ -1,8 +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.binding.impl.utils;
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/test/org/opendaylight/controller/sal/binding/test/GenerationTest.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/test/org/opendaylight/controller/sal/binding/test/GenerationTest.java
new file mode 100644 (file)
index 0000000..9bbb501
--- /dev/null
@@ -0,0 +1,31 @@
+package org.opendaylight.controller.sal.binding.test;
+import static org.junit.Assert.*;
+
+import java.util.concurrent.Future;
+
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.impl.ProxyFactoryGenerator;
+import org.opendaylight.controller.sal.binding.impl.RpcServiceProxy;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+
+public class GenerationTest {
+
+       public interface MockService extends RpcService {
+               
+           Future<RpcResult<java.lang.Void>> cancelToast();
+           
+           Future<RpcResult<java.lang.Void>> makeToast(String input);
+       }
+       
+       @Test
+       public void test() {
+               ProxyFactoryGenerator generator = new ProxyFactoryGenerator();
+               Class<? extends RpcServiceProxy<MockService>> ret = generator.generate(MockService.class);
+               
+               assertTrue(RpcServiceProxy.class.isAssignableFrom(ret));
+               assertTrue(MockService.class.isAssignableFrom(ret));
+       }
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java
new file mode 100644 (file)
index 0000000..5dddd1a
--- /dev/null
@@ -0,0 +1,142 @@
+package org.opendaylight.controller.sal.binding.test;
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import javassist.ClassPool;
+
+import org.junit.Before;
+import org.junit.Test;
+import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*;
+import org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator;
+import org.opendaylight.controller.sal.binding.test.mock.FooService;
+import org.opendaylight.controller.sal.binding.test.mock.ReferencableObject;
+import org.opendaylight.controller.sal.binding.test.mock.ReferencableObjectKey;
+import org.opendaylight.controller.sal.binding.test.mock.SimpleInput;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+
+import static org.mockito.Mockito.*;
+
+
+public class RuntimeCodeGeneratorTest {
+
+    private RuntimeCodeGenerator codeGenerator;
+
+    
+    @Before
+    public void initialize() {
+        this.codeGenerator = new RuntimeCodeGenerator(ClassPool.getDefault());
+    }
+    
+    @Test
+    public void testGenerateDirectProxy() {
+        Class<? extends FooService> product = codeGenerator.generateDirectProxy(FooService.class);
+        assertNotNull(product);
+    }
+
+    @Test
+    public void testGenerateRouter() throws Exception {
+        Class<? extends FooService> product = codeGenerator.generateRouter(FooService.class);
+        assertNotNull(product);
+        assertNotNull(product.getSimpleName());
+        assertEquals("2 fields should be generated.",2,product.getFields().length);
+        
+        verifyRouting(product.newInstance());
+    }
+
+    private void verifyRouting(FooService product) {
+        Map<InstanceIdentifier,FooService> routingTable = new HashMap<>();
+        setRoutingTable(product, BaseIdentity.class, routingTable);
+        
+        assertSame("Returned routing table should be same instance",routingTable,getRoutingTable(product, BaseIdentity.class));
+        
+        int servicesCount = 2;
+        int instancesPerService = 3;
+        
+        InstanceIdentifier[][] identifiers = identifiers(servicesCount,instancesPerService);
+        FooService service[] = new FooService[] {
+                mock(FooService.class, "Instance 0"),
+                mock(FooService.class,"Instance 1")
+        };
+        
+        for(int i = 0;i<service.length;i++) {
+            for (InstanceIdentifier instance : identifiers[i]) {
+                routingTable.put(instance, service[i]);
+            }
+        }
+        
+        assertEquals("All instances should be registered.", servicesCount*instancesPerService, routingTable.size());
+        
+        SimpleInput[] instance_0_input = new SimpleInputImpl[] {
+            new SimpleInputImpl(identifiers[0][0]),
+            new SimpleInputImpl(identifiers[0][1]),
+            new SimpleInputImpl(identifiers[0][2])
+        };
+        
+        SimpleInput[] instance_1_input = new SimpleInputImpl[] {
+                new SimpleInputImpl(identifiers[1][0]),
+                new SimpleInputImpl(identifiers[1][1]),
+                new SimpleInputImpl(identifiers[1][2])
+        };
+        
+        // We test sending mock messages
+        
+        product.simple(instance_0_input[0]);
+        verify(service[0]).simple(instance_0_input[0]);
+        
+        product.simple(instance_0_input[1]);
+        product.simple(instance_0_input[2]);
+        
+        verify(service[0]).simple(instance_0_input[1]);
+        verify(service[0]).simple(instance_0_input[2]);
+        
+        product.simple(instance_1_input[0]);
+        verify(service[1]).simple(instance_1_input[0]);
+    }
+
+    private InstanceIdentifier[][] identifiers(int serviceSize, int instancesPerService) {
+        InstanceIdentifier[][] ret = new InstanceIdentifier[serviceSize][];
+        int service = 0;
+        for (int i = 0;i<serviceSize;i++) {
+            
+            InstanceIdentifier[] instanceIdentifiers = new InstanceIdentifier[instancesPerService];
+            ret[i] = instanceIdentifiers;
+            for(int id = 0;id<instancesPerService;id++) {
+                instanceIdentifiers[id] = referencableIdentifier(service*instancesPerService+id);
+            }
+            service++;
+        }
+        
+        return ret;
+    }
+
+    private InstanceIdentifier referencableIdentifier(int i) {
+        ReferencableObjectKey key = new ReferencableObjectKey(i);
+        IdentifiableItem<ReferencableObject,ReferencableObjectKey> pathArg = new IdentifiableItem<>(ReferencableObject.class,key);
+        return new InstanceIdentifier(Arrays.<PathArgument>asList(pathArg), ReferencableObject.class);
+    }
+
+    private static class SimpleInputImpl implements SimpleInput {
+        private final InstanceIdentifier identifier;
+
+        public SimpleInputImpl(InstanceIdentifier _identifier) {
+            this.identifier = _identifier;
+        }
+
+        @Override
+        public <E extends Augmentation<SimpleInput>> E getAugmentation(Class<E> augmentationType) {
+            return null;
+        }
+
+        @Override
+        public InstanceIdentifier getIdentifier() {
+            return this.identifier;
+        }
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/BarUpdate.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/BarUpdate.java
new file mode 100644 (file)
index 0000000..b64ebdf
--- /dev/null
@@ -0,0 +1,7 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public interface BarUpdate extends Grouping,Notification {
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooListener.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooListener.java
new file mode 100644 (file)
index 0000000..3629689
--- /dev/null
@@ -0,0 +1,10 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+
+public interface FooListener extends NotificationListener {
+
+    void onFooUpdate(FooUpdate notification);
+    void onBarUpdate(BarUpdate notification);
+    
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java
new file mode 100644 (file)
index 0000000..3161e93
--- /dev/null
@@ -0,0 +1,16 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public interface FooService extends RpcService {
+    
+    Future<RpcResult<Void>> foo();
+    
+    Future<RpcResult<Void>> simple(SimpleInput obj);
+    
+    Future<RpcResult<Void>> inheritedContextInput(InheritedContextInput obj);
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooUpdate.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooUpdate.java
new file mode 100644 (file)
index 0000000..a5a5eb8
--- /dev/null
@@ -0,0 +1,7 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public interface FooUpdate extends Notification {
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/Grouping.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/Grouping.java
new file mode 100644 (file)
index 0000000..86624e0
--- /dev/null
@@ -0,0 +1,11 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
+
+public interface Grouping {
+
+    @RoutingContext(BaseIdentity.class)
+    InstanceIdentifier getInheritedIdentifier();
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/InheritedContextInput.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/InheritedContextInput.java
new file mode 100644 (file)
index 0000000..39b20cc
--- /dev/null
@@ -0,0 +1,5 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+public interface InheritedContextInput extends Grouping {
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObject.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObject.java
new file mode 100644 (file)
index 0000000..8e0d457
--- /dev/null
@@ -0,0 +1,8 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+
+public interface ReferencableObject extends DataObject,Identifiable<ReferencableObjectKey> {
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObjectKey.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObjectKey.java
new file mode 100644 (file)
index 0000000..d2e1817
--- /dev/null
@@ -0,0 +1,44 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Identifier;
+
+public class ReferencableObjectKey implements Identifier<ReferencableObject> {
+
+    final Integer value;
+    
+    public ReferencableObjectKey(Integer _value) {
+        this.value = _value;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((value == null) ? 0 : value.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        ReferencableObjectKey other = (ReferencableObjectKey) obj;
+        if (value == null) {
+            if (other.value != null)
+                return false;
+        } else if (!value.equals(other.value))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "ReferencableObjectKey [value=" + value + "]";
+    }
+    
+    
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/SimpleInput.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/SimpleInput.java
new file mode 100644 (file)
index 0000000..dedbd98
--- /dev/null
@@ -0,0 +1,13 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
+
+public interface SimpleInput extends DataObject,Augmentable<SimpleInput> {
+
+    @RoutingContext(BaseIdentity.class)
+    InstanceIdentifier getIdentifier();
+}
index 2ccb4409520557ef750e3c0d1861c4f9e558898c..e001dc8e58765a619e1508c1dc30f5f4cf0362be 100644 (file)
@@ -62,6 +62,7 @@
               !org.codehaus.enunciate.jaxrs
             </Import-Package>
             <Web-ContextPath>/one/nb/v2/lb</Web-ContextPath>
+            <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
           </instructions>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
diff --git a/opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/LoadBalancerNorthboundRSApplication.java b/opendaylight/samples/northbound/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/northbound/LoadBalancerNorthboundRSApplication.java
deleted file mode 100644 (file)
index 2f5aaca..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  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.samples.loadbalancer.northbound;
-
-import java.util.HashSet;
-import java.util.Set;
-import javax.ws.rs.core.Application;
-
-import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
-
-/**
- * This class is an instance of javax.ws.rs.core.Application and is used to return the classes
- * that will be instantiated for JAXRS processing. This is necessary
- * because package scanning in jersey doesn't yet work in OSGi environment.
- *
- */
-public class LoadBalancerNorthboundRSApplication extends Application {
-    @Override
-    public Set<Class<?>> getClasses() {
-        Set<Class<?>> classes = new HashSet<Class<?>>();
-        classes.add(LoadBalancerNorthbound.class);
-        classes.add(JacksonJaxbJsonProvider.class);
-        return classes;
-    }
-}
index 0e8f8c1b5646b7eafcb223a7c4d5dd009cda52df..ae2fce582ae34b9fc49c5a4c32381f1d83dfa25f 100644 (file)
@@ -7,7 +7,7 @@
     <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
     <init-param>
       <param-name>javax.ws.rs.Application</param-name>
-      <param-value>org.opendaylight.controller.samples.loadbalancer.northbound.LoadBalancerNorthboundRSApplication</param-value>
+      <param-value>org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
   </servlet>
index 8be254e6b5eef24bae8eaf087289a81fbf3a851e..d7dea84686eca42ecf15a91e19dd1d58542a6845 100644 (file)
@@ -21,7 +21,7 @@
     <!-- Sonar properties using jacoco to retrieve integration test results -->
     <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
     <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
-    <sonar.jacoco.Reportpath>target/jacoco.exec</sonar.jacoco.Reportpath>
+    <sonar.jacoco.reportpath>target/jacoco.exec</sonar.jacoco.reportpath>
     <sonar.jacoco.itReportPath>target/jacoco-it.exec</sonar.jacoco.itReportPath>
     <sonar.language>java</sonar.language>
   </properties>
@@ -31,7 +31,7 @@
         <plugin>
           <groupId>org.jacoco</groupId>
           <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.5.3.201107060350</version>
+          <version>${jacoco.version}</version>
         </plugin>
       </plugins>
     </pluginManagement>
index 527dd0a02b3671451d6e612d3df25d69c7b0d1ba..d620d676f495bb286cca63dbb10ea0a6d19da81e 100644 (file)
     <!-- Sonar jacoco plugin to get integration test coverage info -->
     <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
     <sonar.jacoco.reportPath>../implementation/target/jacoco.exec</sonar.jacoco.reportPath>
-    <sonar.jacoco.itReportPath>../implementaiton/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+    <sonar.jacoco.itReportPath>../implementation/target/jacoco-it.exec</sonar.jacoco.itReportPath>
     <sonar.language>java</sonar.language>
   </properties>
   <build>
       <plugin>
         <groupId>org.jacoco</groupId>
         <artifactId>jacoco-maven-plugin</artifactId>
-        <version>0.5.3.201107060350</version>
+        <version>${jacoco.version}</version>
         <configuration>
           <destFile>../implementation/target/jacoco-it.exec</destFile>
           <includes>org.opendaylight.controller.*</includes>
index 607c42858e7b4ee52d8e9974c4d677ce1d61cc2f..14a056d5fee3b50ba27f2fe240d378495dc7ad85 100644 (file)
@@ -32,7 +32,7 @@
         <plugin>
           <groupId>org.jacoco</groupId>
           <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.5.3.201107060350</version>
+          <version>${jacoco.version}</version>
         </plugin>
       </plugins>
     </pluginManagement>
index 522f45946d98fbdc170db4ec9531d9128df53f97..4bb6438b32ce40a71b89796ecc81e91e7382c543 100644 (file)
@@ -14,10 +14,8 @@ import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.opendaylight.controller.sal.core.ConstructionException;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
-import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
 import org.opendaylight.controller.sal.utils.GUIField;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -116,32 +114,12 @@ public class SpanConfig implements Serializable {
     }
 
     public ArrayList<NodeConnector> getPortArrayList() {
-        Node node = Node.fromString(nodeId);
         ArrayList<NodeConnector> portList = new ArrayList<NodeConnector>();
         String[] elemArray = spanPort.split(",");
         for (String elem : elemArray) {
-            if (elem.contains("-")) {
-                String[] limits = elem.split("-");
-                for (short j = Short.valueOf(limits[0]); j <= Short
-                        .valueOf(limits[1]); j++) {
-                    try {
-                        portList.add(new NodeConnector(
-                                NodeConnectorIDType.OPENFLOW, Short.valueOf(j),
-                                node));
-                    } catch (ConstructionException e) {
-                        logger.error("",e);
-                    }
-                }
-            } else {
-                try {
-                    portList.add(new NodeConnector(
-                            NodeConnectorIDType.OPENFLOW, Short.valueOf(elem),
-                            node));
-                } catch (NumberFormatException e) {
-                    logger.error("",e);
-                } catch (ConstructionException e) {
-                    logger.error("",e);
-                }
+            NodeConnector nodeConnector = NodeConnector.fromString(elem);
+            if (nodeConnector != null) {
+                portList.add(nodeConnector);
             }
         }
         return portList;
index 1b09f3c34d62a26a204288c9143fc8b1e54f3dd4..ee126f3408ce51d6b1036f351f4ffb7a1be218b8 100644 (file)
@@ -32,7 +32,7 @@
         <plugin>
           <groupId>org.jacoco</groupId>
           <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.5.3.201107060350</version>
+          <version>${jacoco.version}</version>
         </plugin>
       </plugins>
     </pluginManagement>
index d571d9df532d682650033bdf0ae94eca349d176a..3fc63001d4dcc63e5f665b051cf0e5f253ece9c9 100644 (file)
     <!-- Sonar jacoco plugin to get integration test coverage info -->
     <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
     <sonar.jacoco.reportPath>../implementation/target/jacoco.exec</sonar.jacoco.reportPath>
-    <sonar.jacoco.itReportPath>../implementaiton/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+    <sonar.jacoco.itReportPath>../implementation/target/jacoco-it.exec</sonar.jacoco.itReportPath>
     <sonar.language>java</sonar.language>
   </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>
+        <version>${jacoco.version}</version>
         <configuration>
           <destFile>../implementation/target/jacoco-it.exec</destFile>
           <includes>org.opendaylight.controller.*</includes>
similarity index 97%
rename from opendaylight/topologymanager/pom.xml
rename to opendaylight/topologymanager/implementation/pom.xml
index 98bc0e42c81cf0cb08b7bcd5225289726c67b84e..399f878223aa639e5acd421ecb55b7134ab83d12 100755 (executable)
@@ -6,7 +6,7 @@
     <groupId>org.opendaylight.controller</groupId>
     <artifactId>commons.opendaylight</artifactId>
     <version>1.4.0-SNAPSHOT</version>
-    <relativePath>../commons/opendaylight</relativePath>
+    <relativePath>../../commons/opendaylight</relativePath>
   </parent>
   <scm>
     <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
index cca194e95337e30877aaff50332e37e6df4be30f..07c814adf14c7b2d35f9991a9bd3e5875296f922 100644 (file)
@@ -34,9 +34,11 @@ public class UserConfig implements Serializable {
     protected String user;
     protected List<String> roles;
     private String password;
+
+    private static final boolean strongPasswordCheck = Boolean.getBoolean("enableStrongPasswordCheck");
+    private static final String BAD_PASSWORD = "Bad Password";
     private static final int USERNAME_MAXLENGTH = 32;
-    private static final int PASSWORD_MINLENGTH = 5;
-    private static final int PASSWORD_MAXLENGTH = 256;
+    protected static final String PASSWORD_REGEX = "(?=.*[^\\w])(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,256}$";
     private static final Pattern INVALID_USERNAME_CHARACTERS = Pattern.compile("([/\\s\\.\\?#%;\\\\]+)");
     private static MessageDigest oneWayFunction = null;
     static {
@@ -63,16 +65,12 @@ public class UserConfig implements Serializable {
     public UserConfig(String user, String password, List<String> roles) {
         this.user = user;
 
-        this.password = password;
-        if (this.validatePassword().isSuccess()) {
-            /*
-             * Only if the password is a valid one, hash it. So in case it is not
-             * valid, when UserConfig.validate() is called, the proper
-             * validation error will be returned to the caller. If we hashed a
-             * priori instead, the mis-configuration would be masked
-             */
-            this.password = hash(this.password);
-        }
+        /*
+         * Password validation to be done on clear text password. If fails, mark
+         * the password with a well known label, so that object validation can
+         * report the proper error. Only if password is a valid one, hash it.
+         */
+        this.password = (validatePassword(password).isSuccess()) ? hash(password) : BAD_PASSWORD;
 
         this.roles = (roles == null) ? new ArrayList<String>() : new ArrayList<String>(roles);
     }
@@ -142,12 +140,15 @@ public class UserConfig implements Serializable {
     }
 
     public Status validate() {
-        Status validCheck = validateRoles();
+        Status validCheck = validateUsername();
         if (validCheck.isSuccess()) {
-            validCheck = validateUsername();
+            validCheck = (!password.equals(BAD_PASSWORD)) ? new Status(StatusCode.SUCCESS) : new Status(
+                    StatusCode.BADREQUEST,
+                    "Password should be 8 to 256 characters long, contain both upper and lower case letters, "
+                            + "at least one number and at least one non alphanumeric character");
         }
         if (validCheck.isSuccess()) {
-            validCheck = validatePassword();
+            validCheck = validateRoles();
         }
         return validCheck;
     }
@@ -168,15 +169,15 @@ public class UserConfig implements Serializable {
         return new Status(StatusCode.SUCCESS);
     }
 
-    private Status validatePassword() {
+    private Status validatePassword(String password) {
         if (password == null || password.isEmpty()) {
             return new Status(StatusCode.BADREQUEST, "Password cannot be empty");
         }
 
-        if (password.length() < UserConfig.PASSWORD_MINLENGTH
-                || password.length() > UserConfig.PASSWORD_MAXLENGTH) {
-            return new Status(StatusCode.BADREQUEST,
-                    "Password should have 5-256 characters");
+        if (strongPasswordCheck && !password.matches(UserConfig.PASSWORD_REGEX)) {
+            return new Status(StatusCode.BADREQUEST, "Password should be 8 to 256 characters long, "
+                    + "contain both upper and lower case letters, at least one number "
+                    + "and at least one non alphanumeric character");
         }
         return new Status(StatusCode.SUCCESS);
     }
@@ -247,4 +248,25 @@ public class UserConfig implements Serializable {
         UserConfig.oneWayFunction.reset();
         return HexEncode.bytesToHexString(UserConfig.oneWayFunction.digest(message.getBytes(Charset.defaultCharset())));
     }
+
+    /**
+     * Returns UserConfig instance populated with the passed parameters. It does
+     * not run any checks on the passed parameters.
+     *
+     * @param userName
+     *            the user name
+     * @param password
+     *            the plain text password
+     * @param roles
+     *            the list of roles
+     * @return the UserConfig object populated with the passed parameters. No
+     *         validity check is run on the input parameters.
+     */
+    public static UserConfig getUncheckedUserConfig(String userName, String password, List<String> roles) {
+        UserConfig config = new UserConfig();
+        config.user = userName;
+        config.password = hash(password);
+        config.roles = roles;
+        return config;
+    }
 }
index 4c2a19e426f1a88194b5f223a4245b2e67f3fd27..8c029a7488361b778b2749fe327a48a812d675c0 100644 (file)
@@ -117,4 +117,41 @@ public class AuthorizationUserConfigTest {
         UserConfig userConfig2 = new UserConfig("uname", "ciscocisco", roles);
         assertEquals(userConfig, userConfig2);
     }
+
+    @Test
+    public void userConfigPasswordTest() {
+
+        String regex = UserConfig.PASSWORD_REGEX;
+        String password = null;
+
+        // Good password
+        password = "aBc@eF#h9";
+        assertTrue(password.matches(regex));
+        password = "^aBc@eF#h9$88ad*o&";
+        assertTrue(password.matches(regex));
+        password = "_^aBc@\":eF#h;9$\\8|8ad*o&-(){}/,.><?+-";
+        assertTrue(password.matches(regex));
+        password = "culonE1)";
+        assertTrue(password.matches(regex));
+
+        // Too short
+        password = "aB3@eF#";
+        assertFalse(password.matches(regex));
+
+        // No number
+        password = "#BeCCC#CeDfDf";
+        assertFalse(password.matches(regex));
+
+        // No lower case
+        password = "AB8C#CC@C4";
+        assertFalse(password.matches(regex));
+
+        // No upper case
+        password = "ab8defg9!";
+        assertFalse(password.matches(regex));
+
+        // No special characters
+        password = "aBc4ef7H8";
+        assertFalse(password.matches(regex));
+    }
 }
index 0e7e2a37a73f19aefda0919ea8304ac8b375d34f..3898ca589ae710d36ea847eae03aa3742a6cccd6 100644 (file)
@@ -61,7 +61,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      */
     @Override
     public Object[] getImplementations() {
-        return null;
+        return new Object[]{};
     }
 
     /**
index 736568c74ca67911db80bf6ee7efc6c0073a2e3c..8d9e34717e31651cc4086b5a70798e11aceae9e5 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.controller.usermanager.internal;
 
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.ObjectInputStream;
@@ -72,13 +74,14 @@ import org.springframework.security.web.context.SecurityContextRepository;
 public class UserManager implements IUserManager, IObjectReader,
         IConfigurationAware, CommandProvider, AuthenticationProvider {
     private static final Logger logger = LoggerFactory.getLogger(UserManager.class);
-    private static final String defaultAdmin = "admin";
-    private static final String defaultAdminPassword = "admin";
-    private static final String defaultAdminRole = UserLevel.NETWORKADMIN.toString();
+    private static final String DEFAULT_ADMIN = "admin";
+    private static final String DEFAULT_ADMIN_PASSWORD = "admin";
+    private static final String DEFAULT_ADMIN_ROLE = UserLevel.NETWORKADMIN.toString();
     private static final String ROOT = GlobalConstants.STARTUPHOME.toString();
-    private static final String usersFileName = ROOT + "users.conf";
-    private static final String serversFileName = ROOT + "servers.conf";
-    private static final String authFileName = ROOT + "authorization.conf";
+    private static final String USERS_FILE_NAME = ROOT + "users.conf";
+    private static final String SERVERS_FILE_NAME = ROOT + "servers.conf";
+    private static final String AUTH_FILE_NAME = ROOT + "authorization.conf";
+    private static final String RECOVERY_FILE = ROOT + "NETWORK_ADMIN_PASSWORD_RECOVERY";
     private ConcurrentMap<String, UserConfig> localUserConfigList;
     private ConcurrentMap<String, ServerConfig> remoteServerConfigList;
     // local authorization info for remotely authenticated users
@@ -201,12 +204,44 @@ public class UserManager implements IUserManager, IObjectReader,
     }
 
     private void checkDefaultNetworkAdmin() {
-        // If startup config is not there, it's old or it was deleted,
-        // need to add Default Network Admin User
-        if (!localUserConfigList.containsKey(defaultAdmin)) {
+        /*
+         * If startup config is not there, it's old or it was deleted or if a
+         * password recovery was run, need to add Default Network Admin User
+         */
+        if (!localUserConfigList.containsKey(DEFAULT_ADMIN)) {
             List<String> roles = new ArrayList<String>(1);
-            roles.add(defaultAdminRole);
-            localUserConfigList.put(defaultAdmin, new UserConfig(defaultAdmin, defaultAdminPassword, roles));
+            roles.add(DEFAULT_ADMIN_ROLE);
+            // Need to skip the strong password check for the default admin
+            UserConfig defaultAdmin = UserConfig.getUncheckedUserConfig(UserManager.DEFAULT_ADMIN,
+                    UserManager.DEFAULT_ADMIN_PASSWORD, roles);
+            localUserConfigList.put(UserManager.DEFAULT_ADMIN, defaultAdmin);
+        }
+    }
+
+    private void checkPasswordRecovery() {
+        final String fileDescription = "Default Network Administrator password recovery file";
+        try {
+            FileInputStream fis = new FileInputStream(UserManager.RECOVERY_FILE);
+            /*
+             * Recovery file detected, remove current default network
+             * administrator entry from local users configuration list.
+             * Warn user and delete recovery file.
+             */
+            this.localUserConfigList.remove(UserManager.DEFAULT_ADMIN);
+            logger.info("Default Network Administrator password has been reset to factory default.");
+            logger.info("Please change the default Network Administrator password as soon as possible");
+            File filePointer = new File(UserManager.RECOVERY_FILE);
+            boolean status = filePointer.delete();
+            if (!status) {
+                logger.warn("Failed to delete {}", fileDescription);
+            } else {
+                logger.trace("{} deleted", fileDescription);
+            }
+            fis.close();
+        } catch (FileNotFoundException fnf) {
+            logger.trace("{} not present", fileDescription);
+        } catch (IOException e) {
+            logger.warn("Failed to close file stream for {}", fileDescription);
         }
     }
 
@@ -363,7 +398,7 @@ public class UserManager implements IUserManager, IObjectReader,
     private Status saveLocalUserListInternal() {
         ObjectWriter objWriter = new ObjectWriter();
         return objWriter.write(new ConcurrentHashMap<String, UserConfig>(
-                localUserConfigList), usersFileName);
+                localUserConfigList), USERS_FILE_NAME);
     }
 
     @Override
@@ -374,7 +409,7 @@ public class UserManager implements IUserManager, IObjectReader,
     private Status saveAAAServerListInternal() {
         ObjectWriter objWriter = new ObjectWriter();
         return objWriter.write(new ConcurrentHashMap<String, ServerConfig>(
-                remoteServerConfigList), serversFileName);
+                remoteServerConfigList), SERVERS_FILE_NAME);
     }
 
     @Override
@@ -386,7 +421,7 @@ public class UserManager implements IUserManager, IObjectReader,
         ObjectWriter objWriter = new ObjectWriter();
         return objWriter.write(
                 new ConcurrentHashMap<String, AuthorizationConfig>(
-                        authorizationConfList), authFileName);
+                        authorizationConfList), AUTH_FILE_NAME);
     }
 
     @Override
@@ -401,7 +436,7 @@ public class UserManager implements IUserManager, IObjectReader,
     private void loadUserConfig() {
         ObjectReader objReader = new ObjectReader();
         ConcurrentMap<String, UserConfig> confList = (ConcurrentMap<String, UserConfig>) objReader
-                .read(this, usersFileName);
+                .read(this, USERS_FILE_NAME);
 
         if (confList == null) {
             return;
@@ -416,7 +451,7 @@ public class UserManager implements IUserManager, IObjectReader,
     private void loadServerConfig() {
         ObjectReader objReader = new ObjectReader();
         ConcurrentMap<String, ServerConfig> confList = (ConcurrentMap<String, ServerConfig>) objReader
-                .read(this, serversFileName);
+                .read(this, SERVERS_FILE_NAME);
 
         if (confList == null) {
             return;
@@ -431,7 +466,7 @@ public class UserManager implements IUserManager, IObjectReader,
     private void loadAuthConfig() {
         ObjectReader objReader = new ObjectReader();
         ConcurrentMap<String, AuthorizationConfig> confList = (ConcurrentMap<String, AuthorizationConfig>) objReader
-                .read(this, authFileName);
+                .read(this, AUTH_FILE_NAME);
 
         if (confList == null) {
             return;
@@ -455,7 +490,7 @@ public class UserManager implements IUserManager, IObjectReader,
         String user = AAAconf.getUser();
 
         // Check default admin user
-        if (user.equals(UserManager.defaultAdmin)) {
+        if (user.equals(UserManager.DEFAULT_ADMIN)) {
             String msg = "Invalid Request: Default Network Admin  User cannot be " + ((delete)? "removed" : "added");
             logger.debug(msg);
             return new Status(StatusCode.NOTALLOWED, msg);
@@ -791,12 +826,14 @@ public class UserManager implements IUserManager, IObjectReader,
         // Read startup configuration and populate databases
         loadConfigurations();
 
+        // Check if a password recovery was triggered for default network admin user
+        checkPasswordRecovery();
+
         // Make sure default Network Admin account is there
         checkDefaultNetworkAdmin();
-        BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
-                .getBundleContext();
-        bundleContext.registerService(CommandProvider.class.getName(), this,
-                null);
+
+        BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+        bundleContext.registerService(CommandProvider.class.getName(), this, null);
     }
 
     /**
index b322f5845f6907379fb2c7ef13ad5fc4c5d23e5c..ac52095aea62f6f309c751ce4a642df272fa1f71 100644 (file)
@@ -40,6 +40,7 @@
               org.opendaylight.controller.usermanager,
               org.opendaylight.controller.web,
               com.google.gson,
+              com.google.gson.reflect,
               javax.annotation,
               javax.naming,
               javax.servlet,
index 4e08f99bfd411aab360999092045cfa48da0c663..6ca60e857d8a86963be038ca1c4714050d7bff39 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.controller.devices.web;
 
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -54,6 +55,7 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 
 import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
 
 @Controller
 @RequestMapping("/")
@@ -634,6 +636,11 @@ public class Devices implements IDaylightWeb {
                         // Add switch portName value (non-configuration field)
                         config.put("nodeName",
                                 getNodeDesc(config_data.get("nodeId"), containerName));
+                        NodeConnector spanPortNodeConnector = NodeConnector.fromString(config_data.get("spanPort"));
+                        Name ncName = ((Name) switchManager.getNodeConnectorProp(spanPortNodeConnector,
+                                Name.NamePropName));
+                        String spanPortName = (ncName != null) ? ncName.getValue() : "";
+                        config.put("spanPortName", spanPortName);
                     }
                     config.put("json", config_json);
                     spanConfigs.add(config);
@@ -746,22 +753,21 @@ public class Devices implements IDaylightWeb {
             Gson gson = new Gson();
             ISwitchManager switchManager = (ISwitchManager) ServiceHelper
                     .getInstance(ISwitchManager.class, containerName, this);
-            String[] spans = spanPortsToDelete.split("###");
-            resultBean.setStatus(true);
-            resultBean.setMessage("SPAN Port(s) deleted successfully");
-            for (String span : spans) {
-                if (!span.isEmpty()) {
-                    SpanConfig cfgObject = gson
-                            .fromJson(span, SpanConfig.class);
-                    Status result = switchManager.removeSpanConfig(cfgObject);
-                    if (!result.isSuccess()) {
-                        resultBean.setStatus(false);
-                        resultBean.setMessage(result.getDescription());
-                        break;
-                    }
-                    DaylightWebUtil.auditlog("SPAN Port", userName, "removed", cfgObject.getNodeId(), containerName);
+            Type collectionType = new TypeToken<List<SpanPortJsonBean>>() {}.getType();
+            List<SpanPortJsonBean> jsonBeanList = gson.fromJson(spanPortsToDelete, collectionType);
+            for (SpanPortJsonBean jsonBean : jsonBeanList) {
+                SpanConfig cfgObject = gson
+                        .fromJson(gson.toJson(jsonBean), SpanConfig.class);
+                Status result = switchManager.removeSpanConfig(cfgObject);
+                if (!result.isSuccess()) {
+                    resultBean.setStatus(false);
+                    resultBean.setMessage(result.getDescription());
+                    break;
                 }
+                DaylightWebUtil.auditlog("SPAN Port", userName, "removed", cfgObject.getNodeId(), containerName);
             }
+            resultBean.setStatus(true);
+            resultBean.setMessage("SPAN Port(s) deleted successfully");
         } catch (Exception e) {
             resultBean.setStatus(false);
             resultBean.setMessage("Error occurred while deleting span port. "
diff --git a/opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/SpanPortJsonBean.java b/opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/SpanPortJsonBean.java
new file mode 100644 (file)
index 0000000..b9be40b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.devices.web;
+
+public class SpanPortJsonBean {
+
+    private String nodeId;
+    private String spanPort;
+
+    public String getNodeId() {
+        return nodeId;
+    }
+
+    public void setNodeId(String nodeId) {
+        this.nodeId = nodeId;
+    }
+
+    public String getSpanPort() {
+        return spanPort;
+    }
+
+    public void setSpanPort(String spanPort) {
+        this.spanPort = spanPort;
+    }
+
+}
index 813df23f8254753dab7132df8aa4667b459f56fd..2488d06d0cae7745a4efc58c8d8a42ff1f565271 100644 (file)
@@ -1239,7 +1239,12 @@ one.f.switchmanager.spanPortConfig = {
                         return false;
                     }
                     checkedCheckBoxes.each(function(index, value) {
-                        spanPortsToDelete.push(decodeURIComponent(checkedCheckBoxes[index].getAttribute("spanPort")));
+                        var spanPortObj = {};
+                        spanPortObj['spanPortJson'] = decodeURIComponent(checkedCheckBoxes[index].getAttribute("spanPort"));
+                        spanPortObj['spanPortNodeName'] = checkedCheckBoxes[index].getAttribute("spanPortNode");
+                        spanPortObj['spanPortPortName'] = checkedCheckBoxes[index].getAttribute("spanPortPort");
+
+                        spanPortsToDelete.push(spanPortObj);
                     });
                     one.f.switchmanager.spanPortConfig.modal.removeMultiple.dialog(spanPortsToDelete);
                 });
@@ -1392,12 +1397,12 @@ one.f.switchmanager.spanPortConfig = {
                 // bind remove rule button
                 $('#'+one.f.switchmanager.spanPortConfig.id.modal.remove, $modal).click(this, function(e) {
                     var requestData = {};
-                    var spanPorts="";
-                    $(spanPortsToDelete).each(function(){
-                        spanPorts = spanPorts + "###" + this.toString();
+                    var spanPorts = [];
+                    $(spanPortsToDelete).each(function(index, spanPort) {
+                        spanPorts.push(JSON.parse(spanPort.spanPortJson));
                     });
-                    requestData["spanPortsToDelete"] = spanPorts.slice(3,spanPorts.length);
-                    
+                    requestData["spanPortsToDelete"] = JSON.stringify(spanPorts);
+
                     var url = one.f.switchmanager.rootUrl + "/spanPorts/delete";
                     one.f.switchmanager.spanPortConfig.ajax.main(url, requestData, function(response) {
                         $modal.modal('hide');
@@ -1429,10 +1434,9 @@ one.f.switchmanager.spanPortConfig = {
                 var p = 'Remove the following Span Port(s)?';
                 //creata a BS label for each rule and append to list
 
-                var spanPortList = JSON.parse("["+spanPortToDelete.toString()+"]");
-                $(spanPortList).each(function(){
+                $(spanPortToDelete).each(function(index, spanPortItem) {
                     var $span = $(document.createElement('span'));
-                    $span.append(this.nodeId+"-"+this.spanPort);
+                    $span.append(this.spanPortNodeName+"-"+this.spanPortPortName);
                     p += '<br/>' + $span[0].outerHTML;
                 });
                 $p.append(p);
@@ -1457,7 +1461,7 @@ one.f.switchmanager.spanPortConfig = {
                             sortable: true
                         },
                         {
-                            property: 'spanPort',
+                            property: 'spanPortName',
                             label: 'SPAN Port',
                             sortable: true
                         },
@@ -1465,7 +1469,7 @@ one.f.switchmanager.spanPortConfig = {
                     data: data.nodeData,
                     formatter: function(items) {
                         $.each(items, function(index, item) {
-                            item["selector"] = '<input type="checkbox" class="spanPortConfig" spanPort=' + encodeURIComponent(item["json"]) + '></input>';
+                            item["selector"] = '<input type="checkbox" class="spanPortConfig" spanPort=' + encodeURIComponent(item["json"]) + ' spanPortNode=' + item["nodeName"] + ' spanPortPort=' + item["spanPortName"] + '></input>';
                         });
                     },
                     delay: 0
index 2b58bcc4cb6c1fb50b12801e2e6133078a13e47f..eafd8c54a773eb9bb933dd9f0d3f1cdd14d2b9c5 100644 (file)
@@ -15,6 +15,7 @@ import java.util.List;
 import java.util.Set;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
 
 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
 import org.opendaylight.controller.connectionmanager.IConnectionManager;
@@ -212,24 +213,63 @@ public class DaylightWebAdmin {
 
     @RequestMapping(value = "/users/password/{username}", method = RequestMethod.POST)
     @ResponseBody
-    public Status changePassword(@PathVariable("username") String username, HttpServletRequest request,
-            @RequestParam("currentPassword") String currentPassword, @RequestParam("newPassword") String newPassword) {
+    public Status changePassword(
+            @PathVariable("username") String username, HttpServletRequest request,
+            @RequestParam(value = "currentPassword", required=false) String currentPassword,
+            @RequestParam("newPassword") String newPassword) {
         IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
         if (userManager == null) {
-            return new Status(StatusCode.GONE, "User Manager not found");
+            return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
         }
 
-        if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
-            return new Status(StatusCode.FORBIDDEN, "Operation not permitted");
-        }
+        Status status;
+        String requestingUser = request.getUserPrincipal().getName();
+
+        //changing own password
+        if (requestingUser.equals(username) ) {
+            status = userManager.changeLocalUserPassword(username, currentPassword, newPassword);
+            //enforce the user to re-login with new password
+            if (status.isSuccess() && !newPassword.equals(currentPassword)) {
+                userManager.userLogout(username);
+                HttpSession session = request.getSession(false);
+                if ( session != null) {
+                    session.invalidate();
+                }
+            }
+
+        //admin level user resetting other's password
+        } else if (authorize(userManager, UserLevel.NETWORKADMIN, request)) {
+
+            //Since User Manager doesn't have an unprotected password change API,
+            //we re-create the user with the new password (and current roles).
+            List<String> roles = userManager.getUserRoles(username);
+            UserConfig newConfig = new UserConfig(username, newPassword, roles);
+
+            //validate before removing existing config, so we don't remove but fail to add
+            status = newConfig.validate();
+            if (!status.isSuccess()) {
+                return status;
+            }
+
+            userManager.userLogout(username);
+            status = userManager.removeLocalUser(username);
+            if (!status.isSuccess()) {
+                return status;
+            }
+            if (userManager.addLocalUser(newConfig).isSuccess()) {
+                status = new Status(StatusCode.SUCCESS, "Password for user " + username + " reset successfully.");
+            } else {
+                //unexpected
+                status = new Status(StatusCode.INTERNALERROR, "Failed resetting password for user " + username + ". User is now removed.");
+            }
 
-        if (newPassword.isEmpty()) {
-            return new Status(StatusCode.BADREQUEST, "Empty passwords not allowed");
+        //unauthorized
+        } else {
+            status = new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
         }
 
-        Status status = userManager.changeLocalUserPassword(username, currentPassword, newPassword);
         if (status.isSuccess()) {
-            DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "changed password for", username);
+            DaylightWebUtil.auditlog("User", requestingUser, "changed password for", username);
         }
         return status;
     }
index c795a5d56b920de6111141bea501a8b3dbcfaa57..4b0ce2d07d3d55a51c2ac873b642ce081c659728 100644 (file)
@@ -67,6 +67,7 @@
    </div>
    <div class="span3">
     <div id="toolbar" class="btn-group">
+    <input type="hidden" id="currentuser" value="${username}" data-role="${role}">
      <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
       <div class="icon-user"></div> ${username} <span class="caret"></span>
      </a>
index 43a7dfdc443ab7447fb472dc31afa1b83402f9d7..619edcaf2cba5ed4bb5d5d08359c13333a702d5a 100644 (file)
@@ -443,9 +443,12 @@ one.main.admin = {
       // change password binding
       $('#'+one.main.admin.id.modal.password.submit, $modal).click(function() {
         one.main.admin.password.submit(id, $modal, function(result) {
-          if (result.code == 'SUCCESS') {
-            $modal.modal('hide');
-            successCallback();
+          if (result.success) {
+            //if changed own password, enforce relogin
+            if (id.trim() == $('#currentuser').val().trim()) {
+                alert("Password changed successfully. Please re-login with your new password.");
+                window.location = '/';
+            }
           } else {
             alert(result.code+': '+result.description);
           }
index fed81eb2ae886aa6bbbb062a8499aa3be90f8026..a6c390d799bb1fa54ac1329436ab2a3b47d2b037 100644 (file)
@@ -340,29 +340,31 @@ public class Topology implements IObjectReader, IConfigurationAware {
             ITopologyManager topology, String containerName) {
         for (Map.Entry<Node, Set<NodeConnector>> e : hostEdges.entrySet()) {
             for (NodeConnector connector : e.getValue()) {
-                Host host = topology.getHostAttachedToNodeConnector(connector);
-                EthernetAddress dmac = (EthernetAddress) host.getDataLayerAddress();
+                List<Host> hosts = topology.getHostsAttachedToNodeConnector(connector);
+                for (Host host : hosts) {
+                    EthernetAddress dmac = (EthernetAddress) host.getDataLayerAddress();
 
-                ByteBuffer addressByteBuffer = ByteBuffer.allocate(8);
-                addressByteBuffer.putShort((short) 0);
-                addressByteBuffer.put(dmac.getValue());
-                addressByteBuffer.rewind();
+                    ByteBuffer addressByteBuffer = ByteBuffer.allocate(8);
+                    addressByteBuffer.putShort((short) 0);
+                    addressByteBuffer.put(dmac.getValue());
+                    addressByteBuffer.rewind();
 
-                long hid = addressByteBuffer.getLong();
-                String hostId = String.valueOf(hid);
+                    long hid = addressByteBuffer.getLong();
+                    String hostId = String.valueOf(hid);
 
-                NodeBean hostBean = new NodeBean(hostId, host.getNetworkAddressAsString(), NodeType.HOST);
-                List<Map<String, Object>> adjacencies = new LinkedList<Map<String, Object>>();
-                EdgeBean edge = new EdgeBean(connector, hid);
-                adjacencies.add(edge.out());
-                hostBean.setLinks(adjacencies);
+                    NodeBean hostBean = new NodeBean(hostId, host.getNetworkAddressAsString(), NodeType.HOST);
+                    List<Map<String, Object>> adjacencies = new LinkedList<Map<String, Object>>();
+                    EdgeBean edge = new EdgeBean(connector, hid);
+                    adjacencies.add(edge.out());
+                    hostBean.setLinks(adjacencies);
 
-                if (metaCache.get(containerName).containsKey(hostId)) {
+                    if (metaCache.get(containerName).containsKey(hostId)) {
                         Map<String, Object> hostEntry = metaCache.get(containerName).get(hostId);
                         hostEntry.put("adjacencies", adjacencies);
                         stagedNodes.put(hostId, hostEntry);
-                } else {
+                    } else {
                         newNodes.put(String.valueOf(hid), hostBean.out());
+                    }
                 }
             }
         }
index 92a2e866f02840f57c2f70dcf4f8b383eb6dccd9..603f4ccb9e529f20251148e3db452d755eb6e3c3 100644 (file)
@@ -158,7 +158,7 @@ public enum OFType {
      * @param i OpenFlow wire protocol type
      * @param t type
      */
-    static public void addMapping(byte i, OFType t) {
+    public static void addMapping(byte i, OFType t) {
         if (mapping == null)
             mapping = new OFType[32];
         OFType.mapping[i] = t;
@@ -169,7 +169,7 @@ public enum OFType {
      *
      * @param i OpenFlow wire protocol type
      */
-    static public void removeMapping(byte i) {
+    public static void removeMapping(byte i) {
         OFType.mapping[i] = null;
     }
 
@@ -181,7 +181,7 @@ public enum OFType {
      * @return OFType enum type
      */
 
-    static public OFType valueOf(Byte i) {
+    public static OFType valueOf(Byte i) {
         return OFType.mapping[i];
     }