From: Tony Tkacik Date: Mon, 27 Oct 2014 10:22:29 +0000 (+0000) Subject: Merge "BUG 1839 - HTTP delete of non existing data" X-Git-Tag: release/lithium~970 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=531621aac4cff9d39cbd8668a53bdeba8a0e6d81;hp=4c22825994c2519fb1c9d63f0050ebf35c4f8439 Merge "BUG 1839 - HTTP delete of non existing data" --- diff --git a/features/adsal-compatibility/pom.xml b/features/adsal-compatibility/pom.xml index 44b9b0900c..7b8af64445 100644 --- a/features/adsal-compatibility/pom.xml +++ b/features/adsal-compatibility/pom.xml @@ -10,14 +10,14 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../opendaylight/commons/opendaylight features-adsal-compatibility jar features.xml - 0.6.2-SNAPSHOT + 0.7.0-SNAPSHOT diff --git a/features/adsal/src/main/resources/features.xml b/features/adsal/src/main/resources/features.xml index e12ca8e5e9..a665657ba7 100644 --- a/features/adsal/src/main/resources/features.xml +++ b/features/adsal/src/main/resources/features.xml @@ -35,7 +35,6 @@ odl-adsal-core mvn:org.opendaylight.controller/clustering.services/${clustering.services.version} mvn:org.opendaylight.controller/clustering.services-implementation/${clustering.services_implementation.version} - mvn:org.opendaylight.controller/clustering.stub/${clustering.stub.version} odl-adsal-core diff --git a/features/akka/pom.xml b/features/akka/pom.xml index f1f3017c20..f804505c64 100644 --- a/features/akka/pom.xml +++ b/features/akka/pom.xml @@ -10,7 +10,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../opendaylight/commons/opendaylight features-akka @@ -20,11 +20,11 @@ features.xml - 1.0.0-SNAPSHOT - 1.4.2-SNAPSHOT + 1.1.0-SNAPSHOT + 1.5.0-SNAPSHOT 3.0.1 - 0.6.2-SNAPSHOT - 1.4.2-SNAPSHOT + 0.7.0-SNAPSHOT + 1.5.0-SNAPSHOT 2.16 @@ -42,21 +42,21 @@ org.opendaylight.yangtools features-yangtools - 0.6.2-SNAPSHOT + 0.7.0-SNAPSHOT features xml org.opendaylight.controller features-mdsal - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT features xml org.opendaylight.openflowplugin features-openflowplugin - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT features xml diff --git a/features/akka/src/main/resources/features.xml b/features/akka/src/main/resources/features.xml index 182ff766e6..8a3b4a2e25 100644 --- a/features/akka/src/main/resources/features.xml +++ b/features/akka/src/main/resources/features.xml @@ -18,9 +18,9 @@ Necessary TODO: Add repo entries for the repositories of features you refer to in this feature file but do not define here. Examples: - mvn:org.opendaylight.yangtools/features-yangtools/0.6.2-SNAPSHOT/xml/features - mvn:org.opendaylight.controller/features-mdsal/1.1-SNAPSHOT/xml/features - mvn:org.opendaylight.openflowplugin/features-openflowplugin/0.0.3-SNAPSHOT/xml/features + mvn:org.opendaylight.yangtools/features-yangtools/0.7.0-SNAPSHOT/xml/features + mvn:org.opendaylight.controller/features-mdsal/1.2.0-SNAPSHOT/xml/features + mvn:org.opendaylight.openflowplugin/features-openflowplugin/0.1.0-SNAPSHOT/xml/features --> org.opendaylight.controller opendaylight-karaf-empty - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT zip diff --git a/features/base/src/main/resources/features.xml b/features/base/src/main/resources/features.xml index e4c455ccca..d7d8e0ddac 100644 --- a/features/base/src/main/resources/features.xml +++ b/features/base/src/main/resources/features.xml @@ -16,8 +16,8 @@ odl-base-jackson odl-base-spring-security - - mvn:org.opendaylight.controller/dummy-console/1.1.0-SNAPSHOT + + mvn:org.opendaylight.controller/dummy-console/1.2.0-SNAPSHOT mvn:org.osgi/org.osgi.compendium/${osgi.compendium.version} @@ -36,7 +36,7 @@ wrap:mvn:io.netty/netty-common/${netty.version} wrap:mvn:io.netty/netty-handler/${netty.version} wrap:mvn:io.netty/netty-codec-http/${netty.version} - mvn:org.opendaylight.controller.thirdparty/ganymed/1.1-SNAPSHOT + mvn:org.opendaylight.controller.thirdparty/ganymed/1.2.0-SNAPSHOT odl-base-gemini-web @@ -80,6 +80,7 @@ mvn:eclipselink/javax.persistence/2.0.4.v201112161009 mvn:eclipselink/javax.resource/1.5.0.v200906010428 + mvn:org.eclipse.persistence/org.eclipse.persistence.antlr/2.5.0 mvn:org.eclipse.persistence/org.eclipse.persistence.moxy/2.5.0 mvn:org.eclipse.persistence/org.eclipse.persistence.core/2.5.0 diff --git a/features/config-netty/pom.xml b/features/config-netty/pom.xml index bf036979cf..0057fc05c7 100644 --- a/features/config-netty/pom.xml +++ b/features/config-netty/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../../opendaylight/config/ features-config-netty diff --git a/features/config-persister/pom.xml b/features/config-persister/pom.xml index 3346c754d6..f3b42ca143 100644 --- a/features/config-persister/pom.xml +++ b/features/config-persister/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../../opendaylight/config/ features-config-persister diff --git a/features/config/pom.xml b/features/config/pom.xml index 20feceb360..461427c7ce 100644 --- a/features/config/pom.xml +++ b/features/config/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../../opendaylight/config/ features-config @@ -20,7 +20,7 @@ org.opendaylight.controller opendaylight-karaf-empty - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT zip diff --git a/features/controller/pom.xml b/features/controller/pom.xml index ddaf773151..5dd2bd4a2a 100644 --- a/features/controller/pom.xml +++ b/features/controller/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../opendaylight/commons/opendaylight controller-features diff --git a/features/extras/pom.xml b/features/extras/pom.xml index 4563190b9f..e4356e6b49 100644 --- a/features/extras/pom.xml +++ b/features/extras/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../opendaylight/commons/opendaylight extras-features diff --git a/features/flow/pom.xml b/features/flow/pom.xml index ac189737d9..ab30b0b61f 100644 --- a/features/flow/pom.xml +++ b/features/flow/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT ../../opendaylight/md-sal features-flow diff --git a/features/mdsal/pom.xml b/features/mdsal/pom.xml index 960dfb37a1..036d18fb85 100644 --- a/features/mdsal/pom.xml +++ b/features/mdsal/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT ../../opendaylight/md-sal features-mdsal @@ -13,6 +13,7 @@ features.xml + 20131018 @@ -67,6 +68,11 @@ org.opendaylight.controller sal-dom-xsql + + + org.opendaylight.controller + sal-karaf-xsql + org.opendaylight.controller sal-dom-xsql-config @@ -259,6 +265,20 @@ xml config + + org.opendaylight.controller.samples + clustering-it-config + ${mdsal.version} + xml + testmoduleshardconf + + + org.opendaylight.controller.samples + clustering-it-config + ${mdsal.version} + xml + testmoduleconf + org.opendaylight.controller sal-rest-docgen @@ -299,7 +319,7 @@ org.opendaylight.yangtools features-test - 0.6.2-SNAPSHOT + 0.7.0-SNAPSHOT diff --git a/features/mdsal/src/main/resources/features.xml b/features/mdsal/src/main/resources/features.xml index da246b63e3..fb524081e7 100644 --- a/features/mdsal/src/main/resources/features.xml +++ b/features/mdsal/src/main/resources/features.xml @@ -11,13 +11,13 @@ odl-mdsal-broker odl-mdsal-clustering - odl-restconf odl-mdsal-xsql odl-toaster odl-yangtools-common odl-yangtools-binding + odl-yangtools-models odl-mdsal-common odl-config-startup odl-config-netty @@ -32,24 +32,6 @@ mvn:org.opendaylight.controller/sal-inmemory-datastore/${project.version} mvn:org.opendaylight.controller/md-sal-config/${mdsal.version}/xml/config - - odl-mdsal-broker - war - mvn:org.opendaylight.controller/sal-rest-connector/${project.version} - mvn:com.google.code.gson/gson/${gson.version} - mvn:org.opendaylight.yangtools/yang-data-codec-gson/${yangtools.version} - mvn:com.sun.jersey/jersey-core/${jersey.version} - mvn:com.sun.jersey/jersey-server/${jersey.version} - mvn:com.sun.jersey/jersey-servlet/${jersey.version} - mvn:io.netty/netty-buffer/${netty.version} - mvn:io.netty/netty-codec/${netty.version} - mvn:io.netty/netty-codec-http/${netty.version} - mvn:io.netty/netty-common/${netty.version} - mvn:io.netty/netty-handler/${netty.version} - mvn:io.netty/netty-transport/${netty.version} - mvn:org.opendaylight.controller/sal-remote/${project.version} - mvn:org.opendaylight.controller/sal-rest-connector-config/${mdsal.version}/xml/config - odl-yangtools-common odl-yangtools-binding @@ -62,23 +44,9 @@ odl-mdsal-broker mvn:org.opendaylight.controller/sal-dom-xsql/${project.version} + mvn:org.opendaylight.controller/sal-karaf-xsql/${project.version} mvn:org.opendaylight.controller/sal-dom-xsql-config/${project.version}/xml/config - - odl-restconf - mvn:org.opendaylight.controller/sal-rest-docgen/${project.version} - mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson.version} - mvn:com.fasterxml.jackson.core/jackson-core/${jackson.version} - mvn:com.fasterxml.jackson.core/jackson-databind/${jackson.version} - mvn:com.fasterxml.jackson.datatype/jackson-datatype-json-org/${jackson.version} - mvn:com.fasterxml.jackson.module/jackson-module-jaxb-annotations/${jackson.version} - mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/${jackson.version} - mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/${jackson.version} - mvn:com.sun.jersey/jersey-core/${jersey.version} - mvn:com.sun.jersey/jersey-server/${jersey.version} - mvn:com.sun.jersey/jersey-servlet/${jersey.version} - wrap:mvn:org.json/json/${org.json.version} - odl-mdsal-broker odl-akka-system @@ -108,15 +76,4 @@ mvn:org.opendaylight.controller/sal-clustering-config/${project.version}/xml/moduleshardconf mvn:org.opendaylight.controller/sal-clustering-config/${project.version}/xml/moduleconf - - - odl-mdsal-clustering - odl-restconf - odl-yangtools-models - mvn:org.opendaylight.controller.samples/clustering-it-model/${project.version} - mvn:org.opendaylight.controller.samples/clustering-it-provider/${project.version} - mvn:org.opendaylight.controller.samples/clustering-it-config/${project.version}/xml/config - mvn:org.opendaylight.controller.samples/clustering-it-config/${project.version}/xml/testmoduleshardconf - mvn:org.opendaylight.controller.samples/clustering-it-config/${project.version}/xml/testmoduleconf - diff --git a/features/netconf-connector/pom.xml b/features/netconf-connector/pom.xml index 8b19d200a3..b44fa11657 100644 --- a/features/netconf-connector/pom.xml +++ b/features/netconf-connector/pom.xml @@ -10,7 +10,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT ../../opendaylight/md-sal features-netconf-connector jar @@ -42,21 +42,21 @@ org.opendaylight.yangtools features-yangtools - 0.6.2-SNAPSHOT + 0.7.0-SNAPSHOT features xml org.opendaylight.controller features-mdsal - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT features xml org.opendaylight.openflowplugin features-openflowplugin - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT features xml @@ -162,12 +162,13 @@ Optional TODO: Remove TODO comments. --> - - org.opendaylight.yangtools - features-test - ${yangtools.version} - test - + + + + + + + org.opendaylight.controller diff --git a/features/netconf-connector/src/main/resources/features.xml b/features/netconf-connector/src/main/resources/features.xml index 3e576e47f1..6ae308eb0c 100644 --- a/features/netconf-connector/src/main/resources/features.xml +++ b/features/netconf-connector/src/main/resources/features.xml @@ -18,9 +18,9 @@ Necessary TODO: Add repo entries for the repositories of features you refer to in this feature file but do not define here. Examples: - mvn:org.opendaylight.yangtools/features-yangtools/0.6.2-SNAPSHOT/xml/features - mvn:org.opendaylight.controller/features-mdsal/1.1-SNAPSHOT/xml/features - mvn:org.opendaylight.openflowplugin/features-openflowplugin/0.0.3-SNAPSHOT/xml/features + mvn:org.opendaylight.yangtools/features-yangtools/0.7.0-SNAPSHOT/xml/features + mvn:org.opendaylight.controller/features-mdsal/1.2.0-SNAPSHOT/xml/features + mvn:org.opendaylight.openflowplugin/features-openflowplugin/0.1.0-SNAPSHOT/xml/features --> mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features @@ -54,7 +54,7 @@ * Basic MD-SAL Provider - odl-mdsal-broker + odl-mdsal-broker odl-controller-model mvn:org.opendaylight.controller/controller-provider/${project.version} ... whatever other bundles you need @@ -62,15 +62,15 @@ * Basic MD-SAL Model feature - odl-yangtools-binding - odl-yangtools-models + odl-yangtools-binding + odl-yangtools-models mvn:org.opendaylight.controller/controller-model/${project.version} ... whatever other bundles you need * Config Subsystem example - the config file is your config subsystem configuration - odl-mdsal-broker + odl-mdsal-broker mvn:org.opendaylight.controller/controller-provider/${project.version} mvn:org.opendaylight.controller/controller-config/${project.version}/xml/config ... whatever other bundles you need @@ -78,7 +78,7 @@ * Basic MD-SAL Provider that uses openflowplugin-flow-services (which brings along odl-mdsal-broker) - odl-openflowplugin-flow-services + odl-openflowplugin-flow-services mvn:org.opendaylight.controller/controller-provider/${project.version} ... whatever other bundles you need diff --git a/features/netconf/pom.xml b/features/netconf/pom.xml index 1061f4a37d..a944bb4dec 100644 --- a/features/netconf/pom.xml +++ b/features/netconf/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../../opendaylight/netconf features-netconf diff --git a/features/netconf/src/main/resources/features.xml b/features/netconf/src/main/resources/features.xml index 743dae663e..444f20865b 100644 --- a/features/netconf/src/main/resources/features.xml +++ b/features/netconf/src/main/resources/features.xml @@ -11,8 +11,6 @@ odl-netconf-mapping-api odl-netconf-util odl-netconf-impl - odl-netconf-tcp - odl-netconf-ssh odl-config-netconf-connector odl-netconf-netty-util odl-netconf-client diff --git a/features/nsf/pom.xml b/features/nsf/pom.xml index e677d491bc..00dc219b39 100644 --- a/features/nsf/pom.xml +++ b/features/nsf/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../opendaylight/commons/opendaylight features-nsf @@ -25,7 +25,7 @@ org.opendaylight.controller opendaylight-karaf-empty - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT zip diff --git a/features/pom.xml b/features/pom.xml index 9f10b5908b..5270e3f5cd 100644 --- a/features/pom.xml +++ b/features/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../opendaylight/commons/opendaylight features-controller @@ -28,5 +28,6 @@ adsal-compatibility akka netconf-connector + restconf \ No newline at end of file diff --git a/features/protocol-framework/pom.xml b/features/protocol-framework/pom.xml index dcd24d6216..d5387b43c3 100644 --- a/features/protocol-framework/pom.xml +++ b/features/protocol-framework/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../opendaylight/commons/opendaylight features-protocol-framework diff --git a/features/restconf/pom.xml b/features/restconf/pom.xml new file mode 100644 index 0000000000..632b4cd592 --- /dev/null +++ b/features/restconf/pom.xml @@ -0,0 +1,346 @@ + + + 4.0.0 + + org.opendaylight.controller + sal-parent + 1.2.0-SNAPSHOT + ../../opendaylight/md-sal + + + features-restconf + org.opendaylight.controller + + jar + + features.xml + + + + + + + + + org.opendaylight.yangtools + features-yangtools + ${yangtools.version} + features + xml + + + org.opendaylight.controller + features-mdsal + ${mdsal.version} + features + xml + + + org.opendaylight.aaa + features-aaa + ${aaa.version} + features + xml + + + + org.opendaylight.controller + sal-remote + + + + org.opendaylight.controller + sal-rest-connector + + + + com.google.code.gson + gson + + + + com.sun.jersey + jersey-core + + + com.sun.jersey + jersey-server + + + com.sun.jersey + jersey-servlet + + + io.netty + netty-buffer + + + io.netty + netty-codec + + + io.netty + netty-codec-http + + + io.netty + netty-common + + + io.netty + netty-handler + + + io.netty + netty-transport + + + + org.opendaylight.controller + sal-rest-connector-config + ${mdsal.version} + xml + config + + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.datatype + jackson-datatype-json-org + + + com.fasterxml.jackson.module + jackson-module-jaxb-annotations + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-base + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + + + org.json + json + + + + org.opendaylight.yangtools + yang-data-codec-gson + + + + org.opendaylight.controller.samples + clustering-it-model + ${mdsal.version} + + + org.opendaylight.controller.samples + clustering-it-provider + ${mdsal.version} + + + org.opendaylight.controller.samples + clustering-it-config + ${mdsal.version} + xml + config + + + org.opendaylight.controller.samples + clustering-it-config + ${mdsal.version} + xml + testmoduleshardconf + + + org.opendaylight.controller.samples + clustering-it-config + ${mdsal.version} + xml + testmoduleconf + + + org.opendaylight.controller + sal-rest-docgen + + + + + + org.opendaylight.yangtools + features-test + ${yangtools.version} + test + + + + org.opendaylight.controller + opendaylight-karaf-empty + ${commons.opendaylight.version} + zip + + + + + + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-resources-plugin + + + filter + generate-resources + + resources + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + package + + attach-artifact + + + + + ${project.build.directory}/classes/${features.file} + xml + features + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.version} + + + org.opendaylight.controller + opendaylight-karaf-empty + ${commons.opendaylight.version} + + + org.opendaylight.yangtools:features-test + + + + + + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + HEAD + https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=summary + + diff --git a/features/restconf/src/main/resources/features.xml b/features/restconf/src/main/resources/features.xml new file mode 100644 index 0000000000..ab42330eac --- /dev/null +++ b/features/restconf/src/main/resources/features.xml @@ -0,0 +1,151 @@ + + + + + + + mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features + mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features + mvn:org.opendaylight.aaa/features-aaa/${aaa.version}/xml/features + + + odl-restconf + odl-mdsal-apidocs + odl-clustering-test-app + + + + + odl-aaa-authn + odl-restconf-noauth + + + odl-mdsal-broker + war + + mvn:org.opendaylight.controller/sal-remote/${project.version} + mvn:org.opendaylight.controller/sal-rest-connector/${project.version} + mvn:com.google.code.gson/gson/${gson.version} + mvn:org.opendaylight.yangtools/yang-data-codec-gson/${yangtools.version} + mvn:com.sun.jersey/jersey-core/${jersey.version} + mvn:com.sun.jersey/jersey-server/${jersey.version} + mvn:com.sun.jersey/jersey-servlet/${jersey.version} + mvn:io.netty/netty-buffer/${netty.version} + mvn:io.netty/netty-codec/${netty.version} + mvn:io.netty/netty-codec-http/${netty.version} + mvn:io.netty/netty-common/${netty.version} + mvn:io.netty/netty-handler/${netty.version} + mvn:io.netty/netty-transport/${netty.version} + mvn:org.opendaylight.controller/sal-rest-connector-config/${mdsal.version}/xml/config + + + odl-restconf + mvn:org.opendaylight.controller/sal-rest-docgen/${project.version} + mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson.version} + mvn:com.fasterxml.jackson.core/jackson-core/${jackson.version} + mvn:com.fasterxml.jackson.core/jackson-databind/${jackson.version} + mvn:com.fasterxml.jackson.datatype/jackson-datatype-json-org/${jackson.version} + mvn:com.fasterxml.jackson.module/jackson-module-jaxb-annotations/${jackson.version} + mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/${jackson.version} + mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/${jackson.version} + mvn:com.sun.jersey/jersey-core/${jersey.version} + mvn:com.sun.jersey/jersey-server/${jersey.version} + mvn:com.sun.jersey/jersey-servlet/${jersey.version} + wrap:mvn:org.json/json/${org.json.version} + + + + odl-mdsal-clustering + odl-restconf + odl-yangtools-models + mvn:org.opendaylight.controller.samples/clustering-it-model/${project.version} + mvn:org.opendaylight.controller.samples/clustering-it-provider/${project.version} + mvn:org.opendaylight.controller.samples/clustering-it-config/${project.version}/xml/config + mvn:org.opendaylight.controller.samples/clustering-it-config/${project.version}/xml/testmoduleshardconf + mvn:org.opendaylight.controller.samples/clustering-it-config/${project.version}/xml/testmoduleconf + + + + odl-restconf + odl-toaster + + + + odl-mdsal-apidocs + odl-mdsal-xsql + odl-toaster-rest + + + + diff --git a/itests/base-features-it/pom.xml b/itests/base-features-it/pom.xml index 8f73779009..d05e9a515b 100644 --- a/itests/base-features-it/pom.xml +++ b/itests/base-features-it/pom.xml @@ -3,7 +3,7 @@ org.opendaylight.controller itests-controller - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../pom.xml base-features-it diff --git a/itests/pom.xml b/itests/pom.xml index 19836a2ad6..c722149145 100644 --- a/itests/pom.xml +++ b/itests/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../opendaylight/commons/opendaylight itests-controller diff --git a/opendaylight/appauth/pom.xml b/opendaylight/appauth/pom.xml index e74e3cb915..8a035510bf 100644 --- a/opendaylight/appauth/pom.xml +++ b/opendaylight/appauth/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../commons/opendaylight appauth - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/archetypes/odl-model-project/pom.xml b/opendaylight/archetypes/odl-model-project/pom.xml index d2896027fb..4945eb2a66 100644 --- a/opendaylight/archetypes/odl-model-project/pom.xml +++ b/opendaylight/archetypes/odl-model-project/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller.archetypes odl-model-project - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT maven-archetype diff --git a/opendaylight/archetypes/odl-model-project/src/main/resources/archetype-resources/pom.xml b/opendaylight/archetypes/odl-model-project/src/main/resources/archetype-resources/pom.xml index 016c30d787..6b41485e7b 100644 --- a/opendaylight/archetypes/odl-model-project/src/main/resources/archetype-resources/pom.xml +++ b/opendaylight/archetypes/odl-model-project/src/main/resources/archetype-resources/pom.xml @@ -11,8 +11,8 @@ http://nexus.opendaylight.org/content opendaylight.release opendaylight.release - 0.6.2-SNAPSHOT - 0.6.2-SNAPSHOT + 0.7.0-SNAPSHOT + 0.7.0-SNAPSHOT 2.3.7 diff --git a/opendaylight/archetypes/opendaylight-configfile-archetype/pom.xml b/opendaylight/archetypes/opendaylight-configfile-archetype/pom.xml index 38c86164e9..45ec9ac717 100644 --- a/opendaylight/archetypes/opendaylight-configfile-archetype/pom.xml +++ b/opendaylight/archetypes/opendaylight-configfile-archetype/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller opendaylight-configfile-archetype - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT maven-archetype @@ -38,15 +38,15 @@ opendaylight-release - http://nexus.opendaylight.org/content/repositories/opendaylight.release/ + ${nexusproxy}/repositories/opendaylight.release/ opendaylight-snapshot - http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/ + ${nexusproxy}/repositories/opendaylight.snapshot/ website - dav:http://nexus.opendaylight.org/content/sites/site/sal-parent + dav:${nexusproxy}/sites/site/sal-parent diff --git a/opendaylight/archetypes/opendaylight-karaf-distro-archetype/pom.xml b/opendaylight/archetypes/opendaylight-karaf-distro-archetype/pom.xml index 8883c64295..ff2384fb27 100644 --- a/opendaylight/archetypes/opendaylight-karaf-distro-archetype/pom.xml +++ b/opendaylight/archetypes/opendaylight-karaf-distro-archetype/pom.xml @@ -1,10 +1,14 @@ 4.0.0 - + + org.opendaylight.controller.archetypes + archetypes-parent + 0.2.0-SNAPSHOT + org.opendaylight.controller opendaylight-karaf-distro-archetype - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT maven-archetype distribution-karaf-archetype diff --git a/opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/main/resources/archetype-resources/pom.xml b/opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/main/resources/archetype-resources/pom.xml index fdc60625c8..c2e399b370 100644 --- a/opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/main/resources/archetype-resources/pom.xml +++ b/opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/main/resources/archetype-resources/pom.xml @@ -19,8 +19,8 @@ - 1.0.0-SNAPSHOT - 1.4.2-SNAPSHOT + 1.1.0-SNAPSHOT + 1.5.0-SNAPSHOT 3.0.1 @@ -81,7 +81,7 @@ org.opendaylight.openflowplugin features-openflowplugin - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT features xml runtime diff --git a/opendaylight/archetypes/opendaylight-karaf-features/pom.xml b/opendaylight/archetypes/opendaylight-karaf-features/pom.xml index 4973a69537..12861604e8 100644 --- a/opendaylight/archetypes/opendaylight-karaf-features/pom.xml +++ b/opendaylight/archetypes/opendaylight-karaf-features/pom.xml @@ -2,9 +2,14 @@ 4.0.0 + + org.opendaylight.controller.archetypes + archetypes-parent + 0.2.0-SNAPSHOT + org.opendaylight.controller opendaylight-karaf-features-archetype - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT maven-archetype opendaylight-karaf-features-archetype diff --git a/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/pom.xml b/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/pom.xml index e135e6b656..df35831a90 100644 --- a/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/pom.xml +++ b/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/pom.xml @@ -24,11 +24,11 @@ features.xml - 1.0.0-SNAPSHOT - 1.4.2-SNAPSHOT + 1.1.0-SNAPSHOT + 1.5.0-SNAPSHOT 3.0.1 - 0.6.2-SNAPSHOT - 1.4.2-SNAPSHOT + 0.7.0-SNAPSHOT + 1.5.0-SNAPSHOT 2.16 @@ -46,21 +46,21 @@ org.opendaylight.yangtools features-yangtools - 0.6.2-SNAPSHOT + 0.7.0-SNAPSHOT features xml org.opendaylight.controller features-mdsal - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT features xml org.opendaylight.openflowplugin features-openflowplugin - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT features xml diff --git a/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/src/main/resources/features.xml b/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/src/main/resources/features.xml index 4a59657431..54bbfe45fc 100644 --- a/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/src/main/resources/features.xml +++ b/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/src/main/resources/features.xml @@ -21,9 +21,9 @@ Necessary TODO: Add repo entries for the repositories of features you refer to in this feature file but do not define here. Examples: - mvn:org.opendaylight.yangtools/features-yangtools/0.6.2-SNAPSHOT/xml/features - mvn:org.opendaylight.controller/features-mdsal/1.1-SNAPSHOT/xml/features - mvn:org.opendaylight.openflowplugin/features-openflowplugin/0.0.3-SNAPSHOT/xml/features + mvn:org.opendaylight.yangtools/features-yangtools/0.7.0-SNAPSHOT/xml/features + mvn:org.opendaylight.controller/features-mdsal/1.2.0-SNAPSHOT/xml/features + mvn:org.opendaylight.openflowplugin/features-openflowplugin/0.1.0-SNAPSHOT/xml/features --> diff --git a/opendaylight/arphandler/pom.xml b/opendaylight/arphandler/pom.xml index 064d04c25c..ffd528beb0 100644 --- a/opendaylight/arphandler/pom.xml +++ b/opendaylight/arphandler/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../commons/opendaylight arphandler - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT bundle diff --git a/opendaylight/clustering/integrationtest/pom.xml b/opendaylight/clustering/integrationtest/pom.xml index 62c182c3b9..fecf4f8034 100644 --- a/opendaylight/clustering/integrationtest/pom.xml +++ b/opendaylight/clustering/integrationtest/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.integrationtest - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT ../../commons/integrationtest clustering.services.integrationtest - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT ../implementation/target/jacoco-it.exec diff --git a/opendaylight/clustering/services/pom.xml b/opendaylight/clustering/services/pom.xml index 3ff6bac21f..8c66e70cbe 100644 --- a/opendaylight/clustering/services/pom.xml +++ b/opendaylight/clustering/services/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight clustering.services - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT bundle diff --git a/opendaylight/clustering/services_implementation/pom.xml b/opendaylight/clustering/services_implementation/pom.xml index 8d3f53b6c4..f11f7a14c0 100644 --- a/opendaylight/clustering/services_implementation/pom.xml +++ b/opendaylight/clustering/services_implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight clustering.services-implementation - 0.4.3-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/clustering/stub/pom.xml b/opendaylight/clustering/stub/pom.xml index 6a0b3082fb..211dcc29d0 100644 --- a/opendaylight/clustering/stub/pom.xml +++ b/opendaylight/clustering/stub/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight clustering.stub - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/clustering/test/pom.xml b/opendaylight/clustering/test/pom.xml index 9021c9419e..93294f2290 100644 --- a/opendaylight/clustering/test/pom.xml +++ b/opendaylight/clustering/test/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight clustering.test - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/commons/checkstyle/pom.xml b/opendaylight/commons/checkstyle/pom.xml index 55567af437..fee517f08b 100644 --- a/opendaylight/commons/checkstyle/pom.xml +++ b/opendaylight/commons/checkstyle/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.opendaylight.controller checkstyle - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT scm:git:ssh://git.opendaylight.org:29418/controller.git scm:git:ssh://git.opendaylight.org:29418/controller.git diff --git a/opendaylight/commons/concepts/pom.xml b/opendaylight/commons/concepts/pom.xml index 01dd61a1cb..fa97e5fcac 100644 --- a/opendaylight/commons/concepts/pom.xml +++ b/opendaylight/commons/concepts/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight concepts - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT bundle @@ -43,7 +43,7 @@ org.opendaylight.controller checkstyle - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT diff --git a/opendaylight/commons/filter-valve/pom.xml b/opendaylight/commons/filter-valve/pom.xml index 7b5be02514..012b4a2529 100644 --- a/opendaylight/commons/filter-valve/pom.xml +++ b/opendaylight/commons/filter-valve/pom.xml @@ -11,7 +11,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../opendaylight filter-valve diff --git a/opendaylight/commons/httpclient/pom.xml b/opendaylight/commons/httpclient/pom.xml index 07d3cdda96..39364cbcba 100644 --- a/opendaylight/commons/httpclient/pom.xml +++ b/opendaylight/commons/httpclient/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight commons.httpclient - 0.1.2-SNAPSHOT + 0.2.0-SNAPSHOT bundle @@ -71,7 +71,7 @@ org.opendaylight.controller checkstyle - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT diff --git a/opendaylight/commons/integrationtest/pom.xml b/opendaylight/commons/integrationtest/pom.xml index 315611f647..ad4e166cbd 100644 --- a/opendaylight/commons/integrationtest/pom.xml +++ b/opendaylight/commons/integrationtest/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight commons.integrationtest - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT pom @@ -89,7 +89,7 @@ org.opendaylight.controller checkstyle - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT diff --git a/opendaylight/commons/liblldp/pom.xml b/opendaylight/commons/liblldp/pom.xml index 1551041edb..148a4f3792 100644 --- a/opendaylight/commons/liblldp/pom.xml +++ b/opendaylight/commons/liblldp/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../opendaylight liblldp - 0.8.1-SNAPSHOT + 0.9.0-SNAPSHOT bundle diff --git a/opendaylight/commons/logback_settings/pom.xml b/opendaylight/commons/logback_settings/pom.xml index 11a7ffbd0e..f98b7a3a7a 100644 --- a/opendaylight/commons/logback_settings/pom.xml +++ b/opendaylight/commons/logback_settings/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.parent - 1.0.2-SNAPSHOT + 1.1.0-SNAPSHOT ../parent commons.logback_settings - 0.0.2-SNAPSHOT + 0.1.0-SNAPSHOT scm:git:ssh://git.opendaylight.org:29418/controller.git scm:git:ssh://git.opendaylight.org:29418/controller.git diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index 4240db939a..23542dd62b 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -4,13 +4,13 @@ org.opendaylight.odlparent odlparent - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT pom 3.0 @@ -20,24 +20,24 @@ 2.3.4 1.0.0 - 0.4.2-SNAPSHOT - 0.0.1-SNAPSHOT + 0.5.0-SNAPSHOT + 0.1.0-SNAPSHOT 1.1.0 - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT 4.1 1.50 2.4.0 - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT 2.12 - 0.5.1-SNAPSHOT - 0.4.3-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT + 0.6.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT 3.0.1 @@ -51,23 +51,23 @@ 7.0.53.v201406060720 7.0.53.v201406070630 - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT 1.2.2 - 0.1.2-SNAPSHOT + 0.2.0-SNAPSHOT 2.4 3.1 - 0.0.2-SNAPSHOT + 0.1.0-SNAPSHOT 3.0.1 - 0.1.2-SNAPSHOT - 0.5.2-SNAPSHOT - 1.4.2-SNAPSHOT - 1.0.2-SNAPSHOT + 0.2.0-SNAPSHOT + 0.6.0-SNAPSHOT + 1.5.0-SNAPSHOT + 1.1.0-SNAPSHOT 2.3.2 - 0.1.2-SNAPSHOT - 0.5.2-SNAPSHOT + 0.2.0-SNAPSHOT + 0.6.0-SNAPSHOT 1.4 - 0.2.5-SNAPSHOT - 0.1.0-SNAPSHOT + 0.3.0-SNAPSHOT + 0.2.0-SNAPSHOT etc/opendaylight/karaf 05-clustering.xml 00-netty.xml @@ -77,16 +77,16 @@ 03-toaster-sample.xml 10-rest-connector.xml 99-netconf-connector.xml - 0.4.3-SNAPSHOT - 0.4.3-SNAPSHOT - 0.1.2-SNAPSHOT - 0.5.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.5.2-SNAPSHOT - 0.5.2-SNAPSHOT - 0.0.2-SNAPSHOT - 0.4.2-SNAPSHOT - 1.1.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.2.0-SNAPSHOT + 0.6.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.6.0-SNAPSHOT + 0.6.0-SNAPSHOT + 0.1.0-SNAPSHOT + 0.5.0-SNAPSHOT + 1.2.0-SNAPSHOT 2.5.0 3.8.0.I20120518-2145 @@ -98,78 +98,78 @@ 0000.0002.0038.0 1.6.0 - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT 2.4.0 - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.5.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.6.0-SNAPSHOT - 1.1-SNAPSHOT - 0.5.2-SNAPSHOT - 0.5.2-SNAPSHOT - 0.4.2-SNAPSHOT - 1.0.0-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.0.2-SNAPSHOT - 2010.09.24.4-SNAPSHOT - 2013.10.19.1-SNAPSHOT - 2013.10.21.2-SNAPSHOT - 2010.09.24.4-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.6.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.7.0-SNAPSHOT + 1.2.0-SNAPSHOT + 0.6.0-SNAPSHOT + 0.6.0-SNAPSHOT + 0.5.0-SNAPSHOT + 1.1.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.1.0-SNAPSHOT + 2010.09.24.7-SNAPSHOT + 2013.10.19.7-SNAPSHOT + 2013.10.21.7-SNAPSHOT + 2010.09.24.7-SNAPSHOT 2.0-beta-2 src/main/yang-gen-config - 0.0.2-SNAPSHOT + 0.1.0-SNAPSHOT 1.1.4 2.0.1 1.1.1 2.0 - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT 3.0.0 3.0.1 0.7 1.8 1.0.0 1.0.9 - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT 3.0.5 1.9.4 - 1.1-SNAPSHOT - 0.2.5-SNAPSHOT - 0.0.3-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT + 1.2.0-SNAPSHOT + 0.3.0-SNAPSHOT + 0.1.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT http://nexus.opendaylight.org/content - 0.4.2-SNAPSHOT - 1.4.2-SNAPSHOT - 1.4.2-SNAPSHOT - 2013.08.27.4-SNAPSHOT - 0.0.2-SNAPSHOT + 0.5.0-SNAPSHOT + 1.5.0-SNAPSHOT + 1.5.0-SNAPSHOT + 2013.08.27.7-SNAPSHOT + 0.1.0-SNAPSHOT 4.0.0 1.1.6 1.1.6 1.0-alpha-2 2.5.0 - 0.5.0-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.1.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.0.3-SNAPSHOT - 0.8.1-SNAPSHOT + 0.6.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.2.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.1.0-SNAPSHOT + 0.9.0-SNAPSHOT src/main/yang-gen-sal - 0.5.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT + 0.6.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT 2.10 4 - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT 1.2.4 dav:http://nexus.opendaylight.org/content/sites/site ${user.name}-private-view @@ -187,52 +187,45 @@ 3.1.4.RELEASE 3.1.3.RELEASE 3.1.3.RELEASE - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.5.1-SNAPSHOT - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.6.0-SNAPSHOT + 0.5.0-SNAPSHOT 2.15 - 0.7.1-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT + 0.8.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT -Xmx1024m -XX:MaxPermSize=256m - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 1.0.0-SNAPSHOT - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 1.1.0-SNAPSHOT + 0.5.0-SNAPSHOT 1.2.0 1.2.2a - 0.4.2-SNAPSHOT - 0.0.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT + 0.1.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT + 0.5.0-SNAPSHOT src/main/xtend-gen - 2013.09.07.4-SNAPSHOT - 1.0.0-SNAPSHOT - 0.6.2-SNAPSHOT + 2013.09.07.7-SNAPSHOT + 1.1.0-SNAPSHOT + 0.7.0-SNAPSHOT 0.12.0 0.9.7 + - ${project.groupId} - ietf-netconf-monitoring - ${netconf.version} - - - ${project.groupId} - ietf-netconf-monitoring-extension - ${netconf.version} - - - ${project.groupId} - netconf-netty-util + org.opendaylight.controller + netconf-artifacts ${netconf.version} + pom + import org.apache.sshd @@ -863,11 +856,6 @@ config-manager ${config.version} - - org.opendaylight.controller - config-netconf-connector - ${netconf.version} - org.opendaylight.controller config-persister-api @@ -894,11 +882,6 @@ config-persister-feature-adapter ${config.version} - - org.opendaylight.controller - config-persister-impl - ${netconf.version} - org.opendaylight.controller @@ -1035,12 +1018,12 @@ org.opendaylight.controller httpservice-bridge - 0.0.2-SNAPSHOT + 0.1.0-SNAPSHOT org.opendaylight.controller jolokia-bridge - 0.0.2-SNAPSHOT + 0.1.0-SNAPSHOT @@ -1070,94 +1053,6 @@ ${dummy-console.version} - - - org.opendaylight.controller - netconf-api - ${netconf.version} - - - org.opendaylight.controller - netconf-client - ${netconf.version} - - - org.opendaylight.controller - netconf-client - ${netconf.version} - test-jar - - - - - org.opendaylight.controller - netconf-config-dispatcher - ${netconf.version} - - - org.opendaylight.controller - netconf-impl - ${netconf.version} - - - org.opendaylight.controller - netconf-impl - ${netconf.version} - test-jar - - - org.opendaylight.controller - netconf-mapping-api - ${netconf.version} - - - org.opendaylight.controller - netconf-monitoring - ${netconf.version} - - - org.opendaylight.controller - netconf-netty-util - ${netconf.version} - test-jar - - - org.opendaylight.controller - netconf-auth - ${netconf.version} - - - org.opendaylight.controller - netconf-usermanager - ${netconf.version} - - - org.opendaylight.controller - netconf-ssh - ${netconf.version} - - - org.opendaylight.controller - netconf-ssh - ${netconf.version} - test-jar - - - org.opendaylight.controller - netconf-tcp - ${netconf.version} - - - org.opendaylight.controller - netconf-util - ${netconf.version} - - - org.opendaylight.controller - netconf-util - ${netconf.version} - test-jar - org.opendaylight.controller netty-config-api @@ -1298,6 +1193,11 @@ sal-dom-xsql ${mdsal.version} + + org.opendaylight.controller + sal-karaf-xsql + ${mdsal.version} + org.opendaylight.controller sal-dom-xsql-config @@ -1345,16 +1245,6 @@ md-sal-config ${mdsal.version} - - org.opendaylight.controller - netconf-config - ${netconf.version} - - - org.opendaylight.controller - netconf-connector-config - ${netconf.version} - org.opendaylight.controller sal-rest-docgen @@ -1691,6 +1581,7 @@ ganymed ${ganymed.version} + org.opendaylight.controller.thirdparty @@ -1707,174 +1598,16 @@ org.openflow.openflowj 1.0.2 - - org.opendaylight.yangtools - binding-generator-impl - ${yangtools.version} - - - org.opendaylight.yangtools - binding-data-codec - ${yangtools.version} - - - org.opendaylight.yangtools - binding-generator-spi - ${yangtools.version} - - - org.opendaylight.yangtools - binding-generator-util - ${yangtools.version} - - - org.opendaylight.yangtools - binding-type-provider - ${yangtools.version} - - - org.opendaylight.yangtools - concepts - ${yangtools.version} - - - org.opendaylight.yangtools - object-cache-api - ${yangtools.version} - - - org.opendaylight.yangtools - object-cache-guava - ${yangtools.version} - - - org.opendaylight.yangtools - restconf-client-api - ${yangtools.version} - - - org.opendaylight.yangtools - restconf-client-impl - ${yangtools.version} - - - org.opendaylight.yangtools - util - ${yangtools.version} - - - org.opendaylight.yangtools - yang-data-composite-node - ${yangtools.version} - - - org.opendaylight.yangtools - yang-data-codec-gson - ${yangtools.version} - - - - org.opendaylight.yangtools - yang-binding - ${yangtools.version} - - - org.opendaylight.yangtools - yang-common - ${yangtools.version} - - - org.opendaylight.yangtools - yang-data-api - ${yangtools.version} - - - org.opendaylight.yangtools - yang-data-impl - ${yangtools.version} - - - org.opendaylight.yangtools - yang-data-util - ${yangtools.version} - - - org.opendaylight.yangtools - yang-maven-plugin-spi - ${yangtools.version} - - - org.opendaylight.yangtools - yang-model-api - ${yangtools.version} - + org.opendaylight.yangtools - yang-model-util + yangtools-artifacts ${yangtools.version} + pom + import - - org.opendaylight.yangtools - yang-parser-api - ${yangtools.version} - - - org.opendaylight.yangtools - yang-parser-impl - ${yangtools.version} - - - - org.opendaylight.yangtools.model - ietf-inet-types - ${ietf-inet-types.version} - - - org.opendaylight.yangtools.model - ietf-restconf - ${ietf-restconf.version} - - - org.opendaylight.yangtools.model - ietf-topology - ${ietf-topology.version} - - - org.opendaylight.yangtools.model - ietf-topology-l3-unicast-igp - ${ietf-topology.version} - - - org.opendaylight.yangtools.model - ietf-yang-types - ${ietf-yang-types.version} - - - org.opendaylight.yangtools.model - ietf-yang-types-20130715 - 2013.07.15.1-SNAPSHOT - - - org.opendaylight.yangtools.model - opendaylight-l2-types - ${opendaylight-l2-types.version} - - - org.opendaylight.yangtools.model - yang-ext - ${yang-ext.version} - - - org.opendaylight.yangtools.thirdparty - antlr4-runtime-osgi-nohead - 4.0 - - - org.opendaylight.yangtools.thirdparty - xtend-lib-osgi - ${xtend.version} - + org.openexi nagasena @@ -1929,7 +1662,7 @@ org.opendaylight.controller commons.logback_settings - 0.0.2-SNAPSHOT + 0.1.0-SNAPSHOT test @@ -1945,12 +1678,6 @@ ${mdsal.version} test - - org.opendaylight.yangtools - mockito-configuration - ${yangtools.version} - test - org.opendaylight.controller features-config @@ -1967,14 +1694,6 @@ xml runtime - - org.opendaylight.controller - features-netconf - ${netconf.version} - features - xml - runtime - org.opendaylight.controller features-config-persister @@ -2023,6 +1742,14 @@ xml runtime + + org.opendaylight.controller + features-netconf-connector + ${mdsal.version} + features + xml + runtime + org.openjdk.jmh @@ -2152,7 +1879,7 @@ org.opendaylight.controller commons.logback_settings - 0.0.2-SNAPSHOT + 0.1.0-SNAPSHOT @@ -2403,7 +2130,7 @@ org.opendaylight.controller checkstyle - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT @@ -2581,6 +2308,10 @@ + true @@ -2634,16 +2365,24 @@ http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/ + + opendaylight-release - http://nexus.opendaylight.org/content/repositories/opendaylight.release/ + ${nexusproxy}/repositories/opendaylight.release/ opendaylight-snapshot - http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/ + ${nexusproxy}/repositories/opendaylight.snapshot/ diff --git a/opendaylight/commons/parent/pom.xml b/opendaylight/commons/parent/pom.xml index 67d1cb419b..cbd6efaef8 100644 --- a/opendaylight/commons/parent/pom.xml +++ b/opendaylight/commons/parent/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.opendaylight.controller commons.parent - 1.0.2-SNAPSHOT + 1.1.0-SNAPSHOT pom 3.0 diff --git a/opendaylight/commons/protocol-framework/pom.xml b/opendaylight/commons/protocol-framework/pom.xml index 774bc7c23f..00f7b3179b 100644 --- a/opendaylight/commons/protocol-framework/pom.xml +++ b/opendaylight/commons/protocol-framework/pom.xml @@ -6,12 +6,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight protocol-framework - 0.5.0-SNAPSHOT + 0.6.0-SNAPSHOT bundle ${project.artifactId} Common protocol framework diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractSessionNegotiator.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractSessionNegotiator.java index cbe9235245..2ecd267b9f 100644 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractSessionNegotiator.java +++ b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractSessionNegotiator.java @@ -46,7 +46,7 @@ public abstract class AbstractSessionNegotiator, L extends SessionList return; } - // Check if initial connection was fully finished. If the session was dropped during negotiation, reconnect will not happen. - // Session can be dropped during negotiation on purpose by the client side and would make no sense to initiate reconnect if (promise.isInitialConnectFinished() == false) { - return; + LOG.debug("Connection to {} was dropped during negotiation, reattempting", promise.address); } LOG.debug("Reconnecting after connection to {} was dropped", promise.address); diff --git a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ServerTest.java b/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ServerTest.java index 63026e384c..fc38888de3 100644 --- a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ServerTest.java +++ b/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ServerTest.java @@ -250,52 +250,6 @@ public class ServerTest { assertFalse(session.isSuccess()); } - @Test - public void testNegotiationFailedNoReconnect() throws Exception { - final Promise p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE); - - this.dispatcher = getServerDispatcher(p); - - this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory() { - @Override - public SimpleSessionListener getSessionListener() { - return new SimpleSessionListener(); - } - }); - - this.server.get(); - - this.clientDispatcher = new SimpleDispatcher(new SessionNegotiatorFactory() { - @Override - public SessionNegotiator getSessionNegotiator(final SessionListenerFactory factory, - final Channel channel, final Promise promise) { - - return new SimpleSessionNegotiator(promise, channel) { - @Override - protected void startNegotiation() throws Exception { - negotiationFailed(new IllegalStateException("Negotiation failed")); - } - }; - } - }, new DefaultPromise(GlobalEventExecutor.INSTANCE), eventLoopGroup); - - final ReconnectStrategyFactory reconnectStrategyFactory = mock(ReconnectStrategyFactory.class); - final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy(); - doReturn(reconnectStrategy).when(reconnectStrategyFactory).createReconnectStrategy(); - - this.clientDispatcher.createReconnectingClient(this.serverAddress, - reconnectStrategyFactory, new SessionListenerFactory() { - @Override - public SimpleSessionListener getSessionListener() { - return new SimpleSessionListener(); - } - }); - - - // Only one strategy should be created for initial connect, no more = no reconnects - verify(reconnectStrategyFactory, times(1)).createReconnectStrategy(); - } - private SimpleDispatcher getClientDispatcher() { return new SimpleDispatcher(new SessionNegotiatorFactory() { @Override diff --git a/opendaylight/config/config-api/pom.xml b/opendaylight/config/config-api/pom.xml index e145bd2db0..eff635c17e 100644 --- a/opendaylight/config/config-api/pom.xml +++ b/opendaylight/config/config-api/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT config-api diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/IdentityAttributeRef.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/IdentityAttributeRef.java index 5ad6e0da8d..48aa6ae646 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/IdentityAttributeRef.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/IdentityAttributeRef.java @@ -39,7 +39,7 @@ public final class IdentityAttributeRef { @Override public String toString() { - final StringBuffer sb = new StringBuffer("IdentityAttributeRef{"); + final StringBuilder sb = new StringBuilder("IdentityAttributeRef{"); sb.append("qNameOfIdentity='").append(qNameOfIdentity).append('\''); sb.append('}'); return sb.toString(); diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java index abb9f1ae9b..c23a0cbf69 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java @@ -29,6 +29,8 @@ import java.util.Set; */ @ThreadSafe public class ObjectNameUtil { + private ObjectNameUtil() { + } public static final String ON_DOMAIN = ConfigRegistryConstants.ON_DOMAIN; public static final String MODULE_FACTORY_NAME_KEY = "moduleFactoryName"; @@ -270,7 +272,7 @@ public class ObjectNameUtil { } public static Map getAdditionalProperties(ObjectName on) { - Hashtable keyPropertyList = on.getKeyPropertyList(); + Map keyPropertyList = on.getKeyPropertyList(); Map result = new HashMap<>(); for (Entry entry : keyPropertyList.entrySet()) { result.put(entry.getKey(), entry.getValue()); @@ -304,8 +306,8 @@ public class ObjectNameUtil { public static ObjectName createModulePattern(String moduleName, String instanceName) { - moduleName = moduleName == null ? ON_WILDCARD : moduleName; - instanceName = instanceName == null ? ON_WILDCARD : instanceName; + String finalModuleName = moduleName == null ? ON_WILDCARD : moduleName; + String finalInstanceName = instanceName == null ? ON_WILDCARD : instanceName; // do not return object names containing transaction name ObjectName namePattern = ObjectNameUtil @@ -313,34 +315,34 @@ public class ObjectNameUtil { + ObjectNameUtil.TYPE_KEY + "=" + ObjectNameUtil.TYPE_MODULE + "," + ObjectNameUtil.MODULE_FACTORY_NAME_KEY + "=" - + moduleName + "," + "" - + ObjectNameUtil.INSTANCE_NAME_KEY + "=" + instanceName); + + finalModuleName + "," + "" + + ObjectNameUtil.INSTANCE_NAME_KEY + "=" + finalInstanceName); return namePattern; } public static ObjectName createModulePattern(String ifcName, String instanceName, String transactionName) { - ifcName = ifcName == null ? ON_WILDCARD : ifcName; - instanceName = instanceName == null ? ON_WILDCARD : instanceName; - transactionName = transactionName == null ? ON_WILDCARD : transactionName; + String finalIfcName = ifcName == null ? ON_WILDCARD : ifcName; + String finalInstanceName = instanceName == null ? ON_WILDCARD : instanceName; + String finalTransactionName = transactionName == null ? ON_WILDCARD : transactionName; return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":type=Module," + ObjectNameUtil.MODULE_FACTORY_NAME_KEY - + "=" + ifcName + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "=" - + instanceName + "," + ObjectNameUtil.TRANSACTION_NAME_KEY - + "=" + transactionName); + + "=" + finalIfcName + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "=" + + finalInstanceName + "," + ObjectNameUtil.TRANSACTION_NAME_KEY + + "=" + finalTransactionName); } public static ObjectName createRuntimeBeanPattern(String moduleName, String instanceName) { - moduleName = moduleName == null ? ON_WILDCARD : moduleName; - instanceName = instanceName == null ? ON_WILDCARD : instanceName; + String finalModuleName = moduleName == null ? ON_WILDCARD : moduleName; + String finalInstanceName = instanceName == null ? ON_WILDCARD : instanceName; return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":" + ObjectNameUtil.TYPE_KEY + "=" + ObjectNameUtil.TYPE_RUNTIME_BEAN + "," - + ObjectNameUtil.MODULE_FACTORY_NAME_KEY + "=" + moduleName - + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "=" + instanceName + + ObjectNameUtil.MODULE_FACTORY_NAME_KEY + "=" + finalModuleName + + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "=" + finalInstanceName + ",*"); } diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/constants/ConfigRegistryConstants.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/constants/ConfigRegistryConstants.java index 1d9563bf4e..bdb6f0e344 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/constants/ConfigRegistryConstants.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/constants/ConfigRegistryConstants.java @@ -12,6 +12,9 @@ import javax.management.ObjectName; public class ConfigRegistryConstants { + private ConfigRegistryConstants() { + } + public static final String TYPE_CONFIG_REGISTRY = "ConfigRegistry"; public static final String ON_DOMAIN = "org.opendaylight.controller"; diff --git a/opendaylight/config/config-api/src/main/yang/config.yang b/opendaylight/config/config-api/src/main/yang/config.yang index a0a4292adf..e46d327ece 100644 --- a/opendaylight/config/config-api/src/main/yang/config.yang +++ b/opendaylight/config/config-api/src/main/yang/config.yang @@ -122,7 +122,9 @@ module config { the actual service-type which is actually required."; mandatory true; - type service-type-ref; + type leafref { + path "/config:services/config:service/config:type"; + } } leaf name { @@ -138,7 +140,7 @@ module config { "Top level container encapsulating configuration of all modules."; list module { - key "name"; + key "type name"; leaf name { description "Unique module instance name"; type string; diff --git a/opendaylight/config/config-manager/pom.xml b/opendaylight/config/config-manager/pom.xml index c98a47660e..3ebffc65a2 100644 --- a/opendaylight/config/config-manager/pom.xml +++ b/opendaylight/config/config-manager/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT .. config-manager diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java index b7cdf94757..605223ae22 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java @@ -60,7 +60,7 @@ import java.util.Set; */ @ThreadSafe public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBean { - private static final Logger logger = LoggerFactory.getLogger(ConfigRegistryImpl.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigRegistryImpl.class); private final ModuleFactoriesResolver resolver; private final MBeanServer configMBeanServer; @@ -166,7 +166,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe for (ModuleInternalInfo moduleInternalInfo : currentConfig.getEntries()) { String name = moduleInternalInfo.getModuleFactory().getImplementationName(); if (allCurrentFactories.containsKey(name) == false) { - logger.trace("Factory {} not found in SR, using reference from previous commit", name); + LOGGER.trace("Factory {} not found in SR, using reference from previous commit", name); allCurrentFactories.put(name, Maps.immutableEntry(moduleInternalInfo.getModuleFactory(), moduleInternalInfo.getBundleContext())); } @@ -202,7 +202,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe throws ConflictingVersionException, ValidationException { final String transactionName = ObjectNameUtil .getTransactionName(transactionControllerON); - logger.trace("About to commit {}. Current parentVersion: {}, versionCounter {}", transactionName, version, versionCounter); + LOGGER.trace("About to commit {}. Current parentVersion: {}, versionCounter {}", transactionName, version, versionCounter); // find ConfigTransactionController Map> transactions = transactionsHolder.getCurrentTransactions(); @@ -230,7 +230,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe } catch (Error | RuntimeException t) { // some libs throw Errors: e.g. // javax.xml.ws.spi.FactoryFinder$ConfigurationError isHealthy = false; - logger.error("Configuration Transaction failed on 2PC, server is unhealthy", t); + LOGGER.error("Configuration Transaction failed on 2PC, server is unhealthy", t); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { @@ -292,7 +292,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe int orderingIdx = 0; for (ModuleIdentifier moduleIdentifier : orderedModuleIdentifiers) { - logger.trace("Registering {}", moduleIdentifier); + LOGGER.trace("Registering {}", moduleIdentifier); ModuleInternalTransactionalInfo entry = commitInfo.getCommitted() .get(moduleIdentifier); if (entry == null) { @@ -427,7 +427,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe configTransactionControllerEntry.getValue().close(); configTransactionController.abortConfig(); } catch (RuntimeException e) { - logger.warn("Ignoring exception while aborting {}", + LOGGER.warn("Ignoring exception while aborting {}", configTransactionController, e); } } @@ -524,14 +524,10 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe @Override public Set lookupRuntimeBeans(String moduleName, String instanceName) { - if (moduleName == null) { - moduleName = "*"; - } - if (instanceName == null) { - instanceName = "*"; - } + String finalModuleName = moduleName == null ? "*" : moduleName; + String finalInstanceName = instanceName == null ? "*" : instanceName; ObjectName namePattern = ObjectNameUtil.createRuntimeBeanPattern( - moduleName, instanceName); + finalModuleName, finalInstanceName); return baseJMXRegistrator.queryNames(namePattern, null); } @@ -609,7 +605,7 @@ class ConfigHolder { * Service Registry. */ public void addAll(Collection configInfos) { - if (currentConfig.size() > 0) { + if (!currentConfig.isEmpty()) { throw new IllegalStateException( "Error - some config entries were not removed: " + currentConfig); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java index 39eef8741b..a58f7a05c6 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java @@ -53,7 +53,7 @@ class ConfigTransactionControllerImpl implements ConfigTransactionControllerInternal, ConfigTransactionControllerImplMXBean, Identifiable { - private static final Logger logger = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class); private final ConfigTransactionLookupRegistry txLookupRegistry; private final ObjectName controllerON; @@ -226,7 +226,7 @@ class ConfigTransactionControllerImpl implements boolean isDefaultBean, BundleContext bundleContext) throws InstanceAlreadyExistsException { - logger.debug("Adding module {} to transaction {}", moduleIdentifier, this); + LOGGER.debug("Adding module {} to transaction {}", moduleIdentifier, this); if (moduleIdentifier.equals(module.getIdentifier()) == false) { throw new IllegalStateException("Incorrect name reported by module. Expected " + moduleIdentifier + ", got " + module.getIdentifier()); @@ -271,15 +271,13 @@ class ConfigTransactionControllerImpl implements } private synchronized void destroyModule(ModuleIdentifier moduleIdentifier) { - logger.debug("Destroying module {} in transaction {}", moduleIdentifier, this); + LOGGER.debug("Destroying module {} in transaction {}", moduleIdentifier, this); transactionStatus.checkNotAborted(); ModuleInternalTransactionalInfo found = dependencyResolverManager.findModuleInternalTransactionalInfo(moduleIdentifier); - if (blankTransaction == false) { - - if (found.isDefaultBean()) { - logger.warn("Warning: removing default bean. This will be forbidden in next version of config-subsystem"); - } + if (blankTransaction == false && + found.isDefaultBean()) { + LOGGER.warn("Warning: removing default bean. This will be forbidden in next version of config-subsystem"); } // first remove refNames, it checks for objectname existence @@ -287,7 +285,7 @@ class ConfigTransactionControllerImpl implements writableSRRegistry.removeServiceReferences( ObjectNameUtil.createTransactionModuleON(getTransactionName(), moduleIdentifier)); } catch (InstanceNotFoundException e) { - logger.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry); + LOGGER.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry); throw new IllegalStateException("Possible code error: cannot find " + moduleIdentifier, e); } @@ -313,15 +311,15 @@ class ConfigTransactionControllerImpl implements } configBeanModificationDisabled.set(true); try { - validate_noLocks(); + validateNoLocks(); } finally { configBeanModificationDisabled.set(false); } } - private void validate_noLocks() throws ValidationException { + private void validateNoLocks() throws ValidationException { transactionStatus.checkNotAborted(); - logger.trace("Validating transaction {}", getTransactionIdentifier()); + LOGGER.trace("Validating transaction {}", getTransactionIdentifier()); // call validate() List collectedExceptions = new ArrayList<>(); for (Entry entry : dependencyResolverManager @@ -331,17 +329,17 @@ class ConfigTransactionControllerImpl implements try { module.validate(); } catch (Exception e) { - logger.warn("Validation exception in {}", getTransactionName(), + LOGGER.warn("Validation exception in {}", getTransactionName(), e); collectedExceptions.add(ValidationException .createForSingleException(name, e)); } } - if (collectedExceptions.size() > 0) { + if (!collectedExceptions.isEmpty()) { throw ValidationException .createFromCollectedValidationExceptions(collectedExceptions); } - logger.trace("Validated transaction {}", getTransactionIdentifier()); + LOGGER.trace("Validated transaction {}", getTransactionIdentifier()); } /** @@ -358,9 +356,9 @@ class ConfigTransactionControllerImpl implements transactionStatus.checkNotCommitStarted(); configBeanModificationDisabled.set(true); try { - validate_noLocks(); + validateNoLocks(); } catch (ValidationException e) { - logger.trace("Commit failed on validation"); + LOGGER.trace("Commit failed on validation"); configBeanModificationDisabled.set(false); // recoverable error throw e; } @@ -383,7 +381,7 @@ class ConfigTransactionControllerImpl implements + "to obtain a lock"); } - logger.trace("Committing transaction {}", getTransactionIdentifier()); + LOGGER.trace("Committing transaction {}", getTransactionIdentifier()); // call getInstance() for (Entry entry : dependencyResolverManager @@ -391,12 +389,12 @@ class ConfigTransactionControllerImpl implements Module module = entry.getValue(); ModuleIdentifier name = entry.getKey(); try { - logger.debug("About to commit {} in transaction {}", + LOGGER.debug("About to commit {} in transaction {}", name, getTransactionIdentifier()); AutoCloseable instance = module.getInstance(); checkNotNull(instance, "Instance is null:{} in transaction {}", name, getTransactionIdentifier()); } catch (Exception e) { - logger.error("Commit failed on {} in transaction {}", name, + LOGGER.error("Commit failed on {} in transaction {}", name, getTransactionIdentifier(), e); internalAbort(); throw new IllegalStateException( @@ -407,7 +405,7 @@ class ConfigTransactionControllerImpl implements // count dependency order - logger.trace("Committed configuration {}", getTransactionIdentifier()); + LOGGER.trace("Committed configuration {}", getTransactionIdentifier()); transactionStatus.setCommitted(); return dependencyResolverManager.getSortedModuleIdentifiers(); @@ -421,7 +419,7 @@ class ConfigTransactionControllerImpl implements } private void internalAbort() { - logger.trace("Aborting {}", this); + LOGGER.trace("Aborting {}", this); transactionStatus.setAborted(); close(); } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java index d34a739703..b59b48e5a9 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java @@ -11,7 +11,7 @@ import java.util.LinkedList; import java.util.concurrent.TimeUnit; public class DeadlockMonitor implements AutoCloseable { - private static final Logger logger = LoggerFactory.getLogger(DeadlockMonitorRunnable.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DeadlockMonitorRunnable.class); private static final long WARN_AFTER_MILLIS = 5000; @@ -43,7 +43,7 @@ public class DeadlockMonitor implements AutoCloseable { moduleIdentifierWithNanosStack.push(current); top = current; } - logger.trace("setCurrentlyInstantiatedModule {}, top {}", currentlyInstantiatedModule, top); + LOGGER.trace("setCurrentlyInstantiatedModule {}, top {}", currentlyInstantiatedModule, top); } public boolean isAlive() { @@ -78,7 +78,7 @@ public class DeadlockMonitor implements AutoCloseable { // is the getInstance() running longer than WARN_AFTER_MILLIS ? long runningTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - copy.nanoTime); if (runningTime > WARN_AFTER_MILLIS) { - logger.warn("{} did not finish after {} ms", copy.moduleIdentifier, runningTime); + LOGGER.warn("{} did not finish after {} ms", copy.moduleIdentifier, runningTime); } } try { @@ -87,7 +87,7 @@ public class DeadlockMonitor implements AutoCloseable { interrupt(); } } - logger.trace("Exiting {}", this); + LOGGER.trace("Exiting {}", this); } @Override @@ -122,14 +122,21 @@ public class DeadlockMonitor implements AutoCloseable { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } ModuleIdentifierWithNanos that = (ModuleIdentifierWithNanos) o; - if (nanoTime != that.nanoTime) return false; - if (moduleIdentifier != null ? !moduleIdentifier.equals(that.moduleIdentifier) : that.moduleIdentifier != null) + if (nanoTime != that.nanoTime) { return false; + } + if (moduleIdentifier != null ? !moduleIdentifier.equals(that.moduleIdentifier) : that.moduleIdentifier != null) { + return false; + } return true; } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java index 52bb3f5ed1..0f881e95ad 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java @@ -38,7 +38,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceReadableRegistry, SearchableServiceReferenceWritableRegistry { - private static final Logger logger = LoggerFactory.getLogger(ServiceReferenceRegistryImpl.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceReferenceRegistryImpl.class); private final Map factories; private final Map> factoryNamesToQNames; @@ -176,7 +176,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe boolean skipChecks = true; newRegistry.saveServiceReference(refNameEntry.getKey(), currentImplementation, skipChecks); } catch (InstanceNotFoundException e) { - logger.error("Cannot save service reference({}, {})", refNameEntry.getKey(), currentImplementation); + LOGGER.error("Cannot save service reference({}, {})", refNameEntry.getKey(), currentImplementation); throw new IllegalStateException("Possible code error", e); } } @@ -201,22 +201,22 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe Map> modifiableFactoryNamesToQNames = new HashMap<>(); Set allAnnotations = new HashSet<>(); - Set allQNames = new HashSet<>(); + Set allQNameSet = new HashSet<>(); for (Entry entry : factories.entrySet()) { if (entry.getKey().equals(entry.getValue().getImplementationName()) == false) { - logger.error("Possible error in code: Mismatch between supplied and actual name of {}", entry); + LOGGER.error("Possible error in code: Mismatch between supplied and actual name of {}", entry); throw new IllegalArgumentException("Possible error in code: Mismatch between supplied and actual name of " + entry); } Set siAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(entry.getValue()); Set qNames = InterfacesHelper.getQNames(siAnnotations); allAnnotations.addAll(siAnnotations); - allQNames.addAll(qNames); + allQNameSet.addAll(qNames); modifiableFactoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames)); } this.factoryNamesToQNames = Collections.unmodifiableMap(modifiableFactoryNamesToQNames); - this.allQNames = Collections.unmodifiableSet(allQNames); + this.allQNames = Collections.unmodifiableSet(allQNameSet); // fill namespacesToAnnotations Map> modifiableNamespacesToAnnotations = new HashMap<>(); @@ -228,7 +228,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe modifiableNamespacesToAnnotations.put(sia.namespace(), ofNamespace); } if (ofNamespace.containsKey(sia.localName())) { - logger.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}", + LOGGER.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}", sia.namespace(), sia.localName(), modifiableNamespacesToAnnotations); throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName()); } @@ -237,7 +237,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe } this.namespacesToAnnotations = Collections.unmodifiableMap(modifiableNamespacesToAnnotations); this.serviceQNamesToAnnotations = Collections.unmodifiableMap(modifiableServiceQNamesToAnnotations); - logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames); + LOGGER.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames); } @Override @@ -256,7 +256,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe String factoryName = ObjectNameUtil.getFactoryName(objectName); Set serviceInterfaceAnnotations = factoryNamesToQNames.get(factoryName); if (serviceInterfaceAnnotations == null) { - logger.error("Possible error in code: cannot find factory annotations of '{}' extracted from ON {} in {}", + LOGGER.error("Possible error in code: cannot find factory annotations of '{}' extracted from ON {} in {}", factoryName, objectName, factoryNamesToQNames); throw new IllegalArgumentException("Cannot find factory with name " + factoryName); } @@ -267,12 +267,12 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe public synchronized String getServiceInterfaceName(String namespace, String localName) { Map ofNamespace = namespacesToAnnotations.get(namespace); if (ofNamespace == null) { - logger.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations); + LOGGER.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations); throw new IllegalArgumentException("Cannot find namespace " + namespace); } ServiceInterfaceAnnotation sia = ofNamespace.get(localName); if (sia == null) { - logger.error("Cannot find local name {} in namespace {}, found only {}", localName, namespace, ofNamespace); + LOGGER.error("Cannot find local name {} in namespace {}, found only {}", localName, namespace, ofNamespace); throw new IllegalArgumentException("Cannot find local name " + localName + " in namespace " + namespace); } return sia.value(); @@ -300,7 +300,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe try { on = lookupRegistry.lookupConfigBean(moduleIdentifier.getFactoryName(), moduleIdentifier.getInstanceName()); } catch (InstanceNotFoundException e) { - logger.error("Cannot find instance {}", moduleIdentifier); + LOGGER.error("Cannot find instance {}", moduleIdentifier); throw new IllegalStateException("Cannot find instance " + moduleIdentifier, e); } return on; @@ -311,7 +311,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe ServiceReference serviceReference = new ServiceReference(serviceInterfaceQName, refName); ModuleIdentifier moduleIdentifier = refNames.get(serviceReference); if (moduleIdentifier == null) { - logger.error("Cannot find qname {} and refName {} in {}", serviceInterfaceQName, refName, refName); + LOGGER.error("Cannot find qname {} and refName {} in {}", serviceInterfaceQName, refName, refName); throw new IllegalArgumentException("Cannot find " + serviceReference); } return getObjectName(moduleIdentifier); @@ -322,7 +322,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe Map> serviceMapping = getServiceMapping(); Map innerMap = serviceMapping.get(serviceInterfaceQName); if (innerMap == null) { - logger.error("Cannot find qname {} in {}", serviceInterfaceQName, refNames); + LOGGER.error("Cannot find qname {} in {}", serviceInterfaceQName, refNames); throw new IllegalArgumentException("Cannot find " + serviceInterfaceQName); } return innerMap; @@ -348,7 +348,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe String referenceName = ObjectNameUtil.getReferenceName(objectName); ServiceReference serviceReference = new ServiceReference(serviceQName, referenceName); if (refNames.containsKey(serviceReference) == false) { - logger.warn("Cannot find {} in {}", serviceReference, refNames); + LOGGER.warn("Cannot find {} in {}", serviceReference, refNames); throw new InstanceNotFoundException("Service reference not found:" + objectName); } } @@ -387,13 +387,13 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe // check that service interface name exist Set serviceInterfaceQNames = factoryNamesToQNames.get(moduleIdentifier.getFactoryName()); if (serviceInterfaceQNames == null) { - logger.error("Possible error in code: cannot find factoryName {} in {}, {}", moduleIdentifier.getFactoryName(), + LOGGER.error("Possible error in code: cannot find factoryName {} in {}, {}", moduleIdentifier.getFactoryName(), factoryNamesToQNames, moduleIdentifier); throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + moduleIdentifier.getFactoryName()); } // supplied serviceInterfaceName must exist in this collection if (serviceInterfaceQNames.contains(serviceReference.getServiceInterfaceQName()) == false) { - logger.error("Cannot find qName {} with factory name {}, found {}", serviceReference.getServiceInterfaceQName(), moduleIdentifier.getFactoryName(), serviceInterfaceQNames); + LOGGER.error("Cannot find qName {} with factory name {}, found {}", serviceReference.getServiceInterfaceQName(), moduleIdentifier.getFactoryName(), serviceInterfaceQNames); throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceQName() + " within factory " + moduleIdentifier.getFactoryName()); } @@ -465,11 +465,11 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe } private synchronized void removeServiceReference(ServiceReference serviceReference) throws InstanceNotFoundException { - logger.debug("Removing service reference {} from {}", serviceReference, this); + LOGGER.debug("Removing service reference {} from {}", serviceReference, this); assertWritable(); // is the qName known? if (allQNames.contains(serviceReference.getServiceInterfaceQName()) == false) { - logger.error("Cannot find qname {} in {}", serviceReference.getServiceInterfaceQName(), allQNames); + LOGGER.error("Cannot find qname {} in {}", serviceReference.getServiceInterfaceQName(), allQNames); throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceQName()); } ModuleIdentifier removed = refNames.remove(serviceReference); @@ -518,7 +518,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe private Set findServiceReferencesLinkingTo(ObjectName moduleObjectName, Set serviceInterfaceQNames) { String factoryName = ObjectNameUtil.getFactoryName(moduleObjectName); if (serviceInterfaceQNames == null) { - logger.warn("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, moduleObjectName); + LOGGER.warn("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, moduleObjectName); throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName); } String instanceName = ObjectNameUtil.getInstanceName(moduleObjectName); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java index 4f60a673f5..a7a67d3d16 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java @@ -45,7 +45,7 @@ import org.slf4j.LoggerFactory; */ final class DependencyResolverImpl implements DependencyResolver, Comparable { - private static final Logger logger = LoggerFactory.getLogger(DependencyResolverImpl.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DependencyResolverImpl.class); private final ModulesHolder modulesHolder; private final ModuleIdentifier name; @@ -107,9 +107,9 @@ final class DependencyResolverImpl implements DependencyResolver, ), jmxAttribute ); - dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON); + ObjectName newDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON); - ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentReadOnlyON, ObjectNameUtil + ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(newDependentReadOnlyON, ObjectNameUtil .TYPE_MODULE); ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute); @@ -122,7 +122,7 @@ final class DependencyResolverImpl implements DependencyResolver, + "Module name is %s : %s, expected service interface %s, dependent module ON %s , " + "attribute %s", foundFactory.getImplementationName(), foundFactory, - expectedServiceInterface, dependentReadOnlyON, + expectedServiceInterface, newDependentReadOnlyON, jmxAttribute ); throw new JmxAttributeValidationException(message, jmxAttribute); @@ -134,13 +134,14 @@ final class DependencyResolverImpl implements DependencyResolver, // translate from serviceref to module ON private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) { - if (ObjectNameUtil.isServiceReference(dependentReadOnlyON)) { - String serviceQName = ObjectNameUtil.getServiceQName(dependentReadOnlyON); - String refName = ObjectNameUtil.getReferenceName(dependentReadOnlyON); - dependentReadOnlyON = ObjectNameUtil.withoutTransactionName( // strip again of transaction name + ObjectName translatedDependentReadOnlyON = dependentReadOnlyON; + if (ObjectNameUtil.isServiceReference(translatedDependentReadOnlyON)) { + String serviceQName = ObjectNameUtil.getServiceQName(translatedDependentReadOnlyON); + String refName = ObjectNameUtil.getReferenceName(translatedDependentReadOnlyON); + translatedDependentReadOnlyON = ObjectNameUtil.withoutTransactionName( // strip again of transaction name readableRegistry.lookupConfigBeanByServiceInterfaceName(serviceQName, refName)); } - return dependentReadOnlyON; + return translatedDependentReadOnlyON; } /** @@ -155,12 +156,12 @@ final class DependencyResolverImpl implements DependencyResolver, "Null parameters not allowed, got %s %s %s", expectedType, dependentReadOnlyON, jmxAttribute)); } - dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON); + ObjectName translatedDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON); transactionStatus.checkCommitStarted(); transactionStatus.checkNotCommitted(); ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON( - dependentReadOnlyON, ObjectNameUtil.TYPE_MODULE); + translatedDependentReadOnlyON, ObjectNameUtil.TYPE_MODULE); Module module = modulesHolder.findModule(dependentModuleIdentifier, jmxAttribute); synchronized (this) { @@ -199,7 +200,7 @@ final class DependencyResolverImpl implements DependencyResolver, if (expectedBaseClass.isAssignableFrom(deserialized)) { return (Class) deserialized; } else { - logger.error("Cannot resolve class of identity {} : deserialized class {} is not a subclass of {}.", + LOGGER.error("Cannot resolve class of identity {} : deserialized class {} is not a subclass of {}.", identityRef, deserialized, expectedBaseClass); throw new IllegalArgumentException("Deserialized identity " + deserialized + " cannot be cast to " + expectedBaseClass); } @@ -277,17 +278,17 @@ final class DependencyResolverImpl implements DependencyResolver, @Override public Object getAttribute(ObjectName name, String attribute) throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException { - name = translateServiceRefIfPossible(name); + ObjectName newName = translateServiceRefIfPossible(name); // add transaction name - name = ObjectNameUtil.withTransactionName(name, transactionName); - return mBeanServer.getAttribute(name, attribute); + newName = ObjectNameUtil.withTransactionName(newName, transactionName); + return mBeanServer.getAttribute(newName, attribute); } @Override public T newMXBeanProxy(ObjectName name, Class interfaceClass) { - name = translateServiceRefIfPossible(name); + ObjectName newName = translateServiceRefIfPossible(name); // add transaction name - name = ObjectNameUtil.withTransactionName(name, transactionName); - return JMX.newMXBeanProxy(mBeanServer, name, interfaceClass); + newName = ObjectNameUtil.withTransactionName(newName, transactionName); + return JMX.newMXBeanProxy(mBeanServer, newName, interfaceClass); } } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java index 2a1a908e7a..15f5d48a6f 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java @@ -139,7 +139,7 @@ public class DependencyResolverManager implements DependencyResolverFactory, Aut @Override protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { - boolean isGetInstance = method.getName().equals("getInstance"); + boolean isGetInstance = "getInstance".equals(method.getName()); if (isGetInstance) { if (cachedInstance != null) { return cachedInstance; diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DestroyedModule.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DestroyedModule.java index 2aa74758d4..ec2418bc6c 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DestroyedModule.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DestroyedModule.java @@ -22,7 +22,7 @@ import org.slf4j.LoggerFactory; */ public class DestroyedModule implements AutoCloseable, Comparable, Identifiable { - private static final Logger logger = LoggerFactory + private static final Logger LOGGER = LoggerFactory .getLogger(DestroyedModule.class); private final ModuleIdentifier identifier; @@ -43,21 +43,21 @@ public class DestroyedModule implements AutoCloseable, @Override public void close() { - logger.trace("Destroying {}", identifier); + LOGGER.trace("Destroying {}", identifier); try { instance.close(); } catch (Exception e) { - logger.error("Error while closing instance of {}", identifier, e); + LOGGER.error("Error while closing instance of {}", identifier, e); } try { oldJMXRegistrator.close(); } catch (Exception e) { - logger.error("Error while closing jmx registrator of {}", identifier, e); + LOGGER.error("Error while closing jmx registrator of {}", identifier, e); } try { osgiRegistration.close(); } catch (Exception e) { - logger.error("Error while closing osgi registration of {}", identifier, e); + LOGGER.error("Error while closing osgi registration of {}", identifier, e); } } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java index 7e48af1caa..4a148669b1 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java @@ -57,7 +57,7 @@ import static java.lang.String.format; * a read only wrapper. */ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { - private static final Logger logger = LoggerFactory + private static final Logger LOGGER = LoggerFactory .getLogger(AbstractDynamicWrapper.class); protected final boolean writable; @@ -234,7 +234,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { public Object getAttribute(String attributeName) throws AttributeNotFoundException, MBeanException, ReflectionException { - if (attributeName.equals("MBeanInfo")) { + if ("MBeanInfo".equals(attributeName)) { return getMBeanInfo(); } @@ -318,7 +318,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { result.add(new Attribute(attributeName, value)); } catch (Exception e) { - logger.debug("Getting attribute {} failed", attributeName, e); + LOGGER.debug("Getting attribute {} failed", attributeName, e); } } return result; @@ -342,7 +342,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { && signature[0].equals(AttributeList.class.getName())) { return setAttributes((AttributeList) params[0]); } else { - logger.debug("Operation not found {} ", actionName); + LOGGER.debug("Operation not found {} ", actionName); throw new UnsupportedOperationException( format("Operation not found on %s. Method invoke is only supported for getInstance and getAttribute(s) " + "method, got actionName %s, params %s, signature %s ", diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsHelper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsHelper.java index f3e1b4e705..c4dee3513d 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsHelper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsHelper.java @@ -17,6 +17,9 @@ import java.util.Set; public class AnnotationsHelper { + private AnnotationsHelper() { + } + /** * Look for annotation specified by annotationType on method. First observe * method's class, then its super classes, then all provided interfaces. diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java index 044f7a9ada..14be254504 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java @@ -136,7 +136,7 @@ class AttributeHolder { for (RequireInterface ri : foundRequireInterfaces) { foundValues.add(ri.value()); } - if (foundValues.size() == 0) { + if (foundValues.isEmpty()) { return null; } else if (foundValues.size() > 1) { throw new IllegalStateException("Error finding @RequireInterface. " diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicReadableWrapper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicReadableWrapper.java index 3a24940a4c..7d3cb277fb 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicReadableWrapper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicReadableWrapper.java @@ -68,7 +68,7 @@ public class DynamicReadableWrapper extends AbstractDynamicWrapper implements public Object getAttribute(String attributeName) throws AttributeNotFoundException, MBeanException, ReflectionException { - if (attributeName.equals("getInstance")) { + if ("getInstance".equals(attributeName)) { return getInstance(); } return super.getAttribute(attributeName); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java index 07bd63b7c7..c3885150d5 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java @@ -47,7 +47,7 @@ import java.lang.reflect.Method; */ @ThreadSafe public class DynamicWritableWrapper extends AbstractDynamicWrapper { - private static final Logger logger = LoggerFactory + private static final Logger LOGGER = LoggerFactory .getLogger(DynamicWritableWrapper.class); private final ReadOnlyAtomicBoolean configBeanModificationDisabled; @@ -77,23 +77,24 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper { @Override public synchronized void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { + Attribute newAttribute = attribute; if (configBeanModificationDisabled.get() == true) { throw new IllegalStateException("Operation is not allowed now"); } - if (attribute.getName().equals("Attribute")) { - setAttribute((Attribute) attribute.getValue()); + if ("Attribute".equals(newAttribute.getName())) { + setAttribute((Attribute) newAttribute.getValue()); return; } try { - if (attribute.getValue() instanceof ObjectName) { - attribute = fixDependencyAttribute(attribute); - } else if (attribute.getValue() instanceof ObjectName[]) { - attribute = fixDependencyListAttribute(attribute); + if (newAttribute.getValue() instanceof ObjectName) { + newAttribute = fixDependencyAttribute(newAttribute); + } else if (newAttribute.getValue() instanceof ObjectName[]) { + newAttribute = fixDependencyListAttribute(newAttribute); } - internalServer.setAttribute(objectNameInternal, attribute); + internalServer.setAttribute(objectNameInternal, newAttribute); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } @@ -101,21 +102,23 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper { } private Attribute fixDependencyListAttribute(Attribute attribute) { - AttributeHolder attributeHolder = attributeHolderMap.get(attribute.getName()); + Attribute newAttribute = attribute; + AttributeHolder attributeHolder = attributeHolderMap.get(newAttribute.getName()); if (attributeHolder.getRequireInterfaceOrNull() != null) { - attribute = new Attribute(attribute.getName(), fixObjectNames((ObjectName[]) attribute.getValue())); + newAttribute = new Attribute(newAttribute.getName(), fixObjectNames((ObjectName[]) newAttribute.getValue())); } - return attribute; + return newAttribute; } private Attribute fixDependencyAttribute(Attribute attribute) { - AttributeHolder attributeHolder = attributeHolderMap.get(attribute.getName()); + Attribute newAttribute = attribute; + AttributeHolder attributeHolder = attributeHolderMap.get(newAttribute.getName()); if (attributeHolder.getRequireInterfaceOrNull() != null) { - attribute = new Attribute(attribute.getName(), fixObjectName((ObjectName) attribute.getValue())); + newAttribute = new Attribute(newAttribute.getName(), fixObjectName((ObjectName) newAttribute.getValue())); } else { - attribute = new Attribute(attribute.getName(), attribute.getValue()); + newAttribute = new Attribute(newAttribute.getName(), newAttribute.getValue()); } - return attribute; + return newAttribute; } private ObjectName[] fixObjectNames(ObjectName[] dependencies) { @@ -137,7 +140,7 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper { setAttribute(attribute); result.add(attribute); } catch (Exception e) { - logger.warn("Setting attribute {} failed on {}", attribute.getName(), moduleIdentifier, e); + LOGGER.warn("Setting attribute {} failed on {}", attribute.getName(), moduleIdentifier, e); throw new IllegalArgumentException( "Setting attribute failed - " + attribute.getName() + " on " + moduleIdentifier, e); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/InternalJMXRegistrator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/InternalJMXRegistrator.java index 98f0908dc7..ddb9c52c88 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/InternalJMXRegistrator.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/InternalJMXRegistrator.java @@ -27,7 +27,7 @@ import java.util.List; import java.util.Set; public class InternalJMXRegistrator implements Closeable { - private static final Logger logger = LoggerFactory + private static final Logger LOGGER = LoggerFactory .getLogger(InternalJMXRegistrator.class); private final MBeanServer configMBeanServer; @@ -53,6 +53,7 @@ public class InternalJMXRegistrator implements Closeable { @GuardedBy("this") private final Set registeredObjectNames = new HashSet<>(); + @GuardedBy("this") private final List children = new ArrayList<>(); public synchronized InternalJMXRegistration registerMBean(Object object, @@ -79,9 +80,8 @@ public class InternalJMXRegistrator implements Closeable { } } - public InternalJMXRegistrator createChild() { - InternalJMXRegistrator child = new InternalJMXRegistrator( - configMBeanServer); + public synchronized InternalJMXRegistrator createChild() { + InternalJMXRegistrator child = new InternalJMXRegistrator(configMBeanServer); children.add(child); return child; } @@ -100,7 +100,7 @@ public class InternalJMXRegistrator implements Closeable { try { configMBeanServer.unregisterMBean(on); } catch (Exception e) { - logger.warn("Ignoring error while unregistering {}", on, e); + LOGGER.warn("Ignoring error while unregistering {}", on, e); } } registeredObjectNames.clear(); @@ -137,7 +137,7 @@ public class InternalJMXRegistrator implements Closeable { return getSameNames(result); } - private Set getSameNames(Set superSet) { + private synchronized Set getSameNames(Set superSet) { Set result = new HashSet<>(superSet); result.retainAll(registeredObjectNames); for (InternalJMXRegistrator child : children) { diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ModuleJMXRegistrator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ModuleJMXRegistrator.java index 34c0436daf..c0e9b0d101 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ModuleJMXRegistrator.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ModuleJMXRegistrator.java @@ -46,9 +46,10 @@ public class ModuleJMXRegistrator implements Closeable { public ModuleJMXRegistration registerMBean(Object object, ObjectName on) throws InstanceAlreadyExistsException { ObjectNameUtil.checkType(on, ObjectNameUtil.TYPE_MODULE); - if (ObjectNameUtil.getTransactionName(on) != null) + if (ObjectNameUtil.getTransactionName(on) != null) { throw new IllegalArgumentException( "Transaction name not expected in " + on); + } return new ModuleJMXRegistration(childJMXRegistrator.registerMBean( object, on)); } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BeanToOsgiServiceManager.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BeanToOsgiServiceManager.java index b592fa3c79..c03bfa4500 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BeanToOsgiServiceManager.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BeanToOsgiServiceManager.java @@ -49,7 +49,7 @@ public class BeanToOsgiServiceManager { public static class OsgiRegistration implements AutoCloseable { - private static final Logger logger = LoggerFactory.getLogger(OsgiRegistration.class); + private static final Logger LOGGER = LoggerFactory.getLogger(OsgiRegistration.class); @GuardedBy("this") private AutoCloseable instance; @@ -89,7 +89,7 @@ public class BeanToOsgiServiceManager { try { serviceRegistration.unregister(); } catch(IllegalStateException e) { - logger.trace("Cannot unregister {}", serviceRegistration, e); + LOGGER.trace("Cannot unregister {}", serviceRegistration, e); } } serviceRegistrations.clear(); @@ -101,7 +101,7 @@ public class BeanToOsgiServiceManager { notEquals |= newAnnotationMapping.equals(serviceNamesToAnnotations) == false; if (notEquals) { // FIXME: changing from old state to new state can be improved by computing the diff - logger.debug("Detected change in service registrations for {}: old: {}, new: {}", moduleIdentifier, + LOGGER.debug("Detected change in service registrations for {}: old: {}, new: {}", moduleIdentifier, serviceNamesToAnnotations, newAnnotationMapping); close(); this.instance = newInstance; diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java index 375ef59487..b115f1acd9 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java @@ -25,7 +25,7 @@ import org.slf4j.LoggerFactory; * functionality. */ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer { - private static final Logger logger = LoggerFactory.getLogger(BlankTransactionServiceTracker.class); + private static final Logger LOGGER = LoggerFactory.getLogger(BlankTransactionServiceTracker.class); public static final int DEFAULT_MAX_ATTEMPTS = 10; @@ -65,7 +65,7 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer< try { // create transaction CommitStatus commitStatus = blankTransaction.hit(); - logger.debug("Committed blank transaction with status {}", commitStatus); + LOGGER.debug("Committed blank transaction with status {}", commitStatus); return; } catch (ConflictingVersionException e) { lastException = e; @@ -76,7 +76,7 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer< throw new IllegalStateException(interruptedException); } } catch (ValidationException e) { - logger.error("Validation exception while running blank transaction indicates programming error", e); + LOGGER.error("Validation exception while running blank transaction indicates programming error", e); throw new RuntimeException("Validation exception while running blank transaction indicates programming error", e); } } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java index 1e94e5e9c0..7cb4445328 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java @@ -25,7 +25,7 @@ import java.util.Map; */ public class BundleContextBackedModuleFactoriesResolver implements ModuleFactoriesResolver { - private static final Logger logger = LoggerFactory + private static final Logger LOGGER = LoggerFactory .getLogger(BundleContextBackedModuleFactoriesResolver.class); private final BundleContext bundleContext; @@ -62,14 +62,14 @@ public class BundleContextBackedModuleFactoriesResolver implements if (serviceReference.getBundle() == null || serviceReference.getBundle().getBundleContext() == null) { throw new NullPointerException("Bundle context of " + factory + " ModuleFactory not found."); } - logger.debug("Reading factory {} {}", moduleName, factory); + LOGGER.debug("Reading factory {} {}", moduleName, factory); Map.Entry conflicting = result.get(moduleName); if (conflicting != null) { String error = String .format("Module name is not unique. Found two conflicting factories with same name '%s': '%s' '%s'", moduleName, conflicting.getKey(), factory); - logger.error(error); + LOGGER.error(error); throw new IllegalArgumentException(error); } else { result.put(moduleName, new AbstractMap.SimpleImmutableEntry<>(factory, diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java index 3015ed229e..3c8fc042a3 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java @@ -35,7 +35,7 @@ import org.slf4j.LoggerFactory; */ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer { private final BlankTransactionServiceTracker blankTransactionServiceTracker; - private static final Logger logger = LoggerFactory.getLogger(ModuleFactoryBundleTracker.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ModuleFactoryBundleTracker.class); public ModuleFactoryBundleTracker(BlankTransactionServiceTracker blankTransactionServiceTracker) { this.blankTransactionServiceTracker = blankTransactionServiceTracker; @@ -44,7 +44,7 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer clazz = bundle.loadClass(factoryClassName); if (ModuleFactory.class.isAssignableFrom(clazz)) { try { - logger.debug("Registering {} in bundle {}", + LOGGER.debug("Registering {} in bundle {}", clazz.getName(), bundle); return bundle.getBundleContext().registerService( ModuleFactory.class.getName(), clazz.newInstance(), @@ -111,7 +111,7 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer>> { - private static final Logger logger = LoggerFactory.getLogger(ModuleInfoBundleTracker.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ModuleInfoBundleTracker.class); public static final String MODULE_INFO_PROVIDER_PATH_PREFIX = "META-INF/services/"; @@ -45,7 +45,7 @@ public final class ModuleInfoBundleTracker implements BundleTrackerCustomizer> addingBundle(Bundle bundle, BundleEvent event) { URL resource = bundle.getEntry(MODULE_INFO_PROVIDER_PATH_PREFIX + YangModelBindingProvider.class.getName()); - logger.debug("Got addingBundle({}) with YangModelBindingProvider resource {}", bundle, resource); + LOGGER.debug("Got addingBundle({}) with YangModelBindingProvider resource {}", bundle, resource); if(resource==null) { return null; } @@ -54,16 +54,16 @@ public final class ModuleInfoBundleTracker implements BundleTrackerCustomizer lines = IOUtils.readLines(inputStream); for (String moduleInfoName : lines) { - logger.trace("Retrieve ModuleInfo({}, {})", moduleInfoName, bundle); + LOGGER.trace("Retrieve ModuleInfo({}, {})", moduleInfoName, bundle); YangModuleInfo moduleInfo = retrieveModuleInfo(moduleInfoName, bundle); registrations.add(moduleInfoRegistry.registerModuleInfo(moduleInfo)); } } catch (Exception e) { - logger.error("Error while reading {}", resource, e); + LOGGER.error("Error while reading {}", resource, e); throw new RuntimeException(e); } - logger.trace("Got following registrations {}", registrations); + LOGGER.trace("Got following registrations {}", registrations); return registrations; } @@ -111,7 +111,7 @@ public final class ModuleInfoBundleTracker implements BundleTrackerCustomizer> getAllInterfaces(Class clazz) { if (clazz.isInterface()) { throw new IllegalArgumentException(clazz @@ -38,17 +41,17 @@ public class InterfacesHelper { } private static Set> getAllSuperInterfaces(Set> ifcs) { - ifcs = new HashSet<>(ifcs); // create copy to modify + Set> interfaces = new HashSet<>(ifcs); // create copy to modify // each interface can extend other interfaces Set> result = new HashSet<>(); - while (ifcs.size() > 0) { - Iterator> iterator = ifcs.iterator(); + while (!interfaces.isEmpty()) { + Iterator> iterator = interfaces.iterator(); Class ifc = iterator.next(); iterator.remove(); if (ifc.isInterface() == false) { throw new IllegalArgumentException(ifc + " should be an interface"); } - ifcs.addAll(Arrays.asList(ifc.getInterfaces())); + interfaces.addAll(Arrays.asList(ifc.getInterfaces())); result.add(ifc); } return result; diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/LookupBeansUtil.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/LookupBeansUtil.java index fdde0b23ef..284e109f2d 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/LookupBeansUtil.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/LookupBeansUtil.java @@ -16,12 +16,15 @@ import org.opendaylight.controller.config.api.LookupRegistry; public class LookupBeansUtil { + private LookupBeansUtil() { + } + public static ObjectName lookupConfigBean(LookupRegistry lookupRegistry, String moduleName, String instanceName) throws InstanceNotFoundException { Set objectNames = lookupRegistry.lookupConfigBeans( moduleName, instanceName); - if (objectNames.size() == 0) { + if (objectNames.isEmpty()) { throw new InstanceNotFoundException("No instance found"); } else if (objectNames.size() > 1) { throw new InstanceNotFoundException("Too many instances found"); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java index f1072a76ae..1cb31caea1 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java @@ -19,6 +19,9 @@ import java.util.Set; public class ModuleQNameUtil { + private ModuleQNameUtil() { + } + public static Set getQNames(Map> resolved) { Set result = new HashSet<>(); for (Entry entry : resolved.values()) { diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java index 2df28f0a15..f839452dca 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java @@ -21,7 +21,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class OsgiRegistrationUtil { - private static final Logger logger = LoggerFactory.getLogger(OsgiRegistrationUtil.class); + private static final Logger LOGGER = LoggerFactory.getLogger(OsgiRegistrationUtil.class); + + private OsgiRegistrationUtil() { + } @SafeVarargs public static AutoCloseable registerService(BundleContext bundleContext, T service, Class ... interfaces) { @@ -80,7 +83,7 @@ public class OsgiRegistrationUtil { try { ac.close(); } catch (Exception e) { - logger.warn("Exception while closing {}", ac, e); + LOGGER.warn("Exception while closing {}", ac, e); if (firstException == null) { firstException = e; } else { diff --git a/opendaylight/config/config-module-archetype/pom.xml b/opendaylight/config/config-module-archetype/pom.xml index 57d18e2f62..3e9162eb36 100644 --- a/opendaylight/config/config-module-archetype/pom.xml +++ b/opendaylight/config/config-module-archetype/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT config-module-archetype diff --git a/opendaylight/config/config-netty-config/pom.xml b/opendaylight/config/config-netty-config/pom.xml index 8dc31dcc4e..257c36779c 100644 --- a/opendaylight/config/config-netty-config/pom.xml +++ b/opendaylight/config/config-netty-config/pom.xml @@ -12,7 +12,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT config-netty-config Configuration files for sal-rest-connector diff --git a/opendaylight/config/config-persister-api/pom.xml b/opendaylight/config/config-persister-api/pom.xml index 2899acf5df..f83beb0c8b 100644 --- a/opendaylight/config/config-persister-api/pom.xml +++ b/opendaylight/config/config-persister-api/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT .. config-persister-api diff --git a/opendaylight/config/config-persister-directory-xml-adapter/pom.xml b/opendaylight/config/config-persister-directory-xml-adapter/pom.xml index 0cbc0a1db9..302b13fdf9 100644 --- a/opendaylight/config/config-persister-directory-xml-adapter/pom.xml +++ b/opendaylight/config/config-persister-directory-xml-adapter/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT .. config-persister-directory-xml-adapter diff --git a/opendaylight/config/config-persister-feature-adapter/pom.xml b/opendaylight/config/config-persister-feature-adapter/pom.xml index 7412a51425..d7d7889bf9 100644 --- a/opendaylight/config/config-persister-feature-adapter/pom.xml +++ b/opendaylight/config/config-persister-feature-adapter/pom.xml @@ -6,7 +6,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT .. diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/AbstractFeatureWrapper.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/AbstractFeatureWrapper.java index 1bf2025c46..3e004b4d7c 100644 --- a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/AbstractFeatureWrapper.java +++ b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/AbstractFeatureWrapper.java @@ -30,7 +30,7 @@ import com.google.common.base.Preconditions; * Delegates the the contained feature and provides additional methods. */ public class AbstractFeatureWrapper implements Feature { - private static final Logger logger = LoggerFactory.getLogger(AbstractFeatureWrapper.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFeatureWrapper.class); protected Feature feature = null; protected AbstractFeatureWrapper() { @@ -55,7 +55,7 @@ public class AbstractFeatureWrapper implements Feature { try { snapShotHolders.add(new FeatureConfigSnapshotHolder(c,this)); } catch (JAXBException e) { - logger.debug("{} is not a config subsystem config file",c.getFinalname()); + LOGGER.debug("{} is not a config subsystem config file",c.getFinalname()); } } return snapShotHolders; @@ -71,18 +71,23 @@ public class AbstractFeatureWrapper implements Feature { @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (obj == null) + } + if (obj == null) { return false; - if (getClass() != obj.getClass()) + } + if (getClass() != obj.getClass()) { return false; + } AbstractFeatureWrapper other = (AbstractFeatureWrapper) obj; if (feature == null) { - if (other.feature != null) + if (other.feature != null) { return false; - } else if (!feature.equals(other.feature)) + } + } else if (!feature.equals(other.feature)) { return false; + } return true; } diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ChildAwareFeatureWrapper.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ChildAwareFeatureWrapper.java index 8d2ae68a9a..2bff906900 100644 --- a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ChildAwareFeatureWrapper.java +++ b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ChildAwareFeatureWrapper.java @@ -30,7 +30,7 @@ import com.google.common.base.Preconditions; * Delegates the the contained feature and provides additional methods. */ public class ChildAwareFeatureWrapper extends AbstractFeatureWrapper implements Feature { - private static final Logger logger = LoggerFactory.getLogger(ChildAwareFeatureWrapper.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ChildAwareFeatureWrapper.class); private FeaturesService featuresService= null; protected ChildAwareFeatureWrapper(Feature f) { @@ -79,7 +79,7 @@ public class ChildAwareFeatureWrapper extends AbstractFeatureWrapper implements f = new FeatureConfigSnapshotHolder(h,this); snapShotHolders.add(f); } catch (JAXBException e) { - logger.debug("{} is not a config subsystem config file",h.getFileInfo().getFinalname()); + LOGGER.debug("{} is not a config subsystem config file",h.getFileInfo().getFinalname()); } } } @@ -95,11 +95,10 @@ public class ChildAwareFeatureWrapper extends AbstractFeatureWrapper implements for(Feature f: features) { if (f.getName().equals(dependency.getName())) { Version v = VersionTable.getVersion(f.getVersion()); - if (range.contains(v)) { - if (fi == null || VersionTable.getVersion(fi.getVersion()).compareTo(v) < 0) { + if (range.contains(v) && + (fi == null || VersionTable.getVersion(fi.getVersion()).compareTo(v) < 0)) { fi = f; break; - } } } } diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigFeaturesListener.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigFeaturesListener.java index f5f1b856ac..2af4719994 100644 --- a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigFeaturesListener.java +++ b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigFeaturesListener.java @@ -19,8 +19,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ConfigFeaturesListener implements FeaturesListener, AutoCloseable { - private static final Logger logger = LoggerFactory.getLogger(ConfigFeaturesListener.class); - private static final int QUEUE_SIZE = 100; + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigFeaturesListener.class); + private static final int QUEUE_SIZE = 1000; private BlockingQueue queue = new LinkedBlockingQueue(QUEUE_SIZE); Thread pushingThread = null; @@ -36,7 +36,7 @@ public class ConfigFeaturesListener implements FeaturesListener, AutoCloseable @Override public void repositoryEvent(RepositoryEvent event) { - logger.debug("Repository: " + event.getType() + " " + event.getRepository()); + LOGGER.debug("Repository: " + event.getType() + " " + event.getRepository()); } @Override diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPusherCustomizer.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPusherCustomizer.java index d33a8cba92..abb1dbe9aa 100644 --- a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPusherCustomizer.java +++ b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPusherCustomizer.java @@ -17,14 +17,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ConfigPusherCustomizer implements ServiceTrackerCustomizer, AutoCloseable { - private static final Logger logger = LoggerFactory.getLogger(ConfigPusherCustomizer.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigPusherCustomizer.class); private ConfigFeaturesListener configFeaturesListener = null; private FeatureServiceCustomizer featureServiceCustomizer = null; private ServiceTracker fsst = null; @Override public ConfigPusher addingService(ServiceReference configPusherServiceReference) { - logger.trace("Got ConfigPusherCustomizer.addingService {}", configPusherServiceReference); + LOGGER.trace("Got ConfigPusherCustomizer.addingService {}", configPusherServiceReference); BundleContext bc = configPusherServiceReference.getBundle().getBundleContext(); ConfigPusher cpService = bc.getService(configPusherServiceReference); featureServiceCustomizer = new FeatureServiceCustomizer(cpService); diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPushingRunnable.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPushingRunnable.java index 06c5c920f4..b0e64b84d2 100644 --- a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPushingRunnable.java +++ b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPushingRunnable.java @@ -23,7 +23,7 @@ import org.slf4j.LoggerFactory; import com.google.common.collect.LinkedHashMultimap; public class ConfigPushingRunnable implements Runnable { - private static final Logger logger = LoggerFactory.getLogger(ConfigPushingRunnable.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigPushingRunnable.class); private static final int POLL_TIME = 1; private BlockingQueue queue; private FeatureConfigPusher configPusher; @@ -49,14 +49,14 @@ public class ConfigPushingRunnable implements Runnable { processFeatureEvent(event,toInstall); } } else if(toInstall.isEmpty()) { - logger.error("ConfigPushingRunnable - exiting"); + LOGGER.error("ConfigPushingRunnable - exiting"); return; } } catch (InterruptedException e) { - logger.error("ConfigPushingRunnable - interupted"); + LOGGER.error("ConfigPushingRunnable - interupted"); interuppted = true; } catch (Exception e) { - logger.error("Exception while processing features {}", e); + LOGGER.error("Exception while processing features {}", e); } } } @@ -73,7 +73,7 @@ public class ConfigPushingRunnable implements Runnable { protected void logPushResult(LinkedHashMultimap results) { for(Feature f:results.keySet()) { - logger.info("Pushed configs for feature {} {}",f,results.get(f)); + LOGGER.info("Pushed configs for feature {} {}",f,results.get(f)); } } } diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigPusher.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigPusher.java index 1c094ad2dc..5c5061277b 100644 --- a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigPusher.java +++ b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigPusher.java @@ -25,7 +25,9 @@ import com.google.common.collect.LinkedHashMultimap; * Simple class to push configs to the config subsystem from Feature's configfiles */ public class FeatureConfigPusher { - private static final Logger logger = LoggerFactory.getLogger(FeatureConfigPusher.class); + private static final Logger LOGGER = LoggerFactory.getLogger(FeatureConfigPusher.class); + private static final int MAX_RETRIES=100; + private static final int RETRY_PAUSE_MILLIS=1; private FeaturesService featuresService = null; private ConfigPusher pusher = null; /* @@ -82,8 +84,30 @@ public class FeatureConfigPusher { } private boolean isInstalled(Feature feature) { - List installedFeatures = Arrays.asList(featuresService.listInstalledFeatures()); - return installedFeatures.contains(feature); + for(int retries=0;retries installedFeatures = Arrays.asList(featuresService.listInstalledFeatures()); + if(installedFeatures.contains(feature)) { + return true; + } else { + LOGGER.warn("Karaf featuresService.listInstalledFeatures() has not yet finished installing feature (retry {}) {} {}",retries,feature.getName(),feature.getVersion()); + } + } catch (Exception e) { + if(retries < MAX_RETRIES) { + LOGGER.warn("Karaf featuresService.listInstalledFeatures() has thrown an exception, retry {}, Exception {}", retries,e); + } else { + LOGGER.error("Giving up on Karaf featuresService.listInstalledFeatures() which has thrown an exception, retry {}, Exception {}", retries,e); + throw e; + } + } + try { + Thread.sleep(RETRY_PAUSE_MILLIS); + } catch (InterruptedException e1) { + throw new IllegalStateException(e1); + } + } + LOGGER.error("Giving up (after {} retries) on Karaf featuresService.listInstalledFeatures() which has not yet finished installing feature {} {}",MAX_RETRIES,feature.getName(),feature.getVersion()); + return false; } private LinkedHashSet pushConfig(LinkedHashSet configs) throws InterruptedException { diff --git a/opendaylight/config/config-persister-file-xml-adapter/pom.xml b/opendaylight/config/config-persister-file-xml-adapter/pom.xml index d8c81ea971..35df9e1999 100644 --- a/opendaylight/config/config-persister-file-xml-adapter/pom.xml +++ b/opendaylight/config/config-persister-file-xml-adapter/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT .. config-persister-file-xml-adapter diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java index e75c62b81d..02f9f8b80a 100644 --- a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java @@ -31,7 +31,7 @@ import java.util.SortedSet; * StorageAdapter that stores configuration in an xml file. */ public class XmlFileStorageAdapter implements StorageAdapter, Persister { - private static final Logger logger = LoggerFactory.getLogger(XmlFileStorageAdapter.class); + private static final Logger LOGGER = LoggerFactory.getLogger(XmlFileStorageAdapter.class); public static final String FILE_STORAGE_PROP = "fileStorage"; public static final String NUMBER_OF_BACKUPS = "numberOfBackups"; @@ -42,15 +42,15 @@ public class XmlFileStorageAdapter implements StorageAdapter, Persister { @Override public Persister instantiate(PropertiesProvider propertiesProvider) { File storage = extractStorageFileFromProperties(propertiesProvider); - logger.debug("Using file {}", storage.getAbsolutePath()); + LOGGER.debug("Using file {}", storage.getAbsolutePath()); // Create file if it does not exist File parentFile = storage.getAbsoluteFile().getParentFile(); if (parentFile.exists() == false) { - logger.debug("Creating parent folders {}", parentFile); + LOGGER.debug("Creating parent folders {}", parentFile); parentFile.mkdirs(); } if (storage.exists() == false) { - logger.debug("Storage file does not exist, creating empty file"); + LOGGER.debug("Storage file does not exist, creating empty file"); try { boolean result = storage.createNewFile(); if (result == false) @@ -87,7 +87,7 @@ public class XmlFileStorageAdapter implements StorageAdapter, Persister { } else { numberOfStoredBackups = Integer.MAX_VALUE; } - logger.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups); + LOGGER.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups); return result; } @@ -110,10 +110,11 @@ public class XmlFileStorageAdapter implements StorageAdapter, Persister { Optional lastSnapshot = Config.fromXml(storage).getLastSnapshot(); - if (lastSnapshot.isPresent()) + if (lastSnapshot.isPresent()) { return Lists.newArrayList(toConfigSnapshot(lastSnapshot.get())); - else + } else { return Collections.emptyList(); + } } diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java index 7c069dab6b..03b03befe0 100644 --- a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java @@ -59,7 +59,7 @@ public class ConfigSnapshot { @Override public String toString() { - final StringBuffer sb = new StringBuffer("ConfigSnapshot{"); + final StringBuilder sb = new StringBuilder("ConfigSnapshot{"); sb.append("configSnapshot='").append(configSnapshot).append('\''); sb.append(", capabilities=").append(capabilities); sb.append('}'); diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/StringTrimAdapter.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/StringTrimAdapter.java index 3c544d4e49..3c5f0bdab6 100644 --- a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/StringTrimAdapter.java +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/StringTrimAdapter.java @@ -12,15 +12,17 @@ import javax.xml.bind.annotation.adapters.XmlAdapter; final class StringTrimAdapter extends XmlAdapter { @Override public String unmarshal(String v) throws Exception { - if (v == null) + if (v == null) { return null; + } return v.trim(); } @Override public String marshal(String v) throws Exception { - if (v == null) + if (v == null) { return null; + } return v.trim(); } } diff --git a/opendaylight/config/config-plugin-parent/pom.xml b/opendaylight/config/config-plugin-parent/pom.xml index e66a4cfd3f..67370e1e2f 100644 --- a/opendaylight/config/config-plugin-parent/pom.xml +++ b/opendaylight/config/config-plugin-parent/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../ config-plugin-parent diff --git a/opendaylight/config/config-util/pom.xml b/opendaylight/config/config-util/pom.xml index 29a5526451..6a5950dc7e 100644 --- a/opendaylight/config/config-util/pom.xml +++ b/opendaylight/config/config-util/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT .. config-util diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java index 559993f264..11f64e959b 100644 --- a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java +++ b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java @@ -74,16 +74,17 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient { */ @Deprecated public T newMBeanProxy(ObjectName on, Class clazz) { - on = translateServiceRefIfPossible(on, clazz, configMBeanServer); - return JMX.newMBeanProxy(configMBeanServer, on, clazz); + ObjectName onObj = translateServiceRefIfPossible(on, clazz, configMBeanServer); + return JMX.newMBeanProxy(configMBeanServer, onObj, clazz); } static ObjectName translateServiceRefIfPossible(ObjectName on, Class clazz, MBeanServer configMBeanServer) { - if (ObjectNameUtil.isServiceReference(on) && clazz.equals(ServiceReferenceMXBean.class) == false) { - ServiceReferenceMXBean proxy = JMX.newMXBeanProxy(configMBeanServer, on, ServiceReferenceMXBean.class); - on = proxy.getCurrentImplementation(); + ObjectName onObj = on; + if (ObjectNameUtil.isServiceReference(onObj) && clazz.equals(ServiceReferenceMXBean.class) == false) { + ServiceReferenceMXBean proxy = JMX.newMXBeanProxy(configMBeanServer, onObj, ServiceReferenceMXBean.class); + onObj = proxy.getCurrentImplementation(); } - return on; + return onObj; } diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java index bc18851553..20e26f6508 100644 --- a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java +++ b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java @@ -45,12 +45,13 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { } public T newMXBeanProxy(ObjectName on, Class clazz) { + ObjectName onName = on; // if on is without transaction, add it. Reason is that when using getters on MXBeans the transaction name is stripped - on = ObjectNameUtil.withTransactionName(on, getTransactionName()); + onName = ObjectNameUtil.withTransactionName(onName, getTransactionName()); // if this is service reference and user requests for implementation, look it up - on = ConfigRegistryJMXClient.translateServiceRefIfPossible(on, clazz, configMBeanServer); - on = ObjectNameUtil.withTransactionName(on, getTransactionName()); - return JMX.newMXBeanProxy(configMBeanServer, on, clazz); + onName = ConfigRegistryJMXClient.translateServiceRefIfPossible(onName, clazz, configMBeanServer); + onName = ObjectNameUtil.withTransactionName(onName, getTransactionName()); + return JMX.newMXBeanProxy(configMBeanServer, onName, clazz); } /** @@ -260,9 +261,10 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { @Override public void setAttribute(ObjectName on, String attrName, Attribute attribute) { - if (ObjectNameUtil.getTransactionName(on) == null) + if (ObjectNameUtil.getTransactionName(on) == null) { throw new IllegalArgumentException("Not in transaction instance " + on + ", no transaction name present"); + } try { configMBeanServer.setAttribute(on, attribute); @@ -274,9 +276,10 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { @Override public Attribute getAttribute(ObjectName on, String attrName) { - if (ObjectNameUtil.getTransactionName(on) == null) + if (ObjectNameUtil.getTransactionName(on) == null) { throw new IllegalArgumentException("Not in transaction instance " + on + ", no transaction name present"); + } try { return new Attribute(attrName, configMBeanServer.getAttribute(on,attrName)); diff --git a/opendaylight/config/logback-config-loader/pom.xml b/opendaylight/config/logback-config-loader/pom.xml index 03ff65f662..0f379fbe21 100644 --- a/opendaylight/config/logback-config-loader/pom.xml +++ b/opendaylight/config/logback-config-loader/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent logback-config-loader diff --git a/opendaylight/config/logback-config/pom.xml b/opendaylight/config/logback-config/pom.xml index 0fd62aa427..d918fd7ab7 100644 --- a/opendaylight/config/logback-config/pom.xml +++ b/opendaylight/config/logback-config/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent logback-config diff --git a/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/ContextSetterImpl.java b/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/ContextSetterImpl.java index 9837a04e7f..ff7da5df48 100644 --- a/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/ContextSetterImpl.java +++ b/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/ContextSetterImpl.java @@ -38,7 +38,7 @@ import com.google.common.collect.Sets; public class ContextSetterImpl implements ContextSetter, Closeable { private final LogbackStatusListener statusListener; - private static final org.slf4j.Logger classLogger = LoggerFactory.getLogger(ContextSetterImpl.class); + private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ContextSetterImpl.class); public ContextSetterImpl(LogbackRuntimeRegistrator rootRuntimeBeanRegistratorWrapper) { statusListener = new LogbackStatusListener(rootRuntimeBeanRegistratorWrapper); @@ -83,11 +83,11 @@ public class ContextSetterImpl implements ContextSetter, Closeable { Map> appendersMap = getAppenders(module, context); for (LoggerTO logger : module.getLoggerTO()) { - classLogger.trace("Setting configuration for logger {}", logger.getLoggerName()); + LOGGER.trace("Setting configuration for logger {}", logger.getLoggerName()); final ch.qos.logback.classic.Logger logbackLogger = context.getLogger(logger.getLoggerName()); Optional>> appendersBefore = getAppendersBefore(loggersBefore, logbackLogger); - classLogger.trace("Logger {}: Appenders registered before: {}", logger.getLoggerName(), + LOGGER.trace("Logger {}: Appenders registered before: {}", logger.getLoggerName(), appendersBefore.isPresent() ? appendersBefore.get() : "NO APPENDERS BEFORE"); logbackLogger.setLevel(Level.toLevel(logger.getLevel())); @@ -103,7 +103,7 @@ public class ContextSetterImpl implements ContextSetter, Closeable { for (String appenderName : logger.getAppenders()) { if (appendersMap.containsKey(appenderName)) { logbackLogger.addAppender(appendersMap.get(appenderName)); - classLogger.trace("Logger {}: Adding new appender: {}", logger.getLoggerName(), appenderName); + LOGGER.trace("Logger {}: Adding new appender: {}", logger.getLoggerName(), appenderName); } else { throw new IllegalStateException("No appender " + appenderName + " found. This error should have been discovered by validation"); @@ -118,7 +118,7 @@ public class ContextSetterImpl implements ContextSetter, Closeable { for (Appender appenderBefore : appendersBefore.get()) { logbackLogger.detachAppender(appenderBefore); appenderBefore.stop(); - classLogger.trace("Logger {}: Removing old appender: {}", logger.getLoggerName(), + LOGGER.trace("Logger {}: Removing old appender: {}", logger.getLoggerName(), appenderBefore.getName()); } loggersBefore.remove(logbackLogger); @@ -134,8 +134,9 @@ public class ContextSetterImpl implements ContextSetter, Closeable { appendersBefore.add(appenderIt.next()); } return Optional.of(appendersBefore); - } else + } else { return Optional.absent(); + } } diff --git a/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleFactory.java b/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleFactory.java index 5a91796ed6..b5d0d1b4de 100644 --- a/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleFactory.java +++ b/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleFactory.java @@ -173,10 +173,11 @@ public class LogbackModuleFactory extends context.getLogger(Logger.ROOT_LOGGER_NAME)); for (org.slf4j.Logger log : loggersToBeAdd) { LoggerTO logger = new LoggerTO(); - if (((Logger) log).getLevel() != null) + if (((Logger) log).getLevel() != null) { logger.setLevel(((Logger) log).getLevel().levelStr); - else + } else { logger.setLevel(((Logger) log).getEffectiveLevel().levelStr); + } logger.setLoggerName(log.getName()); Iterator> iter = ((Logger) log).iteratorForAppenders(); while (iter.hasNext()) { diff --git a/opendaylight/config/netconf-config-dispatcher/pom.xml b/opendaylight/config/netconf-config-dispatcher/pom.xml index 1e5fcce609..0e0ec9372c 100644 --- a/opendaylight/config/netconf-config-dispatcher/pom.xml +++ b/opendaylight/config/netconf-config-dispatcher/pom.xml @@ -11,7 +11,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent diff --git a/opendaylight/config/netty-config-api/pom.xml b/opendaylight/config/netty-config-api/pom.xml index ca1e28e14c..a5c0831fb8 100644 --- a/opendaylight/config/netty-config-api/pom.xml +++ b/opendaylight/config/netty-config-api/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent netty-config-api diff --git a/opendaylight/config/netty-event-executor-config/pom.xml b/opendaylight/config/netty-event-executor-config/pom.xml index b001dc76f7..6188aed898 100644 --- a/opendaylight/config/netty-event-executor-config/pom.xml +++ b/opendaylight/config/netty-event-executor-config/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent netty-event-executor-config diff --git a/opendaylight/config/netty-event-executor-config/src/test/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleTest.java b/opendaylight/config/netty-event-executor-config/src/test/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleTest.java index 4cc9cc3dde..54c87604a4 100644 --- a/opendaylight/config/netty-event-executor-config/src/test/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleTest.java +++ b/opendaylight/config/netty-event-executor-config/src/test/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleTest.java @@ -21,12 +21,12 @@ import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; public class ImmediateEventExecutorModuleTest extends AbstractConfigTest { - private GlobalEventExecutorModuleFactory factory; + private ImmediateEventExecutorModuleFactory factory; private final String instanceName = ImmediateEventExecutorModuleFactory.SINGLETON_NAME; @Before public void setUp() { - factory = new GlobalEventExecutorModuleFactory(); + factory = new ImmediateEventExecutorModuleFactory(); super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,factory)); } diff --git a/opendaylight/config/netty-threadgroup-config/pom.xml b/opendaylight/config/netty-threadgroup-config/pom.xml index 8c86ca8354..2f3d26dd2f 100644 --- a/opendaylight/config/netty-threadgroup-config/pom.xml +++ b/opendaylight/config/netty-threadgroup-config/pom.xml @@ -7,7 +7,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent netty-threadgroup-config diff --git a/opendaylight/config/netty-timer-config/pom.xml b/opendaylight/config/netty-timer-config/pom.xml index 6b3ecdbceb..75b4709da2 100644 --- a/opendaylight/config/netty-timer-config/pom.xml +++ b/opendaylight/config/netty-timer-config/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent netty-timer-config diff --git a/opendaylight/config/pom.xml b/opendaylight/config/pom.xml index b8ad26116a..ea7b243179 100644 --- a/opendaylight/config/pom.xml +++ b/opendaylight/config/pom.xml @@ -5,12 +5,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../commons/opendaylight config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT pom ${project.artifactId} @@ -193,9 +193,21 @@ ${project.build.directory}/jacoco false - - 80 - + + + CLASS + + *Test + + + + LINE + COVEREDRATIO + 0.50 + + + + diff --git a/opendaylight/config/shutdown-api/pom.xml b/opendaylight/config/shutdown-api/pom.xml index 76c1cfdc54..659052e570 100644 --- a/opendaylight/config/shutdown-api/pom.xml +++ b/opendaylight/config/shutdown-api/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent shutdown-api diff --git a/opendaylight/config/shutdown-impl/pom.xml b/opendaylight/config/shutdown-impl/pom.xml index 9895022df6..f14c285323 100644 --- a/opendaylight/config/shutdown-impl/pom.xml +++ b/opendaylight/config/shutdown-impl/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent shutdown-impl diff --git a/opendaylight/config/shutdown-impl/src/main/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownModuleFactory.java b/opendaylight/config/shutdown-impl/src/main/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownModuleFactory.java index 4df9b036f1..1994e21a6d 100644 --- a/opendaylight/config/shutdown-impl/src/main/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownModuleFactory.java +++ b/opendaylight/config/shutdown-impl/src/main/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownModuleFactory.java @@ -5,26 +5,16 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -/** - * Generated file - - * Generated from: yang module name: shutdown-impl yang module local name: shutdown - * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator - * Generated at: Wed Dec 18 14:02:06 CET 2013 - * - * Do not modify this file unless it is present under src/main directory - */ package org.opendaylight.controller.config.yang.shutdown.impl; +import java.util.Arrays; +import java.util.Set; import org.opendaylight.controller.config.api.DependencyResolver; import org.opendaylight.controller.config.api.DependencyResolverFactory; import org.opendaylight.controller.config.api.ModuleIdentifier; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; -import java.util.Arrays; -import java.util.Set; - public class ShutdownModuleFactory extends AbstractShutdownModuleFactory { public ShutdownModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, diff --git a/opendaylight/config/shutdown-impl/src/main/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownServiceImpl.java b/opendaylight/config/shutdown-impl/src/main/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownServiceImpl.java index 4abbd3b36f..7d97fcd964 100644 --- a/opendaylight/config/shutdown-impl/src/main/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownServiceImpl.java +++ b/opendaylight/config/shutdown-impl/src/main/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownServiceImpl.java @@ -8,15 +8,14 @@ package org.opendaylight.controller.config.yang.shutdown.impl; import com.google.common.base.Optional; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; import org.opendaylight.controller.config.shutdown.ShutdownService; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadInfo; - public class ShutdownServiceImpl implements ShutdownService, AutoCloseable { private final ShutdownService impl; private final ShutdownRuntimeRegistration registration; @@ -42,7 +41,7 @@ public class ShutdownServiceImpl implements ShutdownService, AutoCloseable { } class Impl implements ShutdownService { - private static final Logger logger = LoggerFactory.getLogger(Impl.class); + private static final Logger LOG = LoggerFactory.getLogger(Impl.class); private final String secret; private final Bundle systemBundle; @@ -53,27 +52,27 @@ class Impl implements ShutdownService { @Override public void shutdown(String inputSecret, Long maxWaitTime, Optional reason) { - logger.warn("Shutdown issued with secret {} and reason {}", inputSecret, reason); + LOG.warn("Shutdown issued with secret {} and reason {}", inputSecret, reason); try { Thread.sleep(1000); // prevent brute force attack } catch (InterruptedException e) { Thread.currentThread().interrupt(); - logger.warn("Shutdown process interrupted", e); + LOG.warn("Shutdown process interrupted", e); } if (this.secret.equals(inputSecret)) { - logger.info("Server is shutting down"); + LOG.info("Server is shutting down"); // actual work: Thread stopSystemBundleThread = new StopSystemBundleThread(systemBundle); stopSystemBundleThread.start(); if (maxWaitTime != null && maxWaitTime > 0) { Thread systemExitThread = new CallSystemExitThread(maxWaitTime); - logger.debug("Scheduling {}", systemExitThread); + LOG.debug("Scheduling {}", systemExitThread); systemExitThread.start(); } // end } else { - logger.warn("Unauthorized attempt to shut down server"); + LOG.warn("Unauthorized attempt to shut down server"); throw new IllegalArgumentException("Invalid secret"); } } @@ -81,7 +80,7 @@ class Impl implements ShutdownService { } class StopSystemBundleThread extends Thread { - private static final Logger logger = LoggerFactory.getLogger(StopSystemBundleThread.class); + private static final Logger LOG = LoggerFactory.getLogger(StopSystemBundleThread.class); private final Bundle systemBundle; StopSystemBundleThread(Bundle systemBundle) { @@ -94,18 +93,18 @@ class StopSystemBundleThread extends Thread { try { // wait so that JMX response is received Thread.sleep(1000); - logger.debug("Stopping system bundle"); + LOG.debug("Stopping system bundle"); systemBundle.stop(); } catch (BundleException e) { - logger.warn("Can not stop OSGi server", e); + LOG.warn("Can not stop OSGi server", e); } catch (InterruptedException e) { - logger.warn("Shutdown process interrupted", e); + LOG.warn("Shutdown process interrupted", e); } } } class CallSystemExitThread extends Thread { - private static final Logger logger = LoggerFactory.getLogger(CallSystemExitThread.class); + private static final Logger LOG = LoggerFactory.getLogger(CallSystemExitThread.class); private final long maxWaitTime; CallSystemExitThread(long maxWaitTime) { super("call-system-exit-daemon"); @@ -128,7 +127,7 @@ class CallSystemExitThread extends Thread { try { // wait specified time Thread.sleep(maxWaitTime); - logger.error("Since some threads are still running, server is going to shut down via System.exit(1) !"); + LOG.error("Since some threads are still running, server is going to shut down via System.exit(1) !"); // do a thread dump ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true); StringBuffer sb = new StringBuffer(); @@ -136,10 +135,10 @@ class CallSystemExitThread extends Thread { sb.append(info); sb.append("\n"); } - logger.warn("Thread dump:{}", sb); + LOG.warn("Thread dump:{}", sb); System.exit(1); } catch (InterruptedException e) { - logger.warn("Interrupted, not going to call System.exit(1)"); + LOG.warn("Interrupted, not going to call System.exit(1)"); } } } diff --git a/opendaylight/config/threadpool-config-api/pom.xml b/opendaylight/config/threadpool-config-api/pom.xml index c9a19515ef..5f0c941a19 100644 --- a/opendaylight/config/threadpool-config-api/pom.xml +++ b/opendaylight/config/threadpool-config-api/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent threadpool-config-api diff --git a/opendaylight/config/threadpool-config-impl/pom.xml b/opendaylight/config/threadpool-config-impl/pom.xml index 4fd0d681a1..2787b30df4 100644 --- a/opendaylight/config/threadpool-config-impl/pom.xml +++ b/opendaylight/config/threadpool-config-impl/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent threadpool-config-impl diff --git a/opendaylight/config/yang-jmx-generator-it/pom.xml b/opendaylight/config/yang-jmx-generator-it/pom.xml index f9e0c7036a..6d2663ced5 100644 --- a/opendaylight/config/yang-jmx-generator-it/pom.xml +++ b/opendaylight/config/yang-jmx-generator-it/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT yang-jmx-generator-it diff --git a/opendaylight/config/yang-jmx-generator-plugin/pom.xml b/opendaylight/config/yang-jmx-generator-plugin/pom.xml index 5f51980b94..6c8a591bb8 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/pom.xml +++ b/opendaylight/config/yang-jmx-generator-plugin/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT .. yang-jmx-generator-plugin diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/CodeWriter.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/CodeWriter.java index dd2b504da9..cd0f491ebc 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/CodeWriter.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/CodeWriter.java @@ -41,18 +41,18 @@ import java.util.Map.Entry; final class CodeWriter { - private static final Logger logger = LoggerFactory.getLogger(CodeWriter.class); - private static final Optional copyright = StringUtil.loadCopyright(); + private static final Logger LOGGER = LoggerFactory.getLogger(CodeWriter.class); + private static final Optional COPYRIGHT = StringUtil.loadCopyright(); public File writeSie(ServiceInterfaceEntry sie, File outputBaseDir) { try { GeneralInterfaceTemplate generalInterfaceTemplate = TemplateFactory.serviceInterfaceFromSie(sie); - GeneratedObject go = new GenericGeneratedObjectFactory().toGeneratedObject(generalInterfaceTemplate, copyright); + GeneratedObject go = new GenericGeneratedObjectFactory().toGeneratedObject(generalInterfaceTemplate, COPYRIGHT); return go.persist(outputBaseDir).get().getValue(); } catch (Exception e) { String message = "An error occurred during Service interface generating, sie:" + sie.getTypeName() + ", " + sie.getFullyQualifiedName(); - logger.error(message, e); + LOGGER.error(message, e); throw new RuntimeException(message, e); } } @@ -70,33 +70,33 @@ final class CodeWriter { // TOs Map tosFromMbe = TemplateFactory.tOsFromMbe(mbe); for(GeneralClassTemplate template: tosFromMbe.values()) { - gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(template, copyright), true); + gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(template, COPYRIGHT), true); } // MXBean interface GeneralInterfaceTemplate ifcTemplate = TemplateFactory.mXBeanInterfaceTemplateFromMbe(mbe); - gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(ifcTemplate, copyright), true); + gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(ifcTemplate, COPYRIGHT), true); // generate abstract factory - gos.put(new AbsFactoryGeneratedObjectFactory().toGeneratedObject(mbe, copyright), true); + gos.put(new AbsFactoryGeneratedObjectFactory().toGeneratedObject(mbe, COPYRIGHT), true); // generate abstract module - gos.put(new AbsModuleGeneratedObjectFactory().toGeneratedObject(mbe, copyright), true); + gos.put(new AbsModuleGeneratedObjectFactory().toGeneratedObject(mbe, COPYRIGHT), true); // generate concrete factory StubFactoryTemplate concreteFactory = TemplateFactory.stubFactoryTemplateFromMbe(mbe); - gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(concreteFactory, copyright), false); + gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(concreteFactory, COPYRIGHT), false); // generate concrete module - gos.put(new ConcreteModuleGeneratedObjectFactory().toGeneratedObject(mbe, copyright, Optional.absent()), false); + gos.put(new ConcreteModuleGeneratedObjectFactory().toGeneratedObject(mbe, COPYRIGHT, Optional.absent()), false); // write runtime bean MXBeans and registrators List allFtlFiles = getRuntimeBeanFtlTemplates(mbe.getRuntimeBeans()); for(FtlTemplate template: allFtlFiles) { - gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(template, copyright), true); + gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(template, COPYRIGHT), true); } generatedFiles.addAll(persistGeneratedObjects(targetBaseDir, mainBaseDir, gos)); @@ -113,7 +113,7 @@ final class CodeWriter { } catch (Exception e) { String message = "An error occurred during Module generating, mbe:" + mbe.getJavaNamePrefix(); - logger.error(message, e); + LOGGER.error(message, e); throw new RuntimeException(message, e); } } diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGenerator.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGenerator.java index 1b8905b987..c8356274f8 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGenerator.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGenerator.java @@ -54,7 +54,7 @@ public class JMXGenerator implements CodeGenerator { private PackageTranslator packageTranslator; private final CodeWriter codeWriter; - private static final Logger logger = LoggerFactory + private static final Logger LOGGER = LoggerFactory .getLogger(JMXGenerator.class); private Map namespaceToPackageMapping; private File resourceBaseDir; @@ -83,8 +83,9 @@ public class JMXGenerator implements CodeGenerator { packageTranslator = new PackageTranslator(namespaceToPackageMapping); - if (!outputBaseDir.exists()) + if (!outputBaseDir.exists()) { outputBaseDir.mkdirs(); + } GeneratedFilesTracker generatedFiles = new GeneratedFilesTracker(); // create SIE structure qNamesToSIEs @@ -127,7 +128,7 @@ public class JMXGenerator implements CodeGenerator { Preconditions.checkNotNull(resourceBaseDir, "resource base dir attribute was null"); - StringBuffer fullyQualifiedNamesOfFactories = new StringBuffer(); + StringBuilder fullyQualifiedNamesOfFactories = new StringBuilder(); // create MBEs for (Module module : yangModulesInCurrentMavenModule) { String packageName = packageTranslator.getPackageName(module); @@ -166,7 +167,7 @@ public class JMXGenerator implements CodeGenerator { fullyQualifiedNamesOfFactories.toString()); } catch (IOException e) { String message = "Cannot write to " + serviceLoaderFile; - logger.error(message); + LOGGER.error(message); throw new RuntimeException(message, e); } } @@ -184,10 +185,11 @@ public class JMXGenerator implements CodeGenerator { @Override public void setAdditionalConfig(Map additionalCfg) { - if (logger != null) - logger.debug(getClass().getCanonicalName(), + if (LOGGER != null) { + LOGGER.debug(getClass().getCanonicalName(), ": Additional configuration received: ", additionalCfg.toString()); + } this.namespaceToPackageMapping = extractNamespaceMapping(additionalCfg); this.generateModuleFactoryFile = extractModuleFactoryBoolean(additionalCfg); } @@ -195,10 +197,12 @@ public class JMXGenerator implements CodeGenerator { private boolean extractModuleFactoryBoolean( Map additionalCfg) { String bool = additionalCfg.get(MODULE_FACTORY_FILE_BOOLEAN); - if (bool == null) + if (bool == null) { return true; - if (bool.equals("false")) + } + if ("false".equals(bool)) { return false; + } return true; } @@ -250,8 +254,8 @@ public class JMXGenerator implements CodeGenerator { public void setMavenProject(MavenProject project) { this.projectBaseDir = project.getBasedir(); - if (logger != null) - logger.debug(getClass().getCanonicalName(), " project base dir: ", + if (LOGGER != null) + LOGGER.debug(getClass().getCanonicalName(), " project base dir: ", projectBaseDir); } @@ -268,7 +272,7 @@ public class JMXGenerator implements CodeGenerator { } } if (undeletedFiles.isEmpty() == false) { - logger.error( + LOGGER.error( "Illegal state occurred: Unable to delete already generated files, undeleted files: {}", undeletedFiles); } diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java index c3e51d6550..c3a00b93da 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java @@ -19,14 +19,14 @@ import java.util.List; public class AbstractFactoryTemplate extends GeneralClassTemplate { - private static final List implementedIfcs = Lists + private static final List IMPLEMENTED_IFCS = Lists .newArrayList(ModuleFactory.class.getCanonicalName()); public AbstractFactoryTemplate(Header header, String packageName, String abstractFactoryName, List fields) { super(header, packageName, abstractFactoryName, Collections - . emptyList(), implementedIfcs, fields, Collections + . emptyList(), IMPLEMENTED_IFCS, fields, Collections . emptyList(), true, false, Collections . emptyList()); } diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/RuntimeRegistratorFtlTemplate.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/RuntimeRegistratorFtlTemplate.java index d07edae14e..aa696450a9 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/RuntimeRegistratorFtlTemplate.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/RuntimeRegistratorFtlTemplate.java @@ -108,7 +108,7 @@ public class RuntimeRegistratorFtlTemplate extends GeneralClassTemplate { .getFullyQualifiedName(rootRB.getPackageName(), rootRB.getJavaNameOfRuntimeMXBean()); String childRegistratorFQN = rootFtlFile.getFullyQualifiedName(); Field rbParameter = new Field(fullyQualifiedNameOfMXBean, "rb"); - StringBuffer registerBody = new StringBuffer(); + StringBuilder registerBody = new StringBuilder(); registerBody.append(format("%s %s = this.%s.registerRoot(%s);\n", HierarchicalRuntimeBeanRegistration.class .getCanonicalName(), hierachchicalRegistration @@ -200,12 +200,12 @@ public class RuntimeRegistratorFtlTemplate extends GeneralClassTemplate { unorderedResult.put(entry.getKey(), entry.getValue()); } - if (childRegistratorMap.size() > 0) { + if (!childRegistratorMap.isEmpty()) { // first entry is the direct descendant according to the create // contract RuntimeRegistratorFtlTemplate childRegistrator = childRegistratorMap .values().iterator().next(); - StringBuffer body = new StringBuffer(); + StringBuilder body = new StringBuilder(); String key, value; key = child.getJavaNamePrefix(); body.append(format( diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java index 7b7aab8559..f8f5cd6742 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java @@ -113,7 +113,7 @@ public class TemplateFactory { static String serializeType(Type type, boolean addWildcards) { if (type instanceof ParameterizedType){ ParameterizedType parameterizedType = (ParameterizedType) type; - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(parameterizedType.getRawType().getFullyQualifiedName()); sb.append(addWildcards ? " org.opendaylight.controller config-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../ diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ConfigConstants.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ConfigConstants.java index 775fa9fc20..8cc0ffa165 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ConfigConstants.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ConfigConstants.java @@ -11,6 +11,9 @@ import org.opendaylight.yangtools.yang.common.QName; public class ConfigConstants { + private ConfigConstants() { + } + public static final String CONFIG_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:config"; public static final String CONFIG_MODULE = "config"; diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java index e9f0ac8176..f99d378b6f 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java @@ -93,22 +93,22 @@ final class ModuleMXBeanEntryBuilder { return this; } - private static final Logger logger = LoggerFactory + private static final Logger LOGGER = LoggerFactory .getLogger(ModuleMXBeanEntryBuilder.class); // TODO: the XPath should be parsed by code generator IMO private static final String MAGIC_STRING = "MAGIC_STRING"; private static final String MODULE_CONDITION_XPATH_TEMPLATE = "^/MAGIC_STRING:modules/MAGIC_STRING:module/MAGIC_STRING:type\\s*=\\s*['\"](.+)['\"]$"; - private static final SchemaPath expectedConfigurationAugmentationSchemaPath = SchemaPath.create(true, + private static final SchemaPath EXPECTED_CONFIGURATION_AUGMENTATION_SCHEMA_PATH = SchemaPath.create(true, createConfigQName("modules"), createConfigQName("module"), createConfigQName("configuration")); - private static final SchemaPath expectedStateAugmentationSchemaPath = SchemaPath.create(true, + private static final SchemaPath EXPECTED_STATE_AUGMENTATION_SCHEMA_PATH = SchemaPath.create(true, createConfigQName("modules"), createConfigQName("module"), createConfigQName("state")); private static final Pattern PREFIX_COLON_LOCAL_NAME = Pattern .compile("^(.+):(.+)$"); public Map build() { - logger.debug("Generating ModuleMXBeans of {} to package {}", + LOGGER.debug("Generating ModuleMXBeans of {} to package {}", currentModule.getNamespace(), packageName); String configModulePrefix; @@ -146,7 +146,7 @@ final class ModuleMXBeanEntryBuilder { checkAttributeNamesUniqueness(uniqueGeneratedClassesNames, result); checkUnaugumentedIdentities(unaugmentedModuleIdentities); - logger.debug("Number of ModuleMXBeans to be generated: {}", result.size()); + LOGGER.debug("Number of ModuleMXBeans to be generated: {}", result.size()); return result; } @@ -166,7 +166,7 @@ final class ModuleMXBeanEntryBuilder { private static void checkUnaugumentedIdentities(final Map unaugmentedModuleIdentities) { if (unaugmentedModuleIdentities.size() > 0) { - logger.warn("Augmentation not found for all currentModule identities: {}", + LOGGER.warn("Augmentation not found for all currentModule identities: {}", unaugmentedModuleIdentities.keySet()); } } @@ -190,7 +190,7 @@ final class ModuleMXBeanEntryBuilder { + identityLocalName); } else { moduleIdentities.put(identityLocalName, id); - logger.debug("Found identity {}", identityLocalName); + LOGGER.debug("Found identity {}", identityLocalName); } // validation check on unknown schema nodes boolean providedServiceWasSet = false; @@ -270,13 +270,13 @@ final class ModuleMXBeanEntryBuilder { HAS_CHILDREN_AND_QNAME dataNodeContainer = getDataNodeContainer(choiceCaseNode); - if (expectedConfigurationAugmentationSchemaPath.equals(augmentation.getTargetPath())) { - logger.debug("Parsing configuration of {}", moduleLocalNameFromXPath); + if (EXPECTED_CONFIGURATION_AUGMENTATION_SCHEMA_PATH.equals(augmentation.getTargetPath())) { + LOGGER.debug("Parsing configuration of {}", moduleLocalNameFromXPath); yangToAttributes = fillConfiguration(dataNodeContainer, currentModule, typeProviderWrapper, qNamesToSIEs, schemaContext, packageName); checkUniqueAttributesWithGeneratedClass(uniqueGeneratedClassesNames, when.getQName(), yangToAttributes); - } else if (expectedStateAugmentationSchemaPath.equals(augmentation.getTargetPath())) { - logger.debug("Parsing state of {}", moduleLocalNameFromXPath); + } else if (EXPECTED_STATE_AUGMENTATION_SCHEMA_PATH.equals(augmentation.getTargetPath())) { + LOGGER.debug("Parsing state of {}", moduleLocalNameFromXPath); try { runtimeBeans = fillRuntimeBeans(dataNodeContainer, currentModule, typeProviderWrapper, packageName, moduleLocalNameFromXPath, javaNamePrefix); diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java index ccd701d1fb..10267b28e7 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java @@ -12,6 +12,9 @@ import org.opendaylight.yangtools.yang.model.api.Module; public class ModuleUtil { + private ModuleUtil() { + } + public static QName getQName(final Module currentModule) { return QName.create(currentModule.getNamespace(), currentModule.getRevision(), currentModule.getName()); } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/PackageTranslator.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/PackageTranslator.java index a6a1ac7dc3..a7f6f2f221 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/PackageTranslator.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/PackageTranslator.java @@ -58,19 +58,20 @@ public class PackageTranslator { // TODO add to PackageTranslator private static String sanitizePackage(String namespace) { - namespace = namespace.replace("://", "."); - namespace = namespace.replace("/", "."); - namespace = namespace.replace(":", "."); - namespace = namespace.replace("-", "_"); - namespace = namespace.replace("@", "."); - namespace = namespace.replace("$", "."); - namespace = namespace.replace("#", "."); - namespace = namespace.replace("'", "."); - namespace = namespace.replace("*", "."); - namespace = namespace.replace("+", "."); - namespace = namespace.replace(",", "."); - namespace = namespace.replace(";", "."); - namespace = namespace.replace("=", "."); - return namespace; + String newNamespace = namespace; + newNamespace = newNamespace.replace("://", "."); + newNamespace = newNamespace.replace("/", "."); + newNamespace = newNamespace.replace(":", "."); + newNamespace = newNamespace.replace("-", "_"); + newNamespace = newNamespace.replace("@", "."); + newNamespace = newNamespace.replace("$", "."); + newNamespace = newNamespace.replace("#", "."); + newNamespace = newNamespace.replace("'", "."); + newNamespace = newNamespace.replace("*", "."); + newNamespace = newNamespace.replace("+", "."); + newNamespace = newNamespace.replace(",", "."); + newNamespace = newNamespace.replace(";", "."); + newNamespace = newNamespace.replace("=", "."); + return newNamespace; } } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java index 67f624175b..aec41152de 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java @@ -217,8 +217,6 @@ public class RuntimeBeanEntry { final Map> identitiesToRpcs) { List attributes = Lists.newArrayList(); - // List javaAttributes = new ArrayList<>(); - // List toAttributes = new ArrayList<>(); List runtimeBeanEntries = new ArrayList<>(); for (DataSchemaNode child : subtree.getChildNodes()) { // child leaves can be java attributes, TO attributes, or child @@ -278,7 +276,7 @@ public class RuntimeBeanEntry { .findJavaParameter(rpcDefinition); AttributeIfc returnType; if (rpcDefinition.getOutput() == null - || rpcDefinition.getOutput().getChildNodes().size() == 0) { + || rpcDefinition.getOutput().getChildNodes().isEmpty()) { returnType = VoidAttribute.getInstance(); } else if (rpcDefinition.getOutput().getChildNodes().size() == 1) { DataSchemaNode returnDSN = rpcDefinition.getOutput() @@ -366,7 +364,7 @@ public class RuntimeBeanEntry { currentModule, identitiesToRpcs); Optional keyYangName; - if (listSchemaNode.getKeyDefinition().size() == 0) { + if (listSchemaNode.getKeyDefinition().isEmpty()) { keyYangName = Optional.absent(); } else if (listSchemaNode.getKeyDefinition().size() == 1) { // key must be either null or one of supported key types diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java index ef40d9515b..ee02b303e0 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java @@ -46,7 +46,7 @@ import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstant *

*/ public class ServiceInterfaceEntry extends AbstractEntry { - private static final Logger logger = LoggerFactory + private static final Logger LOGGER = LoggerFactory .getLogger(ServiceInterfaceEntry.class); private static final String CLASS_NAME_SUFFIX = "ServiceInterface"; @@ -121,16 +121,16 @@ public class ServiceInterfaceEntry extends AbstractEntry { */ public static Map create(Module currentModule, String packageName,Map definedSEItracker) { - logger.debug("Generating ServiceInterfaces from {} to package {}", + LOGGER.debug("Generating ServiceInterfaces from {} to package {}", currentModule.getNamespace(), packageName); Map identitiesToSIs = new HashMap<>(); Set notVisited = new HashSet<>( currentModule.getIdentities()); int lastSize = notVisited.size() + 1; - while (notVisited.size() > 0) { + while (!notVisited.isEmpty()) { if (notVisited.size() == lastSize) { - logger.debug( + LOGGER.debug( "Following identities will be ignored while generating ServiceInterfaces, as they are not derived from {} : {}", SERVICE_TYPE_Q_NAME, notVisited); break; @@ -175,7 +175,7 @@ public class ServiceInterfaceEntry extends AbstractEntry { for (ServiceInterfaceEntry sie : identitiesToSIs.values()) { resultMap.put(sie.getQName(), sie); } - logger.debug("Number of ServiceInterfaces to be generated: {}", + LOGGER.debug("Number of ServiceInterfaces to be generated: {}", resultMap.size()); return resultMap; } @@ -198,25 +198,33 @@ public class ServiceInterfaceEntry extends AbstractEntry { @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (o == null || getClass() != o.getClass()) + } + if (o == null || getClass() != o.getClass()) { return false; + } ServiceInterfaceEntry that = (ServiceInterfaceEntry) o; - if (!maybeBaseCache.equals(that.maybeBaseCache)) + if (!maybeBaseCache.equals(that.maybeBaseCache)) { return false; - if (!nullableDescription.equals(that.nullableDescription)) + } + if (!nullableDescription.equals(that.nullableDescription)) { return false; - if (!exportedOsgiClassName.equals(that.exportedOsgiClassName)) + } + if (!exportedOsgiClassName.equals(that.exportedOsgiClassName)) { return false; - if (!qName.equals(that.qName)) + } + if (!qName.equals(that.qName)) { return false; - if (!packageName.equals(that.packageName)) + } + if (!packageName.equals(that.packageName)) { return false; - if (!typeName.equals(that.typeName)) + } + if (!typeName.equals(that.typeName)) { return false; + } return true; } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java index 3c8c8aa2f4..ac1992932f 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java @@ -71,9 +71,10 @@ public class TypeProviderWrapper { try { javaType = typeProvider.javaTypeForSchemaDefinitionType( type, leaf); - if (javaType == null) + if (javaType == null) { throw new IllegalArgumentException("Unknown type received for " + leaf.toString()); + } } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Error while resolving type of " + leaf, e); @@ -87,9 +88,10 @@ public class TypeProviderWrapper { try { javaType = typeProvider.javaTypeForSchemaDefinitionType( leaf.getType(), leaf); - if (javaType == null) + if (javaType == null) { throw new IllegalArgumentException( "Unknown type received for " + leaf.toString()); + } } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Error while resolving type of " + leaf, e); diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractAttribute.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractAttribute.java index edfb4c59af..d9a6dd0452 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractAttribute.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractAttribute.java @@ -33,17 +33,20 @@ public abstract class AbstractAttribute implements AttributeIfc { @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (!(o instanceof AbstractAttribute)) + } + if (!(o instanceof AbstractAttribute)) { return false; + } AbstractAttribute that = (AbstractAttribute) o; if (attributeYangName != null ? !attributeYangName .equals(that.attributeYangName) - : that.attributeYangName != null) + : that.attributeYangName != null) { return false; + } return true; } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractDependencyAttribute.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractDependencyAttribute.java index eb1c9e41a6..205ba893c4 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractDependencyAttribute.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractDependencyAttribute.java @@ -40,25 +40,31 @@ public abstract class AbstractDependencyAttribute extends AbstractAttribute imp @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (o == null || getClass() != o.getClass()) + } + if (o == null || getClass() != o.getClass()) { return false; - if (!super.equals(o)) + } + if (!super.equals(o)) { return false; + } AbstractDependencyAttribute that = (AbstractDependencyAttribute) o; if (dependency != null ? !dependency.equals(that.dependency) - : that.dependency != null) + : that.dependency != null) { return false; + } if (nullableDefault != null ? !nullableDefault - .equals(that.nullableDefault) : that.nullableDefault != null) + .equals(that.nullableDefault) : that.nullableDefault != null) { return false; + } if (nullableDescription != null ? !nullableDescription .equals(that.nullableDescription) - : that.nullableDescription != null) + : that.nullableDescription != null) { return false; + } return true; } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java index fac4d57432..8d3139999e 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java @@ -96,24 +96,30 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute { @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (o == null || getClass() != o.getClass()) + } + if (o == null || getClass() != o.getClass()) { return false; - if (!super.equals(o)) + } + if (!super.equals(o)) { return false; + } JavaAttribute that = (JavaAttribute) o; if (nullableDefault != null ? !nullableDefault - .equals(that.nullableDefault) : that.nullableDefault != null) + .equals(that.nullableDefault) : that.nullableDefault != null) { return false; + } if (nullableDescription != null ? !nullableDescription .equals(that.nullableDescription) - : that.nullableDescription != null) + : that.nullableDescription != null) { return false; - if (type != null ? !type.equals(that.type) : that.type != null) + } + if (type != null ? !type.equals(that.type) : that.type != null) { return false; + } return true; } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListAttribute.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListAttribute.java index 73b557e291..bb71f9dbc7 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListAttribute.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListAttribute.java @@ -82,22 +82,27 @@ public class ListAttribute extends AbstractAttribute implements TypedAttribute { @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (o == null || getClass() != o.getClass()) + } + if (o == null || getClass() != o.getClass()) { return false; - if (!super.equals(o)) + } + if (!super.equals(o)) { return false; + } ListAttribute that = (ListAttribute) o; if (nullableDefault != null ? !nullableDefault - .equals(that.nullableDefault) : that.nullableDefault != null) + .equals(that.nullableDefault) : that.nullableDefault != null) { return false; + } if (nullableDescription != null ? !nullableDescription .equals(that.nullableDescription) - : that.nullableDescription != null) + : that.nullableDescription != null) { return false; + } return true; } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java index f4bd979fac..9b5530175c 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java @@ -19,6 +19,9 @@ import java.util.Map; public class SimpleTypeResolver { + private SimpleTypeResolver() { + } + public static SimpleType getSimpleType(Type type) { SimpleType expectedSimpleType = JAVA_TYPE_TO_SIMPLE_TYPE.get(type .getFullyQualifiedName()); diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java index cbeb5c3b29..e563da1328 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java @@ -73,18 +73,19 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute { TypeProviderWrapper typeProviderWrapper, String packageName) { Class type = isAllowedType(dataSchemaNode); - if (type.equals(LeafSchemaNode.class)) + if (type.equals(LeafSchemaNode.class)) { return new JavaAttribute((LeafSchemaNode) dataSchemaNode, typeProviderWrapper); - else if (type.equals(ListSchemaNode.class)) + } else if (type.equals(ListSchemaNode.class)) { return ListAttribute.create((ListSchemaNode) dataSchemaNode, typeProviderWrapper, packageName); - else if (type.equals(LeafListSchemaNode.class)) + } else if (type.equals(LeafListSchemaNode.class)) { return ListAttribute.create((LeafListSchemaNode) dataSchemaNode, typeProviderWrapper); - else if (type.equals(ContainerSchemaNode.class)) + } else if (type.equals(ContainerSchemaNode.class)) { return TOAttribute.create((ContainerSchemaNode) dataSchemaNode, typeProviderWrapper, packageName); + } throw new IllegalStateException("This should never happen"); } @@ -92,8 +93,9 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute { private static Class isAllowedType( DataSchemaNode dataSchemaNode) { for (Class allowedType : ALLOWED_CHILDREN) { - if (allowedType.isAssignableFrom(dataSchemaNode.getClass()) == true) + if (allowedType.isAssignableFrom(dataSchemaNode.getClass()) == true) { return allowedType; + } } throw new IllegalArgumentException("Illegal child node for TO: " + dataSchemaNode.getClass() + " allowed node types: " @@ -156,26 +158,32 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute { @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (o == null || getClass() != o.getClass()) + } + if (o == null || getClass() != o.getClass()) { return false; - if (!super.equals(o)) + } + if (!super.equals(o)) { return false; + } TOAttribute that = (TOAttribute) o; if (nullableDefault != null ? !nullableDefault - .equals(that.nullableDefault) : that.nullableDefault != null) + .equals(that.nullableDefault) : that.nullableDefault != null) { return false; + } if (nullableDescription != null ? !nullableDescription .equals(that.nullableDescription) - : that.nullableDescription != null) + : that.nullableDescription != null) { return false; + } if (yangNameToAttributeMap != null ? !yangNameToAttributeMap .equals(that.yangNameToAttributeMap) - : that.yangNameToAttributeMap != null) + : that.yangNameToAttributeMap != null) { return false; + } return true; } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/Util.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/Util.java index 30c7919c1a..16c4bd1ec5 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/Util.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/Util.java @@ -13,17 +13,19 @@ import java.util.Date; final class Util { + private Util() { + } /** * Used for date <-> xml serialization */ - private static final SimpleDateFormat dateFormat = new SimpleDateFormat( + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat( "yyyy-MM-dd"); public static String writeDate(Date date) { - return dateFormat.format(date); + return DATE_FORMAT.format(date); } public static Date readDate(String s) throws ParseException { - return dateFormat.parse(s); + return DATE_FORMAT.parse(s); } } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/util/FullyQualifiedNameHelper.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/util/FullyQualifiedNameHelper.java index 50b4485e01..966aff96a0 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/util/FullyQualifiedNameHelper.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/util/FullyQualifiedNameHelper.java @@ -8,6 +8,10 @@ package org.opendaylight.controller.config.yangjmxgenerator.plugin.util; public class FullyQualifiedNameHelper { + + private FullyQualifiedNameHelper() { + } + public static String getFullyQualifiedName(String packageName, String className) { if (packageName.isEmpty()) diff --git a/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryNameConflictTest.java b/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryNameConflictTest.java index 9032a2c930..cac0ac705f 100644 --- a/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryNameConflictTest.java +++ b/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryNameConflictTest.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException; import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.YangModelSearchUtils; @@ -40,6 +41,7 @@ public class ModuleMXBeanEntryNameConflictTest extends AbstractYangTest { Map testedFilesToYangModules = new HashMap<>(); Map testedYangModulesToExpectedConflictingName = new HashMap<>(); + @Ignore @Test public void testNameConflicts() throws Exception { prepareSamples(); diff --git a/opendaylight/config/yang-jmx-generator/src/test/resources/config-jmx-it-impl.yang b/opendaylight/config/yang-jmx-generator/src/test/resources/config-jmx-it-impl.yang index 16085efbba..0cd0d15ad2 100644 --- a/opendaylight/config/yang-jmx-generator/src/test/resources/config-jmx-it-impl.yang +++ b/opendaylight/config/yang-jmx-generator/src/test/resources/config-jmx-it-impl.yang @@ -49,7 +49,7 @@ module config-jmx-it-impl { } - leaf simpleInt { + leaf simpleInt1 { type uint32; default 99L; } @@ -87,7 +87,7 @@ module config-jmx-it-impl { } } - leaf simpleInt { + leaf simpleInt2 { type uint32; } @@ -202,7 +202,7 @@ module config-jmx-it-impl { case impl-netconf { when "/config:modules/config:module/config:type = 'impl-netconf'"; // root runtime bean - leaf created-sessions { + leaf created-sessions-1 { type uint32; } diff --git a/opendaylight/config/yang-jmx-generator/src/test/resources/duplicates/config-test-duplicate-attribute-in-list.yang b/opendaylight/config/yang-jmx-generator/src/test/resources/duplicates/config-test-duplicate-attribute-in-list.yang index 4901b41157..97fca03877 100644 --- a/opendaylight/config/yang-jmx-generator/src/test/resources/duplicates/config-test-duplicate-attribute-in-list.yang +++ b/opendaylight/config/yang-jmx-generator/src/test/resources/duplicates/config-test-duplicate-attribute-in-list.yang @@ -75,7 +75,7 @@ module config-test-duplicate-attribute-in-list { case netconf { when "/config:modules/config:module/config:type = 'netconf'"; // root runtime bean - leaf created-sessions { + leaf created-sessions2 { type uint32; } diff --git a/opendaylight/config/yang-jmx-generator/src/test/resources/duplicates/config-test-duplicate-attribute.yang b/opendaylight/config/yang-jmx-generator/src/test/resources/duplicates/config-test-duplicate-attribute.yang index bf081028cc..d2d4dc534d 100644 --- a/opendaylight/config/yang-jmx-generator/src/test/resources/duplicates/config-test-duplicate-attribute.yang +++ b/opendaylight/config/yang-jmx-generator/src/test/resources/duplicates/config-test-duplicate-attribute.yang @@ -56,7 +56,7 @@ module config-test-duplicate-attribute { case netconf { when "/config:modules/config:module/config:type = 'netconf'"; - container dto-a { + container dto-a2 { leaf simple-arg { type uint32; } @@ -72,7 +72,7 @@ module config-test-duplicate-attribute { case netconf { when "/config:modules/config:module/config:type = 'netconf'"; // root runtime bean - leaf created-sessions { + leaf created-sessions2 { type uint32; } diff --git a/opendaylight/config/yang-jmx-generator/src/test/resources/test-config-files.yang b/opendaylight/config/yang-jmx-generator/src/test/resources/test-config-files.yang index 1db0279506..f6a0b888bd 100644 --- a/opendaylight/config/yang-jmx-generator/src/test/resources/test-config-files.yang +++ b/opendaylight/config/yang-jmx-generator/src/test/resources/test-config-files.yang @@ -62,7 +62,7 @@ module test-config-files { case netconf { when "/config:modules/config:module/config:type = 'netconf'"; // root runtime bean - leaf created-sessions { + leaf created-sessions2 { type uint32; } diff --git a/opendaylight/config/yang-jmx-generator/src/test/resources/test-config-files1.yang b/opendaylight/config/yang-jmx-generator/src/test/resources/test-config-files1.yang index 0a152e7baa..fc0e0730df 100644 --- a/opendaylight/config/yang-jmx-generator/src/test/resources/test-config-files1.yang +++ b/opendaylight/config/yang-jmx-generator/src/test/resources/test-config-files1.yang @@ -62,7 +62,7 @@ module test-config-files1 { case netconf1 { when "/config:modules/config:module/config:type = 'netconf1'"; // root runtime bean - leaf created-sessions { + leaf created-sessions2 { type uint32; } diff --git a/opendaylight/config/yang-test-plugin/pom.xml b/opendaylight/config/yang-test-plugin/pom.xml index c7fb73f385..d03cff305b 100644 --- a/opendaylight/config/yang-test-plugin/pom.xml +++ b/opendaylight/config/yang-test-plugin/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent yang-test-plugin diff --git a/opendaylight/config/yang-test/pom.xml b/opendaylight/config/yang-test/pom.xml index 247b3c0745..5977325574 100644 --- a/opendaylight/config/yang-test/pom.xml +++ b/opendaylight/config/yang-test/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../config-plugin-parent diff --git a/opendaylight/configuration/api/pom.xml b/opendaylight/configuration/api/pom.xml index ef27bfd5e4..50f19278c6 100644 --- a/opendaylight/configuration/api/pom.xml +++ b/opendaylight/configuration/api/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight configuration - 0.4.3-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/configuration/implementation/pom.xml b/opendaylight/configuration/implementation/pom.xml index a4a7ba6746..4387de70ea 100644 --- a/opendaylight/configuration/implementation/pom.xml +++ b/opendaylight/configuration/implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight configuration.implementation - 0.4.3-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/configuration/integrationtest/pom.xml b/opendaylight/configuration/integrationtest/pom.xml index 31b9c07674..238ff12249 100644 --- a/opendaylight/configuration/integrationtest/pom.xml +++ b/opendaylight/configuration/integrationtest/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.integrationtest - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT ../../commons/integrationtest configuration.integrationtest - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT ch.qos.logback diff --git a/opendaylight/connectionmanager/api/pom.xml b/opendaylight/connectionmanager/api/pom.xml index c4ced042d0..2718ed1afe 100644 --- a/opendaylight/connectionmanager/api/pom.xml +++ b/opendaylight/connectionmanager/api/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight connectionmanager - 0.1.2-SNAPSHOT + 0.2.0-SNAPSHOT bundle diff --git a/opendaylight/connectionmanager/implementation/pom.xml b/opendaylight/connectionmanager/implementation/pom.xml index 8be119d507..fe2514e58a 100644 --- a/opendaylight/connectionmanager/implementation/pom.xml +++ b/opendaylight/connectionmanager/implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight connectionmanager.implementation - 0.1.2-SNAPSHOT + 0.2.0-SNAPSHOT bundle diff --git a/opendaylight/containermanager/api/pom.xml b/opendaylight/containermanager/api/pom.xml index a19e27189a..c9b54a1b6c 100644 --- a/opendaylight/containermanager/api/pom.xml +++ b/opendaylight/containermanager/api/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight containermanager - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT bundle diff --git a/opendaylight/containermanager/implementation/pom.xml b/opendaylight/containermanager/implementation/pom.xml index 3ead8be65a..013cd62576 100644 --- a/opendaylight/containermanager/implementation/pom.xml +++ b/opendaylight/containermanager/implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight containermanager.implementation - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT bundle diff --git a/opendaylight/containermanager/it.implementation/pom.xml b/opendaylight/containermanager/it.implementation/pom.xml index a3f140d7e1..8e0475d4a3 100644 --- a/opendaylight/containermanager/it.implementation/pom.xml +++ b/opendaylight/containermanager/it.implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight containermanager.it.implementation - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT bundle diff --git a/opendaylight/containermanager/shell/pom.xml b/opendaylight/containermanager/shell/pom.xml index 1eedd4bc87..c1c2d2055b 100644 --- a/opendaylight/containermanager/shell/pom.xml +++ b/opendaylight/containermanager/shell/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight containermanager.shell diff --git a/opendaylight/distribution/opendaylight-karaf-empty/pom.xml b/opendaylight/distribution/opendaylight-karaf-empty/pom.xml index d3dfe19c2b..72eaf005ad 100644 --- a/opendaylight/distribution/opendaylight-karaf-empty/pom.xml +++ b/opendaylight/distribution/opendaylight-karaf-empty/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight opendaylight-karaf-empty diff --git a/opendaylight/distribution/opendaylight-karaf-resources/pom.xml b/opendaylight/distribution/opendaylight-karaf-resources/pom.xml index e34a5d3c2c..35aac09339 100644 --- a/opendaylight/distribution/opendaylight-karaf-resources/pom.xml +++ b/opendaylight/distribution/opendaylight-karaf-resources/pom.xml @@ -12,7 +12,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight opendaylight-karaf-resources diff --git a/opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/bin/setenv b/opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/bin/setenv index 4f240447b4..947c65f6bd 100755 --- a/opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/bin/setenv +++ b/opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/bin/setenv @@ -46,10 +46,10 @@ # export KARAF_ETC # Karaf etc folder # export KARAF_OPTS # Additional available Karaf options # export KARAF_DEBUG # Enable debug mode -if [ "x$JAVA_MAX_PERM_MEM" == "x" ]; then +if [ "x$JAVA_MAX_PERM_MEM" = "x" ]; then export JAVA_MAX_PERM_MEM="512m" fi -if [ "x$JAVA_MAX_MEM" == "x" ]; then +if [ "x$JAVA_MAX_MEM" = "x" ]; then export JAVA_MAX_MEM="2048m" fi diff --git a/opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/bin/setenv.bat b/opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/bin/setenv.bat new file mode 100644 index 0000000000..7c6192002c --- /dev/null +++ b/opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/bin/setenv.bat @@ -0,0 +1,64 @@ +@echo off +rem +rem +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed with +rem this work for additional information regarding copyright ownership. +rem The ASF licenses this file to You under the Apache License, Version 2.0 +rem (the "License"); you may not use this file except in compliance with +rem the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. +rem + +rem +rem handle specific scripts; the SCRIPT_NAME is exactly the name of the Karaf +rem script; for example karaf.bat, start.bat, stop.bat, admin.bat, client.bat, ... +rem +rem if "%KARAF_SCRIPT%" == "SCRIPT_NAME" ( +rem Actions go here... +rem ) + +rem +rem general settings which should be applied for all scripts go here; please keep +rem in mind that it is possible that scripts might be executed more than once, e.g. +rem in example of the start script where the start script is executed first and the +rem karaf script afterwards. +rem + +rem +rem The following section shows the possible configuration options for the default +rem karaf scripts +rem +rem Window name of the windows console +rem SET KARAF_TITLE +rem Location of Java installation +rem SET JAVA_HOME +rem Minimum memory for the JVM +rem SET JAVA_MIN_MEM +rem Maximum memory for the JVM +rem SET JAVA_MAX_MEM +rem Minimum perm memory for the JVM +rem SET JAVA_PERM_MEM +rem Maximum perm memory for the JVM +rem SET JAVA_MAX_PERM_MEM +rem Karaf home folder +rem SET KARAF_HOME +rem Karaf data folder +rem SET KARAF_DATA +rem Karaf base folder +rem SET KARAF_BASE +rem Karaf etc folder +rem SET KARAF_ETC +rem Additional available Karaf options +rem SET KARAF_OPTS +rem Enable debug mode +rem SET KARAF_DEBUG +IF "%JAVA_MAX_PERM_MEM%"=="" SET JAVA_MAX_PERM_MEM=512m +IF "%JAVA_MAX_MEM%"=="" SET JAVA_MAX_MEM=2048m diff --git a/opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/etc/custom.properties b/opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/etc/custom.properties index e0e2759b37..4a8f5ae795 100644 --- a/opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/etc/custom.properties +++ b/opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/etc/custom.properties @@ -94,6 +94,10 @@ ovsdb.listenPort=6640 # default Openflow version = 1.0, we also support 1.3. # ovsdb.of.version=1.3 +# ovsdb can be configured with ml2 to perform l3 forwarding. The config below enables that functionality, which is +# disabled by default. +# ovsdb.l3.fwd.enabled=yes + # ovsdb can be configured with ml2 to perform l3 forwarding. When used in that scenario, the mac address of the default # gateway --on the external subnet-- is expected to be resolved from its inet address. The config below overrides that # specific arp/neighDiscovery lookup. @@ -127,3 +131,9 @@ java.util.logging.config.file=configuration/tomcat-logging.properties #Hosttracker hostsdb key scheme setting hosttracker.keyscheme=IP +# LISP Flow Mapping configuration +# Map-Register messages overwrite existing RLOC sets in EID-to-RLOC mappings +lisp.mappingOverwrite = true +# Enable the Solicit-Map-Request (SMR) mechanism +lisp.smr = false + diff --git a/opendaylight/distribution/opendaylight-karaf/pom.xml b/opendaylight/distribution/opendaylight-karaf/pom.xml index 795f68c397..3a2f4b0580 100644 --- a/opendaylight/distribution/opendaylight-karaf/pom.xml +++ b/opendaylight/distribution/opendaylight-karaf/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight distribution.opendaylight-karaf @@ -58,18 +58,21 @@ features-base features xml + runtime org.opendaylight.controller features-adsal features xml + runtime org.opendaylight.controller features-nsf features xml + runtime @@ -77,13 +80,31 @@ features-mdsal features xml + runtime org.opendaylight.controller features-flow features xml + runtime + + org.opendaylight.controller + features-restconf + 1.2.0-SNAPSHOT + features + xml + runtime + + + + org.opendaylight.controller + features-netconf-connector + features + xml + + diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index fcb452f422..4f0df441fa 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight distribution.opendaylight - 0.1.2-SNAPSHOT + 0.2.0-SNAPSHOT pom 3.0 @@ -1020,7 +1020,7 @@ org.opendaylight.controller sal-inmemory-datastore - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT org.opendaylight.controller @@ -1133,7 +1133,7 @@ org.opendaylight.controller.model model-topology - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT @@ -1163,7 +1163,6 @@ org.opendaylight.yangtools binding-generator-api - ${yangtools.version} org.opendaylight.yangtools @@ -1184,7 +1183,6 @@ org.opendaylight.yangtools binding-model-api - ${yangtools.version} org.opendaylight.yangtools @@ -1316,6 +1314,41 @@ org.opendaylight.controller sal-clustering-config + + org.eclipse.jetty + jetty-servlets + 8.1.14.v20131031 + + + org.eclipse.jetty + jetty-client + 8.1.14.v20131031 + + + org.eclipse.jetty + jetty-continuation + 8.1.14.v20131031 + + + org.eclipse.jetty + jetty-util + 8.1.14.v20131031 + + + org.eclipse.jetty + jetty-server + 8.1.14.v20131031 + + + org.eclipse.jetty + jetty-io + 8.1.14.v20131031 + + + org.eclipse.jetty + jetty-http + 8.1.14.v20131031 + @@ -1412,7 +1445,7 @@ org.opendaylight.controller swagger-ui - 0.0.1-SNAPSHOT + 0.1.0-SNAPSHOT diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini index 530e46e14a..691d83d45e 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini @@ -116,6 +116,10 @@ ovsdb.listenPort=6640 # default Openflow version = 1.3, we also support 1.0. ovsdb.of.version=1.3 +# ovsdb can be configured with ml2 to perform l3 forwarding. The config below enables that functionality, which is +# disabled by default. +# ovsdb.l3.fwd.enabled=yes + # ovsdb can be configured with ml2 to perform l3 forwarding. When used in that scenario, the mac address of the default # gateway --on the external subnet-- is expected to be resolved from its inet address. The config below overrides that # specific arp/neighDiscovery lookup. diff --git a/opendaylight/distribution/p2site/pom.xml b/opendaylight/distribution/p2site/pom.xml index 78661d8df2..5a66a6191b 100644 --- a/opendaylight/distribution/p2site/pom.xml +++ b/opendaylight/distribution/p2site/pom.xml @@ -14,7 +14,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.0-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight @@ -32,7 +32,7 @@ org.opendaylight.controller distribution.p2site - 0.1.0-SNAPSHOT + 0.2.0-SNAPSHOT pom diff --git a/opendaylight/distribution/sanitytest/pom.xml b/opendaylight/distribution/sanitytest/pom.xml index 793e835647..9955afa274 100644 --- a/opendaylight/distribution/sanitytest/pom.xml +++ b/opendaylight/distribution/sanitytest/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight sanitytest - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/dummy-console/pom.xml b/opendaylight/dummy-console/pom.xml index 8901c2e0b5..4195e53310 100644 --- a/opendaylight/dummy-console/pom.xml +++ b/opendaylight/dummy-console/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../commons/opendaylight dummy-console - 1.1.0-SNAPSHOT + 1.2.0-SNAPSHOT bundle Dummy Console Interfaces for Equinox-specific CLI diff --git a/opendaylight/forwarding/staticrouting/pom.xml b/opendaylight/forwarding/staticrouting/pom.xml index 37c0a3a09d..b006cece40 100644 --- a/opendaylight/forwarding/staticrouting/pom.xml +++ b/opendaylight/forwarding/staticrouting/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight forwarding.staticrouting - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT bundle diff --git a/opendaylight/forwardingrulesmanager/api/pom.xml b/opendaylight/forwardingrulesmanager/api/pom.xml index b6e1dd68d1..3f667e16f0 100644 --- a/opendaylight/forwardingrulesmanager/api/pom.xml +++ b/opendaylight/forwardingrulesmanager/api/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight forwardingrulesmanager - 0.6.0-SNAPSHOT + 0.7.0-SNAPSHOT bundle diff --git a/opendaylight/forwardingrulesmanager/implementation/pom.xml b/opendaylight/forwardingrulesmanager/implementation/pom.xml index f87bed8780..959b71f855 100644 --- a/opendaylight/forwardingrulesmanager/implementation/pom.xml +++ b/opendaylight/forwardingrulesmanager/implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight forwardingrulesmanager.implementation - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/forwardingrulesmanager/integrationtest/pom.xml b/opendaylight/forwardingrulesmanager/integrationtest/pom.xml index ff0bfcc1ef..60b934a492 100644 --- a/opendaylight/forwardingrulesmanager/integrationtest/pom.xml +++ b/opendaylight/forwardingrulesmanager/integrationtest/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.integrationtest - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT ../../commons/integrationtest forwardingrulesmanager.integrationtest - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT ../implementation/target/jacoco-it.exec diff --git a/opendaylight/hosttracker/api/pom.xml b/opendaylight/hosttracker/api/pom.xml index b48d7abd72..10532baa6e 100644 --- a/opendaylight/hosttracker/api/pom.xml +++ b/opendaylight/hosttracker/api/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight hosttracker - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT bundle diff --git a/opendaylight/hosttracker/implementation/pom.xml b/opendaylight/hosttracker/implementation/pom.xml index cb09322b64..370f88defa 100644 --- a/opendaylight/hosttracker/implementation/pom.xml +++ b/opendaylight/hosttracker/implementation/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight hosttracker.implementation - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT bundle diff --git a/opendaylight/hosttracker/integrationtest/pom.xml b/opendaylight/hosttracker/integrationtest/pom.xml index 65fc23265a..dabccf3f71 100644 --- a/opendaylight/hosttracker/integrationtest/pom.xml +++ b/opendaylight/hosttracker/integrationtest/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.integrationtest - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT ../../commons/integrationtest hosttracker.integrationtest - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT ../implementaiton/target/jacoco-it.exec diff --git a/opendaylight/hosttracker/shell/pom.xml b/opendaylight/hosttracker/shell/pom.xml index 3f73303180..9088ae359b 100644 --- a/opendaylight/hosttracker/shell/pom.xml +++ b/opendaylight/hosttracker/shell/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight hosttracker.shell diff --git a/opendaylight/hosttracker_new/api/pom.xml b/opendaylight/hosttracker_new/api/pom.xml index 240976b9c8..db27345d18 100644 --- a/opendaylight/hosttracker_new/api/pom.xml +++ b/opendaylight/hosttracker_new/api/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight hosttracker_new - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/hosttracker_new/implementation/pom.xml b/opendaylight/hosttracker_new/implementation/pom.xml index 036dd5dd31..d3661a12c8 100644 --- a/opendaylight/hosttracker_new/implementation/pom.xml +++ b/opendaylight/hosttracker_new/implementation/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight hosttracker_new.implementation - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/karaf-branding/.gitignore b/opendaylight/karaf-branding/.gitignore new file mode 100644 index 0000000000..b83d22266a --- /dev/null +++ b/opendaylight/karaf-branding/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/opendaylight/karaf-branding/pom.xml b/opendaylight/karaf-branding/pom.xml index 727f224fa1..dfdc3b76cb 100644 --- a/opendaylight/karaf-branding/pom.xml +++ b/opendaylight/karaf-branding/pom.xml @@ -1,34 +1,37 @@ - 4.0.0 - + 4.0.0 + org.opendaylight.controller - karaf.branding - 1.0.0-SNAPSHOT - bundle - OpenDaylight :: Karaf :: Branding + releasepom + 0.2.0-SNAPSHOT + ../.. + + org.opendaylight.controller + karaf.branding + 1.1.0-SNAPSHOT + bundle + OpenDaylight :: Karaf :: Branding - - - - org.apache.felix - maven-bundle-plugin - 2.4.0 - true - - - ${project.artifactId} - * - !* - - org.apache.karaf.branding - - *;public-context:=false - - - - - + + + + org.apache.felix + maven-bundle-plugin + 2.4.0 + true + + + ${project.artifactId} + * + !* + org.apache.karaf.branding + *;public-context:=false + + + + + diff --git a/opendaylight/karaf-tomcat-security/pom.xml b/opendaylight/karaf-tomcat-security/pom.xml index 817e0faeec..30d57d048a 100644 --- a/opendaylight/karaf-tomcat-security/pom.xml +++ b/opendaylight/karaf-tomcat-security/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../commons/opendaylight karaf-tomcat-security - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/logging/bridge/pom.xml b/opendaylight/logging/bridge/pom.xml index 82bc6cd9c1..dc37e30179 100644 --- a/opendaylight/logging/bridge/pom.xml +++ b/opendaylight/logging/bridge/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight logging.bridge - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/md-sal/benchmark-data-store/pom.xml b/opendaylight/md-sal/benchmark-data-store/pom.xml index 1af2287a10..ac384319b8 100644 --- a/opendaylight/md-sal/benchmark-data-store/pom.xml +++ b/opendaylight/md-sal/benchmark-data-store/pom.xml @@ -12,7 +12,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html sal-parent org.opendaylight.controller - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT 4.0.0 diff --git a/opendaylight/md-sal/benchmark-data-store/src/main/java/org/opendaylight/controller/md/sal/dom/store/benchmark/InMemoryDataStoreWithExecutorServiceBenchmark.java b/opendaylight/md-sal/benchmark-data-store/src/main/java/org/opendaylight/controller/md/sal/dom/store/benchmark/InMemoryDataStoreWithExecutorServiceBenchmark.java index 4b9d66f4f2..77a4966ec3 100644 --- a/opendaylight/md-sal/benchmark-data-store/src/main/java/org/opendaylight/controller/md/sal/dom/store/benchmark/InMemoryDataStoreWithExecutorServiceBenchmark.java +++ b/opendaylight/md-sal/benchmark-data-store/src/main/java/org/opendaylight/controller/md/sal/dom/store/benchmark/InMemoryDataStoreWithExecutorServiceBenchmark.java @@ -7,19 +7,21 @@ */ package org.opendaylight.controller.md.sal.dom.store.benchmark; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; import org.opendaylight.yangtools.util.concurrent.SpecialExecutors; -import org.openjdk.jmh.annotations.Level; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.TearDown; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; /** * Benchmark for testing of performance of write operations for InMemoryDataStore. The instance @@ -41,14 +43,15 @@ public class InMemoryDataStoreWithExecutorServiceBenchmark extends AbstractInMem private static final int MAX_DATA_CHANGE_EXECUTOR_QUEUE_SIZE = 1000; private static final int MAX_DATA_STORE_EXECUTOR_QUEUE_SIZE = 5000; + @Override @Setup(Level.Trial) public void setUp() throws Exception { final String name = "DS_BENCHMARK"; final ExecutorService dataChangeListenerExecutor = SpecialExecutors.newBlockingBoundedFastThreadPool( MAX_DATA_CHANGE_EXECUTOR_POOL_SIZE, MAX_DATA_CHANGE_EXECUTOR_QUEUE_SIZE, name + "-DCL"); - final ExecutorService domStoreExecutor = SpecialExecutors.newBoundedSingleThreadExecutor( - MAX_DATA_STORE_EXECUTOR_QUEUE_SIZE, "DOMStore-" + name ); + final ListeningExecutorService domStoreExecutor = MoreExecutors.listeningDecorator(SpecialExecutors.newBoundedSingleThreadExecutor( + MAX_DATA_STORE_EXECUTOR_QUEUE_SIZE, "DOMStore-" + name )); domStore = new InMemoryDOMDataStore(name, domStoreExecutor, dataChangeListenerExecutor); @@ -57,6 +60,7 @@ public class InMemoryDataStoreWithExecutorServiceBenchmark extends AbstractInMem initTestNode(); } + @Override @TearDown public void tearDown() { schemaContext = null; diff --git a/opendaylight/md-sal/compatibility/pom.xml b/opendaylight/md-sal/compatibility/pom.xml index b9e9d19b48..a7da4a1e9c 100644 --- a/opendaylight/md-sal/compatibility/pom.xml +++ b/opendaylight/md-sal/compatibility/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT compatibility-parent pom diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml b/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml index 168dd14d10..32014decd5 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml +++ b/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller compatibility-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-compatibility bundle diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/AbstractDataChangeListener.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/AbstractDataChangeListener.java new file mode 100644 index 0000000000..2306508759 --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/AbstractDataChangeListener.java @@ -0,0 +1,146 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.sal.compatibility; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +public abstract class AbstractDataChangeListener implements AutoCloseable,DataChangeListener{ + + private static final Logger LOG = LoggerFactory.getLogger(AbstractDataChangeListener.class); + protected InventoryAndReadAdapter adapter; + protected final Class clazz; + protected ListenerRegistration listenerRegistration; + + public AbstractDataChangeListener(final InventoryAndReadAdapter adapter, DataBroker db, final Class clazz) { + this.adapter = Preconditions.checkNotNull(adapter, "InventoryAndReadAdapter can not be null!"); + this.clazz = Preconditions.checkNotNull(clazz, "Class can not be null!"); + Preconditions.checkNotNull(db, "DataBroker can not be null!"); + registrationListener(db, 5); + } + + @Override + public void onDataChanged(AsyncDataChangeEvent, DataObject> changeEvent) { + Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!"); + /* All DataObjects for create */ + final Map, DataObject> createdData = changeEvent.getCreatedData() != null + ? changeEvent.getCreatedData() : Collections., DataObject> emptyMap(); + /* All DataObjects for remove */ + final Set> removeData = changeEvent.getRemovedPaths() != null + ? changeEvent.getRemovedPaths() : Collections.> emptySet(); + /* All DataObjects for updates */ + final Map, DataObject> updateData = changeEvent.getUpdatedData() != null + ? changeEvent.getUpdatedData() : Collections., DataObject> emptyMap(); + /* All Original DataObjects */ + final Map, DataObject> originalData = changeEvent.getOriginalData() != null + ? changeEvent.getOriginalData() : Collections., DataObject> emptyMap(); + this.createData(createdData); + this.updateData(updateData, originalData); + this.removeData(removeData, originalData); + } + + @SuppressWarnings("unchecked") + private void createData(final Map, DataObject> createdData) { + final Set> keys = createdData.keySet() != null + ? createdData.keySet() : Collections.> emptySet(); + for (InstanceIdentifier key : keys) { + if (clazz.equals(key.getTargetType())) { + InstanceIdentifier createKeyIdent = key.firstIdentifierOf(clazz); + final Optional value = Optional.of(createdData.get(key)); + if (value.isPresent()) { + this.add(createKeyIdent, (T)value.get()); + } + } + } + } + + abstract protected void add(InstanceIdentifier createKeyIdent, T node); + + @SuppressWarnings("unchecked") + private void updateData(final Map, DataObject> updateData, final Map, DataObject> originalData) { + + final Set> keys = updateData.keySet() != null + ? updateData.keySet() : Collections.> emptySet(); + for (InstanceIdentifier key : keys) { + if (clazz.equals(key.getTargetType())) { + InstanceIdentifier updateKeyIdent = key.firstIdentifierOf(clazz); + final Optional value = Optional.of(updateData.get(key)); + final Optional original = Optional.of(originalData.get(key)); + if (value.isPresent() && original.isPresent()) { + this.update(updateKeyIdent, (T)original.get(), (T)value.get()); + } + } + } + } + + abstract protected void update(InstanceIdentifier updateKeyIdent, T node, + T node2); + + @SuppressWarnings("unchecked") + private void removeData(final Set> removeData, final Map, DataObject> originalData) { + + for (InstanceIdentifier key : removeData) { + if (clazz.equals(key.getTargetType())) { + final InstanceIdentifier ident = key.firstIdentifierOf(clazz); + final DataObject removeValue = originalData.get(key); + this.remove(ident, (T)removeValue); + } + } + } + + abstract protected void remove(InstanceIdentifier ident, T removeValue); + + protected void registrationListener(final DataBroker db, int i) { + try { + listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + getWildCardPath(), this, DataChangeScope.BASE); + } catch (final Exception e) { + if (i >= 1) { + try { + Thread.sleep(100); + } catch (InterruptedException e1) { + LOG.error("Thread interrupted '{}'", e1); + Thread.currentThread().interrupt(); + } + registrationListener(db, --i); + } else { + LOG.error("AbstractDataChangeListener registration fail!", e); + throw new IllegalStateException("AbstractDataChangeListener registration Listener fail! System needs restart.", e); + } + } + } + + protected abstract InstanceIdentifier getWildCardPath(); + + @Override + public void close() { + if (listenerRegistration != null) { + try { + listenerRegistration.close(); + } catch (final Exception e) { + LOG.error("Error by stop AbstractDataChangeListener.", e); + } + listenerRegistration = null; + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.java index d71858e5c3..6a8e3c0e5b 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.java @@ -7,9 +7,7 @@ */ package org.opendaylight.controller.sal.compatibility; -import java.util.Dictionary; -import java.util.Hashtable; - +import com.google.common.base.Preconditions; import org.apache.felix.dm.Component; import org.opendaylight.controller.clustering.services.IClusterGlobalServices; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; @@ -36,7 +34,8 @@ import org.opendaylight.controller.sal.utils.INodeConnectorFactory; import org.opendaylight.controller.sal.utils.INodeFactory; import org.osgi.framework.BundleContext; -import com.google.common.base.Preconditions; +import java.util.Dictionary; +import java.util.Hashtable; public class ComponentActivator extends ComponentActivatorAbstractBase { private final INodeConnectorFactory nodeConnectorFactory = new MDSalNodeConnectorFactory(); @@ -90,8 +89,8 @@ public class ComponentActivator extends ComponentActivatorAbstractBase { @Override public void start(final BundleContext context) { - super.start(context); this.context = Preconditions.checkNotNull(context); + super.start(context); } public ProviderContext setBroker(final BindingAwareBroker broker) { @@ -101,14 +100,14 @@ public class ComponentActivator extends ComponentActivatorAbstractBase { @Override protected Object[] getGlobalImplementations() { return new Object[] { + this, // Used for setBroker callback flow, inventory, dataPacket, nodeFactory, nodeConnectorFactory, topology, - tpProvider, - this // Used for setBroker callback + tpProvider }; } @@ -139,6 +138,7 @@ public class ComponentActivator extends ComponentActivatorAbstractBase { protected Object[] getImplementations() { return new Object[] { dataPacketService, + inventory, }; } @@ -148,6 +148,8 @@ public class ComponentActivator extends ComponentActivatorAbstractBase { _instanceConfigure((ComponentActivator)imp, c, containerName); } else if (imp instanceof DataPacketServiceAdapter) { _instanceConfigure((DataPacketServiceAdapter)imp, c, containerName); + } else if (imp instanceof InventoryAndReadAdapter) { + _instanceConfigure((InventoryAndReadAdapter)imp, c, containerName); } else { throw new IllegalArgumentException(String.format("Unhandled implementation class %s", imp.getClass())); } @@ -213,6 +215,28 @@ public class ComponentActivator extends ComponentActivatorAbstractBase { .setService(IDiscoveryService.class) .setCallbacks("setDiscoveryPublisher", "setDiscoveryPublisher") .setRequired(false)); + it.add(createServiceDependency() + .setService(BindingAwareBroker.class) + .setRequired(true)); + } + + private void _instanceConfigure(final InventoryAndReadAdapter imp, final Component it, String containerName) { + it.setInterface(new String[] { + IPluginInInventoryService.class.getName(), + IPluginInReadService.class.getName(), + }, properties()); + + it.add(createServiceDependency() + .setService(IPluginOutReadService.class) + .setCallbacks("setReadPublisher", "unsetReadPublisher") + .setRequired(false)); + it.add(createServiceDependency() + .setService(IPluginOutInventoryService.class) + .setCallbacks("setInventoryPublisher", "unsetInventoryPublisher") + .setRequired(false)); + it.add(createServiceDependency() + .setService(BindingAwareBroker.class) + .setRequired(true)); } private void _configure(final TopologyAdapter imp, final Component it) { diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java index 1b648dc98c..ecf1a94c18 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java @@ -61,10 +61,16 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026 import com.google.common.net.InetAddresses; -public class FromSalConversionsUtils { +/** + * MD-SAL to AD-SAL conversions collection + */ +public final class FromSalConversionsUtils { - private FromSalConversionsUtils() { + /** http://en.wikipedia.org/wiki/IPv4#Packet_structure (end of octet number 1, bit 14.+15.) */ + public static final int ENC_FIELD_BIT_SIZE = 2; + private FromSalConversionsUtils() { + throw new IllegalAccessError("forcing no instance for factory"); } @SuppressWarnings("unused") @@ -469,5 +475,12 @@ public class FromSalConversionsUtils { return true; } + /** + * @param nwDscp NW-DSCP + * @return shifted to NW-TOS (with empty ECN part) + */ + public static int dscpToTos(int nwDscp) { + return (short) (nwDscp << ENC_FIELD_BIT_SIZE); + } } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.java index e2c1386775..bbb6673a8e 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.java @@ -7,8 +7,6 @@ */ package org.opendaylight.controller.sal.compatibility; -import com.google.common.collect.Iterables; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -48,7 +46,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.ta import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; @@ -71,7 +68,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; @@ -90,7 +86,9 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class InventoryAndReadAdapter implements IPluginInReadService, IPluginInInventoryService, OpendaylightInventoryListener, OpendaylightFlowStatisticsListener, OpendaylightFlowTableStatisticsListener, OpendaylightPortStatisticsListener { +import com.google.common.collect.Iterables; + +public class InventoryAndReadAdapter implements IPluginInReadService, IPluginInInventoryService, OpendaylightFlowStatisticsListener, OpendaylightFlowTableStatisticsListener, OpendaylightPortStatisticsListener { private static final Logger LOG = LoggerFactory.getLogger(InventoryAndReadAdapter.class); private static final short OPENFLOWV10_TABLE_ID = 0; @@ -241,20 +239,20 @@ public class InventoryAndReadAdapter implements IPluginInReadService, IPluginInI * @param id Table id * @return Table contents, or null if not present */ - private Table readConfigTable(final Node node, final short id) { + private Table readOperationalTable(final Node node, final short id) { final InstanceIdentifier tableRef = InstanceIdentifier.builder(Nodes.class) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, InventoryMapping.toNodeKey(node)) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, NodeMapping.toNodeKey(node)) .augmentation(FlowCapableNode.class) .child(Table.class, new TableKey(id)) .build(); - return (Table) startChange().readConfigurationData(tableRef); + return (Table) startChange().readOperationalData(tableRef); } @Override public List readAllFlow(final Node node, final boolean cached) { final ArrayList output = new ArrayList<>(); - final Table table = readConfigTable(node, OPENFLOWV10_TABLE_ID); + final Table table = readOperationalTable(node, OPENFLOWV10_TABLE_ID); if (table != null) { final List flows = table.getFlow(); LOG.trace("Number of flows installed in table 0 of node {} : {}", node, flows.size()); @@ -268,12 +266,6 @@ public class InventoryAndReadAdapter implements IPluginInReadService, IPluginInI } } - // TODO (main): Shall we send request to the switch? It will make async request to the switch. - // Once the plugin receives a response, it will let the adaptor know through onFlowStatisticsUpdate() - // If we assume that md-sal statistics manager will always be running, then it is not required - // But if not, then sending request will collect the latest data for adaptor at least. - getFlowStatisticsService().getAllFlowsStatisticsFromAllFlowTables( - new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder().setNode(NodeMapping.toNodeRef(node)).build()); return output; } @@ -334,7 +326,7 @@ public class InventoryAndReadAdapter implements IPluginInReadService, IPluginInI @Override public FlowOnNode readFlow(final Node node, final org.opendaylight.controller.sal.flowprogrammer.Flow targetFlow, final boolean cached) { FlowOnNode ret = null; - final Table table = readConfigTable(node, OPENFLOWV10_TABLE_ID); + final Table table = readOperationalTable(node, OPENFLOWV10_TABLE_ID); if (table != null) { final List flows = table.getFlow(); InventoryAndReadAdapter.LOG.trace("Number of flows installed in table 0 of node {} : {}", node, flows.size()); @@ -386,7 +378,7 @@ public class InventoryAndReadAdapter implements IPluginInReadService, IPluginInI @Override public NodeTableStatistics readNodeTable(final NodeTable nodeTable, final boolean cached) { NodeTableStatistics nodeStats = null; - final Table table = readConfigTable(nodeTable.getNode(), (short) nodeTable.getID()); + final Table table = readOperationalTable(nodeTable.getNode(), (short) nodeTable.getID()); if (table != null) { final FlowTableStatisticsData tableStats = table.getAugmentation(FlowTableStatisticsData.class); if (tableStats != null) { @@ -405,13 +397,11 @@ public class InventoryAndReadAdapter implements IPluginInReadService, IPluginInI return nodeStats; } - @Override - public void onNodeConnectorRemoved(final NodeConnectorRemoved update) { + public void onNodeConnectorRemovedInternal(final NodeConnectorRemoved update) { // Never received } - @Override - public void onNodeRemoved(final NodeRemoved notification) { + public void onNodeRemovedInternal(final NodeRemoved notification) { this.removeNodeConnectors(notification.getNodeRef().getValue()); try { final Node aDNode = NodeMapping.toADNode(notification.getNodeRef()); @@ -421,8 +411,7 @@ public class InventoryAndReadAdapter implements IPluginInReadService, IPluginInI } } - @Override - public void onNodeConnectorUpdated(final NodeConnectorUpdated update) { + public void onNodeConnectorUpdatedInternal(final NodeConnectorUpdated update) { final NodeConnectorRef ref = update.getNodeConnectorRef(); final UpdateType updateType; if (!this.isKnownNodeConnector(ref.getValue())) { @@ -441,8 +430,7 @@ public class InventoryAndReadAdapter implements IPluginInReadService, IPluginInI } } - @Override - public void onNodeUpdated(final NodeUpdated notification) { + public void onNodeUpdatedInternal(final NodeUpdated notification) { final NodeRef ref = notification.getNodeRef(); final UpdateType updateType; diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDFlowMapping.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDFlowMapping.java index 5837e35b3a..00511bc744 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDFlowMapping.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDFlowMapping.java @@ -315,7 +315,7 @@ public final class MDFlowMapping { private static SetNwTosActionCase _toAction(final SetNwTos sourceAction) { return new SetNwTosActionCaseBuilder() - .setSetNwTosAction(new SetNwTosActionBuilder().setTos(sourceAction.getNwTos()).build()) + .setSetNwTosAction(new SetNwTosActionBuilder().setTos(FromSalConversionsUtils.dscpToTos(sourceAction.getNwTos())).build()) .build(); } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NCDataChangeListener.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NCDataChangeListener.java new file mode 100644 index 0000000000..d93d40d2a6 --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NCDataChangeListener.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.sal.compatibility; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemovedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NCDataChangeListener extends AbstractDataChangeListener { + private static final Logger LOG = LoggerFactory.getLogger(NodeDataChangeListener.class); + private ListenerRegistration listenerRegistration; + public NCDataChangeListener (final InventoryAndReadAdapter adapter, final DataBroker db) { + super(adapter,db,NodeConnector.class); + } + + @Override + protected void add(InstanceIdentifier createKeyIdent, NodeConnector node) { + FlowCapableNodeConnector fcnc = node.getAugmentation(FlowCapableNodeConnector.class); + if(fcnc != null) { + FlowCapableNodeConnectorUpdatedBuilder fcncub = new FlowCapableNodeConnectorUpdatedBuilder(fcnc); + NodeConnectorUpdatedBuilder builder = new NodeConnectorUpdatedBuilder(); + builder.setId(node.getId()); + builder.setNodeConnectorRef(new NodeConnectorRef(createKeyIdent)); + builder.addAugmentation(FlowCapableNodeConnectorUpdated.class, fcncub.build()); + adapter.onNodeConnectorUpdatedInternal(builder.build()); + } + } + + @Override + protected void update(InstanceIdentifier updateKeyIdent, NodeConnector original, + NodeConnector update) { + add(updateKeyIdent,update); + } + + @Override + protected void remove(InstanceIdentifier ident, NodeConnector removeValue) { + NodeConnectorRemovedBuilder builder = new NodeConnectorRemovedBuilder(); + builder.setNodeConnectorRef(new NodeConnectorRef(ident)); + adapter.onNodeConnectorRemovedInternal(builder.build()); + } + + protected InstanceIdentifier getWildCardPath() { + return InstanceIdentifier.create(Nodes.class).child(Node.class).child(NodeConnector.class); + } +} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeDataChangeListener.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeDataChangeListener.java new file mode 100644 index 0000000000..cdb26162c0 --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeDataChangeListener.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.sal.compatibility; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemovedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NodeDataChangeListener extends AbstractDataChangeListener { + private static final Logger LOG = LoggerFactory.getLogger(NodeDataChangeListener.class); + + + public NodeDataChangeListener (final InventoryAndReadAdapter adapter, final DataBroker db) { + super(adapter,db,Node.class); + } + + protected void add(InstanceIdentifier createKeyIdent, Node node) { + FlowCapableNode fcn = node.getAugmentation(FlowCapableNode.class); + if(fcn != null) { + FlowCapableNodeUpdatedBuilder fcbnu = new FlowCapableNodeUpdatedBuilder(fcn); + NodeUpdatedBuilder builder = new NodeUpdatedBuilder(); + builder.setId(node.getId()); + builder.setNodeRef(new NodeRef(createKeyIdent)); + builder.setNodeConnector(node.getNodeConnector()); + builder.addAugmentation(FlowCapableNodeUpdated.class, fcbnu.build()); + adapter.onNodeUpdatedInternal(builder.build()); + } + } + + protected void update(InstanceIdentifier updateKeyIdent, Node original, + Node update) { + this.add(updateKeyIdent, update); + } + + protected void remove(InstanceIdentifier ident, Node removeValue) { + NodeRemovedBuilder builder = new NodeRemovedBuilder(); + builder.setNodeRef(new NodeRef(ident)); + adapter.onNodeRemovedInternal(builder.build()); + } + + protected InstanceIdentifier getWildCardPath() { + return InstanceIdentifier.create(Nodes.class).child(Node.class); + } + +} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java index b873f8a9fe..bcb2367e7a 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java @@ -168,7 +168,22 @@ public final class NodeMapping { * @return */ private static NodeId toNodeId(org.opendaylight.controller.sal.core.Node aDNode) { - return new NodeId(aDNode.getType() + ":" + String.valueOf(aDNode.getID())); + String targetPrefix = null; + if (NodeIDType.OPENFLOW.equals(aDNode.getType())) { + targetPrefix = OPENFLOW_ID_PREFIX; + } else { + targetPrefix = aDNode.getType() + ":"; + } + + return new NodeId(targetPrefix + String.valueOf(aDNode.getID())); + } + + /** + * @param aDNode + * @return md-sal {@link NodeKey} + */ + public static NodeKey toNodeKey(org.opendaylight.controller.sal.core.Node aDNode) { + return new NodeKey(toNodeId(aDNode)); } public static String toNodeConnectorType(final NodeConnectorId ncId, final NodeId nodeId) { diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/SalCompatibilityProvider.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/SalCompatibilityProvider.java index 0ddbcaa2e0..f8f2b37819 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/SalCompatibilityProvider.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/SalCompatibilityProvider.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.sal.compatibility; import java.util.Collection; import java.util.Collections; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; @@ -68,6 +69,10 @@ class SalCompatibilityProvider implements BindingAwareProvider { inv.setNodeConnectorStatisticsService(session.getRpcService(OpendaylightPortStatisticsService.class)); inv.setTopologyDiscovery(session.getRpcService(FlowTopologyDiscoveryService.class)); inv.setDataProviderService(session.getSALService(DataProviderService.class)); + + final NodeDataChangeListener ndcl = new NodeDataChangeListener(inv,session.getSALService(DataBroker.class)); + final NCDataChangeListener ncdcl = new NCDataChangeListener(inv,session.getSALService(DataBroker.class)); + // FIXME: remember registration for clean shutdown subscribe.registerNotificationListener(inv); diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java index 28dd57c3b7..dcc1a4660b 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java @@ -128,7 +128,7 @@ public class ToSalConversionsUtils { private static final Logger LOG = LoggerFactory.getLogger(ToSalConversionsUtils.class); private ToSalConversionsUtils() { - + throw new IllegalAccessError("forcing no instance for factory"); } public static Flow toFlow(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow source, Node node) { @@ -287,7 +287,7 @@ public class ToSalConversionsUtils { } else if (sourceAction instanceof SetNwTosActionCase) { Integer tos = ((SetNwTosActionCase) sourceAction).getSetNwTosAction().getTos(); if (tos != null) { - targetAction.add(new SetNwTos(tos)); + targetAction.add(new SetNwTos(ToSalConversionsUtils.tosToNwDscp(tos))); } } else if (sourceAction instanceof SetTpDstActionCase) { PortNumber port = ((SetTpDstActionCase) sourceAction).getSetTpDstAction().getPort(); @@ -643,4 +643,12 @@ public class ToSalConversionsUtils { return mac; } + + /** + * @param nwTos NW-TOS + * @return shifted to NW-DSCP + */ + public static int tosToNwDscp(int nwTos) { + return (short) (nwTos >>> FromSalConversionsUtils.ENC_FIELD_BIT_SIZE); + } } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyMapping.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyMapping.java index 6bc669f60b..ae723a3165 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyMapping.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyMapping.java @@ -7,12 +7,8 @@ */ package org.opendaylight.controller.sal.compatibility.topology; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; - +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader; import org.opendaylight.controller.sal.compatibility.NodeMapping; import org.opendaylight.controller.sal.core.ConstructionException; @@ -33,11 +29,16 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Function; -import com.google.common.collect.FluentIterable; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.regex.Pattern; + +import static com.google.common.base.Preconditions.checkNotNull; public final class TopologyMapping { private static final Logger LOG = LoggerFactory.getLogger(TopologyMapping.class); + private final static Pattern NUMBERS_ONLY = Pattern.compile("[0-9]+"); private TopologyMapping() { throw new UnsupportedOperationException("Utility class. Instantiation is not allowed."); @@ -100,7 +101,13 @@ public final class TopologyMapping { public static NodeConnector toADNodeConnector(final TpId source, final NodeId nodeId) throws ConstructionException { checkNotNull(source); - return new NodeConnector(NodeConnectorIDType.OPENFLOW, Short.valueOf(toADNodeConnectorId(source)), toADNode(nodeId)); + String nodeConnectorIdStripped = toADNodeConnectorId(source); + if (NUMBERS_ONLY.matcher(nodeConnectorIdStripped).matches()) { + return new NodeConnector(NodeConnectorIDType.OPENFLOW, Short.valueOf(nodeConnectorIdStripped), toADNode(nodeId)); + } + LOG.debug("NodeConnectorId does not match openflow id type, using " + NodeMapping.MD_SAL_TYPE + "instead"); + NodeConnectorIDType.registerIDType(NodeMapping.MD_SAL_TYPE, String.class, NodeMapping.MD_SAL_TYPE); + return new NodeConnector(NodeMapping.MD_SAL_TYPE, nodeConnectorIdStripped, toADNode(nodeId)); } public static String toADNodeConnectorId(final TpId nodeConnectorId) { @@ -109,6 +116,12 @@ public final class TopologyMapping { public static Node toADNode(final NodeId nodeId) throws ConstructionException { checkNotNull(nodeId); - return new Node(NodeIDType.OPENFLOW, Long.valueOf(toADNodeId(nodeId))); + String nodeIdStripped = toADNodeId(nodeId); + if (NUMBERS_ONLY.matcher(nodeIdStripped).matches()) { + return new Node(NodeIDType.OPENFLOW, Long.valueOf(nodeIdStripped)); + } + LOG.debug("NodeId does not match openflow id type, using " + NodeMapping.MD_SAL_TYPE + "instead"); + NodeIDType.registerIDType(NodeMapping.MD_SAL_TYPE, String.class); + return new Node(NodeMapping.MD_SAL_TYPE, nodeId.getValue()); } } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/FromSalConversionsUtilsTest.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/FromSalConversionsUtilsTest.java new file mode 100644 index 0000000000..b09e816f61 --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/FromSalConversionsUtilsTest.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.sal.compatibility.test; + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.sal.compatibility.FromSalConversionsUtils; + +/** + * test of {@link FromSalConversionsUtils} + */ +public class FromSalConversionsUtilsTest { + + /** + * Test method for {@link org.opendaylight.controller.sal.compatibility.FromSalConversionsUtils#dscpToTos(int)}. + */ + @Test + public void testDscpToTos() { + Assert.assertEquals(0, FromSalConversionsUtils.dscpToTos(0)); + Assert.assertEquals(4, FromSalConversionsUtils.dscpToTos(1)); + Assert.assertEquals(252, FromSalConversionsUtils.dscpToTos(63)); + Assert.assertEquals(256, FromSalConversionsUtils.dscpToTos(64)); + Assert.assertEquals(-4, FromSalConversionsUtils.dscpToTos(-1)); + } + +} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/NodeMappingTest.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/NodeMappingTest.java index a776ef2312..759e69f5eb 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/NodeMappingTest.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/NodeMappingTest.java @@ -196,6 +196,19 @@ public class NodeMappingTest { Assert.assertEquals(0xCC4E241C4A000000L, NodeMapping.openflowFullNodeIdToLong("14721743935839928320").longValue()); } + /** + * Test method for + * {@link org.opendaylight.controller.sal.compatibility.NodeMapping#toNodeKey(org.opendaylight.controller.sal.core.Node)} + * . + * @throws ConstructionException + */ + @Test + public void testToNodeKey() throws ConstructionException { + org.opendaylight.controller.sal.core.Node aDNode = new org.opendaylight.controller.sal.core.Node(NodeIDType.OPENFLOW, 42L); + NodeKey nodeKey = NodeMapping.toNodeKey(aDNode); + Assert.assertEquals("openflow:42", nodeKey.getId().getValue()); + } + /** * @param nodeId * @param portId diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestFromSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestFromSalConversionsUtils.java index 9f787b7e39..98df90112d 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestFromSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestFromSalConversionsUtils.java @@ -293,7 +293,7 @@ public class TestFromSalConversionsUtils { } assertTrue("Ipv4 address wasn't found.", ipv4AddressFound); } else if (innerAction instanceof SetNwTosActionCase) { - assertEquals("Wrong TOS in SetNwTosAction.", (Integer) 63, ((SetNwTosActionCase) innerAction).getSetNwTosAction().getTos()); + assertEquals("Wrong TOS in SetNwTosAction.", (Integer) 252, ((SetNwTosActionCase) innerAction).getSetNwTosAction().getTos()); } else if (innerAction instanceof SetNwDstActionCase) { Address address = ((SetNwDstActionCase) innerAction).getSetNwDstAction().getAddress(); boolean ipv4AddressFound = false; diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestToSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestToSalConversionsUtils.java index 60b77394c1..16d0bb424d 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestToSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestToSalConversionsUtils.java @@ -499,7 +499,7 @@ public class TestToSalConversionsUtils { private void prepareActionSetNwTos(SetNwTosActionCaseBuilder wrapper) { SetNwTosActionBuilder setNwTosActionBuilder = new SetNwTosActionBuilder(); - setNwTosActionBuilder.setTos(63); + setNwTosActionBuilder.setTos(252); wrapper.setSetNwTosAction(setNwTosActionBuilder.build()); } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/ToSalConversionsUtilsTest.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/ToSalConversionsUtilsTest.java new file mode 100644 index 0000000000..aa25c18317 --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/ToSalConversionsUtilsTest.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.sal.compatibility.test; + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils; + +/** + * test of {@link ToSalConversionsUtils} + */ +public class ToSalConversionsUtilsTest { + + /** + * Test method for {@link org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils#tosToNwDscp(int)}. + */ + @Test + public void testTosToNwDscp() { + Assert.assertEquals(0, ToSalConversionsUtils.tosToNwDscp(0)); + Assert.assertEquals(0, ToSalConversionsUtils.tosToNwDscp(1)); + Assert.assertEquals(1, ToSalConversionsUtils.tosToNwDscp(4)); + Assert.assertEquals(63, ToSalConversionsUtils.tosToNwDscp(252)); + Assert.assertEquals(63, ToSalConversionsUtils.tosToNwDscp(253)); + Assert.assertEquals(-1, ToSalConversionsUtils.tosToNwDscp(-1)); + } +} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/topology/test/TopologyMappingTest.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/topology/test/TopologyMappingTest.java index b76370a538..9369217d78 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/topology/test/TopologyMappingTest.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/topology/test/TopologyMappingTest.java @@ -69,4 +69,17 @@ public class TopologyMappingTest { Assert.assertEquals("OF|00:00:00:00:00:00:00:01", observedNode.toString()); } + /** + * Test method for {@link org.opendaylight.controller.sal.compatibility.topology.TopologyMapping#toADNodeConnector(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId, org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId)}. + * @throws ConstructionException + */ + @Test + public void bug1309ToADNodeConnector() throws ConstructionException { + NodeId nodeId = new NodeId("some_unknown_node"); + TpId source = new TpId("192.168.0.1"); + NodeConnector observedNodeConnector = TopologyMapping.toADNodeConnector(source, nodeId); + + Assert.assertEquals("MD_SAL_DEPRECATED|192.168.0.1@MD_SAL_DEPRECATED|some_unknown_node", observedNodeConnector.toString()); + } + } diff --git a/opendaylight/md-sal/forwardingrules-manager/pom.xml b/opendaylight/md-sal/forwardingrules-manager/pom.xml index 5a9b190219..12458f5ab9 100644 --- a/opendaylight/md-sal/forwardingrules-manager/pom.xml +++ b/opendaylight/md-sal/forwardingrules-manager/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT org.opendaylight.controller.md forwardingrules-manager diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/FlowForwarder.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/FlowForwarder.java index 9951bf7448..698dbcb0d1 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/FlowForwarder.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/FlowForwarder.java @@ -7,7 +7,6 @@ */ package org.opendaylight.controller.frm.impl; -import com.google.common.base.Preconditions; import org.opendaylight.controller.frm.ForwardingRulesManager; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; @@ -33,6 +32,8 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; + /** * GroupForwarder * It implements {@link org.opendaylight.controller.md.sal.binding.api.DataChangeListener}} @@ -52,8 +53,27 @@ public class FlowForwarder extends AbstractListeningCommiter { public FlowForwarder (final ForwardingRulesManager manager, final DataBroker db) { super(manager, Flow.class); Preconditions.checkNotNull(db, "DataBroker can not be null!"); - this.listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, - getWildCardPath(), FlowForwarder.this, DataChangeScope.SUBTREE); + registrationListener(db, 5); + } + + private void registrationListener(final DataBroker db, int i) { + try { + listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + getWildCardPath(), FlowForwarder.this, DataChangeScope.SUBTREE); + } catch (final Exception e) { + if (i >= 1) { + try { + Thread.sleep(100); + } catch (InterruptedException e1) { + LOG.error("Thread interrupted '{}'", e1); + Thread.currentThread().interrupt(); + } + registrationListener(db, --i); + } else { + LOG.error("FRM Flow DataChange listener registration fail!", e); + throw new IllegalStateException("FlowForwarder registration Listener fail! System needs restart.", e); + } + } } @Override @@ -61,7 +81,7 @@ public class FlowForwarder extends AbstractListeningCommiter { if (listenerRegistration != null) { try { listenerRegistration.close(); - } catch (Exception e) { + } catch (final Exception e) { LOG.error("Error by stop FRM FlowChangeListener.", e); } listenerRegistration = null; @@ -80,7 +100,7 @@ public class FlowForwarder extends AbstractListeningCommiter { builder.setNode(new NodeRef(nodeIdent.firstIdentifierOf(Node.class))); builder.setFlowTable(new FlowTableRef(nodeIdent.child(Table.class, tableKey))); builder.setTransactionUri(new Uri(provider.getNewTransactionId())); - this.provider.getSalFlowService().removeFlow(builder.build()); + provider.getSalFlowService().removeFlow(builder.build()); } } @@ -99,7 +119,7 @@ public class FlowForwarder extends AbstractListeningCommiter { builder.setUpdatedFlow((new UpdatedFlowBuilder(update)).build()); builder.setOriginalFlow((new OriginalFlowBuilder(original)).build()); - this.provider.getSalFlowService().updateFlow(builder.build()); + provider.getSalFlowService().updateFlow(builder.build()); } } @@ -116,7 +136,7 @@ public class FlowForwarder extends AbstractListeningCommiter { builder.setFlowRef(new FlowRef(identifier)); builder.setFlowTable(new FlowTableRef(nodeIdent.child(Table.class, tableKey))); builder.setTransactionUri(new Uri(provider.getNewTransactionId())); - this.provider.getSalFlowService().addFlow(builder.build()); + provider.getSalFlowService().addFlow(builder.build()); } } @@ -129,7 +149,7 @@ public class FlowForwarder extends AbstractListeningCommiter { private boolean tableIdValidationPrecondition (final TableKey tableKey, final Flow flow) { Preconditions.checkNotNull(tableKey, "TableKey can not be null or empty!"); Preconditions.checkNotNull(flow, "Flow can not be null or empty!"); - if (flow.getTableId() != tableKey.getId()) { + if (! tableKey.getId().equals(flow.getTableId())) { LOG.error("TableID in URI tableId={} and in palyload tableId={} is not same.", flow.getTableId(), tableKey.getId()); return false; diff --git a/opendaylight/md-sal/inventory-manager/pom.xml b/opendaylight/md-sal/inventory-manager/pom.xml index 1706996ce4..77e4203269 100644 --- a/opendaylight/md-sal/inventory-manager/pom.xml +++ b/opendaylight/md-sal/inventory-manager/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT org.opendaylight.controller.md inventory-manager diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.java b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.java index 3db929b99d..618fcfc133 100644 --- a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.java +++ b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.java @@ -7,24 +7,23 @@ */ package org.opendaylight.controller.md.inventory.manager; -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; +import java.util.ArrayList; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingDeque; + import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction; import org.opendaylight.controller.md.sal.common.api.data.TransactionChain; import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; + class FlowCapableInventoryProvider implements AutoCloseable, Runnable, TransactionChainListener { private static final Logger LOG = LoggerFactory.getLogger(FlowCapableInventoryProvider.class); private static final int QUEUE_DEPTH = 500; @@ -47,7 +46,7 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable, Transacti final NodeChangeCommiter changeCommiter = new NodeChangeCommiter(FlowCapableInventoryProvider.this); this.listenerRegistration = this.notificationService.registerNotificationListener(changeCommiter); - this.txChain = dataBroker.createTransactionChain(this); + this.txChain = (dataBroker.createTransactionChain(this)); thread = new Thread(this); thread.setDaemon(true); thread.setName("FlowCapableInventoryProvider"); @@ -59,49 +58,20 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable, Transacti void enqueue(final InventoryOperation op) { try { queue.put(op); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { LOG.warn("Failed to enqueue operation {}", op, e); } } - @Override - public void close() throws InterruptedException { - LOG.info("Flow Capable Inventory Provider stopped."); - if (this.listenerRegistration != null) { - try { - this.listenerRegistration.close(); - } catch (Exception e) { - LOG.error("Failed to stop inventory provider", e); - } - listenerRegistration = null; - } - - if (thread != null) { - thread.interrupt(); - thread.join(); - thread = null; - } - if (txChain != null) { - txChain.close(); - txChain = null; - } - - - } - @Override public void run() { try { for (; ; ) { InventoryOperation op = queue.take(); - - final ReadWriteTransaction tx = txChain.newReadWriteTransaction(); - LOG.debug("New operations available, starting transaction {}", tx.getIdentifier()); - int ops = 0; + final ArrayList opsToApply = new ArrayList<>(MAX_BATCH); do { - op.applyOperation(tx); - + opsToApply.add(op); ops++; if (ops < MAX_BATCH) { op = queue.poll(); @@ -109,23 +79,9 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable, Transacti op = null; } } while (op != null); - - LOG.debug("Processed {} operations, submitting transaction {}", ops, tx.getIdentifier()); - - final CheckedFuture result = tx.submit(); - Futures.addCallback(result, new FutureCallback() { - @Override - public void onSuccess(final Void aVoid) { - //NOOP - } - - @Override - public void onFailure(final Throwable throwable) { - LOG.error("Transaction {} failed.", tx.getIdentifier(), throwable); - } - }); + submitOperations(opsToApply); } - } catch (InterruptedException e) { + } catch (final InterruptedException e) { LOG.info("Processing interrupted, terminating", e); } @@ -135,15 +91,131 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable, Transacti } } + /** + * Starts new empty transaction, custimizes it with submitted operations + * and submit it to data broker. + * + * If transaction chain failed during customization of transaction + * it allocates new chain and empty transaction and customizes it + * with submitted operations. + * + * This does not retry failed transaction. It only retries it when + * chain failed during customization of transaction chain. + * + * @param opsToApply + */ + private void submitOperations(final ArrayList opsToApply) { + final ReadWriteTransaction tx = createCustomizedTransaction(opsToApply); + LOG.debug("Processed {} operations, submitting transaction {}", opsToApply.size(), tx.getIdentifier()); + try { + tx.submit(); + } catch (final IllegalStateException e) { + /* + * Transaction chain failed during doing batch, so we need to null + * tx chain and continue processing queue. + * + * We fail current txChain which was allocated with createTransaction. + */ + failCurrentChain(txChain); + /* + * We will retry transaction once in order to not loose any data. + * + */ + final ReadWriteTransaction retryTx = createCustomizedTransaction(opsToApply); + retryTx.submit(); + } + } + + /** + * Creates new empty ReadWriteTransaction. If transaction chain + * was failed, it will allocate new transaction chain + * and assign it with this Operation Executor. + * + * This call is synchronized to prevent reace with {@link #failCurrentChain(TransactionChain)}. + * + * @return New Empty ReadWrite transaction, which continues this chain or starts new transaction + * chain. + */ + private synchronized ReadWriteTransaction newEmptyTransaction() { + try { + if(txChain == null) { + // Chain was broken so we need to replace it. + txChain = dataBroker.createTransactionChain(this); + } + return txChain.newReadWriteTransaction(); + } catch (final IllegalStateException e) { + LOG.debug("Chain is broken, need to allocate new transaction chain.",e); + /* + * Chain was broken by previous transaction, + * but there was race between this. + * Chain will be closed by #onTransactionChainFailed method. + */ + txChain = dataBroker.createTransactionChain(this); + return txChain.newReadWriteTransaction(); + } + } + + /** + * Creates customized not-submitted transaction, which is ready to be submitted. + * + * @param opsToApply Operations which are used to customize transaction. + * @return Non-empty transaction. + */ + private ReadWriteTransaction createCustomizedTransaction(final ArrayList opsToApply) { + final ReadWriteTransaction tx = newEmptyTransaction(); + for(final InventoryOperation op : opsToApply) { + op.applyOperation(tx); + } + return tx; + } + + private synchronized void failCurrentChain(final TransactionChain chain) { + if(txChain == chain) { + txChain = null; + } + } + @Override public void onTransactionChainFailed(final TransactionChain chain, final AsyncTransaction transaction, final Throwable cause) { LOG.error("Failed to export Flow Capable Inventory, Transaction {} failed.", transaction.getIdentifier(), cause); - + chain.close(); + if(txChain == chain) { + // Current chain is broken, so we will null it, in order to not use it. + failCurrentChain(chain); + } } @Override public void onTransactionChainSuccessful(final TransactionChain chain) { // NOOP } + + @Override + public void close() throws InterruptedException { + LOG.info("Flow Capable Inventory Provider stopped."); + if (this.listenerRegistration != null) { + try { + this.listenerRegistration.close(); + } catch (final Exception e) { + LOG.error("Failed to stop inventory provider", e); + } + listenerRegistration = null; + } + + if (thread != null) { + thread.interrupt(); + thread.join(); + thread = null; + } + if (txChain != null) { + try { + txChain.close(); + } catch (final IllegalStateException e) { + // It is possible chain failed and was closed by #onTransactionChainFailed + LOG.debug("Chain was already closed."); + } + txChain = null; + } + } } diff --git a/opendaylight/md-sal/md-sal-config/pom.xml b/opendaylight/md-sal/md-sal-config/pom.xml index 2e19b5a60c..bd1586054d 100644 --- a/opendaylight/md-sal/md-sal-config/pom.xml +++ b/opendaylight/md-sal/md-sal-config/pom.xml @@ -12,7 +12,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT md-sal-config Configuration files for md-sal diff --git a/opendaylight/md-sal/model/model-flow-base/pom.xml b/opendaylight/md-sal/model/model-flow-base/pom.xml index eb8d6a8ddb..cad0e9ea93 100644 --- a/opendaylight/md-sal/model/model-flow-base/pom.xml +++ b/opendaylight/md-sal/model/model-flow-base/pom.xml @@ -6,7 +6,7 @@ org.opendaylight.controller.model model-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT model-flow-base bundle diff --git a/opendaylight/md-sal/model/model-flow-service/pom.xml b/opendaylight/md-sal/model/model-flow-service/pom.xml index 0842bb4505..0f735d7f43 100644 --- a/opendaylight/md-sal/model/model-flow-service/pom.xml +++ b/opendaylight/md-sal/model/model-flow-service/pom.xml @@ -6,7 +6,7 @@ org.opendaylight.controller.model model-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT model-flow-service bundle diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang index 5a40022963..fc0eb4cf72 100644 --- a/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang @@ -236,13 +236,17 @@ module flow-node-inventory { } augment "/inv:nodes/inv:node/table" { - ext:augment-identifier "flow-cookie-mapping"; - list flow-cookie-map { - key "cookie"; - leaf cookie { - type flow:flow-cookie; + ext:augment-identifier "flow-hash-id-mapping"; + description "Flow is identified by match and priority on device. So Operational/DS + has to simulate that behavior and contract between FlowId and match+priority + identification should represent Flow hashCode. Flow has to contain only + match priority and flowCookie for create a hashCode"; + list flow-hash-id-map { + key "hash"; + leaf hash { + type string; } - leaf-list flow-ids { + leaf flow-id { type flow-id; } } diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/node-config.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/node-config.yang new file mode 100644 index 0000000000..98c3228190 --- /dev/null +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/node-config.yang @@ -0,0 +1,39 @@ +module node-config { + namespace "urn:opendaylight:module:config"; + prefix node-config; + + import flow-capable-transaction {prefix tr;} + import opendaylight-inventory {prefix inv;revision-date "2013-08-19";} + + revision "2014-10-15" { + description "Initial revision of node configuration service"; + } + + grouping node-ref { + uses "inv:node-context-ref"; + } + + + + /** Base configuration structure **/ + grouping node-config { + leaf flag { + type string; + description "Switch config flag. Expected values FRAGNORMAL, OFPCFRAGDROP, OFPCFRAGREASM, OFPCFRAGMASK"; + } + leaf miss-search-length{ + type uint16; + } + } + + rpc set-config { + input { + uses node-config; + uses tr:transaction-aware; + uses node-ref; + } + output { + uses tr:transaction-aware; + } + } +} diff --git a/opendaylight/md-sal/model/model-flow-statistics/pom.xml b/opendaylight/md-sal/model/model-flow-statistics/pom.xml index cd26e32781..7a53f062d7 100644 --- a/opendaylight/md-sal/model/model-flow-statistics/pom.xml +++ b/opendaylight/md-sal/model/model-flow-statistics/pom.xml @@ -6,7 +6,7 @@ org.opendaylight.controller.model model-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT model-flow-statistics bundle diff --git a/opendaylight/md-sal/model/model-inventory/pom.xml b/opendaylight/md-sal/model/model-inventory/pom.xml index c2f4f70c40..00aa7761b9 100644 --- a/opendaylight/md-sal/model/model-inventory/pom.xml +++ b/opendaylight/md-sal/model/model-inventory/pom.xml @@ -6,7 +6,7 @@ org.opendaylight.controller.model model-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT model-inventory bundle diff --git a/opendaylight/md-sal/model/model-topology/pom.xml b/opendaylight/md-sal/model/model-topology/pom.xml index e87e4f180d..09a063e887 100644 --- a/opendaylight/md-sal/model/model-topology/pom.xml +++ b/opendaylight/md-sal/model/model-topology/pom.xml @@ -6,7 +6,7 @@ org.opendaylight.controller.model model-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT model-topology bundle diff --git a/opendaylight/md-sal/model/pom.xml b/opendaylight/md-sal/model/pom.xml index 5e6a86745c..3f389f3298 100644 --- a/opendaylight/md-sal/model/pom.xml +++ b/opendaylight/md-sal/model/pom.xml @@ -6,7 +6,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT org.opendaylight.controller.model model-parent diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index 71a0de9939..1f646f2bba 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -5,12 +5,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../commons/opendaylight sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT pom @@ -77,6 +77,7 @@ sal-dom-xsql + sal-karaf-xsql sal-dom-xsql-config diff --git a/opendaylight/md-sal/sal-akka-raft/pom.xml b/opendaylight/md-sal/sal-akka-raft/pom.xml index e68e781525..53353cded1 100644 --- a/opendaylight/md-sal/sal-akka-raft/pom.xml +++ b/opendaylight/md-sal/sal-akka-raft/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-akka-raft bundle @@ -13,7 +13,7 @@ org.opendaylight.controller sal-clustering-commons - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT com.google.guava diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleActor.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleActor.java index c4ff108611..97b912ef74 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleActor.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleActor.java @@ -11,8 +11,10 @@ package org.opendaylight.controller.cluster.example; import akka.actor.ActorRef; import akka.actor.Props; import akka.japi.Creator; + import com.google.common.base.Optional; import com.google.protobuf.ByteString; + import org.opendaylight.controller.cluster.example.messages.KeyValue; import org.opendaylight.controller.cluster.example.messages.KeyValueSaved; import org.opendaylight.controller.cluster.example.messages.PrintRole; @@ -67,11 +69,15 @@ public class ExampleActor extends RaftActor { } } else if (message instanceof PrintState) { - LOG.debug("State of the node:{} has entries={}, {}", - getId(), state.size(), getReplicatedLogState()); + if(LOG.isDebugEnabled()) { + LOG.debug("State of the node:{} has entries={}, {}", + getId(), state.size(), getReplicatedLogState()); + } } else if (message instanceof PrintRole) { - LOG.debug("{} = {}, Peers={}", getId(), getRaftState(),getPeers()); + if(LOG.isDebugEnabled()) { + LOG.debug("{} = {}, Peers={}", getId(), getRaftState(), getPeers()); + } } else { super.onReceiveCommand(message); @@ -94,7 +100,7 @@ public class ExampleActor extends RaftActor { try { bs = fromObject(state); } catch (Exception e) { - LOG.error("Exception in creating snapshot", e); + LOG.error(e, "Exception in creating snapshot"); } getSelf().tell(new CaptureSnapshotReply(bs), null); } @@ -104,9 +110,11 @@ public class ExampleActor extends RaftActor { try { state.putAll((HashMap) toObject(snapshot)); } catch (Exception e) { - LOG.error("Exception in applying snapshot", e); + LOG.error(e, "Exception in applying snapshot"); + } + if(LOG.isDebugEnabled()) { + LOG.debug("Snapshot applied to state : {}", ((HashMap) state).size()); } - LOG.debug("Snapshot applied to state :" + ((HashMap) state).size()); } private ByteString fromObject(Object snapshot) throws Exception { @@ -159,4 +167,24 @@ public class ExampleActor extends RaftActor { @Override public String persistenceId() { return getId(); } + + @Override + protected void startLogRecoveryBatch(int maxBatchSize) { + } + + @Override + protected void appendRecoveredLogEntry(Payload data) { + } + + @Override + protected void applyCurrentLogRecoveryBatch() { + } + + @Override + protected void onRecoveryComplete() { + } + + @Override + protected void applyRecoverySnapshot(ByteString snapshot) { + } } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/TestDriver.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/TestDriver.java index 978ea91089..cb51a8951a 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/TestDriver.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/TestDriver.java @@ -7,7 +7,6 @@ import org.opendaylight.controller.cluster.example.messages.PrintRole; import org.opendaylight.controller.cluster.example.messages.PrintState; import org.opendaylight.controller.cluster.raft.ConfigParams; import org.opendaylight.controller.cluster.raft.client.messages.AddRaftPeer; -import org.opendaylight.controller.cluster.raft.client.messages.RemoveRaftPeer; import java.io.BufferedReader; import java.io.InputStreamReader; @@ -196,11 +195,6 @@ public class TestDriver { actorSystem.stop(actorRef); actorRefs.remove(actorName); - - for (ActorRef actor : actorRefs.values()) { - actor.tell(new RemoveRaftPeer(actorName), null); - } - allPeers.remove(actorName); } @@ -209,11 +203,6 @@ public class TestDriver { allPeers.put(actorName, address); ActorRef exampleActor = createExampleActor(actorName); - - for (ActorRef actor : actorRefs.values()) { - actor.tell(new AddRaftPeer(actorName, address), null); - } - actorRefs.put(actorName, exampleActor); addClientsToNode(actorName, 1); diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImpl.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImpl.java index b436bce500..2be4a0c36f 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImpl.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImpl.java @@ -18,13 +18,14 @@ import java.util.List; */ public abstract class AbstractReplicatedLogImpl implements ReplicatedLog { - protected List journal; + // We define this as ArrayList so we can use ensureCapacity. + protected ArrayList journal; protected ByteString snapshot; protected long snapshotIndex = -1; protected long snapshotTerm = -1; // to be used for rollback during save snapshot failure - protected List snapshottedJournal; + protected ArrayList snapshottedJournal; protected ByteString previousSnapshot; protected long previousSnapshotIndex = -1; protected long previousSnapshotTerm = -1; @@ -106,6 +107,11 @@ public abstract class AbstractReplicatedLogImpl implements ReplicatedLog { journal.add(replicatedLogEntry); } + @Override + public void increaseJournalLogCapacity(int amount) { + journal.ensureCapacity(journal.size() + amount); + } + @Override public List getFrom(long logEntryIndex) { return getFrom(logEntryIndex, journal.size()); @@ -208,7 +214,6 @@ public abstract class AbstractReplicatedLogImpl implements ReplicatedLog { @Override public void snapshotCommit() { - snapshottedJournal.clear(); snapshottedJournal = null; previousSnapshotIndex = -1; previousSnapshotTerm = -1; @@ -218,7 +223,6 @@ public abstract class AbstractReplicatedLogImpl implements ReplicatedLog { @Override public void snapshotRollback() { snapshottedJournal.addAll(journal); - journal.clear(); journal = snapshottedJournal; snapshottedJournal = null; diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java index ed6439d8c3..bff2a27797 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java @@ -26,7 +26,7 @@ public interface ConfigParams { * * @return long */ - public long getSnapshotBatchCount(); + long getSnapshotBatchCount(); /** * The interval at which a heart beat message will be sent to the remote @@ -34,7 +34,7 @@ public interface ConfigParams { * * @return FiniteDuration */ - public FiniteDuration getHeartBeatInterval(); + FiniteDuration getHeartBeatInterval(); /** * The interval in which a new election would get triggered if no leader is found @@ -43,7 +43,7 @@ public interface ConfigParams { * * @return FiniteDuration */ - public FiniteDuration getElectionTimeOutInterval(); + FiniteDuration getElectionTimeOutInterval(); /** * The maximum election time variance. The election is scheduled using both @@ -51,10 +51,15 @@ public interface ConfigParams { * * @return int */ - public int getElectionTimeVariance(); + int getElectionTimeVariance(); /** * The size (in bytes) of the snapshot chunk sent from Leader */ - public int getSnapshotChunkSize(); + int getSnapshotChunkSize(); + + /** + * The number of journal log entries to batch on recovery before applying. + */ + int getJournalRecoveryLogBatchSize(); } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java index 9d06f63604..dc4145358a 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java @@ -20,12 +20,14 @@ public class DefaultConfigParamsImpl implements ConfigParams { private static final int SNAPSHOT_BATCH_COUNT = 20000; + private static final int JOURNAL_RECOVERY_LOG_BATCH_SIZE = 1000; + /** * The maximum election time variance */ private static final int ELECTION_TIME_MAX_VARIANCE = 100; - private final int SNAPSHOT_CHUNK_SIZE = 2048 * 1000; //2MB + private static final int SNAPSHOT_CHUNK_SIZE = 2048 * 1000; //2MB /** @@ -39,17 +41,32 @@ public class DefaultConfigParamsImpl implements ConfigParams { new FiniteDuration(100, TimeUnit.MILLISECONDS); + private FiniteDuration heartBeatInterval = HEART_BEAT_INTERVAL; + private long snapshotBatchCount = SNAPSHOT_BATCH_COUNT; + private int journalRecoveryLogBatchSize = JOURNAL_RECOVERY_LOG_BATCH_SIZE; + + public void setHeartBeatInterval(FiniteDuration heartBeatInterval) { + this.heartBeatInterval = heartBeatInterval; + } + + public void setSnapshotBatchCount(long snapshotBatchCount) { + this.snapshotBatchCount = snapshotBatchCount; + } + + public void setJournalRecoveryLogBatchSize(int journalRecoveryLogBatchSize) { + this.journalRecoveryLogBatchSize = journalRecoveryLogBatchSize; + } + @Override public long getSnapshotBatchCount() { - return SNAPSHOT_BATCH_COUNT; + return snapshotBatchCount; } @Override public FiniteDuration getHeartBeatInterval() { - return HEART_BEAT_INTERVAL; + return heartBeatInterval; } - @Override public FiniteDuration getElectionTimeOutInterval() { // returns 2 times the heart beat interval @@ -65,4 +82,9 @@ public class DefaultConfigParamsImpl implements ConfigParams { public int getSnapshotChunkSize() { return SNAPSHOT_CHUNK_SIZE; } + + @Override + public int getJournalRecoveryLogBatchSize() { + return journalRecoveryLogBatchSize; + } } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java index 190f1bd409..66a46ef3bd 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java @@ -20,16 +20,16 @@ import akka.persistence.SnapshotOffer; import akka.persistence.SnapshotSelectionCriteria; import akka.persistence.UntypedPersistentActor; import com.google.common.base.Optional; +import com.google.common.base.Stopwatch; import com.google.protobuf.ByteString; +import org.opendaylight.controller.cluster.raft.base.messages.ApplyLogEntries; import org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot; import org.opendaylight.controller.cluster.raft.base.messages.ApplyState; import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot; import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply; import org.opendaylight.controller.cluster.raft.base.messages.Replicate; import org.opendaylight.controller.cluster.raft.base.messages.SendHeartBeat; -import org.opendaylight.controller.cluster.raft.behaviors.Candidate; import org.opendaylight.controller.cluster.raft.behaviors.Follower; -import org.opendaylight.controller.cluster.raft.behaviors.Leader; import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior; import org.opendaylight.controller.cluster.raft.client.messages.AddRaftPeer; import org.opendaylight.controller.cluster.raft.client.messages.FindLeader; @@ -38,7 +38,6 @@ import org.opendaylight.controller.cluster.raft.client.messages.RemoveRaftPeer; import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply; import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload; import org.opendaylight.controller.protobuff.messages.cluster.raft.AppendEntriesMessages; - import java.io.Serializable; import java.util.Map; @@ -96,7 +95,7 @@ public abstract class RaftActor extends UntypedPersistentActor { * This context should NOT be passed directly to any other actor it is * only to be consumed by the RaftActorBehaviors */ - private RaftActorContext context; + private final RaftActorContext context; /** * The in-memory journal @@ -107,6 +106,10 @@ public abstract class RaftActor extends UntypedPersistentActor { private volatile boolean hasSnapshotCaptureInitiated = false; + private Stopwatch recoveryTimer; + + private int currentRecoveryBatchCount; + public RaftActor(String id, Map peerAddresses) { this(id, peerAddresses, Optional.absent()); } @@ -121,71 +124,169 @@ public abstract class RaftActor extends UntypedPersistentActor { LOG); } - @Override public void onReceiveRecover(Object message) { - if (message instanceof SnapshotOffer) { - LOG.info("SnapshotOffer called.."); - SnapshotOffer offer = (SnapshotOffer) message; - Snapshot snapshot = (Snapshot) offer.snapshot(); - - // Create a replicated log with the snapshot information - // The replicated log can be used later on to retrieve this snapshot - // when we need to install it on a peer - replicatedLog = new ReplicatedLogImpl(snapshot); - - context.setReplicatedLog(replicatedLog); - context.setLastApplied(snapshot.getLastAppliedIndex()); - - LOG.info("Applied snapshot to replicatedLog. " + - "snapshotIndex={}, snapshotTerm={}, journal-size={}", - replicatedLog.snapshotIndex, replicatedLog.snapshotTerm, - replicatedLog.size() - ); + private void initRecoveryTimer() { + if(recoveryTimer == null) { + recoveryTimer = new Stopwatch(); + recoveryTimer.start(); + } + } - // Apply the snapshot to the actors state - applySnapshot(ByteString.copyFrom(snapshot.getState())); + @Override + public void preStart() throws Exception { + LOG.info("Starting recovery for {} with journal batch size {}", persistenceId(), + context.getConfigParams().getJournalRecoveryLogBatchSize()); + super.preStart(); + } + @Override + public void onReceiveRecover(Object message) { + if (message instanceof SnapshotOffer) { + onRecoveredSnapshot((SnapshotOffer)message); } else if (message instanceof ReplicatedLogEntry) { - ReplicatedLogEntry logEntry = (ReplicatedLogEntry) message; - - // Apply State immediately - replicatedLog.append(logEntry); - applyState(null, "recovery", logEntry.getData()); - context.setLastApplied(logEntry.getIndex()); - context.setCommitIndex(logEntry.getIndex()); + onRecoveredJournalLogEntry((ReplicatedLogEntry)message); + } else if (message instanceof ApplyLogEntries) { + onRecoveredApplyLogEntries((ApplyLogEntries)message); } else if (message instanceof DeleteEntries) { replicatedLog.removeFrom(((DeleteEntries) message).getFromIndex()); } else if (message instanceof UpdateElectionTerm) { - context.getTermInformation().update(((UpdateElectionTerm) message).getCurrentTerm(), ((UpdateElectionTerm) message).getVotedFor()); + context.getTermInformation().update(((UpdateElectionTerm) message).getCurrentTerm(), + ((UpdateElectionTerm) message).getVotedFor()); } else if (message instanceof RecoveryCompleted) { - LOG.debug( - "RecoveryCompleted - Switching actor to Follower - " + - "Persistence Id = " + persistenceId() + - " Last index in log:{}, snapshotIndex={}, snapshotTerm={}, " + - "journal-size={}", - replicatedLog.lastIndex(), replicatedLog.snapshotIndex, - replicatedLog.snapshotTerm, replicatedLog.size()); - currentBehavior = switchBehavior(RaftState.Follower); - onStateChanged(); + onRecoveryCompletedMessage(); } } + private void onRecoveredSnapshot(SnapshotOffer offer) { + if(LOG.isDebugEnabled()) { + LOG.debug("SnapshotOffer called.."); + } + + initRecoveryTimer(); + + Snapshot snapshot = (Snapshot) offer.snapshot(); + + // Create a replicated log with the snapshot information + // The replicated log can be used later on to retrieve this snapshot + // when we need to install it on a peer + replicatedLog = new ReplicatedLogImpl(snapshot); + + context.setReplicatedLog(replicatedLog); + context.setLastApplied(snapshot.getLastAppliedIndex()); + context.setCommitIndex(snapshot.getLastAppliedIndex()); + + Stopwatch timer = new Stopwatch(); + timer.start(); + + // Apply the snapshot to the actors state + applyRecoverySnapshot(ByteString.copyFrom(snapshot.getState())); + + timer.stop(); + LOG.info("Recovery snapshot applied for {} in {}: snapshotIndex={}, snapshotTerm={}, journal-size=" + + replicatedLog.size(), persistenceId(), timer.toString(), + replicatedLog.snapshotIndex, replicatedLog.snapshotTerm); + } + + private void onRecoveredJournalLogEntry(ReplicatedLogEntry logEntry) { + if(LOG.isDebugEnabled()) { + LOG.debug("Received ReplicatedLogEntry for recovery: {}", logEntry.getIndex()); + } + + replicatedLog.append(logEntry); + } + + private void onRecoveredApplyLogEntries(ApplyLogEntries ale) { + if(LOG.isDebugEnabled()) { + LOG.debug("Received ApplyLogEntries for recovery, applying to state: {} to {}", + context.getLastApplied() + 1, ale.getToIndex()); + } + + for (long i = context.getLastApplied() + 1; i <= ale.getToIndex(); i++) { + batchRecoveredLogEntry(replicatedLog.get(i)); + } + + context.setLastApplied(ale.getToIndex()); + context.setCommitIndex(ale.getToIndex()); + } + + private void batchRecoveredLogEntry(ReplicatedLogEntry logEntry) { + initRecoveryTimer(); + + int batchSize = context.getConfigParams().getJournalRecoveryLogBatchSize(); + if(currentRecoveryBatchCount == 0) { + startLogRecoveryBatch(batchSize); + } + + appendRecoveredLogEntry(logEntry.getData()); + + if(++currentRecoveryBatchCount >= batchSize) { + endCurrentLogRecoveryBatch(); + } + } + + private void endCurrentLogRecoveryBatch() { + applyCurrentLogRecoveryBatch(); + currentRecoveryBatchCount = 0; + } + + private void onRecoveryCompletedMessage() { + if(currentRecoveryBatchCount > 0) { + endCurrentLogRecoveryBatch(); + } + + onRecoveryComplete(); + + String recoveryTime = ""; + if(recoveryTimer != null) { + recoveryTimer.stop(); + recoveryTime = " in " + recoveryTimer.toString(); + recoveryTimer = null; + } + + LOG.info( + "Recovery completed" + recoveryTime + " - Switching actor to Follower - " + + "Persistence Id = " + persistenceId() + + " Last index in log={}, snapshotIndex={}, snapshotTerm={}, " + + "journal-size={}", + replicatedLog.lastIndex(), replicatedLog.snapshotIndex, + replicatedLog.snapshotTerm, replicatedLog.size()); + + currentBehavior = new Follower(context); + onStateChanged(); + } + @Override public void onReceiveCommand(Object message) { if (message instanceof ApplyState){ ApplyState applyState = (ApplyState) message; - LOG.debug("Applying state for log index {} data {}", - applyState.getReplicatedLogEntry().getIndex(), - applyState.getReplicatedLogEntry().getData()); + if(LOG.isDebugEnabled()) { + LOG.debug("Applying state for log index {} data {}", + applyState.getReplicatedLogEntry().getIndex(), + applyState.getReplicatedLogEntry().getData()); + } applyState(applyState.getClientActor(), applyState.getIdentifier(), applyState.getReplicatedLogEntry().getData()); + } else if (message instanceof ApplyLogEntries){ + ApplyLogEntries ale = (ApplyLogEntries) message; + if(LOG.isDebugEnabled()) { + LOG.debug("Persisting ApplyLogEntries with index={}", ale.getToIndex()); + } + persist(new ApplyLogEntries(ale.getToIndex()), new Procedure() { + @Override + public void apply(ApplyLogEntries param) throws Exception { + } + }); + } else if(message instanceof ApplySnapshot ) { Snapshot snapshot = ((ApplySnapshot) message).getSnapshot(); - LOG.debug("ApplySnapshot called on Follower Actor " + - "snapshotIndex:{}, snapshotTerm:{}", snapshot.getLastAppliedIndex(), - snapshot.getLastAppliedTerm()); + if(LOG.isDebugEnabled()) { + LOG.debug("ApplySnapshot called on Follower Actor " + + "snapshotIndex:{}, snapshotTerm:{}", snapshot.getLastAppliedIndex(), + snapshot.getLastAppliedTerm() + ); + } applySnapshot(ByteString.copyFrom(snapshot.getState())); //clears the followers log, sets the snapshot index to ensure adjusted-index works @@ -253,13 +354,14 @@ public abstract class RaftActor extends UntypedPersistentActor { } else { if (!(message instanceof AppendEntriesMessages.AppendEntries) && !(message instanceof AppendEntriesReply) && !(message instanceof SendHeartBeat)) { - LOG.debug("onReceiveCommand: message:" + message.getClass()); + if(LOG.isDebugEnabled()) { + LOG.debug("onReceiveCommand: message: {}", message.getClass()); + } } - RaftState state = - currentBehavior.handleMessage(getSender(), message); RaftActorBehavior oldBehavior = currentBehavior; - currentBehavior = switchBehavior(state); + currentBehavior = currentBehavior.handleMessage(getSender(), message); + if(oldBehavior != currentBehavior){ onStateChanged(); } @@ -294,7 +396,9 @@ public abstract class RaftActor extends UntypedPersistentActor { context.getReplicatedLog().lastIndex() + 1, context.getTermInformation().getCurrentTerm(), data); - LOG.debug("Persist data {}", replicatedLogEntry); + if(LOG.isDebugEnabled()) { + LOG.debug("Persist data {}", replicatedLogEntry); + } replicatedLog .appendAndPersist(clientActor, identifier, replicatedLogEntry); @@ -359,6 +463,10 @@ public abstract class RaftActor extends UntypedPersistentActor { return context.getLastApplied(); } + protected RaftActorContext getRaftActorContext() { + return context; + } + /** * setPeerAddress sets the address of a known peer at a later time. *

@@ -399,6 +507,38 @@ public abstract class RaftActor extends UntypedPersistentActor { protected abstract void applyState(ActorRef clientActor, String identifier, Object data); + /** + * This method is called during recovery at the start of a batch of state entries. Derived + * classes should perform any initialization needed to start a batch. + */ + protected abstract void startLogRecoveryBatch(int maxBatchSize); + + /** + * This method is called during recovery to append state data to the current batch. This method + * is called 1 or more times after {@link #startRecoveryStateBatch}. + * + * @param data the state data + */ + protected abstract void appendRecoveredLogEntry(Payload data); + + /** + * This method is called during recovery to reconstruct the state of the actor. + * + * @param snapshot A snapshot of the state of the actor + */ + protected abstract void applyRecoverySnapshot(ByteString snapshot); + + /** + * This method is called during recovery at the end of a batch to apply the current batched + * log entries. This method is called after {@link #appendRecoveryLogEntry}. + */ + protected abstract void applyCurrentLogRecoveryBatch(); + + /** + * This method is called when recovery is complete. + */ + protected abstract void onRecoveryComplete(); + /** * This method will be called by the RaftActor when a snapshot needs to be * created. The derived actor should respond with its current state. @@ -411,10 +551,7 @@ public abstract class RaftActor extends UntypedPersistentActor { protected abstract void createSnapshot(); /** - * This method will be called by the RaftActor during recovery to - * reconstruct the state of the actor. - *

- * This method may also be called at any other point during normal + * This method can be called at any other point during normal * operations when the derived actor is out of sync with it's peers * and the only way to bring it in sync is by applying a snapshot * @@ -431,38 +568,6 @@ public abstract class RaftActor extends UntypedPersistentActor { protected void onLeaderChanged(String oldLeader, String newLeader){}; - private RaftActorBehavior switchBehavior(RaftState state) { - if (currentBehavior != null) { - if (currentBehavior.state() == state) { - return currentBehavior; - } - LOG.info("Switching from state " + currentBehavior.state() + " to " - + state); - - try { - currentBehavior.close(); - } catch (Exception e) { - LOG.error(e, - "Failed to close behavior : " + currentBehavior.state()); - } - - } else { - LOG.info("Switching behavior to " + state); - } - RaftActorBehavior behavior = null; - if (state == RaftState.Candidate) { - behavior = new Candidate(context); - } else if (state == RaftState.Follower) { - behavior = new Follower(context); - } else { - behavior = new Leader(context); - } - - - - return behavior; - } - private void trimPersistentData(long sequenceNumber) { // Trim akka snapshots // FIXME : Not sure how exactly the SnapshotSelectionCriteria is applied @@ -483,8 +588,10 @@ public abstract class RaftActor extends UntypedPersistentActor { return null; } String peerAddress = context.getPeerAddress(leaderId); - LOG.debug("getLeaderAddress leaderId = " + leaderId + " peerAddress = " - + peerAddress); + if(LOG.isDebugEnabled()) { + LOG.debug("getLeaderAddress leaderId = {} peerAddress = {}", + leaderId, peerAddress); + } return peerAddress; } @@ -557,8 +664,11 @@ public abstract class RaftActor extends UntypedPersistentActor { public void appendAndPersist(final ActorRef clientActor, final String identifier, final ReplicatedLogEntry replicatedLogEntry) { - context.getLogger().debug( - "Append log entry and persist {} ", replicatedLogEntry); + + if(LOG.isDebugEnabled()) { + LOG.debug("Append log entry and persist {} ", replicatedLogEntry); + } + // FIXME : By adding the replicated log entry to the in-memory journal we are not truly ensuring durability of the logs journal.add(replicatedLogEntry); @@ -569,6 +679,7 @@ public abstract class RaftActor extends UntypedPersistentActor { // of a single command. persist(replicatedLogEntry, new Procedure() { + @Override public void apply(ReplicatedLogEntry evt) throws Exception { // when a snaphsot is being taken, captureSnapshot != null if (hasSnapshotCaptureInitiated == false && @@ -584,10 +695,13 @@ public abstract class RaftActor extends UntypedPersistentActor { lastAppliedTerm = lastAppliedEntry.getTerm(); } - LOG.debug("Snapshot Capture logSize: {}", journal.size()); - LOG.debug("Snapshot Capture lastApplied:{} ", context.getLastApplied()); - LOG.debug("Snapshot Capture lastAppliedIndex:{}", lastAppliedIndex); - LOG.debug("Snapshot Capture lastAppliedTerm:{}", lastAppliedTerm); + if(LOG.isDebugEnabled()) { + LOG.debug("Snapshot Capture logSize: {}", journal.size()); + LOG.debug("Snapshot Capture lastApplied:{} ", + context.getLastApplied()); + LOG.debug("Snapshot Capture lastAppliedIndex:{}", lastAppliedIndex); + LOG.debug("Snapshot Capture lastAppliedTerm:{}", lastAppliedTerm); + } // send a CaptureSnapshot to self to make the expensive operation async. getSelf().tell(new CaptureSnapshot( @@ -630,17 +744,20 @@ public abstract class RaftActor extends UntypedPersistentActor { private long currentTerm = 0; private String votedFor = null; + @Override public long getCurrentTerm() { return currentTerm; } + @Override public String getVotedFor() { return votedFor; } @Override public void update(long currentTerm, String votedFor) { - LOG.debug("Set currentTerm={}, votedFor={}", currentTerm, votedFor); - + if(LOG.isDebugEnabled()) { + LOG.debug("Set currentTerm={}, votedFor={}", currentTerm, votedFor); + } this.currentTerm = currentTerm; this.votedFor = votedFor; } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContextImpl.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContextImpl.java index 25da37105c..e4aef0a844 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContextImpl.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContextImpl.java @@ -59,26 +59,32 @@ public class RaftActorContextImpl implements RaftActorContext { this.LOG = logger; } + @Override public ActorRef actorOf(Props props){ return context.actorOf(props); } + @Override public ActorSelection actorSelection(String path){ return context.actorSelection(path); } + @Override public String getId() { return id; } + @Override public ActorRef getActor() { return actor; } + @Override public ElectionTerm getTermInformation() { return termInformation; } + @Override public long getCommitIndex() { return commitIndex; } @@ -87,6 +93,7 @@ public class RaftActorContextImpl implements RaftActorContext { this.commitIndex = commitIndex; } + @Override public long getLastApplied() { return lastApplied; } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ReplicatedLog.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ReplicatedLog.java index c17f5448c6..85893333c2 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ReplicatedLog.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ReplicatedLog.java @@ -74,6 +74,13 @@ public interface ReplicatedLog { */ void append(ReplicatedLogEntry replicatedLogEntry); + /** + * Optimization method to increase the capacity of the journal log prior to appending entries. + * + * @param amount the amount to increase by + */ + void increaseJournalLogCapacity(int amount); + /** * * @param replicatedLogEntry diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/ApplyLogEntries.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/ApplyLogEntries.java new file mode 100644 index 0000000000..af3c4fd87d --- /dev/null +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/ApplyLogEntries.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.raft.base.messages; + +import java.io.Serializable; + +/** + * ApplyLogEntries serves as a message which is stored in the akka's persistent + * journal. + * During recovery if this message is found, then all in-mem journal entries from + * context.lastApplied to ApplyLogEntries.toIndex are applied to the state + * + * This class is also used as a internal message sent from Behaviour to + * RaftActor to persist the ApplyLogEntries + * + */ +public class ApplyLogEntries implements Serializable { + private final int toIndex; + + public ApplyLogEntries(int toIndex) { + this.toIndex = toIndex; + } + + public int getToIndex() { + return toIndex; + } +} diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java index 86447509d7..eed74bba82 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java @@ -10,11 +10,12 @@ package org.opendaylight.controller.cluster.raft.behaviors; import akka.actor.ActorRef; import akka.actor.Cancellable; +import akka.event.LoggingAdapter; import org.opendaylight.controller.cluster.raft.ClientRequestTracker; import org.opendaylight.controller.cluster.raft.RaftActorContext; -import org.opendaylight.controller.cluster.raft.RaftState; import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry; import org.opendaylight.controller.cluster.raft.SerializationUtils; +import org.opendaylight.controller.cluster.raft.base.messages.ApplyLogEntries; import org.opendaylight.controller.cluster.raft.base.messages.ApplyState; import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout; import org.opendaylight.controller.cluster.raft.messages.AppendEntries; @@ -43,6 +44,11 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { */ protected final RaftActorContext context; + /** + * + */ + protected final LoggingAdapter LOG; + /** * */ @@ -56,6 +62,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { protected AbstractRaftActorBehavior(RaftActorContext context) { this.context = context; + this.LOG = context.getLogger(); } /** @@ -70,7 +77,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { * @param appendEntries The AppendEntries message * @return */ - protected abstract RaftState handleAppendEntries(ActorRef sender, + protected abstract RaftActorBehavior handleAppendEntries(ActorRef sender, AppendEntries appendEntries); @@ -82,19 +89,21 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { * @param appendEntries * @return */ - protected RaftState appendEntries(ActorRef sender, + protected RaftActorBehavior appendEntries(ActorRef sender, AppendEntries appendEntries) { // 1. Reply false if term < currentTerm (§5.1) if (appendEntries.getTerm() < currentTerm()) { - context.getLogger().debug( - "Cannot append entries because sender term " + appendEntries - .getTerm() + " is less than " + currentTerm()); + if(LOG.isDebugEnabled()) { + LOG.debug("Cannot append entries because sender term {} is less than {}", + appendEntries.getTerm(), currentTerm()); + } + sender.tell( new AppendEntriesReply(context.getId(), currentTerm(), false, lastIndex(), lastTerm()), actor() ); - return state(); + return this; } @@ -113,7 +122,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { * @param appendEntriesReply The AppendEntriesReply message * @return */ - protected abstract RaftState handleAppendEntriesReply(ActorRef sender, + protected abstract RaftActorBehavior handleAppendEntriesReply(ActorRef sender, AppendEntriesReply appendEntriesReply); /** @@ -124,11 +133,12 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { * @param requestVote * @return */ - protected RaftState requestVote(ActorRef sender, + protected RaftActorBehavior requestVote(ActorRef sender, RequestVote requestVote) { - - context.getLogger().debug(requestVote.toString()); + if(LOG.isDebugEnabled()) { + LOG.debug(requestVote.toString()); + } boolean grantVote = false; @@ -166,7 +176,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { sender.tell(new RequestVoteReply(currentTerm(), grantVote), actor()); - return state(); + return this; } /** @@ -181,7 +191,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { * @param requestVoteReply The RequestVoteReply message * @return */ - protected abstract RaftState handleRequestVoteReply(ActorRef sender, + protected abstract RaftActorBehavior handleRequestVoteReply(ActorRef sender, RequestVoteReply requestVoteReply); /** @@ -272,6 +282,17 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { return null; } + /** + * Find the client request tracker for a specific logIndex + * + * @param logIndex + * @return + */ + protected ClientRequestTracker removeClientRequestTracker(long logIndex) { + return null; + } + + /** * Find the log index from the previous to last entry in the log * @@ -311,7 +332,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { i < index + 1; i++) { ActorRef clientActor = null; String identifier = null; - ClientRequestTracker tracker = findClientRequestTracker(i); + ClientRequestTracker tracker = removeClientRequestTracker(i); if (tracker != null) { clientActor = tracker.getClientActor(); @@ -329,13 +350,21 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { } else { //if one index is not present in the log, no point in looping // around as the rest wont be present either - context.getLogger().warning( - "Missing index {} from log. Cannot apply state. Ignoring {} to {}", i, i, index ); + LOG.warning( + "Missing index {} from log. Cannot apply state. Ignoring {} to {}", i, i, index); break; } } - context.getLogger().debug("Setting last applied to {}", newLastApplied); + if(LOG.isDebugEnabled()) { + LOG.debug("Setting last applied to {}", newLastApplied); + } context.setLastApplied(newLastApplied); + + // send a message to persist a ApplyLogEntries marker message into akka's persistent journal + // will be used during recovery + //in case if the above code throws an error and this message is not sent, it would be fine + // as the append entries received later would initiate add this message to the journal + actor().tell(new ApplyLogEntries((int) context.getLastApplied()), actor()); } protected Object fromSerializableMessage(Object serializable){ @@ -343,7 +372,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { } @Override - public RaftState handleMessage(ActorRef sender, Object message) { + public RaftActorBehavior handleMessage(ActorRef sender, Object message) { if (message instanceof AppendEntries) { return appendEntries(sender, (AppendEntries) message); } else if (message instanceof AppendEntriesReply) { @@ -353,10 +382,21 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { } else if (message instanceof RequestVoteReply) { return handleRequestVoteReply(sender, (RequestVoteReply) message); } - return state(); + return this; } @Override public String getLeaderId() { return leaderId; } + + protected RaftActorBehavior switchBehavior(RaftActorBehavior behavior) { + LOG.info("Switching from behavior {} to {}", this.state(), behavior.state()); + try { + close(); + } catch (Exception e) { + LOG.error(e, "Failed to close behavior : {}", this.state()); + } + + return behavior; + } } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Candidate.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Candidate.java index bb1927ef23..4a3e2c5d66 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Candidate.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Candidate.java @@ -52,7 +52,9 @@ public class Candidate extends AbstractRaftActorBehavior { peers = context.getPeerAddresses().keySet(); - context.getLogger().debug("Election:Candidate has following peers:"+ peers); + if(LOG.isDebugEnabled()) { + LOG.debug("Election:Candidate has following peers: {}", peers); + } if(peers.size() > 0) { // Votes are required from a majority of the peers including self. @@ -78,21 +80,23 @@ public class Candidate extends AbstractRaftActorBehavior { scheduleElection(electionDuration()); } - @Override protected RaftState handleAppendEntries(ActorRef sender, + @Override protected RaftActorBehavior handleAppendEntries(ActorRef sender, AppendEntries appendEntries) { - context.getLogger().debug(appendEntries.toString()); + if(LOG.isDebugEnabled()) { + LOG.debug(appendEntries.toString()); + } - return state(); + return this; } - @Override protected RaftState handleAppendEntriesReply(ActorRef sender, + @Override protected RaftActorBehavior handleAppendEntriesReply(ActorRef sender, AppendEntriesReply appendEntriesReply) { - return state(); + return this; } - @Override protected RaftState handleRequestVoteReply(ActorRef sender, + @Override protected RaftActorBehavior handleRequestVoteReply(ActorRef sender, RequestVoteReply requestVoteReply) { if (requestVoteReply.isVoteGranted()) { @@ -100,10 +104,10 @@ public class Candidate extends AbstractRaftActorBehavior { } if (voteCount >= votesRequired) { - return RaftState.Leader; + return switchBehavior(new Leader(context)); } - return state(); + return this; } @Override public RaftState state() { @@ -111,7 +115,7 @@ public class Candidate extends AbstractRaftActorBehavior { } @Override - public RaftState handleMessage(ActorRef sender, Object originalMessage) { + public RaftActorBehavior handleMessage(ActorRef sender, Object originalMessage) { Object message = fromSerializableMessage(originalMessage); @@ -119,14 +123,17 @@ public class Candidate extends AbstractRaftActorBehavior { RaftRPC rpc = (RaftRPC) message; - context.getLogger().debug("RaftRPC message received {} my term is {}", rpc.toString(), context.getTermInformation().getCurrentTerm()); + if(LOG.isDebugEnabled()) { + LOG.debug("RaftRPC message received {} my term is {}", rpc, context.getTermInformation().getCurrentTerm()); + } // If RPC request or response contains term T > currentTerm: // set currentTerm = T, convert to follower (§5.1) // This applies to all RPC messages and responses if (rpc.getTerm() > context.getTermInformation().getCurrentTerm()) { context.getTermInformation().updateAndPersist(rpc.getTerm(), null); - return RaftState.Follower; + + return switchBehavior(new Follower(context)); } } @@ -137,11 +144,12 @@ public class Candidate extends AbstractRaftActorBehavior { // ourselves the leader. This gives enough time for a leader // who we do not know about (as a peer) // to send a message to the candidate - return RaftState.Leader; + + return switchBehavior(new Leader(context)); } startNewTerm(); scheduleElection(electionDuration()); - return state(); + return this; } return super.handleMessage(sender, message); @@ -159,7 +167,9 @@ public class Candidate extends AbstractRaftActorBehavior { context.getTermInformation().updateAndPersist(currentTerm + 1, context.getId()); - context.getLogger().debug("Starting new term " + (currentTerm + 1)); + if(LOG.isDebugEnabled()) { + LOG.debug("Starting new term {}", (currentTerm + 1)); + } // Request for a vote // TODO: Retry request for vote if replies do not arrive in a reasonable diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java index 610fdc987f..7ada8b31c5 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java @@ -44,12 +44,13 @@ public class Follower extends AbstractRaftActorBehavior { scheduleElection(electionDuration()); } - @Override protected RaftState handleAppendEntries(ActorRef sender, + @Override protected RaftActorBehavior handleAppendEntries(ActorRef sender, AppendEntries appendEntries) { if(appendEntries.getEntries() != null && appendEntries.getEntries().size() > 0) { - context.getLogger() - .debug(appendEntries.toString()); + if(LOG.isDebugEnabled()) { + LOG.debug(appendEntries.toString()); + } } // TODO : Refactor this method into a bunch of smaller methods @@ -79,9 +80,10 @@ public class Follower extends AbstractRaftActorBehavior { // an entry at prevLogIndex and this follower has no entries in // it's log. - context.getLogger().debug( - "The followers log is empty and the senders prevLogIndex is {}", - appendEntries.getPrevLogIndex()); + if(LOG.isDebugEnabled()) { + LOG.debug("The followers log is empty and the senders prevLogIndex is {}", + appendEntries.getPrevLogIndex()); + } } else if (lastIndex() > -1 && appendEntries.getPrevLogIndex() != -1 @@ -90,9 +92,10 @@ public class Follower extends AbstractRaftActorBehavior { // The follower's log is out of sync because the Leader's // prevLogIndex entry was not found in it's log - context.getLogger().debug( - "The log is not empty but the prevLogIndex {} was not found in it", - appendEntries.getPrevLogIndex()); + if(LOG.isDebugEnabled()) { + LOG.debug("The log is not empty but the prevLogIndex {} was not found in it", + appendEntries.getPrevLogIndex()); + } } else if (lastIndex() > -1 && previousEntry != null @@ -102,10 +105,12 @@ public class Follower extends AbstractRaftActorBehavior { // prevLogIndex entry does exist in the follower's log but it has // a different term in it - context.getLogger().debug( - "Cannot append entries because previous entry term {} is not equal to append entries prevLogTerm {}" - , previousEntry.getTerm() - , appendEntries.getPrevLogTerm()); + if(LOG.isDebugEnabled()) { + LOG.debug( + "Cannot append entries because previous entry term {} is not equal to append entries prevLogTerm {}" + , previousEntry.getTerm() + , appendEntries.getPrevLogTerm()); + } } else { outOfSync = false; } @@ -113,22 +118,26 @@ public class Follower extends AbstractRaftActorBehavior { if (outOfSync) { // We found that the log was out of sync so just send a negative // reply and return - context.getLogger().debug("Follower is out-of-sync, " + - "so sending negative reply, lastIndex():{}, lastTerm():{}", - lastIndex(), lastTerm()); + if(LOG.isDebugEnabled()) { + LOG.debug("Follower is out-of-sync, " + + "so sending negative reply, lastIndex():{}, lastTerm():{}", + lastIndex(), lastTerm() + ); + } sender.tell( new AppendEntriesReply(context.getId(), currentTerm(), false, lastIndex(), lastTerm()), actor() ); - return state(); + return this; } if (appendEntries.getEntries() != null && appendEntries.getEntries().size() > 0) { - context.getLogger().debug( - "Number of entries to be appended = " + appendEntries - .getEntries().size() - ); + if(LOG.isDebugEnabled()) { + LOG.debug( + "Number of entries to be appended = {}", appendEntries.getEntries().size() + ); + } // 3. If an existing entry conflicts with a new one (same index // but different terms), delete the existing entry and all that @@ -151,10 +160,11 @@ public class Follower extends AbstractRaftActorBehavior { continue; } - context.getLogger().debug( - "Removing entries from log starting at " - + matchEntry.getIndex() - ); + if(LOG.isDebugEnabled()) { + LOG.debug( + "Removing entries from log starting at {}", matchEntry.getIndex() + ); + } // Entries do not match so remove all subsequent entries context.getReplicatedLog() @@ -163,26 +173,24 @@ public class Follower extends AbstractRaftActorBehavior { } } - context.getLogger().debug( - "After cleanup entries to be added from = " + (addEntriesFrom - + lastIndex()) - ); + if(LOG.isDebugEnabled()) { + LOG.debug("After cleanup entries to be added from = {}", (addEntriesFrom + lastIndex()) + ); + } // 4. Append any new entries not already in the log for (int i = addEntriesFrom; i < appendEntries.getEntries().size(); i++) { - context.getLogger().info( - "Append entry to log " + appendEntries.getEntries().get( - i).getData() - .toString() - ); - context.getReplicatedLog() - .appendAndPersist(appendEntries.getEntries().get(i)); + if(LOG.isDebugEnabled()) { + LOG.debug("Append entry to log {}", appendEntries.getEntries().get(i).getData()); + } + context.getReplicatedLog().appendAndPersist(appendEntries.getEntries().get(i)); } - context.getLogger().debug( - "Log size is now " + context.getReplicatedLog().size()); + if(LOG.isDebugEnabled()) { + LOG.debug("Log size is now {}", context.getReplicatedLog().size()); + } } @@ -195,8 +203,9 @@ public class Follower extends AbstractRaftActorBehavior { context.getReplicatedLog().lastIndex())); if (prevCommitIndex != context.getCommitIndex()) { - context.getLogger() - .debug("Commit index set to " + context.getCommitIndex()); + if(LOG.isDebugEnabled()) { + LOG.debug("Commit index set to {}", context.getCommitIndex()); + } } // If commitIndex > lastApplied: increment lastApplied, apply @@ -204,34 +213,38 @@ public class Follower extends AbstractRaftActorBehavior { // check if there are any entries to be applied. last-applied can be equal to last-index if (appendEntries.getLeaderCommit() > context.getLastApplied() && context.getLastApplied() < lastIndex()) { - context.getLogger().debug("applyLogToStateMachine, " + - "appendEntries.getLeaderCommit():{}," + - "context.getLastApplied():{}, lastIndex():{}", - appendEntries.getLeaderCommit(), context.getLastApplied(), lastIndex()); + if(LOG.isDebugEnabled()) { + LOG.debug("applyLogToStateMachine, " + + "appendEntries.getLeaderCommit():{}," + + "context.getLastApplied():{}, lastIndex():{}", + appendEntries.getLeaderCommit(), context.getLastApplied(), lastIndex() + ); + } + applyLogToStateMachine(appendEntries.getLeaderCommit()); } sender.tell(new AppendEntriesReply(context.getId(), currentTerm(), true, lastIndex(), lastTerm()), actor()); - return state(); + return this; } - @Override protected RaftState handleAppendEntriesReply(ActorRef sender, + @Override protected RaftActorBehavior handleAppendEntriesReply(ActorRef sender, AppendEntriesReply appendEntriesReply) { - return state(); + return this; } - @Override protected RaftState handleRequestVoteReply(ActorRef sender, + @Override protected RaftActorBehavior handleRequestVoteReply(ActorRef sender, RequestVoteReply requestVoteReply) { - return state(); + return this; } @Override public RaftState state() { return RaftState.Follower; } - @Override public RaftState handleMessage(ActorRef sender, Object originalMessage) { + @Override public RaftActorBehavior handleMessage(ActorRef sender, Object originalMessage) { Object message = fromSerializableMessage(originalMessage); @@ -246,7 +259,7 @@ public class Follower extends AbstractRaftActorBehavior { } if (message instanceof ElectionTimeout) { - return RaftState.Candidate; + return switchBehavior(new Candidate(context)); } else if (message instanceof InstallSnapshot) { InstallSnapshot installSnapshot = (InstallSnapshot) message; @@ -259,17 +272,23 @@ public class Follower extends AbstractRaftActorBehavior { } private void handleInstallSnapshot(ActorRef sender, InstallSnapshot installSnapshot) { - context.getLogger().debug("InstallSnapshot received by follower " + - "datasize:{} , Chunk:{}/{}", installSnapshot.getData().size(), - installSnapshot.getChunkIndex(), installSnapshot.getTotalChunks()); + + if(LOG.isDebugEnabled()) { + LOG.debug("InstallSnapshot received by follower " + + "datasize:{} , Chunk:{}/{}", installSnapshot.getData().size(), + installSnapshot.getChunkIndex(), installSnapshot.getTotalChunks() + ); + } try { if (installSnapshot.getChunkIndex() == installSnapshot.getTotalChunks()) { // this is the last chunk, create a snapshot object and apply snapshotChunksCollected = snapshotChunksCollected.concat(installSnapshot.getData()); - context.getLogger().debug("Last chunk received: snapshotChunksCollected.size:{}", - snapshotChunksCollected.size()); + if(LOG.isDebugEnabled()) { + LOG.debug("Last chunk received: snapshotChunksCollected.size:{}", + snapshotChunksCollected.size()); + } Snapshot snapshot = Snapshot.create(snapshotChunksCollected.toByteArray(), new ArrayList(), @@ -283,8 +302,11 @@ public class Follower extends AbstractRaftActorBehavior { } else { // we have more to go snapshotChunksCollected = snapshotChunksCollected.concat(installSnapshot.getData()); - context.getLogger().debug("Chunk={},snapshotChunksCollected.size:{}", - installSnapshot.getChunkIndex(), snapshotChunksCollected.size()); + + if(LOG.isDebugEnabled()) { + LOG.debug("Chunk={},snapshotChunksCollected.size:{}", + installSnapshot.getChunkIndex(), snapshotChunksCollected.size()); + } } sender.tell(new InstallSnapshotReply( @@ -292,7 +314,7 @@ public class Follower extends AbstractRaftActorBehavior { true), actor()); } catch (Exception e) { - context.getLogger().error("Exception in InstallSnapshot of follower", e); + LOG.error(e, "Exception in InstallSnapshot of follower:"); //send reply with success as false. The chunk will be sent again on failure sender.tell(new InstallSnapshotReply(currentTerm(), context.getId(), installSnapshot.getChunkIndex(), false), actor()); diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Leader.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Leader.java index 90948ffef7..9edba85865 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Leader.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Leader.java @@ -83,22 +83,20 @@ public class Leader extends AbstractRaftActorBehavior { public Leader(RaftActorContext context) { super(context); - if (lastIndex() >= 0) { - context.setCommitIndex(lastIndex()); - } - followers = context.getPeerAddresses().keySet(); for (String followerId : followers) { FollowerLogInformation followerLogInformation = new FollowerLogInformationImpl(followerId, - new AtomicLong(lastIndex()), + new AtomicLong(context.getCommitIndex()), new AtomicLong(-1)); followerToLog.put(followerId, followerLogInformation); } - context.getLogger().debug("Election:Leader has following peers:"+ followers); + if(LOG.isDebugEnabled()) { + LOG.debug("Election:Leader has following peers: {}", followers); + } if (followers.size() > 0) { minReplicationCount = (followers.size() + 1) / 2 + 1; @@ -120,20 +118,23 @@ public class Leader extends AbstractRaftActorBehavior { } - @Override protected RaftState handleAppendEntries(ActorRef sender, + @Override protected RaftActorBehavior handleAppendEntries(ActorRef sender, AppendEntries appendEntries) { - context.getLogger().debug(appendEntries.toString()); + if(LOG.isDebugEnabled()) { + LOG.debug(appendEntries.toString()); + } - return state(); + return this; } - @Override protected RaftState handleAppendEntriesReply(ActorRef sender, + @Override protected RaftActorBehavior handleAppendEntriesReply(ActorRef sender, AppendEntriesReply appendEntriesReply) { if(! appendEntriesReply.isSuccess()) { - context.getLogger() - .debug(appendEntriesReply.toString()); + if(LOG.isDebugEnabled()) { + LOG.debug(appendEntriesReply.toString()); + } } // Update the FollowerLogInformation @@ -142,8 +143,8 @@ public class Leader extends AbstractRaftActorBehavior { followerToLog.get(followerId); if(followerLogInformation == null){ - context.getLogger().error("Unknown follower {}", followerId); - return state(); + LOG.error("Unknown follower {}", followerId); + return this; } if (appendEntriesReply.isSuccess()) { @@ -193,7 +194,17 @@ public class Leader extends AbstractRaftActorBehavior { applyLogToStateMachine(context.getCommitIndex()); } - return state(); + return this; + } + + protected ClientRequestTracker removeClientRequestTracker(long logIndex) { + + ClientRequestTracker toRemove = findClientRequestTracker(logIndex); + if(toRemove != null) { + trackerList.remove(toRemove); + } + + return toRemove; } protected ClientRequestTracker findClientRequestTracker(long logIndex) { @@ -206,16 +217,16 @@ public class Leader extends AbstractRaftActorBehavior { return null; } - @Override protected RaftState handleRequestVoteReply(ActorRef sender, + @Override protected RaftActorBehavior handleRequestVoteReply(ActorRef sender, RequestVoteReply requestVoteReply) { - return state(); + return this; } @Override public RaftState state() { return RaftState.Leader; } - @Override public RaftState handleMessage(ActorRef sender, Object originalMessage) { + @Override public RaftActorBehavior handleMessage(ActorRef sender, Object originalMessage) { Preconditions.checkNotNull(sender, "sender should not be null"); Object message = fromSerializableMessage(originalMessage); @@ -227,13 +238,15 @@ public class Leader extends AbstractRaftActorBehavior { // This applies to all RPC messages and responses if (rpc.getTerm() > context.getTermInformation().getCurrentTerm()) { context.getTermInformation().updateAndPersist(rpc.getTerm(), null); - return RaftState.Follower; + + return switchBehavior(new Follower(context)); } } try { if (message instanceof SendHeartBeat) { - return sendHeartBeat(); + sendHeartBeat(); + return this; } else if(message instanceof SendInstallSnapshot) { installSnapshotIfNeeded(); } else if (message instanceof Replicate) { @@ -260,10 +273,13 @@ public class Leader extends AbstractRaftActorBehavior { if (reply.isSuccess()) { if(followerToSnapshot.isLastChunk(reply.getChunkIndex())) { //this was the last chunk reply - context.getLogger().debug("InstallSnapshotReply received, " + - "last chunk received, Chunk:{}. Follower:{} Setting nextIndex:{}", - reply.getChunkIndex(), followerId, - context.getReplicatedLog().getSnapshotIndex() + 1); + if(LOG.isDebugEnabled()) { + LOG.debug("InstallSnapshotReply received, " + + "last chunk received, Chunk:{}. Follower:{} Setting nextIndex:{}", + reply.getChunkIndex(), followerId, + context.getReplicatedLog().getSnapshotIndex() + 1 + ); + } FollowerLogInformation followerLogInformation = followerToLog.get(followerId); @@ -272,31 +288,38 @@ public class Leader extends AbstractRaftActorBehavior { followerLogInformation.setNextIndex( context.getReplicatedLog().getSnapshotIndex() + 1); mapFollowerToSnapshot.remove(followerId); - context.getLogger().debug("followerToLog.get(followerId).getNextIndex().get()=" + - followerToLog.get(followerId).getNextIndex().get()); + + if(LOG.isDebugEnabled()) { + LOG.debug("followerToLog.get(followerId).getNextIndex().get()=" + + followerToLog.get(followerId).getNextIndex().get()); + } } else { followerToSnapshot.markSendStatus(true); } } else { - context.getLogger().info("InstallSnapshotReply received, " + - "sending snapshot chunk failed, Will retry, Chunk:{}", - reply.getChunkIndex()); + LOG.info("InstallSnapshotReply received, " + + "sending snapshot chunk failed, Will retry, Chunk:{}", + reply.getChunkIndex() + ); followerToSnapshot.markSendStatus(false); } } else { - context.getLogger().error("ERROR!!" + - "FollowerId in InstallSnapshotReply not known to Leader" + - " or Chunk Index in InstallSnapshotReply not matching {} != {}", - followerToSnapshot.getChunkIndex(), reply.getChunkIndex() ); + LOG.error("ERROR!!" + + "FollowerId in InstallSnapshotReply not known to Leader" + + " or Chunk Index in InstallSnapshotReply not matching {} != {}", + followerToSnapshot.getChunkIndex(), reply.getChunkIndex() + ); } } private void replicate(Replicate replicate) { long logIndex = replicate.getReplicatedLogEntry().getIndex(); - context.getLogger().debug("Replicate message " + logIndex); + if(LOG.isDebugEnabled()) { + LOG.debug("Replicate message {}", logIndex); + } // Create a tracker entry we will use this later to notify the // client actor @@ -350,10 +373,13 @@ public class Leader extends AbstractRaftActorBehavior { if (followerNextIndex >= 0 && leaderLastIndex >= followerNextIndex ) { // if the follower is just not starting and leader's index // is more than followers index - context.getLogger().debug("SendInstallSnapshot to follower:{}," + - "follower-nextIndex:{}, leader-snapshot-index:{}, " + - "leader-last-index:{}", followerId, - followerNextIndex, leaderSnapShotIndex, leaderLastIndex); + if(LOG.isDebugEnabled()) { + LOG.debug("SendInstallSnapshot to follower:{}," + + "follower-nextIndex:{}, leader-snapshot-index:{}, " + + "leader-last-index:{}", followerId, + followerNextIndex, leaderSnapShotIndex, leaderLastIndex + ); + } actor().tell(new SendInstallSnapshot(), actor()); } else { @@ -412,11 +438,11 @@ public class Leader extends AbstractRaftActorBehavior { ).toSerializable(), actor() ); - context.getLogger().info("InstallSnapshot sent to follower {}, Chunk: {}/{}", + LOG.info("InstallSnapshot sent to follower {}, Chunk: {}/{}", followerActor.path(), mapFollowerToSnapshot.get(followerId).getChunkIndex(), mapFollowerToSnapshot.get(followerId).getTotalChunks()); } catch (IOException e) { - context.getLogger().error("InstallSnapshot failed for Leader.", e); + LOG.error(e, "InstallSnapshot failed for Leader."); } } @@ -431,16 +457,17 @@ public class Leader extends AbstractRaftActorBehavior { mapFollowerToSnapshot.put(followerId, followerToSnapshot); } ByteString nextChunk = followerToSnapshot.getNextChunk(); - context.getLogger().debug("Leader's snapshot nextChunk size:{}", nextChunk.size()); + if(LOG.isDebugEnabled()) { + LOG.debug("Leader's snapshot nextChunk size:{}", nextChunk.size()); + } return nextChunk; } - private RaftState sendHeartBeat() { + private void sendHeartBeat() { if (followers.size() > 0) { sendAppendEntries(); } - return state(); } private void stopHeartBeat() { @@ -526,8 +553,10 @@ public class Leader extends AbstractRaftActorBehavior { int size = snapshotBytes.size(); totalChunks = ( size / context.getConfigParams().getSnapshotChunkSize()) + ((size % context.getConfigParams().getSnapshotChunkSize()) > 0 ? 1 : 0); - context.getLogger().debug("Snapshot {} bytes, total chunks to send:{}", - size, totalChunks); + if(LOG.isDebugEnabled()) { + LOG.debug("Snapshot {} bytes, total chunks to send:{}", + size, totalChunks); + } } public ByteString getSnapshotBytes() { @@ -591,8 +620,10 @@ public class Leader extends AbstractRaftActorBehavior { } } - context.getLogger().debug("length={}, offset={},size={}", - snapshotLength, start, size); + if(LOG.isDebugEnabled()) { + LOG.debug("length={}, offset={},size={}", + snapshotLength, start, size); + } return getSnapshotBytes().substring(start, start + size); } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/RaftActorBehavior.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/RaftActorBehavior.java index ca2d916ecf..064cd8b88c 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/RaftActorBehavior.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/RaftActorBehavior.java @@ -25,17 +25,18 @@ import org.opendaylight.controller.cluster.raft.RaftState; * differently. */ public interface RaftActorBehavior extends AutoCloseable{ + /** * Handle a message. If the processing of the message warrants a state - * change then a new state should be returned otherwise this method should - * return the state for the current behavior. + * change then a new behavior should be returned otherwise this method should + * return the current behavior. * * @param sender The sender of the message * @param message A message that needs to be processed * - * @return The new state or self (this) + * @return The new behavior or current behavior */ - RaftState handleMessage(ActorRef sender, Object message); + RaftActorBehavior handleMessage(ActorRef sender, Object message); /** * The state associated with a given behavior diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/MockRaftActorContext.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/MockRaftActorContext.java index ca34a34ca4..0d5f644b3d 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/MockRaftActorContext.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/MockRaftActorContext.java @@ -200,6 +200,10 @@ public class MockRaftActorContext implements RaftActorContext { public static class MockPayload extends Payload implements Serializable { private String value = ""; + public MockPayload(){ + + } + public MockPayload(String s) { this.value = s; } @@ -251,4 +255,24 @@ public class MockRaftActorContext implements RaftActorContext { return index; } } + + public static class MockReplicatedLogBuilder { + private ReplicatedLog mockLog = new SimpleReplicatedLog(); + + public MockReplicatedLogBuilder createEntries(int start, int end, int term) { + for (int i=start; i peerAddresses) { - super(id, peerAddresses); + public static final class MockRaftActorCreator implements Creator { + private final Map peerAddresses; + private final String id; + private final Optional config; + + private MockRaftActorCreator(Map peerAddresses, String id, + Optional config) { + this.peerAddresses = peerAddresses; + this.id = id; + this.config = config; + } + + @Override + public MockRaftActor create() throws Exception { + return new MockRaftActor(id, peerAddresses, config); + } } - public static Props props(final String id, final Map peerAddresses){ - return Props.create(new Creator(){ + private final CountDownLatch recoveryComplete = new CountDownLatch(1); + private final List state; - @Override public MockRaftActor create() throws Exception { - return new MockRaftActor(id, peerAddresses); - } - }); + public MockRaftActor(String id, Map peerAddresses, Optional config) { + super(id, peerAddresses, config); + state = new ArrayList<>(); + } + + public void waitForRecoveryComplete() { + try { + assertEquals("Recovery complete", true, recoveryComplete.await(5, TimeUnit.SECONDS)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public List getState() { + return state; + } + + public static Props props(final String id, final Map peerAddresses, + Optional config){ + return Props.create(new MockRaftActorCreator(peerAddresses, id, config)); + } + + @Override protected void applyState(ActorRef clientActor, String identifier, Object data) { + } + + @Override + protected void startLogRecoveryBatch(int maxBatchSize) { + } + + @Override + protected void appendRecoveredLogEntry(Payload data) { + state.add(data); + } + + @Override + protected void applyCurrentLogRecoveryBatch() { + } + + @Override + protected void onRecoveryComplete() { + recoveryComplete.countDown(); } - @Override protected void applyState(ActorRef clientActor, - String identifier, - Object data) { + @Override + protected void applyRecoverySnapshot(ByteString snapshot) { + try { + Object data = toObject(snapshot); + System.out.println("!!!!!applyRecoverySnapshot: "+data); + if (data instanceof List) { + state.addAll((List) data); + } + } catch (Exception e) { + e.printStackTrace(); + } } @Override protected void createSnapshot() { @@ -45,7 +127,6 @@ public class RaftActorTest extends AbstractActorTest { } @Override protected void applySnapshot(ByteString snapshot) { - throw new UnsupportedOperationException("applySnapshot"); } @Override protected void onStateChanged() { @@ -55,6 +136,26 @@ public class RaftActorTest extends AbstractActorTest { return this.getId(); } + private Object toObject(ByteString bs) throws ClassNotFoundException, IOException { + Object obj = null; + ByteArrayInputStream bis = null; + ObjectInputStream ois = null; + try { + bis = new ByteArrayInputStream(bs.toByteArray()); + ois = new ObjectInputStream(bis); + obj = ois.readObject(); + } finally { + if (bis != null) { + bis.close(); + } + if (ois != null) { + ois.close(); + } + } + return obj; + } + + } @@ -64,9 +165,8 @@ public class RaftActorTest extends AbstractActorTest { public RaftActorTestKit(ActorSystem actorSystem, String actorName) { super(actorSystem); - raftActor = this.getSystem() - .actorOf(MockRaftActor.props(actorName, - Collections.EMPTY_MAP), actorName); + raftActor = this.getSystem().actorOf(MockRaftActor.props(actorName, + Collections.EMPTY_MAP, Optional.absent()), actorName); } @@ -76,48 +176,27 @@ public class RaftActorTest extends AbstractActorTest { return new JavaTestKit.EventFilter(Logging.Info.class ) { + @Override protected Boolean run() { return true; } }.from(raftActor.path().toString()) - .message("Switching from state Candidate to Leader") + .message("Switching from behavior Candidate to Leader") .occurrences(1).exec(); } public void findLeader(final String expectedLeader){ + raftActor.tell(new FindLeader(), getRef()); - - new Within(duration("1 seconds")) { - protected void run() { - - raftActor.tell(new FindLeader(), getRef()); - - String s = new ExpectMsg(duration("1 seconds"), - "findLeader") { - // do not put code outside this method, will run afterwards - protected String match(Object in) { - if (in instanceof FindLeaderReply) { - return ((FindLeaderReply) in).getLeaderActor(); - } else { - throw noMatch(); - } - } - }.get();// this extracts the received message - - assertEquals(expectedLeader, s); - - } - - - }; + FindLeaderReply reply = expectMsgClass(duration("5 seconds"), FindLeaderReply.class); + assertEquals("getLeaderActor", expectedLeader, reply.getLeaderActor()); } public ActorRef getRaftActor() { return raftActor; } - } @@ -134,5 +213,104 @@ public class RaftActorTest extends AbstractActorTest { kit.findLeader(kit.getRaftActor().path().toString()); } + @Test + public void testRaftActorRecovery() throws Exception { + new JavaTestKit(getSystem()) {{ + String persistenceId = "follower10"; + + DefaultConfigParamsImpl config = new DefaultConfigParamsImpl(); + // Set the heartbeat interval high to essentially disable election otherwise the test + // may fail if the actor is switched to Leader and the commitIndex is set to the last + // log entry. + config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS)); + + ActorRef followerActor = getSystem().actorOf(MockRaftActor.props(persistenceId, + Collections.EMPTY_MAP, Optional.of(config)), persistenceId); + + watch(followerActor); + + List snapshotUnappliedEntries = new ArrayList<>(); + ReplicatedLogEntry entry1 = new MockRaftActorContext.MockReplicatedLogEntry(1, 4, + new MockRaftActorContext.MockPayload("E")); + snapshotUnappliedEntries.add(entry1); + + int lastAppliedDuringSnapshotCapture = 3; + int lastIndexDuringSnapshotCapture = 4; + + // 4 messages as part of snapshot, which are applied to state + ByteString snapshotBytes = fromObject(Arrays.asList( + new MockRaftActorContext.MockPayload("A"), + new MockRaftActorContext.MockPayload("B"), + new MockRaftActorContext.MockPayload("C"), + new MockRaftActorContext.MockPayload("D"))); + + Snapshot snapshot = Snapshot.create(snapshotBytes.toByteArray(), + snapshotUnappliedEntries, lastIndexDuringSnapshotCapture, 1 , + lastAppliedDuringSnapshotCapture, 1); + MockSnapshotStore.setMockSnapshot(snapshot); + MockSnapshotStore.setPersistenceId(persistenceId); + + // add more entries after snapshot is taken + List entries = new ArrayList<>(); + ReplicatedLogEntry entry2 = new MockRaftActorContext.MockReplicatedLogEntry(1, 5, + new MockRaftActorContext.MockPayload("F")); + ReplicatedLogEntry entry3 = new MockRaftActorContext.MockReplicatedLogEntry(1, 6, + new MockRaftActorContext.MockPayload("G")); + ReplicatedLogEntry entry4 = new MockRaftActorContext.MockReplicatedLogEntry(1, 7, + new MockRaftActorContext.MockPayload("H")); + entries.add(entry2); + entries.add(entry3); + entries.add(entry4); + + int lastAppliedToState = 5; + int lastIndex = 7; + + MockAkkaJournal.addToJournal(5, entry2); + // 2 entries are applied to state besides the 4 entries in snapshot + MockAkkaJournal.addToJournal(6, new ApplyLogEntries(lastAppliedToState)); + MockAkkaJournal.addToJournal(7, entry3); + MockAkkaJournal.addToJournal(8, entry4); + + // kill the actor + followerActor.tell(PoisonPill.getInstance(), null); + expectMsgClass(duration("5 seconds"), Terminated.class); + + unwatch(followerActor); + + //reinstate the actor + TestActorRef ref = TestActorRef.create(getSystem(), + MockRaftActor.props(persistenceId, Collections.EMPTY_MAP, + Optional.of(config))); + + ref.underlyingActor().waitForRecoveryComplete(); + + RaftActorContext context = ref.underlyingActor().getRaftActorContext(); + assertEquals("Journal log size", snapshotUnappliedEntries.size() + entries.size(), + context.getReplicatedLog().size()); + assertEquals("Last index", lastIndex, context.getReplicatedLog().lastIndex()); + assertEquals("Last applied", lastAppliedToState, context.getLastApplied()); + assertEquals("Commit index", lastAppliedToState, context.getCommitIndex()); + assertEquals("Recovered state size", 6, ref.underlyingActor().getState().size()); + }}; + } + private ByteString fromObject(Object snapshot) throws Exception { + ByteArrayOutputStream b = null; + ObjectOutputStream o = null; + try { + b = new ByteArrayOutputStream(); + o = new ObjectOutputStream(b); + o.writeObject(snapshot); + byte[] snapshotBytes = b.toByteArray(); + return ByteString.copyFrom(snapshotBytes); + } finally { + if (o != null) { + o.flush(); + o.close(); + } + if (b != null) { + b.close(); + } + } + } } diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehaviorTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehaviorTest.java index 8068dfbcff..3893018008 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehaviorTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehaviorTest.java @@ -7,7 +7,6 @@ import org.junit.Test; import org.opendaylight.controller.cluster.raft.AbstractActorTest; import org.opendaylight.controller.cluster.raft.MockRaftActorContext; import org.opendaylight.controller.cluster.raft.RaftActorContext; -import org.opendaylight.controller.cluster.raft.RaftState; import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry; import org.opendaylight.controller.cluster.raft.SerializationUtils; import org.opendaylight.controller.cluster.raft.messages.AppendEntries; @@ -22,6 +21,7 @@ import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { @@ -79,12 +79,12 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { RaftActorBehavior behavior = createBehavior(context); // Send an unknown message so that the state of the RaftActor remains unchanged - RaftState expected = behavior.handleMessage(getRef(), "unknown"); + RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown"); - RaftState raftState = + RaftActorBehavior raftBehavior = behavior.handleMessage(getRef(), appendEntries); - assertEquals(expected, raftState); + assertEquals(expected, raftBehavior); // Also expect an AppendEntriesReply to be sent where success is false final Boolean out = new ExpectMsg(duration("1 seconds"), @@ -145,12 +145,12 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { } // Send an unknown message so that the state of the RaftActor remains unchanged - RaftState expected = behavior.handleMessage(getRef(), "unknown"); + RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown"); - RaftState raftState = + RaftActorBehavior raftBehavior = behavior.handleMessage(getRef(), appendEntries); - assertEquals(expected, raftState); + assertEquals(expected, raftBehavior); assertEquals(1, log.size()); @@ -174,11 +174,11 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { RaftActorBehavior behavior = createBehavior( createActorContext(behaviorActor)); - RaftState raftState = behavior.handleMessage(getTestActor(), + RaftActorBehavior raftBehavior = behavior.handleMessage(getTestActor(), new RequestVote(1000, "test", 10000, 999)); - if(behavior.state() != RaftState.Follower){ - assertEquals(RaftState.Follower, raftState); + if(!(behavior instanceof Follower)){ + assertTrue(raftBehavior instanceof Follower); } else { final Boolean out = @@ -228,11 +228,11 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { RaftActorBehavior behavior = createBehavior(actorContext); - RaftState raftState = behavior.handleMessage(getTestActor(), + RaftActorBehavior raftBehavior = behavior.handleMessage(getTestActor(), new RequestVote(1000, "test", 10000, 999)); - if(behavior.state() != RaftState.Follower){ - assertEquals(RaftState.Follower, raftState); + if(!(behavior instanceof Follower)){ + assertTrue(raftBehavior instanceof Follower); } else { final Boolean out = new ExpectMsg(duration("1 seconds"), @@ -309,10 +309,10 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { setLastLogEntry( (MockRaftActorContext) actorContext, 0, 0, p); - RaftState raftState = createBehavior(actorContext) + RaftActorBehavior raftBehavior = createBehavior(actorContext) .handleMessage(actorRef, rpc); - assertEquals(RaftState.Follower, raftState); + assertTrue(raftBehavior instanceof Follower); } protected MockRaftActorContext.SimpleReplicatedLog setLastLogEntry( diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java index d478b17555..a8d47e2c60 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java @@ -9,7 +9,6 @@ import org.junit.Test; import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl; import org.opendaylight.controller.cluster.raft.MockRaftActorContext; import org.opendaylight.controller.cluster.raft.RaftActorContext; -import org.opendaylight.controller.cluster.raft.RaftState; import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout; import org.opendaylight.controller.cluster.raft.messages.AppendEntries; import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply; @@ -109,10 +108,10 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { Candidate candidate = new Candidate(raftActorContext); - RaftState raftState = + RaftActorBehavior raftBehavior = candidate.handleMessage(candidateActor, new ElectionTimeout()); - Assert.assertEquals(RaftState.Leader, raftState); + Assert.assertTrue(raftBehavior instanceof Leader); } @Test @@ -123,10 +122,10 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { Candidate candidate = new Candidate(raftActorContext); - RaftState raftState = + RaftActorBehavior raftBehavior = candidate.handleMessage(candidateActor, new ElectionTimeout()); - Assert.assertEquals(RaftState.Candidate, raftState); + Assert.assertTrue(raftBehavior instanceof Candidate); } @Test @@ -137,9 +136,9 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { Candidate candidate = new Candidate(raftActorContext); - RaftState stateOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true)); + RaftActorBehavior behaviorOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true)); - Assert.assertEquals(RaftState.Leader, stateOnFirstVote); + Assert.assertTrue(behaviorOnFirstVote instanceof Leader); } @@ -151,12 +150,12 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { Candidate candidate = new Candidate(raftActorContext); - RaftState stateOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true)); + RaftActorBehavior behaviorOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true)); - RaftState stateOnSecondVote = candidate.handleMessage(peerActor2, new RequestVoteReply(0, true)); + RaftActorBehavior behaviorOnSecondVote = candidate.handleMessage(peerActor2, new RequestVoteReply(0, true)); - Assert.assertEquals(RaftState.Candidate, stateOnFirstVote); - Assert.assertEquals(RaftState.Leader, stateOnSecondVote); + Assert.assertTrue(behaviorOnFirstVote instanceof Candidate); + Assert.assertTrue(behaviorOnSecondVote instanceof Leader); } diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java index 227d1effa7..edeab11e2a 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java @@ -3,26 +3,36 @@ package org.opendaylight.controller.cluster.raft.behaviors; import akka.actor.ActorRef; import akka.actor.Props; import akka.testkit.JavaTestKit; +import com.google.protobuf.ByteString; import junit.framework.Assert; import org.junit.Test; import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl; import org.opendaylight.controller.cluster.raft.MockRaftActorContext; import org.opendaylight.controller.cluster.raft.RaftActorContext; -import org.opendaylight.controller.cluster.raft.RaftState; import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry; +import org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot; import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout; import org.opendaylight.controller.cluster.raft.messages.AppendEntries; import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply; +import org.opendaylight.controller.cluster.raft.messages.InstallSnapshot; +import org.opendaylight.controller.cluster.raft.messages.InstallSnapshotReply; import org.opendaylight.controller.cluster.raft.messages.RequestVote; import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply; import org.opendaylight.controller.cluster.raft.utils.DoNothingActor; +import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; public class FollowerTest extends AbstractRaftActorBehaviorTest { @@ -34,8 +44,12 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { return new Follower(actorContext); } - @Override protected RaftActorContext createActorContext() { - return new MockRaftActorContext("test", getSystem(), followerActor); + @Override protected RaftActorContext createActorContext() { + return createActorContext(followerActor); + } + + protected RaftActorContext createActorContext(ActorRef actorRef){ + return new MockRaftActorContext("test", getSystem(), actorRef); } @Test @@ -70,10 +84,10 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { Follower follower = new Follower(raftActorContext); - RaftState raftState = + RaftActorBehavior raftBehavior = follower.handleMessage(followerActor, new ElectionTimeout()); - Assert.assertEquals(RaftState.Candidate, raftState); + Assert.assertTrue(raftBehavior instanceof Candidate); } @Test @@ -158,20 +172,21 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { createActorContext(); context.setLastApplied(100); - setLastLogEntry((MockRaftActorContext) context, 1, 100, new MockRaftActorContext.MockPayload("")); + setLastLogEntry((MockRaftActorContext) context, 1, 100, + new MockRaftActorContext.MockPayload("")); ((MockRaftActorContext) context).getReplicatedLog().setSnapshotIndex(99); List entries = Arrays.asList( - (ReplicatedLogEntry) new MockRaftActorContext.MockReplicatedLogEntry(2, 101, - new MockRaftActorContext.MockPayload("foo")) + (ReplicatedLogEntry) new MockRaftActorContext.MockReplicatedLogEntry(2, 101, + new MockRaftActorContext.MockPayload("foo")) ); // The new commitIndex is 101 AppendEntries appendEntries = new AppendEntries(2, "leader-1", 100, 1, entries, 101); - RaftState raftState = + RaftActorBehavior raftBehavior = createBehavior(context).handleMessage(getRef(), appendEntries); assertEquals(101L, context.getLastApplied()); @@ -210,12 +225,12 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { RaftActorBehavior behavior = createBehavior(context); // Send an unknown message so that the state of the RaftActor remains unchanged - RaftState expected = behavior.handleMessage(getRef(), "unknown"); + RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown"); - RaftState raftState = + RaftActorBehavior raftBehavior = behavior.handleMessage(getRef(), appendEntries); - assertEquals(expected, raftState); + assertEquals(expected, raftBehavior); // Also expect an AppendEntriesReply to be sent where success is false final Boolean out = new ExpectMsg(duration("1 seconds"), @@ -286,12 +301,12 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { RaftActorBehavior behavior = createBehavior(context); // Send an unknown message so that the state of the RaftActor remains unchanged - RaftState expected = behavior.handleMessage(getRef(), "unknown"); + RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown"); - RaftState raftState = + RaftActorBehavior raftBehavior = behavior.handleMessage(getRef(), appendEntries); - assertEquals(expected, raftState); + assertEquals(expected, raftBehavior); assertEquals(5, log.last().getIndex() + 1); assertNotNull(log.get(3)); assertNotNull(log.get(4)); @@ -366,12 +381,12 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { RaftActorBehavior behavior = createBehavior(context); // Send an unknown message so that the state of the RaftActor remains unchanged - RaftState expected = behavior.handleMessage(getRef(), "unknown"); + RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown"); - RaftState raftState = + RaftActorBehavior raftBehavior = behavior.handleMessage(getRef(), appendEntries); - assertEquals(expected, raftState); + assertEquals(expected, raftBehavior); // The entry at index 2 will be found out-of-sync with the leader // and will be removed @@ -409,4 +424,140 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { }}; } + + /** + * This test verifies that when InstallSnapshot is received by + * the follower its applied correctly. + * + * @throws Exception + */ + @Test + public void testHandleInstallSnapshot() throws Exception { + JavaTestKit javaTestKit = new JavaTestKit(getSystem()) {{ + + ActorRef leaderActor = getSystem().actorOf(Props.create( + MessageCollectorActor.class)); + + MockRaftActorContext context = (MockRaftActorContext) + createActorContext(getRef()); + + Follower follower = (Follower)createBehavior(context); + + HashMap followerSnapshot = new HashMap<>(); + followerSnapshot.put("1", "A"); + followerSnapshot.put("2", "B"); + followerSnapshot.put("3", "C"); + + ByteString bsSnapshot = toByteString(followerSnapshot); + ByteString chunkData = ByteString.EMPTY; + int offset = 0; + int snapshotLength = bsSnapshot.size(); + int i = 1; + + do { + chunkData = getNextChunk(bsSnapshot, offset); + final InstallSnapshot installSnapshot = + new InstallSnapshot(1, "leader-1", i, 1, + chunkData, i, 3); + follower.handleMessage(leaderActor, installSnapshot); + offset = offset + 50; + i++; + } while ((offset+50) < snapshotLength); + + final InstallSnapshot installSnapshot3 = new InstallSnapshot(1, "leader-1", 3, 1, chunkData, 3, 3); + follower.handleMessage(leaderActor, installSnapshot3); + + String[] matches = new ReceiveWhile(String.class, duration("2 seconds")) { + @Override + protected String match(Object o) throws Exception { + if (o instanceof ApplySnapshot) { + ApplySnapshot as = (ApplySnapshot)o; + if (as.getSnapshot().getLastIndex() != installSnapshot3.getLastIncludedIndex()) { + return "applySnapshot-lastIndex-mismatch"; + } + if (as.getSnapshot().getLastAppliedTerm() != installSnapshot3.getLastIncludedTerm()) { + return "applySnapshot-lastAppliedTerm-mismatch"; + } + if (as.getSnapshot().getLastAppliedIndex() != installSnapshot3.getLastIncludedIndex()) { + return "applySnapshot-lastAppliedIndex-mismatch"; + } + if (as.getSnapshot().getLastTerm() != installSnapshot3.getLastIncludedTerm()) { + return "applySnapshot-lastTerm-mismatch"; + } + return "applySnapshot"; + } + + return "ignoreCase"; + } + }.get(); + + String applySnapshotMatch = ""; + for (String reply: matches) { + if (reply.startsWith("applySnapshot")) { + applySnapshotMatch = reply; + } + } + + assertEquals("applySnapshot", applySnapshotMatch); + + Object messages = executeLocalOperation(leaderActor, "get-all-messages"); + + assertNotNull(messages); + assertTrue(messages instanceof List); + List listMessages = (List) messages; + + int installSnapshotReplyReceivedCount = 0; + for (Object message: listMessages) { + if (message instanceof InstallSnapshotReply) { + ++installSnapshotReplyReceivedCount; + } + } + + assertEquals(3, installSnapshotReplyReceivedCount); + + }}; + } + + public Object executeLocalOperation(ActorRef actor, Object message) throws Exception { + return MessageCollectorActor.getAllMessages(actor); + } + + public ByteString getNextChunk (ByteString bs, int offset){ + int snapshotLength = bs.size(); + int start = offset; + int size = 50; + if (50 > snapshotLength) { + size = snapshotLength; + } else { + if ((start + 50) > snapshotLength) { + size = snapshotLength - start; + } + } + return bs.substring(start, start + size); + } + + private ByteString toByteString(Map state) { + ByteArrayOutputStream b = null; + ObjectOutputStream o = null; + try { + try { + b = new ByteArrayOutputStream(); + o = new ObjectOutputStream(b); + o.writeObject(state); + byte[] snapshotBytes = b.toByteArray(); + return ByteString.copyFrom(snapshotBytes); + } finally { + if (o != null) { + o.flush(); + o.close(); + } + if (b != null) { + b.close(); + } + } + } catch (IOException e) { + org.junit.Assert.fail("IOException in converting Hashmap to Bytestring:" + e); + } + return null; + } } diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/LeaderTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/LeaderTest.java index c4ef51d968..48543d7de2 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/LeaderTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/LeaderTest.java @@ -12,7 +12,6 @@ import org.opendaylight.controller.cluster.raft.FollowerLogInformation; import org.opendaylight.controller.cluster.raft.FollowerLogInformationImpl; import org.opendaylight.controller.cluster.raft.MockRaftActorContext; import org.opendaylight.controller.cluster.raft.RaftActorContext; -import org.opendaylight.controller.cluster.raft.RaftState; import org.opendaylight.controller.cluster.raft.ReplicatedLogImplEntry; import org.opendaylight.controller.cluster.raft.SerializationUtils; import org.opendaylight.controller.cluster.raft.base.messages.ApplyState; @@ -20,9 +19,12 @@ import org.opendaylight.controller.cluster.raft.base.messages.Replicate; import org.opendaylight.controller.cluster.raft.base.messages.SendHeartBeat; import org.opendaylight.controller.cluster.raft.base.messages.SendInstallSnapshot; import org.opendaylight.controller.cluster.raft.messages.AppendEntries; +import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply; import org.opendaylight.controller.cluster.raft.messages.InstallSnapshot; import org.opendaylight.controller.cluster.raft.messages.InstallSnapshotReply; import org.opendaylight.controller.cluster.raft.utils.DoNothingActor; +import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor; +import org.opendaylight.controller.protobuff.messages.cluster.raft.AppendEntriesMessages; import org.opendaylight.controller.protobuff.messages.cluster.raft.InstallSnapshotMessages; import java.io.ByteArrayOutputStream; @@ -51,8 +53,8 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest { // handle message should return the Leader state when it receives an // unknown message - RaftState state = leader.handleMessage(senderActor, "foo"); - Assert.assertEquals(RaftState.Leader, state); + RaftActorBehavior behavior = leader.handleMessage(senderActor, "foo"); + Assert.assertTrue(behavior instanceof Leader); }}; } @@ -122,7 +124,7 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest { actorContext.setPeerAddresses(peerAddresses); Leader leader = new Leader(actorContext); - RaftState raftState = leader + RaftActorBehavior raftBehavior = leader .handleMessage(senderActor, new Replicate(null, null, new MockRaftActorContext.MockReplicatedLogEntry(1, 100, @@ -130,7 +132,7 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest { )); // State should not change - assertEquals(RaftState.Leader, raftState); + assertTrue(raftBehavior instanceof Leader); final String out = new ExpectMsg(duration("1 seconds"), "match hint") { @@ -171,21 +173,16 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest { actorContext.getReplicatedLog().removeFrom(0); - actorContext.getReplicatedLog().append(new ReplicatedLogImplEntry(0, 1, - new MockRaftActorContext.MockPayload("foo"))); - - ReplicatedLogImplEntry entry = - new ReplicatedLogImplEntry(1, 1, - new MockRaftActorContext.MockPayload("foo")); - - actorContext.getReplicatedLog().append(entry); + actorContext.setReplicatedLog( + new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 2, 1) + .build()); Leader leader = new Leader(actorContext); - RaftState raftState = leader - .handleMessage(senderActor, new Replicate(null, "state-id",entry)); + RaftActorBehavior raftBehavior = leader + .handleMessage(senderActor, new Replicate(null, "state-id",actorContext.getReplicatedLog().get(1))); // State should not change - assertEquals(RaftState.Leader, raftState); + assertTrue(raftBehavior instanceof Leader); assertEquals(1, actorContext.getCommitIndex()); @@ -260,10 +257,10 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest { new MockRaftActorContext.MockPayload("D")); // this should invoke a sendinstallsnapshot as followersLastIndex < snapshotIndex - RaftState raftState = leader.handleMessage( + RaftActorBehavior raftBehavior = leader.handleMessage( senderActor, new Replicate(null, "state-id", entry)); - assertEquals(RaftState.Leader, raftState); + assertTrue(raftBehavior instanceof Leader); // we might receive some heartbeat messages, so wait till we SendInstallSnapshot Boolean[] matches = new ReceiveWhile(Boolean.class, duration("2 seconds")) { @@ -335,10 +332,9 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest { new ReplicatedLogImplEntry(newEntryIndex, currentTerm, new MockRaftActorContext.MockPayload("D")); + RaftActorBehavior raftBehavior = leader.handleMessage(senderActor, new SendInstallSnapshot()); - RaftState raftState = leader.handleMessage(senderActor, new SendInstallSnapshot()); - - assertEquals(RaftState.Leader, raftState); + assertTrue(raftBehavior instanceof Leader); // check if installsnapshot gets called with the correct values. final String out = @@ -422,11 +418,11 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest { //clears leaders log actorContext.getReplicatedLog().removeFrom(0); - RaftState raftState = leader.handleMessage(senderActor, + RaftActorBehavior raftBehavior = leader.handleMessage(senderActor, new InstallSnapshotReply(currentTerm, followerActor.path().toString(), leader.getFollowerToSnapshot().getChunkIndex(), true)); - assertEquals(RaftState.Leader, raftState); + assertTrue(raftBehavior instanceof Leader); assertEquals(leader.mapFollowerToSnapshot.size(), 0); assertEquals(leader.followerToLog.size(), 1); @@ -526,6 +522,157 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest { return null; } + public static class ForwardMessageToBehaviorActor extends MessageCollectorActor { + private static AbstractRaftActorBehavior behavior; + + public ForwardMessageToBehaviorActor(){ + + } + + @Override public void onReceive(Object message) throws Exception { + super.onReceive(message); + behavior.handleMessage(sender(), message); + } + + public static void setBehavior(AbstractRaftActorBehavior behavior){ + ForwardMessageToBehaviorActor.behavior = behavior; + } + } + + @Test + public void testLeaderCreatedWithCommitIndexLessThanLastIndex() throws Exception { + new JavaTestKit(getSystem()) {{ + + ActorRef leaderActor = getSystem().actorOf(Props.create(MessageCollectorActor.class)); + + MockRaftActorContext leaderActorContext = + new MockRaftActorContext("leader", getSystem(), leaderActor); + + ActorRef followerActor = getSystem().actorOf(Props.create(ForwardMessageToBehaviorActor.class)); + + MockRaftActorContext followerActorContext = + new MockRaftActorContext("follower", getSystem(), followerActor); + + Follower follower = new Follower(followerActorContext); + + ForwardMessageToBehaviorActor.setBehavior(follower); + + Map peerAddresses = new HashMap(); + peerAddresses.put(followerActor.path().toString(), + followerActor.path().toString()); + + leaderActorContext.setPeerAddresses(peerAddresses); + + leaderActorContext.getReplicatedLog().removeFrom(0); + + //create 3 entries + leaderActorContext.setReplicatedLog( + new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build()); + + leaderActorContext.setCommitIndex(1); + + followerActorContext.getReplicatedLog().removeFrom(0); + + // follower too has the exact same log entries and has the same commit index + followerActorContext.setReplicatedLog( + new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build()); + + followerActorContext.setCommitIndex(1); + + Leader leader = new Leader(leaderActorContext); + + leader.handleMessage(leaderActor, new SendHeartBeat()); + + AppendEntriesMessages.AppendEntries appendEntries = + (AppendEntriesMessages.AppendEntries) MessageCollectorActor + .getFirstMatching(followerActor, AppendEntriesMessages.AppendEntries.class); + + assertNotNull(appendEntries); + + assertEquals(1, appendEntries.getLeaderCommit()); + assertEquals(1, appendEntries.getLogEntries(0).getIndex()); + assertEquals(0, appendEntries.getPrevLogIndex()); + + AppendEntriesReply appendEntriesReply = + (AppendEntriesReply) MessageCollectorActor.getFirstMatching( + leaderActor, AppendEntriesReply.class); + + assertNotNull(appendEntriesReply); + + // follower returns its next index + assertEquals(2, appendEntriesReply.getLogLastIndex()); + assertEquals(1, appendEntriesReply.getLogLastTerm()); + + }}; + } + + + @Test + public void testLeaderCreatedWithCommitIndexLessThanFollowersCommitIndex() throws Exception { + new JavaTestKit(getSystem()) {{ + + ActorRef leaderActor = getSystem().actorOf(Props.create(MessageCollectorActor.class)); + + MockRaftActorContext leaderActorContext = + new MockRaftActorContext("leader", getSystem(), leaderActor); + + ActorRef followerActor = getSystem().actorOf( + Props.create(ForwardMessageToBehaviorActor.class)); + + MockRaftActorContext followerActorContext = + new MockRaftActorContext("follower", getSystem(), followerActor); + + Follower follower = new Follower(followerActorContext); + + ForwardMessageToBehaviorActor.setBehavior(follower); + + Map peerAddresses = new HashMap(); + peerAddresses.put(followerActor.path().toString(), + followerActor.path().toString()); + + leaderActorContext.setPeerAddresses(peerAddresses); + + leaderActorContext.getReplicatedLog().removeFrom(0); + + leaderActorContext.setReplicatedLog( + new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build()); + + leaderActorContext.setCommitIndex(1); + + followerActorContext.getReplicatedLog().removeFrom(0); + + followerActorContext.setReplicatedLog( + new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build()); + + // follower has the same log entries but its commit index > leaders commit index + followerActorContext.setCommitIndex(2); + + Leader leader = new Leader(leaderActorContext); + + leader.handleMessage(leaderActor, new SendHeartBeat()); + + AppendEntriesMessages.AppendEntries appendEntries = + (AppendEntriesMessages.AppendEntries) MessageCollectorActor + .getFirstMatching(followerActor, AppendEntriesMessages.AppendEntries.class); + + assertNotNull(appendEntries); + + assertEquals(1, appendEntries.getLeaderCommit()); + assertEquals(1, appendEntries.getLogEntries(0).getIndex()); + assertEquals(0, appendEntries.getPrevLogIndex()); + + AppendEntriesReply appendEntriesReply = + (AppendEntriesReply) MessageCollectorActor.getFirstMatching( + leaderActor, AppendEntriesReply.class); + + assertNotNull(appendEntriesReply); + + assertEquals(2, appendEntriesReply.getLogLastIndex()); + assertEquals(1, appendEntriesReply.getLogLastTerm()); + + }}; + } + private static class LeaderTestKit extends JavaTestKit { private LeaderTestKit(ActorSystem actorSystem) { diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/MessageCollectorActor.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/MessageCollectorActor.java new file mode 100644 index 0000000000..58928453b4 --- /dev/null +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/MessageCollectorActor.java @@ -0,0 +1,68 @@ +/* + * 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.cluster.raft.utils; + +import akka.actor.ActorRef; +import akka.actor.UntypedActor; +import akka.pattern.Patterns; +import akka.util.Timeout; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; +import scala.concurrent.duration.FiniteDuration; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + + +public class MessageCollectorActor extends UntypedActor { + private List messages = new ArrayList<>(); + + @Override public void onReceive(Object message) throws Exception { + if(message instanceof String){ + if("get-all-messages".equals(message)){ + getSender().tell(messages, getSelf()); + } + } else { + messages.add(message); + } + } + + public static List getAllMessages(ActorRef actor) throws Exception { + FiniteDuration operationDuration = Duration.create(5, TimeUnit.SECONDS); + Timeout operationTimeout = new Timeout(operationDuration); + Future future = Patterns.ask(actor, "get-all-messages", operationTimeout); + + try { + return (List) Await.result(future, operationDuration); + } catch (Exception e) { + throw e; + } + } + + /** + * Get the first message that matches the specified class + * @param actor + * @param clazz + * @return + */ + public static Object getFirstMatching(ActorRef actor, Class clazz) throws Exception { + List allMessages = getAllMessages(actor); + + for(Object message : allMessages){ + if(message.getClass().equals(clazz)){ + return message; + } + } + + return null; + } + +} diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/MockAkkaJournal.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/MockAkkaJournal.java new file mode 100644 index 0000000000..85edc07bc5 --- /dev/null +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/MockAkkaJournal.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.raft.utils; + +import akka.dispatch.Futures; +import akka.japi.Procedure; +import akka.persistence.PersistentConfirmation; +import akka.persistence.PersistentId; +import akka.persistence.PersistentImpl; +import akka.persistence.PersistentRepr; +import akka.persistence.journal.japi.AsyncWriteJournal; +import com.google.common.collect.Maps; +import scala.concurrent.Future; + +import java.util.Map; +import java.util.concurrent.Callable; + +public class MockAkkaJournal extends AsyncWriteJournal { + + private static Map journal = Maps.newHashMap(); + + public static void addToJournal(long sequenceNr, Object message) { + journal.put(sequenceNr, message); + } + + public static void clearJournal() { + journal.clear(); + } + + @Override + public Future doAsyncReplayMessages(final String persistenceId, long fromSequenceNr, + long toSequenceNr, long max, final Procedure replayCallback) { + + return Futures.future(new Callable() { + @Override + public Void call() throws Exception { + for (Map.Entry entry : journal.entrySet()) { + PersistentRepr persistentMessage = + new PersistentImpl(entry.getValue(), entry.getKey(), persistenceId, false, null, null); + replayCallback.apply(persistentMessage); + } + return null; + } + }, context().dispatcher()); + } + + @Override + public Future doAsyncReadHighestSequenceNr(String s, long l) { + return Futures.successful(new Long(0)); + } + + @Override + public Future doAsyncWriteMessages(Iterable persistentReprs) { + return Futures.successful(null); + } + + @Override + public Future doAsyncWriteConfirmations(Iterable persistentConfirmations) { + return Futures.successful(null); + } + + @Override + public Future doAsyncDeleteMessages(Iterable persistentIds, boolean b) { + return Futures.successful(null); + } + + @Override + public Future doAsyncDeleteMessagesTo(String s, long l, boolean b) { + return Futures.successful(null); + } +} diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/MockSnapshotStore.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/MockSnapshotStore.java new file mode 100644 index 0000000000..d70bf920ae --- /dev/null +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/MockSnapshotStore.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.cluster.raft.utils; + +import akka.dispatch.Futures; +import akka.japi.Option; +import akka.persistence.SelectedSnapshot; +import akka.persistence.SnapshotMetadata; +import akka.persistence.SnapshotSelectionCriteria; +import akka.persistence.snapshot.japi.SnapshotStore; +import org.opendaylight.controller.cluster.raft.Snapshot; +import scala.concurrent.Future; + + +public class MockSnapshotStore extends SnapshotStore { + + private static Snapshot mockSnapshot; + private static String persistenceId; + + public static void setMockSnapshot(Snapshot s) { + mockSnapshot = s; + } + + public static void setPersistenceId(String pId) { + persistenceId = pId; + } + + @Override + public Future> doLoadAsync(String s, SnapshotSelectionCriteria snapshotSelectionCriteria) { + if (mockSnapshot == null) { + return Futures.successful(Option.none()); + } + + SnapshotMetadata smd = new SnapshotMetadata(persistenceId, 1, 12345); + SelectedSnapshot selectedSnapshot = + new SelectedSnapshot(smd, mockSnapshot); + return Futures.successful(Option.some(selectedSnapshot)); + } + + @Override + public Future doSaveAsync(SnapshotMetadata snapshotMetadata, Object o) { + return null; + } + + @Override + public void onSaved(SnapshotMetadata snapshotMetadata) throws Exception { + + } + + @Override + public void doDelete(SnapshotMetadata snapshotMetadata) throws Exception { + + } + + @Override + public void doDelete(String s, SnapshotSelectionCriteria snapshotSelectionCriteria) throws Exception { + + } +} diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/resources/application.conf b/opendaylight/md-sal/sal-akka-raft/src/test/resources/application.conf index 2b753004c4..2f53d4a4eb 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/resources/application.conf +++ b/opendaylight/md-sal/sal-akka-raft/src/test/resources/application.conf @@ -1,4 +1,7 @@ akka { + persistence.snapshot-store.plugin = "mock-snapshot-store" + persistence.journal.plugin = "mock-journal" + loglevel = "DEBUG" loggers = ["akka.testkit.TestEventListener", "akka.event.slf4j.Slf4jLogger"] @@ -19,3 +22,17 @@ akka { } } } + +mock-snapshot-store { + # Class name of the plugin. + class = "org.opendaylight.controller.cluster.raft.utils.MockSnapshotStore" + # Dispatcher for the plugin actor. + plugin-dispatcher = "akka.persistence.dispatchers.default-plugin-dispatcher" +} + +mock-journal { + # Class name of the plugin. + class = "org.opendaylight.controller.cluster.raft.utils.MockAkkaJournal" + # Dispatcher for the plugin actor. + plugin-dispatcher = "akka.persistence.dispatchers.default-plugin-dispatcher" +} diff --git a/opendaylight/md-sal/sal-binding-api/pom.xml b/opendaylight/md-sal/sal-binding-api/pom.xml index 7f45fb458b..690957ed0b 100644 --- a/opendaylight/md-sal/sal-binding-api/pom.xml +++ b/opendaylight/md-sal/sal-binding-api/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-binding-api bundle diff --git a/opendaylight/md-sal/sal-binding-broker/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index 539f9d45c8..7482c52fdd 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-binding-broker-impl bundle @@ -70,7 +70,7 @@ org.opendaylight.yangtools binding-data-codec - 0.6.2-SNAPSHOT + 0.7.0-SNAPSHOT org.opendaylight.yangtools diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingTranslatedTransactionChain.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingTranslatedTransactionChain.java index 73c81ca3a3..36b7a0f5f2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingTranslatedTransactionChain.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingTranslatedTransactionChain.java @@ -34,15 +34,15 @@ final class BindingTranslatedTransactionChain implements BindingTransactionChain private final DOMTransactionChain delegate; private final BindingToNormalizedNodeCodec codec; - private final DelegateChainListener delegatingListener; - private final TransactionChainListener listener; + private final DelegateChainListener domListener; + private final TransactionChainListener bindingListener; public BindingTranslatedTransactionChain(final DOMDataBroker chainFactory, final BindingToNormalizedNodeCodec codec, final TransactionChainListener listener) { Preconditions.checkNotNull(chainFactory, "DOM Transaction chain factory must not be null"); - this.delegatingListener = new DelegateChainListener(); - this.listener = listener; - this.delegate = chainFactory.createTransactionChain(listener); + this.domListener = new DelegateChainListener(); + this.bindingListener = listener; + this.delegate = chainFactory.createTransactionChain(domListener); this.codec = codec; } @@ -110,7 +110,7 @@ final class BindingTranslatedTransactionChain implements BindingTransactionChain * chain, so we are not changing any of our internal state * to mark that we failed. */ - this.delegatingListener.onTransactionChainFailed(this, tx, t); + this.bindingListener.onTransactionChainFailed(this, tx, t); } @Override @@ -141,7 +141,7 @@ final class BindingTranslatedTransactionChain implements BindingTransactionChain public void onTransactionChainSuccessful(final TransactionChain chain) { Preconditions.checkState(delegate.equals(chain), "Illegal state - listener for %s was invoked for incorrect chain %s.", delegate, chain); - listener.onTransactionChainSuccessful(BindingTranslatedTransactionChain.this); + bindingListener.onTransactionChainSuccessful(BindingTranslatedTransactionChain.this); } } diff --git a/opendaylight/md-sal/sal-binding-config/pom.xml b/opendaylight/md-sal/sal-binding-config/pom.xml index 2342745f92..68af914f57 100644 --- a/opendaylight/md-sal/sal-binding-config/pom.xml +++ b/opendaylight/md-sal/sal-binding-config/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-binding-config bundle diff --git a/opendaylight/md-sal/sal-binding-dom-it/pom.xml b/opendaylight/md-sal/sal-binding-dom-it/pom.xml index 7a66c41196..fefd85b44b 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-dom-it/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-binding-dom-it jar @@ -52,7 +52,7 @@ org.opendaylight.controller sal-test-model - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/md/sal/binding/data/ListProcessingAndOrderingTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/md/sal/binding/data/ListProcessingAndOrderingTest.java index aa136451a1..3053b057b2 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/md/sal/binding/data/ListProcessingAndOrderingTest.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/md/sal/binding/data/ListProcessingAndOrderingTest.java @@ -57,14 +57,14 @@ import com.google.common.util.concurrent.ListenableFuture; public class ListProcessingAndOrderingTest extends AbstractDataServiceTest { private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier DOM_UNORDERED_LIST_PATH = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier - .builder(Lists.QNAME).node(UnorderedContainer.QNAME).node(UnorderedList.QNAME).build(); + .builder().node(Lists.QNAME).node(UnorderedContainer.QNAME).node(UnorderedList.QNAME).build(); private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier DOM_ORDERED_LIST_PATH = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier - .builder(Lists.QNAME).node(OrderedContainer.QNAME).node(OrderedList.QNAME).build(); + .builder().node(Lists.QNAME).node(OrderedContainer.QNAME).node(OrderedList.QNAME).build(); private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier DOM_UNKEYED_LIST_PATH = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier - .builder(Lists.QNAME).node(UnkeyedContainer.QNAME).node(UnkeyedList.QNAME).build(); + .builder().node(Lists.QNAME).node(UnkeyedContainer.QNAME).node(UnkeyedList.QNAME).build(); private static final InstanceIdentifier UNORDERED_CONTAINER_PATH = InstanceIdentifier.builder(Lists.class).child(UnorderedContainer.class).build(); private static final InstanceIdentifier ORDERED_CONTAINER_PATH = InstanceIdentifier.builder(Lists.class).child(OrderedContainer.class).build(); diff --git a/opendaylight/md-sal/sal-binding-it/pom.xml b/opendaylight/md-sal/sal-binding-it/pom.xml index 1912462cf0..009adb6d4a 100644 --- a/opendaylight/md-sal/sal-binding-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-it/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-binding-it diff --git a/opendaylight/md-sal/sal-binding-util/pom.xml b/opendaylight/md-sal/sal-binding-util/pom.xml index 229c54f557..efe2e84507 100644 --- a/opendaylight/md-sal/sal-binding-util/pom.xml +++ b/opendaylight/md-sal/sal-binding-util/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-binding-util bundle diff --git a/opendaylight/md-sal/sal-clustering-commons/pom.xml b/opendaylight/md-sal/sal-clustering-commons/pom.xml index d12f867ac5..54a1fe7a95 100644 --- a/opendaylight/md-sal/sal-clustering-commons/pom.xml +++ b/opendaylight/md-sal/sal-clustering-commons/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-clustering-commons diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedActor.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedActor.java index ef56d02a2e..cf37cbdd00 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedActor.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedActor.java @@ -17,7 +17,9 @@ public abstract class AbstractUntypedActor extends UntypedActor { Logging.getLogger(getContext().system(), this); public AbstractUntypedActor() { - LOG.debug("Actor created {}", getSelf()); + if(LOG.isDebugEnabled()) { + LOG.debug("Actor created {}", getSelf()); + } getContext(). system(). actorSelection("user/termination-monitor"). @@ -27,11 +29,13 @@ public abstract class AbstractUntypedActor extends UntypedActor { @Override public void onReceive(Object message) throws Exception { final String messageType = message.getClass().getSimpleName(); - LOG.debug("Received message {}", messageType); - + if(LOG.isDebugEnabled()) { + LOG.debug("Received message {}", messageType); + } handleReceive(message); - - LOG.debug("Done handling message {}", messageType); + if(LOG.isDebugEnabled()) { + LOG.debug("Done handling message {}", messageType); + } } protected abstract void handleReceive(Object message) throws Exception; @@ -41,7 +45,9 @@ public abstract class AbstractUntypedActor extends UntypedActor { } protected void unknownMessage(Object message) throws Exception { - LOG.debug("Received unhandled message {}", message); + if(LOG.isDebugEnabled()) { + LOG.debug("Received unhandled message {}", message); + } unhandled(message); } } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedPersistentActor.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedPersistentActor.java new file mode 100644 index 0000000000..36b2866210 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedPersistentActor.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.cluster.common.actor; + +import akka.event.Logging; +import akka.event.LoggingAdapter; +import akka.persistence.UntypedPersistentActor; + +public abstract class AbstractUntypedPersistentActor extends UntypedPersistentActor { + + protected final LoggingAdapter LOG = + Logging.getLogger(getContext().system(), this); + + public AbstractUntypedPersistentActor() { + if(LOG.isDebugEnabled()) { + LOG.debug("Actor created {}", getSelf()); + } + getContext(). + system(). + actorSelection("user/termination-monitor"). + tell(new Monitor(getSelf()), getSelf()); + + } + + + @Override public void onReceiveCommand(Object message) throws Exception { + final String messageType = message.getClass().getSimpleName(); + if(LOG.isDebugEnabled()) { + LOG.debug("Received message {}", messageType); + } + handleCommand(message); + if(LOG.isDebugEnabled()) { + LOG.debug("Done handling message {}", messageType); + } + + } + + @Override public void onReceiveRecover(Object message) throws Exception { + final String messageType = message.getClass().getSimpleName(); + if(LOG.isDebugEnabled()) { + LOG.debug("Received message {}", messageType); + } + handleRecover(message); + if(LOG.isDebugEnabled()) { + LOG.debug("Done handling message {}", messageType); + } + + } + + protected abstract void handleRecover(Object message) throws Exception; + + protected abstract void handleCommand(Object message) throws Exception; + + protected void ignoreMessage(Object message) { + LOG.debug("Unhandled message {} ", message); + } + + protected void unknownMessage(Object message) throws Exception { + if(LOG.isDebugEnabled()) { + LOG.debug("Received unhandled message {}", message); + } + unhandled(message); + } +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedPersistentActorWithMetering.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedPersistentActorWithMetering.java new file mode 100644 index 0000000000..365a5bd015 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedPersistentActorWithMetering.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.common.actor; + +/** + * Actor with its behaviour metered. Metering is enabled by configuration. + */ +public abstract class AbstractUntypedPersistentActorWithMetering extends AbstractUntypedPersistentActor { + + public AbstractUntypedPersistentActorWithMetering() { + if (isMetricsCaptureEnabled()) + getContext().become(new MeteringBehavior(this)); + } + + private boolean isMetricsCaptureEnabled(){ + CommonConfig config = new CommonConfig(getContext().system().settings().config()); + return config.isMetricCaptureEnabled(); + } +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeToNormalizedNodeBuilder.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeToNormalizedNodeBuilder.java deleted file mode 100644 index 03d632b61f..0000000000 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeToNormalizedNodeBuilder.java +++ /dev/null @@ -1,856 +0,0 @@ -/* - * - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - * - */ - -package org.opendaylight.controller.cluster.datastore.node; - -import com.google.common.base.Preconditions; -import com.google.common.collect.FluentIterable; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node; -import org.opendaylight.yangtools.concepts.Identifiable; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder; -import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; -import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; -import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; -import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; -import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import static com.google.common.base.Preconditions.checkArgument; - -/** - * NormalizedNodeBuilder is a builder that walks through a tree like structure and constructs a - * NormalizedNode from it. - *

- * A large part of this code has been copied over from a similar class in sal-common-impl which was - * originally supposed to convert a CompositeNode to NormalizedNode - * - * @param - */ -public abstract class NodeToNormalizedNodeBuilder - implements Identifiable { - - private final T identifier; - - protected static final Logger logger = LoggerFactory - .getLogger(NodeToNormalizedNodeBuilder.class); - - @Override - public T getIdentifier() { - return identifier; - } - - ; - - protected NodeToNormalizedNodeBuilder(final T identifier) { - super(); - this.identifier = identifier; - - } - - /** - * @return Should return true if the node that this operation corresponds to is a mixin - */ - public boolean isMixin() { - return false; - } - - - /** - * @return Should return true if the node that this operation corresponds to has a 'key' - * associated with it. This is typically true for a list-item or leaf-list entry in yang - */ - public boolean isKeyedEntry() { - return false; - } - - protected Set getQNameIdentifiers() { - return Collections.singleton(identifier.getNodeType()); - } - - public abstract NodeToNormalizedNodeBuilder getChild( - final PathArgument child); - - public abstract NodeToNormalizedNodeBuilder getChild(QName child); - - public abstract NormalizedNode normalize(QName nodeType, Node node); - - - - private static abstract class SimpleTypeNormalization - extends NodeToNormalizedNodeBuilder { - - protected SimpleTypeNormalization(final T identifier) { - super(identifier); - } - - @Override - public NormalizedNode normalize(final QName nodeType, - final Node node) { - checkArgument(node != null); - return normalizeImpl(nodeType, node); - } - - protected abstract NormalizedNode normalizeImpl(QName nodeType, - Node node); - - @Override - public NodeToNormalizedNodeBuilder getChild( - final PathArgument child) { - return null; - } - - @Override - public NodeToNormalizedNodeBuilder getChild(final QName child) { - return null; - } - - @Override - public NormalizedNode createDefault( - final PathArgument currentArg) { - // TODO Auto-generated method stub - return null; - } - - } - - - private static final class LeafNormalization extends - SimpleTypeNormalization { - - private final LeafSchemaNode schema; - - protected LeafNormalization(final LeafSchemaNode schema, final NodeIdentifier identifier) { - super(identifier); - this.schema = schema; - } - - @Override - protected NormalizedNode normalizeImpl(final QName nodeType, - final Node node) { - Object value = NodeValueCodec.toTypeSafeValue(this.schema, this.schema.getType(), node); - return ImmutableNodes.leafNode(nodeType, value); - - } - - } - - - private static final class LeafListEntryNormalization extends - SimpleTypeNormalization { - - private final LeafListSchemaNode schema; - - public LeafListEntryNormalization(final LeafListSchemaNode potential) { - super(new NodeWithValue(potential.getQName(), null)); - this.schema = potential; - } - - @Override - protected NormalizedNode normalizeImpl(final QName nodeType, - final Node node) { - final Object data = node.getValue(); - if (data == null) { - Preconditions.checkArgument(false, - "No data available in leaf list entry for " + nodeType); - } - - Object value = NodeValueCodec.toTypeSafeValue(this.schema, this.schema.getType(), node); - - NodeWithValue nodeId = new NodeWithValue(nodeType, value); - return Builders.leafSetEntryBuilder().withNodeIdentifier(nodeId) - .withValue(value).build(); - } - - - @Override - public boolean isKeyedEntry() { - return true; - } - } - - - private static abstract class NodeToNormalizationNodeOperation - extends NodeToNormalizedNodeBuilder { - - protected NodeToNormalizationNodeOperation(final T identifier) { - super(identifier); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - @Override - public final NormalizedNodeContainer normalize( - final QName nodeType, final Node node) { - checkArgument(node != null); - - if (!node.getType().equals(AugmentationNode.class.getSimpleName()) - && !node.getType().equals(ContainerNode.class.getSimpleName()) - && !node.getType().equals(MapNode.class.getSimpleName())) { - checkArgument(nodeType != null); - } - - NormalizedNodeContainerBuilder builder = createBuilder(node); - - Set> usedMixins = new HashSet<>(); - - logNode(node); - - if (node.getChildCount() == 0 && ( - node.getType().equals(LeafSetEntryNode.class.getSimpleName()) - || node.getType().equals(LeafNode.class.getSimpleName()))) { - PathArgument childPathArgument = - NodeIdentifierFactory.getArgument(node.getPath()); - - final NormalizedNode child; - if (childPathArgument instanceof NodeWithValue) { - final NodeWithValue nodeWithValue = - new NodeWithValue(childPathArgument.getNodeType(), - node.getValue()); - child = - Builders.leafSetEntryBuilder() - .withNodeIdentifier(nodeWithValue) - .withValue(node.getValue()).build(); - } else { - child = - ImmutableNodes.leafNode(childPathArgument.getNodeType(), - node.getValue()); - } - builder.addChild(child); - } - - final List children = node.getChildList(); - for (Node nodeChild : children) { - - PathArgument childPathArgument = - NodeIdentifierFactory.getArgument(nodeChild.getPath()); - - QName childNodeType = null; - NodeToNormalizedNodeBuilder childOp = null; - - if (childPathArgument instanceof AugmentationIdentifier) { - childOp = getChild(childPathArgument); - checkArgument(childOp instanceof AugmentationNormalization, childPathArgument); - } else { - childNodeType = childPathArgument.getNodeType(); - childOp = getChild(childNodeType); - } - // We skip unknown nodes if this node is mixin since - // it's nodes and parent nodes are interleaved - if (childOp == null && isMixin()) { - continue; - } else if (childOp == null) { - logger.error( - "childOp is null and this operation is not a mixin : this = {}", - this.toString()); - } - - checkArgument(childOp != null, - "Node %s is not allowed inside %s", - childNodeType, getIdentifier()); - - if (childOp.isMixin()) { - if (usedMixins.contains(childOp)) { - // We already run / processed that mixin, so to avoid - // duplicate we are - // skipping next nodes. - continue; - } - // builder.addChild(childOp.normalize(nodeType, treeCacheNode)); - final NormalizedNode childNode = - childOp.normalize(childNodeType, nodeChild); - if (childNode != null) - builder.addChild(childNode); - usedMixins.add(childOp); - } else { - final NormalizedNode childNode = - childOp.normalize(childNodeType, nodeChild); - if (childNode != null) - builder.addChild(childNode); - } - } - - - try { - return (NormalizedNodeContainer) builder.build(); - } catch (Exception e) { - return null; - } - - } - - private void logNode(Node node) { - //let us find out the type of the node - logger.debug("We got a {} , with identifier {} with {} children", - node.getType(), node.getPath(), - node.getChildList()); - } - - @SuppressWarnings("rawtypes") - protected abstract NormalizedNodeContainerBuilder createBuilder( - final Node node); - - } - - - private static abstract class DataContainerNormalizationOperation - extends NodeToNormalizationNodeOperation { - - private final DataNodeContainer schema; - private final Map> byQName; - private final Map> byArg; - - protected DataContainerNormalizationOperation(final T identifier, - final DataNodeContainer schema) { - super(identifier); - this.schema = schema; - this.byArg = new ConcurrentHashMap<>(); - this.byQName = new ConcurrentHashMap<>(); - } - - @Override - public NodeToNormalizedNodeBuilder getChild( - final PathArgument child) { - NodeToNormalizedNodeBuilder potential = byArg.get(child); - if (potential != null) { - return potential; - } - potential = fromSchema(schema, child); - return register(potential); - } - - @Override - public NodeToNormalizedNodeBuilder getChild(final QName child) { - if (child == null) { - return null; - } - - NodeToNormalizedNodeBuilder potential = byQName.get(child); - if (potential != null) { - return potential; - } - potential = fromSchemaAndPathArgument(schema, child); - return register(potential); - } - - private NodeToNormalizedNodeBuilder register( - final NodeToNormalizedNodeBuilder potential) { - if (potential != null) { - byArg.put(potential.getIdentifier(), potential); - for (QName qName : potential.getQNameIdentifiers()) { - byQName.put(qName, potential); - } - } - return potential; - } - - } - - - private static final class ListItemNormalization extends - DataContainerNormalizationOperation { - - private final List keyDefinition; - private final ListSchemaNode schemaNode; - - protected ListItemNormalization( - final NodeIdentifierWithPredicates identifier, - final ListSchemaNode schema) { - super(identifier, schema); - this.schemaNode = schema; - keyDefinition = schema.getKeyDefinition(); - } - - @Override - protected NormalizedNodeContainerBuilder createBuilder( - final Node node) { - NodeIdentifierWithPredicates nodeIdentifierWithPredicates = - (NodeIdentifierWithPredicates) NodeIdentifierFactory - .createPathArgument(node - .getPath(), schemaNode); - return Builders.mapEntryBuilder() - .withNodeIdentifier( - nodeIdentifierWithPredicates - ); - } - - @Override - public NormalizedNode createDefault( - final PathArgument currentArg) { - DataContainerNodeAttrBuilder - builder = - Builders.mapEntryBuilder().withNodeIdentifier( - (NodeIdentifierWithPredicates) currentArg); - for (Entry keyValue : ((NodeIdentifierWithPredicates) currentArg) - .getKeyValues().entrySet()) { - if (keyValue.getValue() == null) { - throw new NullPointerException( - "Null value found for path : " - + currentArg); - } - builder.addChild(Builders.leafBuilder() - // - .withNodeIdentifier(new NodeIdentifier(keyValue.getKey())) - .withValue(keyValue.getValue()).build()); - } - return builder.build(); - } - - - @Override - public boolean isKeyedEntry() { - return true; - } - } - - - private static final class ContainerNormalization extends - DataContainerNormalizationOperation { - - protected ContainerNormalization(final ContainerSchemaNode schema) { - super(new NodeIdentifier(schema.getQName()), schema); - } - - @Override - protected NormalizedNodeContainerBuilder createBuilder( - final Node node) { - return Builders.containerBuilder() - .withNodeIdentifier(getIdentifier()); - } - - @Override - public NormalizedNode createDefault( - final PathArgument currentArg) { - return Builders.containerBuilder() - .withNodeIdentifier((NodeIdentifier) currentArg).build(); - } - - } - - - private static abstract class MixinNormalizationOp - extends NodeToNormalizationNodeOperation { - - protected MixinNormalizationOp(final T identifier) { - super(identifier); - } - - @Override - public final boolean isMixin() { - return true; - } - - } - - - private static final class LeafListMixinNormalization extends - MixinNormalizationOp { - - private final NodeToNormalizedNodeBuilder innerOp; - - public LeafListMixinNormalization(final LeafListSchemaNode potential) { - super(new NodeIdentifier(potential.getQName())); - innerOp = new LeafListEntryNormalization(potential); - } - - @Override - protected NormalizedNodeContainerBuilder createBuilder( - final Node node) { - return Builders.leafSetBuilder() - .withNodeIdentifier(getIdentifier()); - } - - @Override - public NormalizedNode createDefault( - final PathArgument currentArg) { - return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier()) - .build(); - } - - @Override - public NodeToNormalizedNodeBuilder getChild( - final PathArgument child) { - if (child instanceof NodeWithValue) { - return innerOp; - } - return null; - } - - @Override - public NodeToNormalizedNodeBuilder getChild(final QName child) { - if (getIdentifier().getNodeType().equals(child)) { - return innerOp; - } - return null; - } - - } - - - private static final class AugmentationNormalization extends - MixinNormalizationOp { - - private final Map> byQName; - private final Map> byArg; - - public AugmentationNormalization(final AugmentationSchema augmentation, - final DataNodeContainer schema) { - super(augmentationIdentifierFrom(augmentation)); - - ImmutableMap.Builder> - byQNameBuilder = - ImmutableMap.builder(); - ImmutableMap.Builder> - byArgBuilder = - ImmutableMap.builder(); - - for (DataSchemaNode augNode : augmentation.getChildNodes()) { - DataSchemaNode resolvedNode = - schema.getDataChildByName(augNode.getQName()); - NodeToNormalizedNodeBuilder resolvedOp = - fromDataSchemaNode(resolvedNode); - byArgBuilder.put(resolvedOp.getIdentifier(), resolvedOp); - for (QName resQName : resolvedOp.getQNameIdentifiers()) { - byQNameBuilder.put(resQName, resolvedOp); - } - } - byQName = byQNameBuilder.build(); - byArg = byArgBuilder.build(); - - } - - @Override - public NodeToNormalizedNodeBuilder getChild( - final PathArgument child) { - return byArg.get(child); - } - - @Override - public NodeToNormalizedNodeBuilder getChild(final QName child) { - return byQName.get(child); - } - - @Override - protected Set getQNameIdentifiers() { - return getIdentifier().getPossibleChildNames(); - } - - @SuppressWarnings("rawtypes") - @Override - protected NormalizedNodeContainerBuilder createBuilder( - final Node node) { - return Builders.augmentationBuilder() - .withNodeIdentifier(getIdentifier()); - } - - @Override - public NormalizedNode createDefault( - final PathArgument currentArg) { - return Builders.augmentationBuilder() - .withNodeIdentifier(getIdentifier()) - .build(); - } - - } - - - private static final class ListMixinNormalization extends - MixinNormalizationOp { - - private final ListItemNormalization innerNode; - - public ListMixinNormalization(final ListSchemaNode list) { - super(new NodeIdentifier(list.getQName())); - this.innerNode = - new ListItemNormalization(new NodeIdentifierWithPredicates( - list.getQName(), Collections.emptyMap()), - list); - } - - @SuppressWarnings("rawtypes") - @Override - protected NormalizedNodeContainerBuilder createBuilder( - final Node node) { - return Builders.mapBuilder().withNodeIdentifier(getIdentifier()); - } - - @Override - public NormalizedNode createDefault( - final PathArgument currentArg) { - return Builders.mapBuilder().withNodeIdentifier(getIdentifier()) - .build(); - } - - @Override - public NodeToNormalizedNodeBuilder getChild( - final PathArgument child) { - if (child.getNodeType().equals(getIdentifier().getNodeType())) { - return innerNode; - } - return null; - } - - @Override - public NodeToNormalizedNodeBuilder getChild(final QName child) { - if (getIdentifier().getNodeType().equals(child)) { - return innerNode; - } - return null; - } - - } - - - private static class ChoiceNodeNormalization extends - MixinNormalizationOp { - - private final ImmutableMap> - byQName; - private final ImmutableMap> - byArg; - - protected ChoiceNodeNormalization( - final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) { - super(new NodeIdentifier(schema.getQName())); - ImmutableMap.Builder> - byQNameBuilder = - ImmutableMap.builder(); - ImmutableMap.Builder> - byArgBuilder = - ImmutableMap.builder(); - - for (ChoiceCaseNode caze : schema.getCases()) { - for (DataSchemaNode cazeChild : caze.getChildNodes()) { - NodeToNormalizedNodeBuilder childOp = - fromDataSchemaNode(cazeChild); - byArgBuilder.put(childOp.getIdentifier(), childOp); - for (QName qname : childOp.getQNameIdentifiers()) { - byQNameBuilder.put(qname, childOp); - } - } - } - byQName = byQNameBuilder.build(); - byArg = byArgBuilder.build(); - } - - @Override - public NodeToNormalizedNodeBuilder getChild( - final PathArgument child) { - return byArg.get(child); - } - - @Override - public NodeToNormalizedNodeBuilder getChild(final QName child) { - return byQName.get(child); - } - - @Override - protected NormalizedNodeContainerBuilder createBuilder( - final Node node) { - return Builders.choiceBuilder().withNodeIdentifier(getIdentifier()); - } - - @Override - public NormalizedNode createDefault( - final PathArgument currentArg) { - return Builders.choiceBuilder().withNodeIdentifier(getIdentifier()) - .build(); - } - } - - /** - * Find an appropriate NormalizedNodeBuilder using both the schema and the - * Path Argument - * - * @param schema - * @param child - * @return - */ - public static NodeToNormalizedNodeBuilder fromSchemaAndPathArgument( - final DataNodeContainer schema, final QName child) { - DataSchemaNode potential = schema.getDataChildByName(child); - if (potential == null) { - Iterable - choices = - FluentIterable.from(schema.getChildNodes()).filter( - org.opendaylight.yangtools.yang.model.api.ChoiceNode.class); - potential = findChoice(choices, child); - } - if (potential == null) { - if (logger.isTraceEnabled()) { - logger.trace("BAD CHILD = {}", child.toString()); - } - } - - checkArgument(potential != null, - "Supplied QName %s is not valid according to schema %s", child, - schema); - - // If the schema in an instance of DataSchemaNode and the potential - // is augmenting something then there is a chance that this may be - // and augmentation node - if ((schema instanceof DataSchemaNode) - && potential.isAugmenting()) { - - AugmentationNormalization augmentation = - fromAugmentation(schema, (AugmentationTarget) schema, - potential); - - // If an augmentation normalization (builder) is not found then - // we fall through to the regular processing - if(augmentation != null){ - return augmentation; - } - } - return fromDataSchemaNode(potential); - } - - /** - * Given a bunch of choice nodes and a the name of child find a choice node for that child which - * has a non-null value - * - * @param choices - * @param child - * @return - */ - private static org.opendaylight.yangtools.yang.model.api.ChoiceNode findChoice( - final Iterable choices, - final QName child) { - org.opendaylight.yangtools.yang.model.api.ChoiceNode foundChoice = null; - choiceLoop: - for (org.opendaylight.yangtools.yang.model.api.ChoiceNode choice : choices) { - for (ChoiceCaseNode caze : choice.getCases()) { - if (caze.getDataChildByName(child) != null) { - foundChoice = choice; - break choiceLoop; - } - } - } - return foundChoice; - } - - - /** - * Create an AugmentationIdentifier based on the AugmentationSchema - * - * @param augmentation - * @return - */ - public static AugmentationIdentifier augmentationIdentifierFrom( - final AugmentationSchema augmentation) { - ImmutableSet.Builder potentialChildren = ImmutableSet.builder(); - for (DataSchemaNode child : augmentation.getChildNodes()) { - potentialChildren.add(child.getQName()); - } - return new AugmentationIdentifier(potentialChildren.build()); - } - - /** - * Create an AugmentationNormalization based on the schema of the DataContainer, the - * AugmentationTarget and the potential schema node - * - * @param schema - * @param augments - * @param potential - * @return - */ - private static AugmentationNormalization fromAugmentation( - final DataNodeContainer schema, final AugmentationTarget augments, - final DataSchemaNode potential) { - AugmentationSchema augmentation = null; - for (AugmentationSchema aug : augments.getAvailableAugmentations()) { - DataSchemaNode child = aug.getDataChildByName(potential.getQName()); - if (child != null) { - augmentation = aug; - break; - } - - } - if (augmentation != null) { - return new AugmentationNormalization(augmentation, schema); - } else { - return null; - } - } - - /** - * @param schema - * @param child - * @return - */ - private static NodeToNormalizedNodeBuilder fromSchema( - final DataNodeContainer schema, final PathArgument child) { - if (child instanceof AugmentationIdentifier) { - QName childQName = ((AugmentationIdentifier) child) - .getPossibleChildNames().iterator().next(); - - return fromSchemaAndPathArgument(schema, childQName); - } - return fromSchemaAndPathArgument(schema, child.getNodeType()); - } - - public static NodeToNormalizedNodeBuilder fromDataSchemaNode( - final DataSchemaNode potential) { - if (potential instanceof ContainerSchemaNode) { - return new ContainerNormalization((ContainerSchemaNode) potential); - } else if (potential instanceof ListSchemaNode) { - return new ListMixinNormalization((ListSchemaNode) potential); - } else if (potential instanceof LeafSchemaNode) { - return new LeafNormalization((LeafSchemaNode) potential, - new NodeIdentifier(potential.getQName())); - } else if (potential instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) { - return new ChoiceNodeNormalization( - (org.opendaylight.yangtools.yang.model.api.ChoiceNode) potential); - } else if (potential instanceof LeafListSchemaNode) { - return new LeafListMixinNormalization( - (LeafListSchemaNode) potential); - } - return null; - } - - public static NodeToNormalizedNodeBuilder from(final SchemaContext ctx) { - return new ContainerNormalization(ctx); - } - - public abstract NormalizedNode createDefault(PathArgument currentArg); - -} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeValueCodec.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeValueCodec.java deleted file mode 100644 index b6dbefbbac..0000000000 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeValueCodec.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - * - */ - -package org.opendaylight.controller.cluster.datastore.node; - -import org.opendaylight.controller.cluster.datastore.node.utils.QNameFactory; -import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; -import org.opendaylight.yangtools.yang.data.api.codec.BitsCodec; -import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.TypeDefinition; -import org.opendaylight.yangtools.yang.model.util.IdentityrefType; -import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType; -import org.opendaylight.yangtools.yang.model.util.Leafref; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NodeValueCodec { - protected static final Logger logger = LoggerFactory - .getLogger(NodeValueCodec.class); - - public static Object toTypeSafeValue(DataSchemaNode schema, TypeDefinition type, NormalizedNodeMessages.Node node){ - - String value = node.getValue(); - - if(schema != null && value != null){ - TypeDefinition baseType = type; - - while (baseType.getBaseType() != null) { - baseType = baseType.getBaseType(); - } - - TypeDefinitionAwareCodec> codec = - TypeDefinitionAwareCodec.from(type); - - if(codec instanceof BitsCodec){ - if(value.contains("[]")){ - value = ""; - } else { - value = value.replace("[", ""); - value = value.replace("]", ""); - value = value.replace(",", " "); - } - } - - if (codec != null) { - return codec.deserialize(value); - } else if(baseType instanceof Leafref) { - return value; - } else if(baseType instanceof IdentityrefType) { - return QNameFactory.create(value); - } else if(baseType instanceof InstanceIdentifierType) { - return InstanceIdentifierUtils.fromSerializable(node.getInstanceIdentifierValue()); - } else { - logger.error("Could not figure out how to transform value " + value + " for schemaType " + type); - } - } - - return value; - } -} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodec.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodec.java index 4e76e37fa2..6669e48627 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodec.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodec.java @@ -10,47 +10,116 @@ package org.opendaylight.controller.cluster.datastore.node; -import org.opendaylight.controller.cluster.datastore.node.utils.PathUtils; import org.opendaylight.controller.cluster.datastore.node.utils.serialization.NormalizedNodeSerializer; +import org.opendaylight.controller.cluster.datastore.node.utils.serialization.NormalizedNodeSerializer.DeSerializer; +import org.opendaylight.controller.cluster.datastore.node.utils.serialization.NormalizedNodeSerializer.Serializer; import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; +import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Container; +import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class NormalizedNodeToNodeCodec { + public interface Encoded { + NormalizedNodeMessages.Container getEncodedNode(); + + NormalizedNodeMessages.InstanceIdentifier getEncodedPath(); + } + + public interface Decoded { + NormalizedNode getDecodedNode(); + + YangInstanceIdentifier getDecodedPath(); + } + private final SchemaContext ctx; - private static final Logger logger = LoggerFactory.getLogger(NormalizedNodeToNodeCodec.class); public NormalizedNodeToNodeCodec(final SchemaContext ctx){ this.ctx = ctx; + } + public NormalizedNodeMessages.Container encode(NormalizedNode node){ + return encode(null, node).getEncodedNode(); } - public NormalizedNodeMessages.Container encode(YangInstanceIdentifier id, NormalizedNode node){ + public Encoded encode(YangInstanceIdentifier path, NormalizedNode node) { + + NormalizedNodeMessages.InstanceIdentifier serializedPath = null; NormalizedNodeMessages.Container.Builder builder = NormalizedNodeMessages.Container.newBuilder(); - String parentPath = ""; - if(id != null){ - parentPath = PathUtils.getParentPath(PathUtils.toString(id)); - } + // Note: parent path is no longer used + builder.setParentPath(""); - builder.setParentPath(parentPath); if(node != null) { - builder.setNormalizedNode(NormalizedNodeSerializer.serialize(node)); + if(path == null) { + builder.setNormalizedNode(NormalizedNodeSerializer.serialize(node)); + } else { + Serializer serializer = NormalizedNodeSerializer.newSerializer(node); + builder.setNormalizedNode(serializer.serialize(path)); + serializedPath = serializer.getSerializedPath(); + } } - return builder.build(); + return new EncodedImpl(builder.build(), serializedPath); + } + + + public NormalizedNode decode(NormalizedNodeMessages.Node node){ + return decode(null, node).getDecodedNode(); } - public NormalizedNode decode(YangInstanceIdentifier id, NormalizedNodeMessages.Node node){ + public Decoded decode(NormalizedNodeMessages.InstanceIdentifier path, + NormalizedNodeMessages.Node node) { if(node.getIntType() < 0 || node.getSerializedSize() == 0){ - return null; + return new DecodedImpl(null, null); } - return NormalizedNodeSerializer.deSerialize(node); + + DeSerializer deSerializer = NormalizedNodeSerializer.newDeSerializer(path, node); + NormalizedNode decodedNode = deSerializer.deSerialize(); + return new DecodedImpl(decodedNode, deSerializer.getDeserializedPath()); } + private static class DecodedImpl implements Decoded { + + private final NormalizedNode decodedNode; + private final YangInstanceIdentifier decodedPath; + public DecodedImpl(NormalizedNode decodedNode, YangInstanceIdentifier decodedPath) { + this.decodedNode = decodedNode; + this.decodedPath = decodedPath; + } + + @Override + public NormalizedNode getDecodedNode() { + return decodedNode; + } + + @Override + public YangInstanceIdentifier getDecodedPath() { + return decodedPath; + } + } + + private static class EncodedImpl implements Encoded { + + private final Container encodedNode; + private final InstanceIdentifier encodedPath; + + EncodedImpl(Container encodedNode, InstanceIdentifier encodedPath) { + this.encodedNode = encodedNode; + this.encodedPath = encodedPath; + } + + @Override + public Container getEncodedNode() { + return encodedNode; + } + + @Override + public InstanceIdentifier getEncodedPath() { + return encodedPath; + } + } } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToProtocolBufferNode.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToProtocolBufferNode.java deleted file mode 100644 index 68d3c590e0..0000000000 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToProtocolBufferNode.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - * - */ - -package org.opendaylight.controller.cluster.datastore.node; - -import com.google.common.base.Preconditions; -import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; -import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapNode; -import org.opendaylight.yangtools.yang.data.api.schema.MixinNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer; -import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; - -import java.util.Map; - -/** - * NormalizedNodeToProtocolBufferNode walks the NormalizedNode tree converting it to the - * NormalizedMessage.Node - *

- * {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode } is a tree like structure that provides a generic structure for a yang data - * model - */ -public class NormalizedNodeToProtocolBufferNode { - - - private final Node.Builder builderRoot; - private NormalizedNodeMessages.Container container; - - public NormalizedNodeToProtocolBufferNode() { - - builderRoot = Node.newBuilder(); - } - - public void encode(String parentPath, NormalizedNode normalizedNode) { - if (parentPath == null) { - parentPath = ""; - } - - NormalizedNodeMessages.Container.Builder containerBuilder = - NormalizedNodeMessages.Container.newBuilder(); - - if (normalizedNode != null) { - - navigateNormalizedNode(0, parentPath, normalizedNode, builderRoot); - // here we need to put back the Node Tree in Container - - container = - containerBuilder.setParentPath(parentPath).setNormalizedNode( - builderRoot.build()).build(); - } else { - //this can happen when an attempt was made to read from datastore and normalized node was null. - container = containerBuilder.setParentPath(parentPath).build(); - - } - - } - - - private void navigateDataContainerNode(int level, final String parentPath, - final DataContainerNode dataContainerNode, - Node.Builder builderParent) { - - String newParentPath = - parentPath + "/" + dataContainerNode.getIdentifier().toString(); - String type = getDataContainerType(dataContainerNode).getSimpleName(); - builderParent.setPath(dataContainerNode.getIdentifier().toString()) - .setType(type); - - final Iterable> - value = - dataContainerNode.getValue(); - for (NormalizedNode node : value) { - Node.Builder builderChild = Node.newBuilder(); - if (node instanceof MixinNode - && node instanceof NormalizedNodeContainer) { - - navigateNormalizedNodeContainerMixin(level, newParentPath, - (NormalizedNodeContainer) node, builderChild); - } else { - navigateNormalizedNode(level, newParentPath, node, - builderChild); - } - builderParent.addChild(builderChild); - } - } - - private Class getDataContainerType( - NormalizedNodeContainer dataContainerNode) { - if (dataContainerNode instanceof ChoiceNode) { - return ChoiceNode.class; - } else if (dataContainerNode instanceof AugmentationNode) { - return AugmentationNode.class; - } else if (dataContainerNode instanceof ContainerNode) { - return ContainerNode.class; - } else if (dataContainerNode instanceof MapEntryNode) { - return MapEntryNode.class; - } else if (dataContainerNode instanceof UnkeyedListEntryNode) { - return UnkeyedListEntryNode.class; - } else if (dataContainerNode instanceof MapNode) { - return MapNode.class; - } else if (dataContainerNode instanceof LeafSetNode) { - return LeafSetNode.class; - } - throw new IllegalArgumentException( - "could not find the data container node type " - + dataContainerNode.toString() - ); - } - - private void navigateNormalizedNodeContainerMixin(int level, - final String parentPath, - NormalizedNodeContainer node, Node.Builder builderParent) { - String newParentPath = - parentPath + "/" + node.getIdentifier().toString(); - - builderParent.setPath(node.getIdentifier().toString()).setType( - this.getDataContainerType(node).getSimpleName()); - final Iterable> value = node.getValue(); - for (NormalizedNode normalizedNode : value) { - // child node builder - Node.Builder builderChild = Node.newBuilder(); - if (normalizedNode instanceof MixinNode - && normalizedNode instanceof NormalizedNodeContainer) { - navigateNormalizedNodeContainerMixin(level + 1, newParentPath, - (NormalizedNodeContainer) normalizedNode, builderChild); - } else { - navigateNormalizedNode(level, newParentPath, normalizedNode, - builderChild); - } - builderParent.addChild(builderChild); - - } - - - - } - - - private void navigateNormalizedNode(int level, - String parentPath, NormalizedNode normalizedNode, - Node.Builder builderParent) { - - if (normalizedNode instanceof DataContainerNode) { - - final DataContainerNode dataContainerNode = - (DataContainerNode) normalizedNode; - - navigateDataContainerNode(level + 1, parentPath, dataContainerNode, - builderParent); - } else if (normalizedNode instanceof MixinNode - && normalizedNode instanceof NormalizedNodeContainer) { - - navigateNormalizedNodeContainerMixin(level, parentPath, - (NormalizedNodeContainer) normalizedNode, - builderParent); - } else { - if (normalizedNode instanceof LeafNode) { - buildLeafNode(parentPath, normalizedNode, builderParent); - } else if (normalizedNode instanceof LeafSetEntryNode) { - buildLeafSetEntryNode(parentPath, normalizedNode, - builderParent); - } - - } - - } - - private void buildLeafSetEntryNode(String parentPath, - NormalizedNode normalizedNode, - Node.Builder builderParent) { - String path = - parentPath + "/" + normalizedNode.getIdentifier().toString(); - LeafSetEntryNode leafSetEntryNode = (LeafSetEntryNode) normalizedNode; - Map attributes = leafSetEntryNode.getAttributes(); - if (!attributes.isEmpty()) { - NormalizedNodeMessages.Attribute.Builder builder = null; - for (Map.Entry attribute : attributes.entrySet()) { - builder = NormalizedNodeMessages.Attribute.newBuilder(); - - builder - .setName(attribute.getKey().toString()) - .setValue(normalizedNode.getValue().toString()); - - builderParent.addAttributes(builder.build()); - } - } - buildNodeValue(normalizedNode, builderParent); - } - - private void buildLeafNode(String parentPath, - NormalizedNode normalizedNode, - Node.Builder builderParent) { - Preconditions.checkNotNull(parentPath); - Preconditions.checkNotNull(normalizedNode); - String path = - parentPath + "/" + normalizedNode.getIdentifier().toString(); - LeafNode leafNode = (LeafNode) normalizedNode; - Map attributes = leafNode.getAttributes(); - if (!attributes.isEmpty()) { - NormalizedNodeMessages.Attribute.Builder builder = null; - for (Map.Entry attribute : attributes.entrySet()) { - builder = NormalizedNodeMessages.Attribute.newBuilder(); - builder - .setName(attribute.getKey().toString()) - .setValue(attribute.getValue().toString()); - - builderParent.addAttributes(builder.build()); - } - } - - Object value = normalizedNode.getValue(); - if (value == null) { - builderParent - .setPath(normalizedNode.getIdentifier().toString()) - .setType(LeafNode.class.getSimpleName()) - .setValueType(String.class.getSimpleName()) - .setValue(""); - } else { - buildNodeValue(normalizedNode, builderParent); - } - } - - private void buildNodeValue(NormalizedNode normalizedNode, - Node.Builder builderParent) { - - Object value = normalizedNode.getValue(); - - builderParent - .setPath(normalizedNode.getIdentifier().toString()) - .setType(LeafNode.class.getSimpleName()) - .setValueType((value.getClass().getSimpleName())) - .setValue(value.toString()); - - if(value.getClass().equals(YangInstanceIdentifier.class)){ - builderParent.setInstanceIdentifierValue( - InstanceIdentifierUtils - .toSerializable((YangInstanceIdentifier) value)); - } - } - - public NormalizedNodeMessages.Container getContainer() { - return container; - } -} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/AugmentationIdentifierGenerator.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/AugmentationIdentifierGenerator.java index e2c4c35893..7f7cdc650e 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/AugmentationIdentifierGenerator.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/AugmentationIdentifierGenerator.java @@ -46,7 +46,7 @@ public class AugmentationIdentifierGenerator { .create(name.trim())); } - return new YangInstanceIdentifier.AugmentationIdentifier(null, childNames); + return new YangInstanceIdentifier.AugmentationIdentifier(childNames); } } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactory.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactory.java index ea3986f4a0..da61e6de73 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactory.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactory.java @@ -32,20 +32,6 @@ public class NodeIdentifierFactory { return value; } - public static YangInstanceIdentifier.PathArgument getArgument(String id, DataSchemaNode schemaNode){ - YangInstanceIdentifier.PathArgument value = cache.get(id); - if(value == null){ - synchronized (cache){ - value = cache.get(id); - if(value == null) { - value = createPathArgument(id, schemaNode); - cache.put(id, value); - } - } - } - return value; - } - public static YangInstanceIdentifier.PathArgument createPathArgument(String id, DataSchemaNode schemaNode){ final NodeIdentifierWithPredicatesGenerator nodeIdentifierWithPredicatesGenerator = new NodeIdentifierWithPredicatesGenerator(id, schemaNode); diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtils.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtils.java index 25b65f0168..6cdddfd271 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtils.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtils.java @@ -20,23 +20,6 @@ import java.util.Set; public class PathUtils { - public static String getParentPath(String currentElementPath){ - StringBuilder parentPath = new StringBuilder(); - - if(currentElementPath != null){ - String[] parentPaths = currentElementPath.split("/"); - if(parentPaths.length > 2){ - for(int i=0;i 0){ - parentPath.append("/"); - parentPath.append(parentPaths[i]); - } - } - } - } - return parentPath.toString(); - } - /** * Given a YangInstanceIdentifier return a serialized version of the same * as a String diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/NormalizedNodeSerializationContext.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/NormalizedNodeSerializationContext.java index 660bc28e62..1920702527 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/NormalizedNodeSerializationContext.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/NormalizedNodeSerializationContext.java @@ -8,15 +8,9 @@ package org.opendaylight.controller.cluster.datastore.node.utils.serialization; -import java.net.URI; -import java.util.Date; - /** * NormalizedNodeSerializationContext provides methods which help in encoding * certain components of a NormalizedNode properly */ public interface NormalizedNodeSerializationContext { - int addNamespace(URI namespace); - int addRevision(Date revision); - int addLocalName(String localName); } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/NormalizedNodeSerializer.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/NormalizedNodeSerializer.java index 3e1bd35632..15d51e1d80 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/NormalizedNodeSerializer.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/NormalizedNodeSerializer.java @@ -9,8 +9,9 @@ package org.opendaylight.controller.cluster.datastore.node.utils.serialization; import com.google.common.base.Preconditions; +import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils; import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; -import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; +import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder; import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode; @@ -32,14 +33,8 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContaine import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder; - -import java.net.URI; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; +import java.util.EnumMap; import java.util.Map; - import static org.opendaylight.controller.cluster.datastore.node.utils.serialization.NormalizedNodeType.ANY_XML_NODE_TYPE; import static org.opendaylight.controller.cluster.datastore.node.utils.serialization.NormalizedNodeType.AUGMENTATION_NODE_TYPE; import static org.opendaylight.controller.cluster.datastore.node.utils.serialization.NormalizedNodeType.CHOICE_NODE_TYPE; @@ -91,6 +86,10 @@ public class NormalizedNodeSerializer { return new Serializer(node).serialize(); } + public static Serializer newSerializer(NormalizedNode node) { + Preconditions.checkNotNull(node, "node should not be null"); + return new Serializer(node); + } /** * DeSerialize a protocol buffer message back into a NormalizedNode @@ -98,8 +97,15 @@ public class NormalizedNodeSerializer { * @param node * @return */ - public static NormalizedNode deSerialize(NormalizedNodeMessages.Node node){ - return new DeSerializer(node).deSerialize(); + public static NormalizedNode deSerialize(NormalizedNodeMessages.Node node) { + Preconditions.checkNotNull(node, "node should not be null"); + return new DeSerializer(null, node).deSerialize(); + } + + public static DeSerializer newDeSerializer(NormalizedNodeMessages.InstanceIdentifier path, + NormalizedNodeMessages.Node node) { + Preconditions.checkNotNull(node, "node should not be null"); + return new DeSerializer(path, node); } /** @@ -115,25 +121,36 @@ public class NormalizedNodeSerializer { * @param pathArgument * @return */ - public static YangInstanceIdentifier.PathArgument deSerialize(NormalizedNodeMessages.Node node, NormalizedNodeMessages.PathArgument pathArgument){ + public static YangInstanceIdentifier.PathArgument deSerialize(NormalizedNodeMessages.Node node, + NormalizedNodeMessages.PathArgument pathArgument){ Preconditions.checkNotNull(node, "node should not be null"); Preconditions.checkNotNull(pathArgument, "pathArgument should not be null"); - return new DeSerializer(node).deSerialize(pathArgument); + return new DeSerializer(null, node).deSerialize(pathArgument); } - private static class Serializer implements NormalizedNodeSerializationContext { + public static class Serializer extends QNameSerializationContextImpl + implements NormalizedNodeSerializationContext { private final NormalizedNode node; - private final Map codeMap = new HashMap<>(); - private final List codes = new ArrayList<>(); + private NormalizedNodeMessages.InstanceIdentifier serializedPath; private Serializer(NormalizedNode node) { this.node = node; } - private NormalizedNodeMessages.Node serialize() { - return this.serialize(node).addAllCode(codes).build(); + public NormalizedNodeMessages.InstanceIdentifier getSerializedPath() { + return serializedPath; + } + + public NormalizedNodeMessages.Node serialize() { + return this.serialize(node).addAllCode(getCodes()).build(); + } + + public NormalizedNodeMessages.Node serialize(YangInstanceIdentifier path) { + Builder builder = serialize(node); + serializedPath = InstanceIdentifierUtils.toSerializable(path, this); + return builder.addAllCode(getCodes()).build(); } private NormalizedNodeMessages.Node.Builder serialize( @@ -181,58 +198,12 @@ public class NormalizedNodeSerializer { return builder; } - - - @Override public int addNamespace(URI namespace) { - int namespaceInt = getCode(namespace); - - if(namespaceInt == -1) { - namespaceInt = addCode(namespace, namespace.toString()); - } - return namespaceInt; - } - - @Override public int addRevision(Date revision) { - if(revision == null){ - return -1; - } - - int revisionInt = getCode(revision); - if(revisionInt == -1) { - String formattedRevision = - SimpleDateFormatUtil.getRevisionFormat().format(revision); - revisionInt = addCode(revision, formattedRevision); - } - return revisionInt; - } - - @Override public int addLocalName(String localName) { - int localNameInt = getCode(localName); - if(localNameInt == -1) { - localNameInt = addCode(localName, localName.toString()); - } - return localNameInt; - - } - - public int addCode(Object code, String codeStr){ - int count = codes.size(); - codes.add(codeStr); - codeMap.put(code, Integer.valueOf(count)); - return count; - } - - public int getCode(Object code){ - if(codeMap.containsKey(code)){ - return codeMap.get(code); - } - return -1; - } } - private static class DeSerializer implements NormalizedNodeDeSerializationContext { + public static class DeSerializer extends QNameDeSerializationContextImpl + implements NormalizedNodeDeSerializationContext { private static Map - deSerializationFunctions = new HashMap<>(); + deSerializationFunctions = new EnumMap<>(NormalizedNodeType.class); static { deSerializationFunctions.put(CONTAINER_NODE_TYPE, @@ -436,19 +407,34 @@ public class NormalizedNodeSerializer { } private final NormalizedNodeMessages.Node node; + private final NormalizedNodeMessages.InstanceIdentifier path; + private YangInstanceIdentifier deserializedPath; - public DeSerializer(NormalizedNodeMessages.Node node){ + public DeSerializer(NormalizedNodeMessages.InstanceIdentifier path, + NormalizedNodeMessages.Node node) { + super(node.getCodeList()); + this.path = path; this.node = node; } - public NormalizedNode deSerialize(){ - return deSerialize(node); + public YangInstanceIdentifier getDeserializedPath() { + return deserializedPath; + } + + public NormalizedNode deSerialize() { + NormalizedNode deserializedNode = deSerialize(node); + if(path != null) { + deserializedPath = InstanceIdentifierUtils.fromSerializable(path, this); + } + + return deserializedNode; } private NormalizedNode deSerialize(NormalizedNodeMessages.Node node){ Preconditions.checkNotNull(node, "node should not be null"); - DeSerializationFunction deSerializationFunction = - Preconditions.checkNotNull(deSerializationFunctions.get(NormalizedNodeType.values()[node.getIntType()]), "Unknown type " + node); + + DeSerializationFunction deSerializationFunction = deSerializationFunctions.get( + NormalizedNodeType.values()[node.getIntType()]); return deSerializationFunction.apply(this, node); } @@ -523,18 +509,6 @@ public class NormalizedNodeSerializer { this, path); } - @Override public String getNamespace(int namespace) { - return node.getCode(namespace); - } - - @Override public String getRevision(int revision) { - return node.getCode(revision); - } - - @Override public String getLocalName(int localName) { - return node.getCode(localName); - } - public YangInstanceIdentifier.PathArgument deSerialize( NormalizedNodeMessages.PathArgument pathArgument) { return PathArgumentSerializer.deSerialize(this, pathArgument); @@ -544,8 +518,4 @@ public class NormalizedNodeSerializer { NormalizedNode apply(DeSerializer deserializer, NormalizedNodeMessages.Node node); } } - - - - } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/NormalizedNodeType.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/NormalizedNodeType.java index eebd58013a..2d6d738b76 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/NormalizedNodeType.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/NormalizedNodeType.java @@ -42,20 +42,20 @@ public enum NormalizedNodeType { public static NormalizedNodeType getSerializableNodeType(NormalizedNode node){ Preconditions.checkNotNull(node, "node should not be null"); - if(node instanceof ContainerNode){ - return CONTAINER_NODE_TYPE; - } else if(node instanceof LeafNode){ + if(node instanceof LeafNode){ return LEAF_NODE_TYPE; - } else if(node instanceof MapNode){ - return MAP_NODE_TYPE; + } else if(node instanceof LeafSetEntryNode){ + return LEAF_SET_ENTRY_NODE_TYPE; } else if(node instanceof MapEntryNode){ return MAP_ENTRY_NODE_TYPE; + } else if(node instanceof ContainerNode){ + return CONTAINER_NODE_TYPE; + } else if(node instanceof MapNode){ + return MAP_NODE_TYPE; } else if(node instanceof AugmentationNode){ return AUGMENTATION_NODE_TYPE; } else if(node instanceof LeafSetNode){ return LEAF_SET_NODE_TYPE; - } else if(node instanceof LeafSetEntryNode){ - return LEAF_SET_ENTRY_NODE_TYPE; } else if(node instanceof ChoiceNode){ return CHOICE_NODE_TYPE; } else if(node instanceof OrderedLeafSetNode){ @@ -69,6 +69,7 @@ public enum NormalizedNodeType { } else if(node instanceof AnyXmlNode){ return ANY_XML_NODE_TYPE; } + throw new IllegalArgumentException("Node type unknown : " + node.getClass().getSimpleName()); } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/PathArgumentSerializer.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/PathArgumentSerializer.java index d7627c008e..bf10316fd5 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/PathArgumentSerializer.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/PathArgumentSerializer.java @@ -14,21 +14,23 @@ import org.opendaylight.controller.cluster.datastore.node.utils.QNameFactory; import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; - import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; - import static org.opendaylight.controller.cluster.datastore.node.utils.serialization.PathArgumentType.getSerializablePathArgumentType; public class PathArgumentSerializer { - private static final Map pathArgumentAttributesGetters = new HashMap<>(); + private static final String REVISION_ARG = "?revision="; + private static final Map, PathArgumentAttributesGetter> pathArgumentAttributesGetters = new HashMap<>(); - public static NormalizedNodeMessages.PathArgument serialize(NormalizedNodeSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument){ + public static NormalizedNodeMessages.PathArgument serialize(QNameSerializationContext context, + YangInstanceIdentifier.PathArgument pathArgument){ Preconditions.checkNotNull(context, "context should not be null"); Preconditions.checkNotNull(pathArgument, "pathArgument should not be null"); @@ -51,7 +53,8 @@ public class PathArgumentSerializer { } - public static YangInstanceIdentifier.PathArgument deSerialize(NormalizedNodeDeSerializationContext context, NormalizedNodeMessages.PathArgument pathArgument){ + public static YangInstanceIdentifier.PathArgument deSerialize(QNameDeSerializationContext context, + NormalizedNodeMessages.PathArgument pathArgument){ Preconditions.checkNotNull(context, "context should not be null"); Preconditions.checkNotNull(pathArgument, "pathArgument should not be null"); @@ -60,18 +63,15 @@ public class PathArgumentSerializer { private static interface PathArgumentAttributesGetter { - Iterable get(NormalizedNodeSerializationContext context, - YangInstanceIdentifier.PathArgument pathArgument); + Iterable get( + QNameSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument); } static { pathArgumentAttributesGetters.put(YangInstanceIdentifier.NodeWithValue.class, new PathArgumentAttributesGetter() { @Override public Iterable get( - NormalizedNodeSerializationContext context, - YangInstanceIdentifier.PathArgument pathArgument) { - List attributes = - new ArrayList<>(); + QNameSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument) { YangInstanceIdentifier.NodeWithValue identifier = (YangInstanceIdentifier.NodeWithValue) pathArgument; @@ -79,62 +79,52 @@ public class PathArgumentSerializer { NormalizedNodeMessages.PathArgumentAttribute attribute = buildAttribute(context, null, identifier.getValue()); - attributes.add(attribute); - - return attributes; - + return Arrays.asList(attribute); } }); pathArgumentAttributesGetters.put(YangInstanceIdentifier.NodeIdentifierWithPredicates.class, new PathArgumentAttributesGetter() { @Override public Iterable get( - NormalizedNodeSerializationContext context, - YangInstanceIdentifier.PathArgument pathArgument) { - - List attributes = - new ArrayList<>(); + QNameSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument) { YangInstanceIdentifier.NodeIdentifierWithPredicates identifier = (YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument; - for (QName key : identifier.getKeyValues().keySet()) { - Object value = identifier.getKeyValues().get(key); + Map keyValues = identifier.getKeyValues(); + List attributes = + new ArrayList<>(keyValues.size()); + for (Entry e : keyValues.entrySet()) { NormalizedNodeMessages.PathArgumentAttribute attribute = - buildAttribute(context, key, value); + buildAttribute(context, e.getKey(), e.getValue()); attributes.add(attribute); - } return attributes; - } }); pathArgumentAttributesGetters.put(YangInstanceIdentifier.AugmentationIdentifier.class, new PathArgumentAttributesGetter() { @Override public Iterable get( - NormalizedNodeSerializationContext context, - YangInstanceIdentifier.PathArgument pathArgument) { - - List attributes = - new ArrayList<>(); + QNameSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument) { YangInstanceIdentifier.AugmentationIdentifier identifier = (YangInstanceIdentifier.AugmentationIdentifier) pathArgument; - for (QName key : identifier.getPossibleChildNames()) { + Set possibleChildNames = identifier.getPossibleChildNames(); + List attributes = + new ArrayList<>(possibleChildNames.size()); + for (QName key : possibleChildNames) { Object value = key; NormalizedNodeMessages.PathArgumentAttribute attribute = buildAttribute(context, key, value); attributes.add(attribute); - } return attributes; - } }); @@ -142,14 +132,14 @@ public class PathArgumentSerializer { pathArgumentAttributesGetters.put(YangInstanceIdentifier.NodeIdentifier.class, new PathArgumentAttributesGetter() { @Override public Iterable get( - NormalizedNodeSerializationContext context, - YangInstanceIdentifier.PathArgument pathArgument) { + QNameSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument) { return Collections.emptyList(); } }); } - private static NormalizedNodeMessages.PathArgumentAttribute buildAttribute(NormalizedNodeSerializationContext context,QName name, Object value){ + private static NormalizedNodeMessages.PathArgumentAttribute buildAttribute( + QNameSerializationContext context, QName name, Object value) { NormalizedNodeMessages.PathArgumentAttribute.Builder builder = NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); @@ -160,8 +150,9 @@ public class PathArgumentSerializer { } - private static NormalizedNodeMessages.QName.Builder encodeQName(NormalizedNodeSerializationContext context, QName qName){ - if(qName == null){ + private static NormalizedNodeMessages.QName.Builder encodeQName(QNameSerializationContext context, + QName qName) { + if(qName == null) { return NormalizedNodeMessages.QName.getDefaultInstance().toBuilder(); } NormalizedNodeMessages.QName.Builder qNameBuilder = @@ -177,40 +168,35 @@ public class PathArgumentSerializer { } private static Iterable getPathArgumentAttributes( - NormalizedNodeSerializationContext context, - YangInstanceIdentifier.PathArgument pathArgument) { + QNameSerializationContext context, YangInstanceIdentifier.PathArgument pathArgument) { return pathArgumentAttributesGetters.get(pathArgument.getClass()).get(context, pathArgument); - } - private static String qNameToString(NormalizedNodeDeSerializationContext context, + private static String qNameToString(QNameDeSerializationContext context, NormalizedNodeMessages.QName qName){ // If this serializer is used qName cannot be null (see encodeQName) // adding null check only in case someone tried to deSerialize a protocol buffer node // that was not serialized using the PathArgumentSerializer - Preconditions.checkNotNull(qName, "qName should not be null"); - Preconditions.checkArgument(!"".equals(qName.getLocalName()), - "qName.localName cannot be empty qName = " + qName.toString()); - Preconditions.checkArgument(qName.getNamespace() != -1, "qName.namespace should be valid"); +// Preconditions.checkNotNull(qName, "qName should not be null"); +// Preconditions.checkArgument(qName.getNamespace() != -1, "qName.namespace should be valid"); - StringBuilder sb = new StringBuilder(); String namespace = context.getNamespace(qName.getNamespace()); - String revision = ""; String localName = context.getLocalName(qName.getLocalName()); + StringBuilder sb; if(qName.getRevision() != -1){ - revision = context.getRevision(qName.getRevision()); - sb.append("(").append(namespace).append("?revision=").append( - revision).append(")").append( - localName); + String revision = context.getRevision(qName.getRevision()); + sb = new StringBuilder(namespace.length() + REVISION_ARG.length() + revision.length() + + localName.length() + 2); + sb.append('(').append(namespace).append(REVISION_ARG).append( + revision).append(')').append(localName); } else { - sb.append("(").append(namespace).append(")").append( - localName); + sb = new StringBuilder(namespace.length() + localName.length() + 2); + sb.append('(').append(namespace).append(')').append(localName); } return sb.toString(); - } /** @@ -220,12 +206,7 @@ public class PathArgumentSerializer { * @return MD-SAL PathArgument */ private static YangInstanceIdentifier.PathArgument parsePathArgument( - NormalizedNodeDeSerializationContext context, - NormalizedNodeMessages.PathArgument pathArgument) { - - Preconditions.checkArgument(pathArgument.getIntType() >= 0 - && pathArgument.getIntType() < PathArgumentType.values().length, - "Illegal PathArgumentType " + pathArgument.getIntType()); + QNameDeSerializationContext context, NormalizedNodeMessages.PathArgument pathArgument) { switch(PathArgumentType.values()[pathArgument.getIntType()]){ case NODE_IDENTIFIER_WITH_VALUE : { @@ -269,22 +250,31 @@ public class PathArgumentSerializer { } private static Map toAttributesMap( - NormalizedNodeDeSerializationContext context, - List attributesList) { - - Map map = new HashMap<>(); + QNameDeSerializationContext context, + List attributesList) { - for(NormalizedNodeMessages.PathArgumentAttribute attribute : attributesList){ + Map map; + if(attributesList.size() == 1) { + NormalizedNodeMessages.PathArgumentAttribute attribute = attributesList.get(0); NormalizedNodeMessages.QName name = attribute.getName(); Object value = parseAttribute(context, attribute); + map = Collections.singletonMap(QNameFactory.create(qNameToString(context, name)), value); + } else { + map = new HashMap<>(); + + for(NormalizedNodeMessages.PathArgumentAttribute attribute : attributesList){ + NormalizedNodeMessages.QName name = attribute.getName(); + Object value = parseAttribute(context, attribute); - map.put(QNameFactory.create(qNameToString(context, name)), value); + map.put(QNameFactory.create(qNameToString(context, name)), value); + } } return map; } - private static Object parseAttribute(NormalizedNodeDeSerializationContext context, NormalizedNodeMessages.PathArgumentAttribute attribute){ + private static Object parseAttribute(QNameDeSerializationContext context, + NormalizedNodeMessages.PathArgumentAttribute attribute){ return ValueSerializer.deSerialize(context, attribute); } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/PathArgumentType.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/PathArgumentType.java index 20009d8347..58a09ae885 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/PathArgumentType.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/PathArgumentType.java @@ -8,8 +8,9 @@ package org.opendaylight.controller.cluster.datastore.node.utils.serialization; -import com.google.common.base.Preconditions; +import java.util.Map; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import com.google.common.collect.ImmutableMap; public enum PathArgumentType { AUGMENTATION_IDENTIFIER, @@ -17,19 +18,21 @@ public enum PathArgumentType { NODE_IDENTIFIER_WITH_VALUE, NODE_IDENTIFIER_WITH_PREDICATES; + private static Map, PathArgumentType> CLASS_TO_ENUM_MAP = + ImmutableMap., PathArgumentType>builder(). + put(YangInstanceIdentifier.AugmentationIdentifier.class, AUGMENTATION_IDENTIFIER). + put(YangInstanceIdentifier.NodeIdentifier.class, NODE_IDENTIFIER). + put(YangInstanceIdentifier.NodeIdentifierWithPredicates.class, NODE_IDENTIFIER_WITH_PREDICATES). + put(YangInstanceIdentifier.NodeWithValue.class, NODE_IDENTIFIER_WITH_VALUE).build(); + public static int getSerializablePathArgumentType(YangInstanceIdentifier.PathArgument pathArgument){ - Preconditions.checkNotNull(pathArgument, "pathArgument should not be null"); - - if(pathArgument instanceof YangInstanceIdentifier.AugmentationIdentifier){ - return AUGMENTATION_IDENTIFIER.ordinal(); - } else if(pathArgument instanceof YangInstanceIdentifier.NodeIdentifier){ - return NODE_IDENTIFIER.ordinal(); - } else if(pathArgument instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates){ - return NODE_IDENTIFIER_WITH_PREDICATES.ordinal(); - } else if(pathArgument instanceof YangInstanceIdentifier.NodeWithValue){ - return NODE_IDENTIFIER_WITH_VALUE.ordinal(); + + PathArgumentType type = CLASS_TO_ENUM_MAP.get(pathArgument.getClass()); + if(type == null) { + throw new IllegalArgumentException("Unknown type of PathArgument = " + pathArgument); } - throw new IllegalArgumentException("Unknown type of PathArgument = " + pathArgument.toString()); + + return type.ordinal(); } } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/QNameDeSerializationContext.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/QNameDeSerializationContext.java new file mode 100644 index 0000000000..ca9ead7483 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/QNameDeSerializationContext.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.cluster.datastore.node.utils.serialization; + +/** + * Interface that provides methods which help in decoding components of a QName. + * + * @author Thomas Pantelis + */ +public interface QNameDeSerializationContext { + String getNamespace(int namespace); + + String getRevision(int revision); + + String getLocalName(int localName); +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/QNameDeSerializationContextImpl.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/QNameDeSerializationContextImpl.java new file mode 100644 index 0000000000..ac3d362ec4 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/QNameDeSerializationContextImpl.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.cluster.datastore.node.utils.serialization; + +import java.util.List; + +/** + * Implementation of the QNameDeSerializationContext interface. + * + * @author Thomas Pantelis + */ +public class QNameDeSerializationContextImpl implements QNameDeSerializationContext { + + private final List codeList; + + public QNameDeSerializationContextImpl(List codeList) { + this.codeList = codeList; + } + + @Override + public String getNamespace(int namespace) { + return codeList.get(namespace); + } + + @Override + public String getRevision(int revision) { + return codeList.get(revision); + } + + @Override + public String getLocalName(int localName) { + return codeList.get(localName); + } +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/QNameSerializationContext.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/QNameSerializationContext.java new file mode 100644 index 0000000000..9096add404 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/QNameSerializationContext.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.cluster.datastore.node.utils.serialization; + +import java.net.URI; +import java.util.Date; + +/** + * Interface that provides methods which help in encoding components of a QName. + * + * @author Thomas Pantelis + */ +public interface QNameSerializationContext { + int addNamespace(URI namespace); + + int addRevision(Date revision); + + int addLocalName(String localName); + +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/QNameSerializationContextImpl.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/QNameSerializationContextImpl.java new file mode 100644 index 0000000000..09fe2efc3e --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/QNameSerializationContextImpl.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.cluster.datastore.node.utils.serialization; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; + +/** + * Implementation of the QNameSerializationContext interface. + * + * @author Thomas Pantelis + */ +public class QNameSerializationContextImpl implements QNameSerializationContext { + + private final Map codeMap = new HashMap<>(); + private final List codes = new ArrayList<>(); + + public List getCodes() { + return codes; + } + + @Override public int addNamespace(URI namespace) { + int namespaceInt = getCode(namespace); + + if(namespaceInt == -1) { + namespaceInt = addCode(namespace, namespace.toString()); + } + return namespaceInt; + } + + @Override public int addRevision(Date revision) { + if(revision == null){ + return -1; + } + + int revisionInt = getCode(revision); + if(revisionInt == -1) { + String formattedRevision = + SimpleDateFormatUtil.getRevisionFormat().format(revision); + revisionInt = addCode(revision, formattedRevision); + } + return revisionInt; + } + + @Override public int addLocalName(String localName) { + int localNameInt = getCode(localName); + if(localNameInt == -1) { + localNameInt = addCode(localName, localName); + } + return localNameInt; + + } + + private int addCode(Object code, String codeStr){ + int count = codes.size(); + codes.add(codeStr); + codeMap.put(code, Integer.valueOf(count)); + return count; + } + + private int getCode(Object code){ + Integer value = codeMap.get(code); + return value == null ? -1 : value.intValue(); + } +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/ValueSerializer.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/ValueSerializer.java index 04c95d61ce..6a843f57c7 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/ValueSerializer.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/ValueSerializer.java @@ -8,7 +8,6 @@ package org.opendaylight.controller.cluster.datastore.node.utils.serialization; -import com.google.common.base.Preconditions; import org.opendaylight.controller.cluster.datastore.node.utils.QNameFactory; import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils; import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; @@ -21,12 +20,12 @@ import java.util.Set; public class ValueSerializer { public static void serialize(NormalizedNodeMessages.Node.Builder builder, - NormalizedNodeSerializationContext context, Object value){ + QNameSerializationContext context, Object value) { builder.setIntValueType(ValueType.getSerializableType(value).ordinal()); if(value instanceof YangInstanceIdentifier) { builder.setInstanceIdentifierValue( - InstanceIdentifierUtils.toSerializable((YangInstanceIdentifier) value)); + InstanceIdentifierUtils.toSerializable((YangInstanceIdentifier) value, context)); } else if(value instanceof Set) { Set set = (Set) value; if(!set.isEmpty()){ @@ -45,34 +44,30 @@ public class ValueSerializer { } public static void serialize(NormalizedNodeMessages.PathArgumentAttribute.Builder builder, - NormalizedNodeSerializationContext context, Object value){ + QNameSerializationContext context, Object value){ builder.setType(ValueType.getSerializableType(value).ordinal()); builder.setValue(value.toString()); } - public static Object deSerialize( - NormalizedNodeDeSerializationContext context, NormalizedNodeMessages.Node node) { + public static Object deSerialize(QNameDeSerializationContext context, + NormalizedNodeMessages.Node node) { if(node.getIntValueType() == ValueType.YANG_IDENTIFIER_TYPE.ordinal()){ return InstanceIdentifierUtils.fromSerializable( - node.getInstanceIdentifierValue()); + node.getInstanceIdentifierValue(), context); } else if(node.getIntValueType() == ValueType.BITS_TYPE.ordinal()){ return new HashSet(node.getBitsValueList()); } return deSerializeBasicTypes(node.getIntValueType(), node.getValue()); } - public static Object deSerialize( - NormalizedNodeDeSerializationContext context, - NormalizedNodeMessages.PathArgumentAttribute attribute) { + public static Object deSerialize(QNameDeSerializationContext context, + NormalizedNodeMessages.PathArgumentAttribute attribute) { return deSerializeBasicTypes(attribute.getType(), attribute.getValue()); } private static Object deSerializeBasicTypes(int valueType, String value) { - Preconditions.checkArgument(valueType >= 0 && valueType < ValueType.values().length, - "Illegal value type " + valueType ); - switch(ValueType.values()[valueType]){ case SHORT_TYPE: { return Short.valueOf(value); diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/ValueType.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/ValueType.java index 8724dfe43a..49db8967a6 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/ValueType.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/ValueType.java @@ -50,8 +50,9 @@ public enum ValueType { public static final ValueType getSerializableType(Object node){ Preconditions.checkNotNull(node, "node should not be null"); - if(types.containsKey(node.getClass())) { - return types.get(node.getClass()); + ValueType type = types.get(node.getClass()); + if(type != null) { + return type; } else if(node instanceof Set){ return BITS_TYPE; } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/EncoderDecoderUtil.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/EncoderDecoderUtil.java deleted file mode 100644 index 90f5cf3396..0000000000 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/EncoderDecoderUtil.java +++ /dev/null @@ -1,333 +0,0 @@ -/* - * - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - * - */ - -package org.opendaylight.controller.cluster.datastore.util; - -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import org.opendaylight.controller.protobuff.messages.common.SimpleNormalizedNodeMessage; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils; -import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils; -import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory; -import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory; -import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; -import org.opendaylight.yangtools.yang.model.api.ChoiceNode; -import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; -import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.Module; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.TransformerFactoryConfigurationError; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.ByteArrayInputStream; -import java.io.StringWriter; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -/* - * - * EncoderDecoderUtil helps in wrapping the NormalizedNode into a SimpleNormalizedNode - * protobuf message containing the XML representation of the NormalizeNode - * - * @author: syedbahm - */ -public class EncoderDecoderUtil { - static DocumentBuilderFactory factory; - - private static DomFromNormalizedNodeSerializerFactory serializerFactory = - DomFromNormalizedNodeSerializerFactory - .getInstance(XmlDocumentUtils.getDocument(), - DomUtils.defaultValueCodecProvider()); - - private static DomToNormalizedNodeParserFactory parserFactory = - DomToNormalizedNodeParserFactory - .getInstance(DomUtils.defaultValueCodecProvider()); - - static { - factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setCoalescing(true); - factory.setIgnoringElementContentWhitespace(true); - factory.setIgnoringComments(true); - } - - private static DataSchemaNode findChildNode(Collection children, - String name) { - List containers = Lists.newArrayList(); - - for (DataSchemaNode dataSchemaNode : children) { - if (dataSchemaNode.getQName().getLocalName().equals(name)) - return dataSchemaNode; - if (dataSchemaNode instanceof DataNodeContainer) { - containers.add((DataNodeContainer) dataSchemaNode); - } else if (dataSchemaNode instanceof ChoiceNode) { - containers.addAll(((ChoiceNode) dataSchemaNode).getCases()); - } - } - - for (DataNodeContainer container : containers) { - DataSchemaNode retVal = - findChildNode(container.getChildNodes(), name); - if (retVal != null) { - return retVal; - } - } - - return null; - } - - private static DataSchemaNode getSchemaNode(SchemaContext context, - QName qname) { - - for (Module module : context - .findModuleByNamespace(qname.getNamespace())) { - // we will take the first child as the start of the - if (module.getChildNodes() != null || !module.getChildNodes() - .isEmpty()) { - - DataSchemaNode found = - findChildNode(module.getChildNodes(), qname.getLocalName()); - return found; - } - } - return null; - } - - private static String toString(Element xml) { - try { - Transformer transformer = - TransformerFactory.newInstance().newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - - StreamResult result = new StreamResult(new StringWriter()); - DOMSource source = new DOMSource(xml); - transformer.transform(source, result); - - return result.getWriter().toString(); - } catch (IllegalArgumentException | TransformerFactoryConfigurationError - | TransformerException e) { - throw new RuntimeException("Unable to serialize xml element " + xml, - e); - } - } - - private static String toString(Iterable xmlIterable) { - try { - Transformer transformer = - TransformerFactory.newInstance().newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - - StreamResult result = new StreamResult(new StringWriter()); - Iterator iterator = xmlIterable.iterator(); - DOMSource source; - if(iterator.hasNext()) { - source = new DOMSource((org.w3c.dom.Node) iterator.next()); - transformer.transform(source, result); - transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); - } - - while(iterator.hasNext()) { - source = new DOMSource((org.w3c.dom.Node) iterator.next()); - transformer.transform(source, result); - } - System.out.println(result.getWriter().toString()); - return result.getWriter().toString(); - } catch (IllegalArgumentException | TransformerFactoryConfigurationError - | TransformerException e) { - throw new RuntimeException("Unable to serialize xml element(s) " + xmlIterable.toString(), - e); - } - } - - private static Iterable serialize(DataSchemaNode schemaNode, NormalizedNode normalizedNode){ - if(schemaNode instanceof ContainerSchemaNode){ //1 - return serializerFactory - .getContainerNodeSerializer() - .serialize((ContainerSchemaNode) schemaNode, - (ContainerNode) normalizedNode); - } else if(schemaNode instanceof ChoiceNode){ //2 - return serializerFactory - .getChoiceNodeSerializer() - .serialize((ChoiceNode) schemaNode, - (org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode) normalizedNode); - } else if(schemaNode instanceof LeafSchemaNode){ //3 - return serializerFactory - .getLeafNodeSerializer() - .serialize((LeafSchemaNode) schemaNode, (LeafNode) normalizedNode); - } else if(schemaNode instanceof ListSchemaNode){ //4 - return serializerFactory - .getMapNodeSerializer() - .serialize((ListSchemaNode) schemaNode, (MapNode) normalizedNode); - } else if(schemaNode instanceof LeafListSchemaNode){ //5 - return serializerFactory - .getLeafSetNodeSerializer() - .serialize((LeafListSchemaNode) schemaNode, (LeafSetNode) normalizedNode); - } else if(schemaNode instanceof AugmentationSchema){//6 - return serializerFactory - .getAugmentationNodeSerializer() - .serialize((AugmentationSchema) schemaNode, (AugmentationNode) normalizedNode); - } else if(schemaNode instanceof ListSchemaNode && normalizedNode instanceof LeafSetEntryNode){ //7 - return serializerFactory - .getLeafSetEntryNodeSerializer() - .serialize((LeafListSchemaNode) schemaNode, (LeafSetEntryNode) normalizedNode); - } else if(schemaNode instanceof ListSchemaNode){ //8 - return serializerFactory - .getMapEntryNodeSerializer() - .serialize((ListSchemaNode) schemaNode, (MapEntryNode) normalizedNode); - } - - - - throw new UnsupportedOperationException(schemaNode.getClass().toString()); - } - - private static NormalizedNode parse(Document doc, DataSchemaNode schemaNode){ - if(schemaNode instanceof ContainerSchemaNode){ - return parserFactory - .getContainerNodeParser() - .parse(Collections.singletonList(doc.getDocumentElement()), - (ContainerSchemaNode) schemaNode); - - } else if(schemaNode instanceof ChoiceNode){ - return parserFactory - .getChoiceNodeParser() - .parse(Collections.singletonList(doc.getDocumentElement()), - (ChoiceNode) schemaNode); - } else if(schemaNode instanceof LeafNode){ - return parserFactory - .getLeafNodeParser() - .parse(Collections.singletonList(doc.getDocumentElement()), - (LeafSchemaNode) schemaNode); - } else if(schemaNode instanceof ListSchemaNode){ - return parserFactory - .getMapNodeParser() - .parse(Collections.singletonList(doc.getDocumentElement()), - (ListSchemaNode) schemaNode); - } else if(schemaNode instanceof LeafListSchemaNode){ - return parserFactory - .getLeafSetNodeParser() - .parse(Collections.singletonList(doc.getDocumentElement()), - (LeafListSchemaNode) schemaNode); - } else if(schemaNode instanceof AugmentationSchema){ - return parserFactory - .getAugmentationNodeParser() - .parse(Collections.singletonList(doc.getDocumentElement()), - (AugmentationSchema) schemaNode); - } else if(schemaNode instanceof ListSchemaNode){ - return parserFactory - .getMapEntryNodeParser() - .parse(Collections.singletonList(doc.getDocumentElement()), - (ListSchemaNode) schemaNode); - - } - - throw new UnsupportedOperationException(schemaNode.getClass().toString()); - } - - - /** - * Helps in generation of NormalizedNodeXml message for the supplied NormalizedNode - * - * @param sc --SchemaContext - * @param normalizedNode -- Normalized Node to be encoded - * @return SimpleNormalizedNodeMessage.NormalizedNodeXml - */ - public static SimpleNormalizedNodeMessage.NormalizedNodeXml encode( - SchemaContext sc, NormalizedNode normalizedNode) { - - Preconditions.checkArgument(sc != null, "Schema context found null"); - - Preconditions.checkArgument(normalizedNode != null, - "normalized node found null"); - - DataSchemaNode schemaNode = getSchemaNode(sc, - normalizedNode.getIdentifier() - .getNodeType() - ); - - Preconditions.checkState(schemaNode != null, - "Couldn't find schema node for " + normalizedNode.getIdentifier()); - - Iterable els = serialize(schemaNode, normalizedNode); - - String xmlString = toString(els.iterator().next()); - SimpleNormalizedNodeMessage.NormalizedNodeXml.Builder builder = - SimpleNormalizedNodeMessage.NormalizedNodeXml.newBuilder(); - builder.setXmlString(xmlString); - builder - .setNodeIdentifier(normalizedNode.getIdentifier() - .getNodeType().toString()); - return builder.build(); - - } - - /** - * Utilizes the SimpleNormalizedNodeMessage.NormalizedNodeXml to convert into NormalizedNode - * - * @param sc -- schema context - * @param normalizedNodeXml -- containing the normalized Node XML - * @return NormalizedNode return - * @throws Exception - */ - - public static NormalizedNode decode(SchemaContext sc, - SimpleNormalizedNodeMessage.NormalizedNodeXml normalizedNodeXml) - throws Exception { - - Preconditions - .checkArgument(sc != null, "schema context seems to be null"); - - Preconditions.checkArgument(normalizedNodeXml != null, - "SimpleNormalizedNodeMessage.NormalizedNodeXml found to be null"); - QName qname = QName.create(normalizedNodeXml.getNodeIdentifier()); - - // here we will try to get back the NormalizedNode - DataSchemaNode schemaNode = getSchemaNode(sc, qname); - - // now we need to read the XML - Document doc = - factory.newDocumentBuilder().parse( - new ByteArrayInputStream( - normalizedNodeXml.getXmlString().getBytes( - "utf-8")) - ); - - doc.getDocumentElement().normalize(); - - - return parse(doc, schemaNode); - } - - - -} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtils.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtils.java index 0bb0d4fe87..64a1e3a18a 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtils.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtils.java @@ -12,12 +12,17 @@ package org.opendaylight.controller.cluster.datastore.util; import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory; import org.opendaylight.controller.cluster.datastore.node.utils.QNameFactory; +import org.opendaylight.controller.cluster.datastore.node.utils.serialization.PathArgumentSerializer; +import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameDeSerializationContext; +import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameDeSerializationContextImpl; +import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameSerializationContext; +import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameSerializationContextImpl; import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; +import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -41,61 +46,54 @@ public class InstanceIdentifierUtils { protected static final Logger logger = LoggerFactory .getLogger(InstanceIdentifierUtils.class); - @Deprecated - public static YangInstanceIdentifier from(String path) { - String[] ids = path.split("/"); - - List pathArguments = - new ArrayList<>(); - for (String nodeId : ids) { - if (!"".equals(nodeId)) { - pathArguments - .add(NodeIdentifierFactory.getArgument(nodeId)); - } - } - final YangInstanceIdentifier instanceIdentifier = - YangInstanceIdentifier.create(pathArguments); - return instanceIdentifier; - } - - /** * Convert an MD-SAL YangInstanceIdentifier into a protocol buffer version of it * * @param path an MD-SAL YangInstanceIdentifier * @return a protocol buffer version of the MD-SAL YangInstanceIdentifier */ - public static NormalizedNodeMessages.InstanceIdentifier toSerializable(YangInstanceIdentifier path){ + public static NormalizedNodeMessages.InstanceIdentifier toSerializable(YangInstanceIdentifier path) { + QNameSerializationContextImpl context = new QNameSerializationContextImpl(); + Builder builder = toSerializableBuilder(path, context); + return builder.addAllCode(context.getCodes()).build(); + } + + public static NormalizedNodeMessages.InstanceIdentifier toSerializable( + YangInstanceIdentifier path, QNameSerializationContext context) { + return toSerializableBuilder(path, context).build(); + } + + private static NormalizedNodeMessages.InstanceIdentifier.Builder toSerializableBuilder( + YangInstanceIdentifier path, QNameSerializationContext context) { NormalizedNodeMessages.InstanceIdentifier.Builder builder = NormalizedNodeMessages.InstanceIdentifier.newBuilder(); try { - - for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument pathArgument : path - .getPathArguments()) { - - String nodeType = ""; - if(!(pathArgument instanceof YangInstanceIdentifier.AugmentationIdentifier)){ - nodeType = pathArgument.getNodeType().toString(); + for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier. + PathArgument pathArgument : path.getPathArguments()) { + NormalizedNodeMessages.PathArgument serializablePathArgument; + if(context == null) { + String nodeType = ""; + if(!(pathArgument instanceof YangInstanceIdentifier.AugmentationIdentifier)){ + nodeType = pathArgument.getNodeType().toString(); + } + + serializablePathArgument = NormalizedNodeMessages.PathArgument.newBuilder() + .setValue(pathArgument.toString()) + .setType(pathArgument.getClass().getSimpleName()) + .setNodeType(NormalizedNodeMessages.QName.newBuilder().setValue(nodeType)) + .addAllAttributes(getPathArgumentAttributes(pathArgument)).build(); + } else { + serializablePathArgument = PathArgumentSerializer.serialize(context, pathArgument); } - NormalizedNodeMessages.PathArgument serializablePathArgument = - NormalizedNodeMessages.PathArgument.newBuilder() - .setValue(pathArgument.toString()) - .setType(pathArgument.getClass().getSimpleName()) - .setNodeType(NormalizedNodeMessages.QName.newBuilder() - .setValue(nodeType)) - .addAllAttributes(getPathArgumentAttributes( - pathArgument)) - .build(); - builder.addArguments(serializablePathArgument); } - } catch(Exception e){ logger.error("An exception occurred", e); } - return builder.build(); + + return builder; } @@ -106,21 +104,24 @@ public class InstanceIdentifierUtils { * @param path a protocol buffer version of the MD-SAL YangInstanceIdentifier * @return an MD-SAL YangInstanceIdentifier */ - public static YangInstanceIdentifier fromSerializable(NormalizedNodeMessages.InstanceIdentifier path){ - - List pathArguments = - new ArrayList<>(); + public static YangInstanceIdentifier fromSerializable(NormalizedNodeMessages.InstanceIdentifier path) { + return fromSerializable(path, new QNameDeSerializationContextImpl(path.getCodeList())); + } - for(NormalizedNodeMessages.PathArgument pathArgument : path.getArgumentsList()){ + public static YangInstanceIdentifier fromSerializable(NormalizedNodeMessages.InstanceIdentifier path, + QNameDeSerializationContext context) { - pathArguments - .add(parsePathArgument(pathArgument)); + List pathArguments = new ArrayList<>(); + for(NormalizedNodeMessages.PathArgument pathArgument : path.getArgumentsList()) { + if(context == null || pathArgument.hasType()) { + pathArguments.add(parsePathArgument(pathArgument)); + } else { + pathArguments.add(PathArgumentSerializer.deSerialize(context, pathArgument)); + } } - final YangInstanceIdentifier instanceIdentifier = YangInstanceIdentifier.create(pathArguments); - - return instanceIdentifier; + return YangInstanceIdentifier.create(pathArguments); } /** @@ -218,7 +219,8 @@ public class InstanceIdentifierUtils { * @param pathArgument protocol buffer PathArgument * @return MD-SAL PathArgument */ - private static YangInstanceIdentifier.PathArgument parsePathArgument(NormalizedNodeMessages.PathArgument pathArgument) { + private static YangInstanceIdentifier.PathArgument parsePathArgument( + NormalizedNodeMessages.PathArgument pathArgument) { if (YangInstanceIdentifier.NodeWithValue.class.getSimpleName().equals(pathArgument.getType())) { YangInstanceIdentifier.NodeWithValue nodeWithValue = diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessages.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessages.java index 22a93c0e10..e43b44582d 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessages.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessages.java @@ -10,6 +10,21 @@ public final class ThreePhaseCommitCohortMessages { } public interface CanCommitTransactionOrBuilder extends com.google.protobuf.MessageOrBuilder { + + // required string transactionId = 1; + /** + * required string transactionId = 1; + */ + boolean hasTransactionId(); + /** + * required string transactionId = 1; + */ + java.lang.String getTransactionId(); + /** + * required string transactionId = 1; + */ + com.google.protobuf.ByteString + getTransactionIdBytes(); } /** * Protobuf type {@code org.opendaylight.controller.mdsal.CanCommitTransaction} @@ -44,6 +59,7 @@ public final class ThreePhaseCommitCohortMessages { com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { initFields(); + int mutable_bitField0_ = 0; com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet.newBuilder(); try { @@ -61,6 +77,11 @@ public final class ThreePhaseCommitCohortMessages { } break; } + case 10: { + bitField0_ |= 0x00000001; + transactionId_ = input.readBytes(); + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -100,13 +121,62 @@ public final class ThreePhaseCommitCohortMessages { return PARSER; } + private int bitField0_; + // required string transactionId = 1; + public static final int TRANSACTIONID_FIELD_NUMBER = 1; + private java.lang.Object transactionId_; + /** + * required string transactionId = 1; + */ + public boolean hasTransactionId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string transactionId = 1; + */ + public java.lang.String getTransactionId() { + java.lang.Object ref = transactionId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + transactionId_ = s; + } + return s; + } + } + /** + * required string transactionId = 1; + */ + public com.google.protobuf.ByteString + getTransactionIdBytes() { + java.lang.Object ref = transactionId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + transactionId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + private void initFields() { + transactionId_ = ""; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized != -1) return isInitialized == 1; + if (!hasTransactionId()) { + memoizedIsInitialized = 0; + return false; + } memoizedIsInitialized = 1; return true; } @@ -114,6 +184,9 @@ public final class ThreePhaseCommitCohortMessages { public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getTransactionIdBytes()); + } getUnknownFields().writeTo(output); } @@ -123,6 +196,10 @@ public final class ThreePhaseCommitCohortMessages { if (size != -1) return size; size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getTransactionIdBytes()); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -239,6 +316,8 @@ public final class ThreePhaseCommitCohortMessages { public Builder clear() { super.clear(); + transactionId_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); return this; } @@ -265,6 +344,13 @@ public final class ThreePhaseCommitCohortMessages { public org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CanCommitTransaction buildPartial() { org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CanCommitTransaction result = new org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CanCommitTransaction(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.transactionId_ = transactionId_; + result.bitField0_ = to_bitField0_; onBuilt(); return result; } @@ -280,11 +366,20 @@ public final class ThreePhaseCommitCohortMessages { public Builder mergeFrom(org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CanCommitTransaction other) { if (other == org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CanCommitTransaction.getDefaultInstance()) return this; + if (other.hasTransactionId()) { + bitField0_ |= 0x00000001; + transactionId_ = other.transactionId_; + onChanged(); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } public final boolean isInitialized() { + if (!hasTransactionId()) { + + return false; + } return true; } @@ -305,6 +400,81 @@ public final class ThreePhaseCommitCohortMessages { } return this; } + private int bitField0_; + + // required string transactionId = 1; + private java.lang.Object transactionId_ = ""; + /** + * required string transactionId = 1; + */ + public boolean hasTransactionId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string transactionId = 1; + */ + public java.lang.String getTransactionId() { + java.lang.Object ref = transactionId_; + if (!(ref instanceof java.lang.String)) { + java.lang.String s = ((com.google.protobuf.ByteString) ref) + .toStringUtf8(); + transactionId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string transactionId = 1; + */ + public com.google.protobuf.ByteString + getTransactionIdBytes() { + java.lang.Object ref = transactionId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + transactionId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string transactionId = 1; + */ + public Builder setTransactionId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + transactionId_ = value; + onChanged(); + return this; + } + /** + * required string transactionId = 1; + */ + public Builder clearTransactionId() { + bitField0_ = (bitField0_ & ~0x00000001); + transactionId_ = getDefaultInstance().getTransactionId(); + onChanged(); + return this; + } + /** + * required string transactionId = 1; + */ + public Builder setTransactionIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + transactionId_ = value; + onChanged(); + return this; + } // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.mdsal.CanCommitTransaction) } @@ -723,6 +893,21 @@ public final class ThreePhaseCommitCohortMessages { public interface AbortTransactionOrBuilder extends com.google.protobuf.MessageOrBuilder { + + // required string transactionId = 1; + /** + * required string transactionId = 1; + */ + boolean hasTransactionId(); + /** + * required string transactionId = 1; + */ + java.lang.String getTransactionId(); + /** + * required string transactionId = 1; + */ + com.google.protobuf.ByteString + getTransactionIdBytes(); } /** * Protobuf type {@code org.opendaylight.controller.mdsal.AbortTransaction} @@ -757,6 +942,7 @@ public final class ThreePhaseCommitCohortMessages { com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { initFields(); + int mutable_bitField0_ = 0; com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet.newBuilder(); try { @@ -774,6 +960,11 @@ public final class ThreePhaseCommitCohortMessages { } break; } + case 10: { + bitField0_ |= 0x00000001; + transactionId_ = input.readBytes(); + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -813,13 +1004,62 @@ public final class ThreePhaseCommitCohortMessages { return PARSER; } + private int bitField0_; + // required string transactionId = 1; + public static final int TRANSACTIONID_FIELD_NUMBER = 1; + private java.lang.Object transactionId_; + /** + * required string transactionId = 1; + */ + public boolean hasTransactionId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string transactionId = 1; + */ + public java.lang.String getTransactionId() { + java.lang.Object ref = transactionId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + transactionId_ = s; + } + return s; + } + } + /** + * required string transactionId = 1; + */ + public com.google.protobuf.ByteString + getTransactionIdBytes() { + java.lang.Object ref = transactionId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + transactionId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + private void initFields() { + transactionId_ = ""; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized != -1) return isInitialized == 1; + if (!hasTransactionId()) { + memoizedIsInitialized = 0; + return false; + } memoizedIsInitialized = 1; return true; } @@ -827,6 +1067,9 @@ public final class ThreePhaseCommitCohortMessages { public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getTransactionIdBytes()); + } getUnknownFields().writeTo(output); } @@ -836,6 +1079,10 @@ public final class ThreePhaseCommitCohortMessages { if (size != -1) return size; size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getTransactionIdBytes()); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -952,6 +1199,8 @@ public final class ThreePhaseCommitCohortMessages { public Builder clear() { super.clear(); + transactionId_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); return this; } @@ -978,6 +1227,13 @@ public final class ThreePhaseCommitCohortMessages { public org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.AbortTransaction buildPartial() { org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.AbortTransaction result = new org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.AbortTransaction(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.transactionId_ = transactionId_; + result.bitField0_ = to_bitField0_; onBuilt(); return result; } @@ -993,11 +1249,20 @@ public final class ThreePhaseCommitCohortMessages { public Builder mergeFrom(org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.AbortTransaction other) { if (other == org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.AbortTransaction.getDefaultInstance()) return this; + if (other.hasTransactionId()) { + bitField0_ |= 0x00000001; + transactionId_ = other.transactionId_; + onChanged(); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } public final boolean isInitialized() { + if (!hasTransactionId()) { + + return false; + } return true; } @@ -1018,6 +1283,81 @@ public final class ThreePhaseCommitCohortMessages { } return this; } + private int bitField0_; + + // required string transactionId = 1; + private java.lang.Object transactionId_ = ""; + /** + * required string transactionId = 1; + */ + public boolean hasTransactionId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string transactionId = 1; + */ + public java.lang.String getTransactionId() { + java.lang.Object ref = transactionId_; + if (!(ref instanceof java.lang.String)) { + java.lang.String s = ((com.google.protobuf.ByteString) ref) + .toStringUtf8(); + transactionId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string transactionId = 1; + */ + public com.google.protobuf.ByteString + getTransactionIdBytes() { + java.lang.Object ref = transactionId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + transactionId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string transactionId = 1; + */ + public Builder setTransactionId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + transactionId_ = value; + onChanged(); + return this; + } + /** + * required string transactionId = 1; + */ + public Builder clearTransactionId() { + bitField0_ = (bitField0_ & ~0x00000001); + transactionId_ = getDefaultInstance().getTransactionId(); + onChanged(); + return this; + } + /** + * required string transactionId = 1; + */ + public Builder setTransactionIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + transactionId_ = value; + onChanged(); + return this; + } // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.mdsal.AbortTransaction) } @@ -1341,6 +1681,21 @@ public final class ThreePhaseCommitCohortMessages { public interface CommitTransactionOrBuilder extends com.google.protobuf.MessageOrBuilder { + + // required string transactionId = 1; + /** + * required string transactionId = 1; + */ + boolean hasTransactionId(); + /** + * required string transactionId = 1; + */ + java.lang.String getTransactionId(); + /** + * required string transactionId = 1; + */ + com.google.protobuf.ByteString + getTransactionIdBytes(); } /** * Protobuf type {@code org.opendaylight.controller.mdsal.CommitTransaction} @@ -1375,6 +1730,7 @@ public final class ThreePhaseCommitCohortMessages { com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { initFields(); + int mutable_bitField0_ = 0; com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet.newBuilder(); try { @@ -1392,6 +1748,11 @@ public final class ThreePhaseCommitCohortMessages { } break; } + case 10: { + bitField0_ |= 0x00000001; + transactionId_ = input.readBytes(); + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -1431,13 +1792,62 @@ public final class ThreePhaseCommitCohortMessages { return PARSER; } + private int bitField0_; + // required string transactionId = 1; + public static final int TRANSACTIONID_FIELD_NUMBER = 1; + private java.lang.Object transactionId_; + /** + * required string transactionId = 1; + */ + public boolean hasTransactionId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string transactionId = 1; + */ + public java.lang.String getTransactionId() { + java.lang.Object ref = transactionId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + transactionId_ = s; + } + return s; + } + } + /** + * required string transactionId = 1; + */ + public com.google.protobuf.ByteString + getTransactionIdBytes() { + java.lang.Object ref = transactionId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + transactionId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + private void initFields() { + transactionId_ = ""; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized != -1) return isInitialized == 1; + if (!hasTransactionId()) { + memoizedIsInitialized = 0; + return false; + } memoizedIsInitialized = 1; return true; } @@ -1445,6 +1855,9 @@ public final class ThreePhaseCommitCohortMessages { public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getTransactionIdBytes()); + } getUnknownFields().writeTo(output); } @@ -1454,6 +1867,10 @@ public final class ThreePhaseCommitCohortMessages { if (size != -1) return size; size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getTransactionIdBytes()); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -1570,6 +1987,8 @@ public final class ThreePhaseCommitCohortMessages { public Builder clear() { super.clear(); + transactionId_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); return this; } @@ -1596,6 +2015,13 @@ public final class ThreePhaseCommitCohortMessages { public org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CommitTransaction buildPartial() { org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CommitTransaction result = new org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CommitTransaction(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.transactionId_ = transactionId_; + result.bitField0_ = to_bitField0_; onBuilt(); return result; } @@ -1611,11 +2037,20 @@ public final class ThreePhaseCommitCohortMessages { public Builder mergeFrom(org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CommitTransaction other) { if (other == org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CommitTransaction.getDefaultInstance()) return this; + if (other.hasTransactionId()) { + bitField0_ |= 0x00000001; + transactionId_ = other.transactionId_; + onChanged(); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } public final boolean isInitialized() { + if (!hasTransactionId()) { + + return false; + } return true; } @@ -1636,6 +2071,81 @@ public final class ThreePhaseCommitCohortMessages { } return this; } + private int bitField0_; + + // required string transactionId = 1; + private java.lang.Object transactionId_ = ""; + /** + * required string transactionId = 1; + */ + public boolean hasTransactionId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string transactionId = 1; + */ + public java.lang.String getTransactionId() { + java.lang.Object ref = transactionId_; + if (!(ref instanceof java.lang.String)) { + java.lang.String s = ((com.google.protobuf.ByteString) ref) + .toStringUtf8(); + transactionId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string transactionId = 1; + */ + public com.google.protobuf.ByteString + getTransactionIdBytes() { + java.lang.Object ref = transactionId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + transactionId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string transactionId = 1; + */ + public Builder setTransactionId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + transactionId_ = value; + onChanged(); + return this; + } + /** + * required string transactionId = 1; + */ + public Builder clearTransactionId() { + bitField0_ = (bitField0_ & ~0x00000001); + transactionId_ = getDefaultInstance().getTransactionId(); + onChanged(); + return this; + } + /** + * required string transactionId = 1; + */ + public Builder setTransactionIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + transactionId_ = value; + onChanged(); + return this; + } // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.mdsal.CommitTransaction) } @@ -2625,14 +3135,16 @@ public final class ThreePhaseCommitCohortMessages { static { java.lang.String[] descriptorData = { "\n\014Cohort.proto\022!org.opendaylight.control" + - "ler.mdsal\"\026\n\024CanCommitTransaction\".\n\031Can" + - "CommitTransactionReply\022\021\n\tcanCommit\030\001 \002(" + - "\010\"\022\n\020AbortTransaction\"\027\n\025AbortTransactio" + - "nReply\"\023\n\021CommitTransaction\"\030\n\026CommitTra" + - "nsactionReply\"\026\n\024PreCommitTransaction\"\033\n" + - "\031PreCommitTransactionReplyBZ\n8org.openda" + - "ylight.controller.protobuff.messages.coh" + - "ort3pcB\036ThreePhaseCommitCohortMessages" + "ler.mdsal\"-\n\024CanCommitTransaction\022\025\n\rtra" + + "nsactionId\030\001 \002(\t\".\n\031CanCommitTransaction" + + "Reply\022\021\n\tcanCommit\030\001 \002(\010\")\n\020AbortTransac" + + "tion\022\025\n\rtransactionId\030\001 \002(\t\"\027\n\025AbortTran" + + "sactionReply\"*\n\021CommitTransaction\022\025\n\rtra" + + "nsactionId\030\001 \002(\t\"\030\n\026CommitTransactionRep" + + "ly\"\026\n\024PreCommitTransaction\"\033\n\031PreCommitT" + + "ransactionReplyBZ\n8org.opendaylight.cont" + + "roller.protobuff.messages.cohort3pcB\036Thr", + "eePhaseCommitCohortMessages" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -2644,7 +3156,7 @@ public final class ThreePhaseCommitCohortMessages { internal_static_org_opendaylight_controller_mdsal_CanCommitTransaction_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_org_opendaylight_controller_mdsal_CanCommitTransaction_descriptor, - new java.lang.String[] { }); + new java.lang.String[] { "TransactionId", }); internal_static_org_opendaylight_controller_mdsal_CanCommitTransactionReply_descriptor = getDescriptor().getMessageTypes().get(1); internal_static_org_opendaylight_controller_mdsal_CanCommitTransactionReply_fieldAccessorTable = new @@ -2656,7 +3168,7 @@ public final class ThreePhaseCommitCohortMessages { internal_static_org_opendaylight_controller_mdsal_AbortTransaction_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_org_opendaylight_controller_mdsal_AbortTransaction_descriptor, - new java.lang.String[] { }); + new java.lang.String[] { "TransactionId", }); internal_static_org_opendaylight_controller_mdsal_AbortTransactionReply_descriptor = getDescriptor().getMessageTypes().get(3); internal_static_org_opendaylight_controller_mdsal_AbortTransactionReply_fieldAccessorTable = new @@ -2668,7 +3180,7 @@ public final class ThreePhaseCommitCohortMessages { internal_static_org_opendaylight_controller_mdsal_CommitTransaction_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_org_opendaylight_controller_mdsal_CommitTransaction_descriptor, - new java.lang.String[] { }); + new java.lang.String[] { "TransactionId", }); internal_static_org_opendaylight_controller_mdsal_CommitTransactionReply_descriptor = getDescriptor().getMessageTypes().get(5); internal_static_org_opendaylight_controller_mdsal_CommitTransactionReply_fieldAccessorTable = new diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessages.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessages.java index 3926bc7dc3..e7f2c361ae 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessages.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessages.java @@ -4176,6 +4176,50 @@ public final class NormalizedNodeMessages { */ org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.PathArgumentOrBuilder getArgumentsOrBuilder( int index); + + // repeated string code = 2; + /** + * repeated string code = 2; + * + *

+     * A list of string codes which can be used for any repeated strings in the path args. This is
+     * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+     * that contains the codes.
+     * 
+ */ + java.util.List + getCodeList(); + /** + * repeated string code = 2; + * + *
+     * A list of string codes which can be used for any repeated strings in the path args. This is
+     * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+     * that contains the codes.
+     * 
+ */ + int getCodeCount(); + /** + * repeated string code = 2; + * + *
+     * A list of string codes which can be used for any repeated strings in the path args. This is
+     * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+     * that contains the codes.
+     * 
+ */ + java.lang.String getCode(int index); + /** + * repeated string code = 2; + * + *
+     * A list of string codes which can be used for any repeated strings in the path args. This is
+     * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+     * that contains the codes.
+     * 
+ */ + com.google.protobuf.ByteString + getCodeBytes(int index); } /** * Protobuf type {@code org.opendaylight.controller.mdsal.InstanceIdentifier} @@ -4236,6 +4280,14 @@ public final class NormalizedNodeMessages { arguments_.add(input.readMessage(org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.PathArgument.PARSER, extensionRegistry)); break; } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + code_ = new com.google.protobuf.LazyStringArrayList(); + mutable_bitField0_ |= 0x00000002; + } + code_.add(input.readBytes()); + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -4247,6 +4299,9 @@ public final class NormalizedNodeMessages { if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) { arguments_ = java.util.Collections.unmodifiableList(arguments_); } + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + code_ = new com.google.protobuf.UnmodifiableLazyStringList(code_); + } this.unknownFields = unknownFields.build(); makeExtensionsImmutable(); } @@ -4314,8 +4369,63 @@ public final class NormalizedNodeMessages { return arguments_.get(index); } + // repeated string code = 2; + public static final int CODE_FIELD_NUMBER = 2; + private com.google.protobuf.LazyStringList code_; + /** + * repeated string code = 2; + * + *
+     * A list of string codes which can be used for any repeated strings in the path args. This is
+     * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+     * that contains the codes.
+     * 
+ */ + public java.util.List + getCodeList() { + return code_; + } + /** + * repeated string code = 2; + * + *
+     * A list of string codes which can be used for any repeated strings in the path args. This is
+     * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+     * that contains the codes.
+     * 
+ */ + public int getCodeCount() { + return code_.size(); + } + /** + * repeated string code = 2; + * + *
+     * A list of string codes which can be used for any repeated strings in the path args. This is
+     * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+     * that contains the codes.
+     * 
+ */ + public java.lang.String getCode(int index) { + return code_.get(index); + } + /** + * repeated string code = 2; + * + *
+     * A list of string codes which can be used for any repeated strings in the path args. This is
+     * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+     * that contains the codes.
+     * 
+ */ + public com.google.protobuf.ByteString + getCodeBytes(int index) { + return code_.getByteString(index); + } + private void initFields() { arguments_ = java.util.Collections.emptyList(); + code_ = com.google.protobuf.LazyStringArrayList.EMPTY; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -4338,6 +4448,9 @@ public final class NormalizedNodeMessages { for (int i = 0; i < arguments_.size(); i++) { output.writeMessage(1, arguments_.get(i)); } + for (int i = 0; i < code_.size(); i++) { + output.writeBytes(2, code_.getByteString(i)); + } getUnknownFields().writeTo(output); } @@ -4351,6 +4464,15 @@ public final class NormalizedNodeMessages { size += com.google.protobuf.CodedOutputStream .computeMessageSize(1, arguments_.get(i)); } + { + int dataSize = 0; + for (int i = 0; i < code_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeBytesSizeNoTag(code_.getByteString(i)); + } + size += dataSize; + size += 1 * getCodeList().size(); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -4474,6 +4596,8 @@ public final class NormalizedNodeMessages { } else { argumentsBuilder_.clear(); } + code_ = com.google.protobuf.LazyStringArrayList.EMPTY; + bitField0_ = (bitField0_ & ~0x00000002); return this; } @@ -4510,6 +4634,12 @@ public final class NormalizedNodeMessages { } else { result.arguments_ = argumentsBuilder_.build(); } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + code_ = new com.google.protobuf.UnmodifiableLazyStringList( + code_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.code_ = code_; onBuilt(); return result; } @@ -4551,6 +4681,16 @@ public final class NormalizedNodeMessages { } } } + if (!other.code_.isEmpty()) { + if (code_.isEmpty()) { + code_ = other.code_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureCodeIsMutable(); + code_.addAll(other.code_); + } + onChanged(); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -4824,6 +4964,153 @@ public final class NormalizedNodeMessages { return argumentsBuilder_; } + // repeated string code = 2; + private com.google.protobuf.LazyStringList code_ = com.google.protobuf.LazyStringArrayList.EMPTY; + private void ensureCodeIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + code_ = new com.google.protobuf.LazyStringArrayList(code_); + bitField0_ |= 0x00000002; + } + } + /** + * repeated string code = 2; + * + *
+       * A list of string codes which can be used for any repeated strings in the path args. This is
+       * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+       * that contains the codes.
+       * 
+ */ + public java.util.List + getCodeList() { + return java.util.Collections.unmodifiableList(code_); + } + /** + * repeated string code = 2; + * + *
+       * A list of string codes which can be used for any repeated strings in the path args. This is
+       * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+       * that contains the codes.
+       * 
+ */ + public int getCodeCount() { + return code_.size(); + } + /** + * repeated string code = 2; + * + *
+       * A list of string codes which can be used for any repeated strings in the path args. This is
+       * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+       * that contains the codes.
+       * 
+ */ + public java.lang.String getCode(int index) { + return code_.get(index); + } + /** + * repeated string code = 2; + * + *
+       * A list of string codes which can be used for any repeated strings in the path args. This is
+       * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+       * that contains the codes.
+       * 
+ */ + public com.google.protobuf.ByteString + getCodeBytes(int index) { + return code_.getByteString(index); + } + /** + * repeated string code = 2; + * + *
+       * A list of string codes which can be used for any repeated strings in the path args. This is
+       * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+       * that contains the codes.
+       * 
+ */ + public Builder setCode( + int index, java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureCodeIsMutable(); + code_.set(index, value); + onChanged(); + return this; + } + /** + * repeated string code = 2; + * + *
+       * A list of string codes which can be used for any repeated strings in the path args. This is
+       * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+       * that contains the codes.
+       * 
+ */ + public Builder addCode( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureCodeIsMutable(); + code_.add(value); + onChanged(); + return this; + } + /** + * repeated string code = 2; + * + *
+       * A list of string codes which can be used for any repeated strings in the path args. This is
+       * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+       * that contains the codes.
+       * 
+ */ + public Builder addAllCode( + java.lang.Iterable values) { + ensureCodeIsMutable(); + super.addAll(values, code_); + onChanged(); + return this; + } + /** + * repeated string code = 2; + * + *
+       * A list of string codes which can be used for any repeated strings in the path args. This is
+       * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+       * that contains the codes.
+       * 
+ */ + public Builder clearCode() { + code_ = com.google.protobuf.LazyStringArrayList.EMPTY; + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + * repeated string code = 2; + * + *
+       * A list of string codes which can be used for any repeated strings in the path args. This is
+       * optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode,
+       * that contains the codes.
+       * 
+ */ + public Builder addCodeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + ensureCodeIsMutable(); + code_.add(value); + onChanged(); + return this; + } + // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.mdsal.InstanceIdentifier) } @@ -9998,30 +10285,30 @@ public final class NormalizedNodeMessages { "controller.mdsal.PathArgumentAttribute\022@" + "\n\nattributes\030\005 \003(\0132,.org.opendaylight.co" + "ntroller.mdsal.Attribute\022\017\n\007intType\030\006 \001(" + - "\005\"X\n\022InstanceIdentifier\022B\n\targuments\030\001 \003" + + "\005\"f\n\022InstanceIdentifier\022B\n\targuments\030\001 \003" + "(\0132/.org.opendaylight.controller.mdsal.P" + - "athArgument\"\245\003\n\004Node\022\014\n\004path\030\001 \001(\t\022\014\n\004ty" + - "pe\030\002 \001(\t\022E\n\014pathArgument\030\003 \001(\0132/.org.ope" + - "ndaylight.controller.mdsal.PathArgument\022" + - "\017\n\007intType\030\004 \001(\005\022@\n\nattributes\030\005 \003(\0132,.o", - "rg.opendaylight.controller.mdsal.Attribu" + - "te\0226\n\005child\030\006 \003(\0132\'.org.opendaylight.con" + - "troller.mdsal.Node\022\r\n\005value\030\007 \001(\t\022\021\n\tval" + - "ueType\030\010 \001(\t\022\024\n\014intValueType\030\t \001(\005\022V\n\027in" + - "stanceIdentifierValue\030\n \001(\01325.org.openda" + - "ylight.controller.mdsal.InstanceIdentifi" + - "er\022\021\n\tbitsValue\030\013 \003(\t\022\014\n\004code\030\014 \003(\t\"`\n\tC" + - "ontainer\022\022\n\nparentPath\030\001 \002(\t\022?\n\016normaliz" + - "edNode\030\002 \001(\0132\'.org.opendaylight.controll" + - "er.mdsal.Node\"\246\001\n\014NodeMapEntry\022U\n\026instan", - "ceIdentifierPath\030\001 \002(\01325.org.opendayligh" + - "t.controller.mdsal.InstanceIdentifier\022?\n" + - "\016normalizedNode\030\002 \001(\0132\'.org.opendaylight" + - ".controller.mdsal.Node\"N\n\007NodeMap\022C\n\nmap" + - "Entries\030\001 \003(\0132/.org.opendaylight.control" + - "ler.mdsal.NodeMapEntryBO\n5org.opendaylig" + - "ht.controller.protobuff.messages.commonB" + - "\026NormalizedNodeMessages" + "athArgument\022\014\n\004code\030\002 \003(\t\"\245\003\n\004Node\022\014\n\004pa" + + "th\030\001 \001(\t\022\014\n\004type\030\002 \001(\t\022E\n\014pathArgument\030\003" + + " \001(\0132/.org.opendaylight.controller.mdsal" + + ".PathArgument\022\017\n\007intType\030\004 \001(\005\022@\n\nattrib", + "utes\030\005 \003(\0132,.org.opendaylight.controller" + + ".mdsal.Attribute\0226\n\005child\030\006 \003(\0132\'.org.op" + + "endaylight.controller.mdsal.Node\022\r\n\005valu" + + "e\030\007 \001(\t\022\021\n\tvalueType\030\010 \001(\t\022\024\n\014intValueTy" + + "pe\030\t \001(\005\022V\n\027instanceIdentifierValue\030\n \001(" + + "\01325.org.opendaylight.controller.mdsal.In" + + "stanceIdentifier\022\021\n\tbitsValue\030\013 \003(\t\022\014\n\004c" + + "ode\030\014 \003(\t\"`\n\tContainer\022\022\n\nparentPath\030\001 \002" + + "(\t\022?\n\016normalizedNode\030\002 \001(\0132\'.org.openday" + + "light.controller.mdsal.Node\"\246\001\n\014NodeMapE", + "ntry\022U\n\026instanceIdentifierPath\030\001 \002(\01325.o" + + "rg.opendaylight.controller.mdsal.Instanc" + + "eIdentifier\022?\n\016normalizedNode\030\002 \001(\0132\'.or" + + "g.opendaylight.controller.mdsal.Node\"N\n\007" + + "NodeMap\022C\n\nmapEntries\030\001 \003(\0132/.org.openda" + + "ylight.controller.mdsal.NodeMapEntryBO\n5" + + "org.opendaylight.controller.protobuff.me" + + "ssages.commonB\026NormalizedNodeMessages" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -10057,7 +10344,7 @@ public final class NormalizedNodeMessages { internal_static_org_opendaylight_controller_mdsal_InstanceIdentifier_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_org_opendaylight_controller_mdsal_InstanceIdentifier_descriptor, - new java.lang.String[] { "Arguments", }); + new java.lang.String[] { "Arguments", "Code", }); internal_static_org_opendaylight_controller_mdsal_Node_descriptor = getDescriptor().getMessageTypes().get(5); internal_static_org_opendaylight_controller_mdsal_Node_fieldAccessorTable = new diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessages.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessages.java index d956bb174b..feb60ae829 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessages.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessages.java @@ -788,794 +788,6 @@ public final class ShardTransactionChainMessages { // @@protoc_insertion_point(class_scope:org.opendaylight.controller.mdsal.CloseTransactionChainReply) } - public interface CreateTransactionChainOrBuilder - extends com.google.protobuf.MessageOrBuilder { - } - /** - * Protobuf type {@code org.opendaylight.controller.mdsal.CreateTransactionChain} - */ - public static final class CreateTransactionChain extends - com.google.protobuf.GeneratedMessage - implements CreateTransactionChainOrBuilder { - // Use CreateTransactionChain.newBuilder() to construct. - private CreateTransactionChain(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - this.unknownFields = builder.getUnknownFields(); - } - private CreateTransactionChain(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - - private static final CreateTransactionChain defaultInstance; - public static CreateTransactionChain getDefaultInstance() { - return defaultInstance; - } - - public CreateTransactionChain getDefaultInstanceForType() { - return defaultInstance; - } - - private final com.google.protobuf.UnknownFieldSet unknownFields; - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private CreateTransactionChain( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - initFields(); - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.class, org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.Builder.class); - } - - public static com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public CreateTransactionChain parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new CreateTransactionChain(input, extensionRegistry); - } - }; - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - private void initFields() { - } - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized != -1) return isInitialized == 1; - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - getUnknownFields().writeTo(output); - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - size += getUnknownFields().getSerializedSize(); - memoizedSerializedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - @java.lang.Override - protected java.lang.Object writeReplace() - throws java.io.ObjectStreamException { - return super.writeReplace(); - } - - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input, extensionRegistry); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code org.opendaylight.controller.mdsal.CreateTransactionChain} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder - implements org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.class, org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.Builder.class); - } - - // Construct using org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - } - } - private static Builder create() { - return new Builder(); - } - - public Builder clear() { - super.clear(); - return this; - } - - public Builder clone() { - return create().mergeFrom(buildPartial()); - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_descriptor; - } - - public org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain getDefaultInstanceForType() { - return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.getDefaultInstance(); - } - - public org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain build() { - org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain buildPartial() { - org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain result = new org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain(this); - onBuilt(); - return result; - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain) { - return mergeFrom((org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain other) { - if (other == org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.getDefaultInstance()) return this; - this.mergeUnknownFields(other.getUnknownFields()); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - - // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.mdsal.CreateTransactionChain) - } - - static { - defaultInstance = new CreateTransactionChain(true); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:org.opendaylight.controller.mdsal.CreateTransactionChain) - } - - public interface CreateTransactionChainReplyOrBuilder - extends com.google.protobuf.MessageOrBuilder { - - // required string transactionChainPath = 1; - /** - * required string transactionChainPath = 1; - */ - boolean hasTransactionChainPath(); - /** - * required string transactionChainPath = 1; - */ - java.lang.String getTransactionChainPath(); - /** - * required string transactionChainPath = 1; - */ - com.google.protobuf.ByteString - getTransactionChainPathBytes(); - } - /** - * Protobuf type {@code org.opendaylight.controller.mdsal.CreateTransactionChainReply} - */ - public static final class CreateTransactionChainReply extends - com.google.protobuf.GeneratedMessage - implements CreateTransactionChainReplyOrBuilder { - // Use CreateTransactionChainReply.newBuilder() to construct. - private CreateTransactionChainReply(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - this.unknownFields = builder.getUnknownFields(); - } - private CreateTransactionChainReply(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - - private static final CreateTransactionChainReply defaultInstance; - public static CreateTransactionChainReply getDefaultInstance() { - return defaultInstance; - } - - public CreateTransactionChainReply getDefaultInstanceForType() { - return defaultInstance; - } - - private final com.google.protobuf.UnknownFieldSet unknownFields; - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private CreateTransactionChainReply( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - initFields(); - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - bitField0_ |= 0x00000001; - transactionChainPath_ = input.readBytes(); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.class, org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.Builder.class); - } - - public static com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public CreateTransactionChainReply parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new CreateTransactionChainReply(input, extensionRegistry); - } - }; - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - private int bitField0_; - // required string transactionChainPath = 1; - public static final int TRANSACTIONCHAINPATH_FIELD_NUMBER = 1; - private java.lang.Object transactionChainPath_; - /** - * required string transactionChainPath = 1; - */ - public boolean hasTransactionChainPath() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * required string transactionChainPath = 1; - */ - public java.lang.String getTransactionChainPath() { - java.lang.Object ref = transactionChainPath_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (bs.isValidUtf8()) { - transactionChainPath_ = s; - } - return s; - } - } - /** - * required string transactionChainPath = 1; - */ - public com.google.protobuf.ByteString - getTransactionChainPathBytes() { - java.lang.Object ref = transactionChainPath_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - transactionChainPath_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private void initFields() { - transactionChainPath_ = ""; - } - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized != -1) return isInitialized == 1; - - if (!hasTransactionChainPath()) { - memoizedIsInitialized = 0; - return false; - } - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - if (((bitField0_ & 0x00000001) == 0x00000001)) { - output.writeBytes(1, getTransactionChainPathBytes()); - } - getUnknownFields().writeTo(output); - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - size += com.google.protobuf.CodedOutputStream - .computeBytesSize(1, getTransactionChainPathBytes()); - } - size += getUnknownFields().getSerializedSize(); - memoizedSerializedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - @java.lang.Override - protected java.lang.Object writeReplace() - throws java.io.ObjectStreamException { - return super.writeReplace(); - } - - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input, extensionRegistry); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code org.opendaylight.controller.mdsal.CreateTransactionChainReply} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder - implements org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReplyOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.class, org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.Builder.class); - } - - // Construct using org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - } - } - private static Builder create() { - return new Builder(); - } - - public Builder clear() { - super.clear(); - transactionChainPath_ = ""; - bitField0_ = (bitField0_ & ~0x00000001); - return this; - } - - public Builder clone() { - return create().mergeFrom(buildPartial()); - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_descriptor; - } - - public org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply getDefaultInstanceForType() { - return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.getDefaultInstance(); - } - - public org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply build() { - org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply buildPartial() { - org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply result = new org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) == 0x00000001)) { - to_bitField0_ |= 0x00000001; - } - result.transactionChainPath_ = transactionChainPath_; - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply) { - return mergeFrom((org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply other) { - if (other == org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.getDefaultInstance()) return this; - if (other.hasTransactionChainPath()) { - bitField0_ |= 0x00000001; - transactionChainPath_ = other.transactionChainPath_; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - return this; - } - - public final boolean isInitialized() { - if (!hasTransactionChainPath()) { - - return false; - } - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - // required string transactionChainPath = 1; - private java.lang.Object transactionChainPath_ = ""; - /** - * required string transactionChainPath = 1; - */ - public boolean hasTransactionChainPath() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * required string transactionChainPath = 1; - */ - public java.lang.String getTransactionChainPath() { - java.lang.Object ref = transactionChainPath_; - if (!(ref instanceof java.lang.String)) { - java.lang.String s = ((com.google.protobuf.ByteString) ref) - .toStringUtf8(); - transactionChainPath_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - * required string transactionChainPath = 1; - */ - public com.google.protobuf.ByteString - getTransactionChainPathBytes() { - java.lang.Object ref = transactionChainPath_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - transactionChainPath_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * required string transactionChainPath = 1; - */ - public Builder setTransactionChainPath( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - transactionChainPath_ = value; - onChanged(); - return this; - } - /** - * required string transactionChainPath = 1; - */ - public Builder clearTransactionChainPath() { - bitField0_ = (bitField0_ & ~0x00000001); - transactionChainPath_ = getDefaultInstance().getTransactionChainPath(); - onChanged(); - return this; - } - /** - * required string transactionChainPath = 1; - */ - public Builder setTransactionChainPathBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - transactionChainPath_ = value; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.mdsal.CreateTransactionChainReply) - } - - static { - defaultInstance = new CreateTransactionChainReply(true); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:org.opendaylight.controller.mdsal.CreateTransactionChainReply) - } - private static com.google.protobuf.Descriptors.Descriptor internal_static_org_opendaylight_controller_mdsal_CloseTransactionChain_descriptor; private static @@ -1586,16 +798,6 @@ public final class ShardTransactionChainMessages { private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_org_opendaylight_controller_mdsal_CloseTransactionChainReply_fieldAccessorTable; - private static com.google.protobuf.Descriptors.Descriptor - internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_fieldAccessorTable; - private static com.google.protobuf.Descriptors.Descriptor - internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { @@ -1608,12 +810,9 @@ public final class ShardTransactionChainMessages { "\n\033ShardTransactionChain.proto\022!org.opend" + "aylight.controller.mdsal\"3\n\025CloseTransac" + "tionChain\022\032\n\022transactionChainId\030\001 \001(\t\"\034\n" + - "\032CloseTransactionChainReply\"\030\n\026CreateTra" + - "nsactionChain\";\n\033CreateTransactionChainR" + - "eply\022\034\n\024transactionChainPath\030\001 \002(\tB[\n:or" + - "g.opendaylight.controller.protobuff.mess" + - "ages.transactionB\035ShardTransactionChainM" + - "essages" + "\032CloseTransactionChainReplyB[\n:org.opend" + + "aylight.controller.protobuff.messages.tr" + + "ansactionB\035ShardTransactionChainMessages" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -1632,18 +831,6 @@ public final class ShardTransactionChainMessages { com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_org_opendaylight_controller_mdsal_CloseTransactionChainReply_descriptor, new java.lang.String[] { }); - internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_descriptor = - getDescriptor().getMessageTypes().get(2); - internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_descriptor, - new java.lang.String[] { }); - internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_descriptor = - getDescriptor().getMessageTypes().get(3); - internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_descriptor, - new java.lang.String[] { "TransactionChainPath", }); return null; } }; diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/xml/codec/XmlStreamUtils.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/xml/codec/XmlStreamUtils.java index c9d5e89ae1..0f93f43c56 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/xml/codec/XmlStreamUtils.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/xml/codec/XmlStreamUtils.java @@ -100,7 +100,9 @@ public class XmlStreamUtils { for (Entry e: prefixes.getPrefixes()) { writer.writeNamespace(e.getValue(), e.getKey().toString()); } - LOG.debug("Instance identifier with Random prefix is now {}", str); + if(LOG.isDebugEnabled()) { + LOG.debug("Instance identifier with Random prefix is now {}", str); + } writer.writeCharacters(str); } @@ -169,7 +171,7 @@ public class XmlStreamUtils { DataSchemaNode childSchema = null; if (schema instanceof DataNodeContainer) { childSchema = SchemaUtils.findFirstSchema(child.getNodeType(), ((DataNodeContainer) schema).getChildNodes()).orNull(); - if (childSchema == null) { + if (childSchema == null && LOG.isDebugEnabled()) { LOG.debug("Probably the data node \"{}\" does not conform to schema", child == null ? "" : child.getNodeType().getLocalName()); } } @@ -192,7 +194,9 @@ public class XmlStreamUtils { */ public void writeValue(final @Nonnull XMLStreamWriter writer, final @Nonnull TypeDefinition type, final Object value) throws XMLStreamException { if (value == null) { - LOG.debug("Value of {}:{} is null, not encoding it", type.getQName().getNamespace(), type.getQName().getLocalName()); + if(LOG.isDebugEnabled()){ + LOG.debug("Value of {}:{} is null, not encoding it", type.getQName().getNamespace(), type.getQName().getLocalName()); + } return; } @@ -232,18 +236,24 @@ public class XmlStreamUtils { writer.writeNamespace(prefix, qname.getNamespace().toString()); writer.writeCharacters(prefix + ':' + qname.getLocalName()); } else { - LOG.debug("Value of {}:{} is not a QName but {}", type.getQName().getNamespace(), type.getQName().getLocalName(), value.getClass()); + if(LOG.isDebugEnabled()) { + LOG.debug("Value of {}:{} is not a QName but {}", type.getQName().getNamespace(), type.getQName().getLocalName(), value.getClass()); + } writer.writeCharacters(String.valueOf(value)); } } private static void write(final @Nonnull XMLStreamWriter writer, final @Nonnull InstanceIdentifierTypeDefinition type, final @Nonnull Object value) throws XMLStreamException { if (value instanceof YangInstanceIdentifier) { - LOG.debug("Writing InstanceIdentifier object {}", value); + if(LOG.isDebugEnabled()) { + LOG.debug("Writing InstanceIdentifier object {}", value); + } write(writer, (YangInstanceIdentifier)value); } else { - LOG.debug("Value of {}:{} is not an InstanceIdentifier but {}", type.getQName().getNamespace(), type.getQName().getLocalName(), value.getClass()); - writer.writeCharacters(String.valueOf(value)); + if(LOG.isDebugEnabled()) { + LOG.debug("Value of {}:{} is not an InstanceIdentifier but {}", type.getQName().getNamespace(), type.getQName().getLocalName(), value.getClass()); + } + writer.writeCharacters(String.valueOf(value)); } } } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/xml/codec/XmlUtils.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/xml/codec/XmlUtils.java index ea8f4a3ef1..d0cc2adb5f 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/xml/codec/XmlUtils.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/xml/codec/XmlUtils.java @@ -74,7 +74,9 @@ public class XmlUtils { * @return xml String */ public static String inputCompositeNodeToXml(CompositeNode cNode, SchemaContext schemaContext){ - LOG.debug("Converting input composite node to xml {}", cNode); + if(LOG.isDebugEnabled()) { + LOG.debug("Converting input composite node to xml {}", cNode); + } if (cNode == null) { return BLANK; } @@ -88,12 +90,14 @@ public class XmlUtils { Set rpcs = schemaContext.getOperations(); for(RpcDefinition rpc : rpcs) { if(rpc.getQName().equals(cNode.getNodeType())){ - LOG.debug("Found the rpc definition from schema context matching with input composite node {}", rpc.getQName()); - + if(LOG.isDebugEnabled()) { + LOG.debug("Found the rpc definition from schema context matching with input composite node {}", rpc.getQName()); + } CompositeNode inputContainer = cNode.getFirstCompositeByName(QName.create(cNode.getNodeType(), "input")); domTree = XmlDocumentUtils.toDocument(inputContainer, rpc.getInput(), XmlDocumentUtils.defaultValueCodecProvider()); - - LOG.debug("input composite node to document conversion complete, document is {}", domTree); + if(LOG.isDebugEnabled()) { + LOG.debug("input composite node to document conversion complete, document is {}", domTree); + } break; } } @@ -111,7 +115,9 @@ public class XmlUtils { * @return xml string */ public static String outputCompositeNodeToXml(CompositeNode cNode, SchemaContext schemaContext){ - LOG.debug("Converting output composite node to xml {}", cNode); + if(LOG.isDebugEnabled()) { + LOG.debug("Converting output composite node to xml {}", cNode); + } if (cNode == null) { return BLANK; } @@ -125,12 +131,14 @@ public class XmlUtils { Set rpcs = schemaContext.getOperations(); for(RpcDefinition rpc : rpcs) { if(rpc.getQName().equals(cNode.getNodeType())){ - LOG.debug("Found the rpc definition from schema context matching with output composite node {}", rpc.getQName()); - + if(LOG.isDebugEnabled()) { + LOG.debug("Found the rpc definition from schema context matching with output composite node {}", rpc.getQName()); + } CompositeNode outputContainer = cNode.getFirstCompositeByName(QName.create(cNode.getNodeType(), "output")); domTree = XmlDocumentUtils.toDocument(outputContainer, rpc.getOutput(), XmlDocumentUtils.defaultValueCodecProvider()); - - LOG.debug("output composite node to document conversion complete, document is {}", domTree); + if(LOG.isDebugEnabled()) { + LOG.debug("output composite node to document conversion complete, document is {}", domTree); + } break; } } @@ -152,8 +160,9 @@ public class XmlUtils { LOG.error("Error during translation of Document to OutputStream", e); } - LOG.debug("Document to string conversion complete, xml string is {} ", writer.toString()); - + if(LOG.isDebugEnabled()) { + LOG.debug("Document to string conversion complete, xml string is {} ", writer.toString()); + } return writer.toString(); } @@ -188,7 +197,9 @@ public class XmlUtils { * @return CompositeNode object based on the input, if any of the input parameter is null, a null object is returned */ public static CompositeNode inputXmlToCompositeNode(QName rpc, String xml, SchemaContext schemaContext){ - LOG.debug("Converting input xml to composite node {}", xml); + if(LOG.isDebugEnabled()) { + LOG.debug("Converting input xml to composite node {}", xml); + } if (xml==null || xml.length()==0) { return null; } @@ -208,8 +219,9 @@ public class XmlUtils { Set rpcs = schemaContext.getOperations(); for(RpcDefinition rpcDef : rpcs) { if(rpcDef.getQName().equals(rpc)){ - LOG.debug("found the rpc definition from schema context matching rpc {}", rpc); - + if(LOG.isDebugEnabled()) { + LOG.debug("found the rpc definition from schema context matching rpc {}", rpc); + } if(rpcDef.getInput() == null) { LOG.warn("found rpc definition's input is null"); return null; @@ -225,9 +237,9 @@ public class XmlUtils { List> dataNodes = XmlDocumentUtils.toDomNodes(xmlData, Optional.of(rpcDef.getInput().getChildNodes()), schemaContext); - - LOG.debug("Converted xml input to list of nodes {}", dataNodes); - + if(LOG.isDebugEnabled()) { + LOG.debug("Converted xml input to list of nodes {}", dataNodes); + } final CompositeNodeBuilder it = ImmutableCompositeNode.builder(); it.setQName(rpc); it.add(ImmutableCompositeNode.create(input, dataNodes)); @@ -240,8 +252,9 @@ public class XmlUtils { } catch (IOException e) { LOG.error("Error during building data tree from XML", e); } - - LOG.debug("Xml to composite node conversion complete {} ", compositeNode); + if(LOG.isDebugEnabled()) { + LOG.debug("Xml to composite node conversion complete {} ", compositeNode); + } return compositeNode; } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/resources/Cohort.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/Cohort.proto index dab64131e6..49c6cd07a8 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/resources/Cohort.proto +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/Cohort.proto @@ -5,7 +5,7 @@ option java_outer_classname = "ThreePhaseCommitCohortMessages"; message CanCommitTransaction{ - + required string transactionId = 1; } message CanCommitTransactionReply{ @@ -14,7 +14,7 @@ message CanCommitTransactionReply{ } message AbortTransaction{ - + required string transactionId = 1; } message AbortTransactionReply { @@ -22,7 +22,7 @@ message AbortTransactionReply { } message CommitTransaction{ - + required string transactionId = 1; } message CommitTransactionReply{ diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/resources/Common.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/Common.proto index 0b3ff21eb7..356bfbf684 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/resources/Common.proto +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/Common.proto @@ -37,6 +37,11 @@ message PathArgument { message InstanceIdentifier { repeated PathArgument arguments=1; + + // A list of string codes which can be used for any repeated strings in the path args. This is + // optional - an InstanceIdentifier may be encoded as part of another message, eg NormalizedNode, + // that contains the codes. + repeated string code = 2; } message Node{ diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodecTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodecTest.java index a9f9c722de..6de1083cbe 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodecTest.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodecTest.java @@ -68,15 +68,12 @@ public class NormalizedNodeToNodeCodecTest { new NormalizedNodeToNodeCodec(schemaContext); long start = System.currentTimeMillis(); Container container = - codec.encode(instanceIdentifierFromString(id), output); + codec.encode(output); long end = System.currentTimeMillis(); System.out.println("Timetaken to encode :"+(end-start)); assertNotNull(container); - assertEquals(id, container.getParentPath() + "/" - + NormalizedNodeSerializer.deSerialize(container.getNormalizedNode(), - container.getNormalizedNode().getPathArgument())); // Decode the normalized node from the ProtocolBuffer form // first get the node representation of normalized node @@ -84,7 +81,7 @@ public class NormalizedNodeToNodeCodecTest { start = System.currentTimeMillis(); NormalizedNode normalizedNode = - codec.decode(instanceIdentifierFromString(id), node); + codec.decode(node); end = System.currentTimeMillis(); System.out.println("Timetaken to decode :"+(end-start)); @@ -102,26 +99,18 @@ public class NormalizedNodeToNodeCodecTest { new NormalizedNodeToNodeCodec(schemaContext); Container container = - normalizedNodeToNodeCodec.encode(YangInstanceIdentifier.builder() - .build(), documentOne); + normalizedNodeToNodeCodec.encode(documentOne); final NormalizedNode decode = normalizedNodeToNodeCodec .decode( - instanceIdentifierFromString("/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test"), container.getNormalizedNode()); assertNotNull(decode); // let us ensure that the return decode normalized node encode returns same container Container containerResult = - normalizedNodeToNodeCodec.encode(YangInstanceIdentifier.builder() - .build(), decode); - - assertEquals(container.getParentPath(), containerResult.getParentPath()); - - assertEquals(containerResult.getNormalizedNode().getChildCount(), - container.getNormalizedNode().getChildCount()); + normalizedNodeToNodeCodec.encode(decode); // check first level children are proper List childrenResult = @@ -174,11 +163,11 @@ public class NormalizedNodeToNodeCodecTest { NormalizedNodeToNodeCodec codec = new NormalizedNodeToNodeCodec(schemaContext); - Container encode = codec.encode(identifier, uno); + Container encode = codec.encode(uno); System.out.println(encode.getNormalizedNode()); - codec.decode(identifier, encode.getNormalizedNode()); + codec.decode(encode.getNormalizedNode()); } } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtilsTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtilsTest.java index ffa8a1059e..d1e3eb202f 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtilsTest.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtilsTest.java @@ -14,15 +14,6 @@ import static junit.framework.TestCase.assertEquals; public class PathUtilsTest { - @Test - public void getParentPath(){ - assertEquals("", PathUtils.getParentPath("foobar")); - assertEquals("", PathUtils.getParentPath("/a")); - assertEquals("/a", PathUtils.getParentPath("/a/b")); - assertEquals("/a/b", PathUtils.getParentPath("/a/b/c")); - assertEquals("/a/b", PathUtils.getParentPath("a/b/c")); - } - @Test public void toStringNodeIdentifier(){ YangInstanceIdentifier.PathArgument pathArgument = nodeIdentifier(); diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/PathArgumentSerializerTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/PathArgumentSerializerTest.java index d1f21ee6f4..0990cdd4aa 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/PathArgumentSerializerTest.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/PathArgumentSerializerTest.java @@ -40,8 +40,7 @@ public class PathArgumentSerializerTest{ expectedException.expect(NullPointerException.class); expectedException.expectMessage("pathArgument should not be null"); - PathArgumentSerializer.serialize(mock( - NormalizedNodeSerializationContext.class), null); + PathArgumentSerializer.serialize(mock(QNameSerializationContext.class), null); } @@ -59,14 +58,13 @@ public class PathArgumentSerializerTest{ expectedException.expect(NullPointerException.class); expectedException.expectMessage("pathArgument should not be null"); - PathArgumentSerializer.deSerialize(mock(NormalizedNodeDeSerializationContext.class), null); + PathArgumentSerializer.deSerialize(mock(QNameDeSerializationContext.class), null); } @Test public void testSerializeNodeIdentifier(){ - NormalizedNodeSerializationContext serializationContext = - mock(NormalizedNodeSerializationContext.class); + QNameSerializationContext serializationContext = mock(QNameSerializationContext.class); when(serializationContext.addLocalName(anyString())).thenReturn(5); when(serializationContext.addNamespace(any(URI.class))).thenReturn(10); @@ -87,8 +85,7 @@ public class PathArgumentSerializerTest{ @Test public void testSerializeNodeIdentifierWithValue(){ - NormalizedNodeSerializationContext serializationContext = - mock(NormalizedNodeSerializationContext.class); + QNameSerializationContext serializationContext = mock(QNameSerializationContext.class); when(serializationContext.addLocalName(anyString())).thenReturn(5); when(serializationContext.addNamespace(any(URI.class))).thenReturn(10); @@ -110,9 +107,7 @@ public class PathArgumentSerializerTest{ @Test public void testSerializeNodeIdentifierWithPredicates(){ - NormalizedNodeSerializationContext serializationContext = - mock(NormalizedNodeSerializationContext.class); - + QNameSerializationContext serializationContext = mock(QNameSerializationContext.class); when(serializationContext.addLocalName("test")).thenReturn(5); when(serializationContext.addLocalName("child-name")).thenReturn(55); @@ -150,8 +145,7 @@ public class PathArgumentSerializerTest{ @Test public void testSerializeAugmentationIdentifier(){ - NormalizedNodeSerializationContext serializationContext = - mock(NormalizedNodeSerializationContext.class); + QNameSerializationContext serializationContext = mock(QNameSerializationContext.class); when(serializationContext.addLocalName(anyString())).thenReturn(55); when(serializationContext.addNamespace(any(URI.class))).thenReturn(66); diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/ValueSerializerTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/ValueSerializerTest.java index af7a385cbb..88c2695075 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/ValueSerializerTest.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/serialization/ValueSerializerTest.java @@ -5,15 +5,14 @@ import com.google.common.collect.ImmutableSet; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.mockito.Mockito; import org.opendaylight.controller.cluster.datastore.util.TestModel; import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; - import java.math.BigDecimal; import java.math.BigInteger; import java.util.Set; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; @@ -27,14 +26,15 @@ public class ValueSerializerTest{ public void testSerializeShort(){ short v1 = 5; NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock(NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.SHORT_TYPE.ordinal(), builder.getIntValueType()); assertEquals("5", builder.getValue()); - NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); + NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = + NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); - ValueSerializer.serialize(builder1, mock(NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder1, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.SHORT_TYPE.ordinal(), builder1.getType()); assertEquals("5", builder.getValue()); @@ -49,16 +49,15 @@ public class ValueSerializerTest{ NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock( - NormalizedNodeSerializationContext.class), expected); + ValueSerializer.serialize(builder, mock(QNameSerializationContext.class), expected); assertEquals(ValueType.INT_TYPE.ordinal(), builder.getIntValueType()); assertEquals("243", builder.getValue()); - NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); + NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = + NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); - ValueSerializer.serialize(builder1, mock( - NormalizedNodeSerializationContext.class), expected); + ValueSerializer.serialize(builder1, mock(QNameSerializationContext.class), expected); assertEquals(ValueType.INT_TYPE.ordinal(), builder1.getType()); assertEquals("243", builder1.getValue()); @@ -71,16 +70,14 @@ public class ValueSerializerTest{ public void testSerializeLong(){ long v1 = 5; NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock( - NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.LONG_TYPE.ordinal(), builder.getIntValueType()); assertEquals("5", builder.getValue()); NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); - ValueSerializer.serialize(builder1, mock( - NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder1, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.LONG_TYPE.ordinal(), builder1.getType()); assertEquals("5", builder1.getValue()); @@ -91,16 +88,14 @@ public class ValueSerializerTest{ public void testSerializeByte(){ byte v1 = 5; NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock( - NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.BYTE_TYPE.ordinal(), builder.getIntValueType()); assertEquals("5", builder.getValue()); NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); - ValueSerializer.serialize(builder1, mock( - NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder1, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.BYTE_TYPE.ordinal(), builder1.getType()); assertEquals("5", builder1.getValue()); @@ -110,8 +105,7 @@ public class ValueSerializerTest{ @Test public void testSerializeBits(){ NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock( - NormalizedNodeSerializationContext.class), + ValueSerializer.serialize(builder, mock(QNameSerializationContext.class), ImmutableSet.of("foo", "bar")); assertEquals(ValueType.BITS_TYPE.ordinal(), builder.getIntValueType()); @@ -120,8 +114,7 @@ public class ValueSerializerTest{ NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); - ValueSerializer.serialize(builder1, mock( - NormalizedNodeSerializationContext.class), + ValueSerializer.serialize(builder1, mock(QNameSerializationContext.class), ImmutableSet.of("foo", "bar")); assertEquals(ValueType.BITS_TYPE.ordinal(), builder1.getType()); @@ -134,8 +127,7 @@ public class ValueSerializerTest{ expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Expected value type to be Bits but was :"); NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock( - NormalizedNodeSerializationContext.class), + ValueSerializer.serialize(builder, mock(QNameSerializationContext.class), ImmutableSet.of(1, 2)); } @@ -143,16 +135,14 @@ public class ValueSerializerTest{ @Test public void testSerializeEmptyString(){ NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock( - NormalizedNodeSerializationContext.class),""); + ValueSerializer.serialize(builder, mock(QNameSerializationContext.class),""); assertEquals(ValueType.STRING_TYPE.ordinal(), builder.getIntValueType()); assertEquals("", builder.getValue()); NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); - ValueSerializer.serialize(builder1, mock( - NormalizedNodeSerializationContext.class),""); + ValueSerializer.serialize(builder1, mock(QNameSerializationContext.class),""); assertEquals(ValueType.STRING_TYPE.ordinal(), builder1.getType()); assertEquals("", builder1.getValue()); @@ -162,16 +152,15 @@ public class ValueSerializerTest{ @Test public void testSerializeString(){ NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock( - NormalizedNodeSerializationContext.class),"foo"); + ValueSerializer.serialize(builder, mock(QNameSerializationContext.class),"foo"); assertEquals(ValueType.STRING_TYPE.ordinal(), builder.getIntValueType()); assertEquals("foo", builder.getValue()); - NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); + NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = + NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); - ValueSerializer.serialize(builder1, mock( - NormalizedNodeSerializationContext.class),"foo"); + ValueSerializer.serialize(builder1, mock(QNameSerializationContext.class),"foo"); assertEquals(ValueType.STRING_TYPE.ordinal(), builder1.getType()); assertEquals("foo", builder1.getValue()); @@ -183,15 +172,14 @@ public class ValueSerializerTest{ public void testSerializeBoolean(){ boolean v1 = true; NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock( - NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.BOOL_TYPE.ordinal(), builder.getIntValueType()); assertEquals("true", builder.getValue()); - NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); - ValueSerializer.serialize(builder1, mock( - NormalizedNodeSerializationContext.class), v1); + NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = + NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); + ValueSerializer.serialize(builder1, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.BOOL_TYPE.ordinal(), builder1.getType()); assertEquals("true", builder1.getValue()); @@ -201,16 +189,14 @@ public class ValueSerializerTest{ public void testSerializeQName(){ QName v1 = TestModel.TEST_QNAME; NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock( - NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.QNAME_TYPE.ordinal(), builder.getIntValueType()); assertEquals("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test", builder.getValue()); NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); - ValueSerializer.serialize(builder1, mock( - NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder1, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.QNAME_TYPE.ordinal(), builder1.getType()); assertEquals("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test", builder1.getValue()); @@ -222,32 +208,30 @@ public class ValueSerializerTest{ YangInstanceIdentifier v1 = TestModel.TEST_PATH; NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock( - NormalizedNodeSerializationContext.class), v1); - + QNameSerializationContext mockContext = mock(QNameSerializationContext.class); + ValueSerializer.serialize(builder, mockContext, v1); assertEquals(ValueType.YANG_IDENTIFIER_TYPE.ordinal(), builder.getIntValueType()); NormalizedNodeMessages.InstanceIdentifier serializedYangInstanceIdentifier = builder.getInstanceIdentifierValue(); assertEquals(1, serializedYangInstanceIdentifier.getArgumentsCount()); - assertEquals(TestModel.TEST_QNAME.toString(), serializedYangInstanceIdentifier.getArguments(0).getNodeType().getValue()); + Mockito.verify(mockContext).addLocalName(TestModel.TEST_QNAME.getLocalName()); + Mockito.verify(mockContext).addNamespace(TestModel.TEST_QNAME.getNamespace()); } @Test public void testSerializeBigInteger(){ BigInteger v1 = new BigInteger("1000000000000000000000000"); NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock( - NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.BIG_INTEGER_TYPE.ordinal(), builder.getIntValueType()); assertEquals("1000000000000000000000000", builder.getValue()); NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); - ValueSerializer.serialize(builder1, mock( - NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder1, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.BIG_INTEGER_TYPE.ordinal(), builder1.getType()); assertEquals("1000000000000000000000000", builder1.getValue()); @@ -258,15 +242,13 @@ public class ValueSerializerTest{ public void testSerializeBigDecimal(){ BigDecimal v1 = new BigDecimal("1000000000000000000000000.51616"); NormalizedNodeMessages.Node.Builder builder = NormalizedNodeMessages.Node.newBuilder(); - ValueSerializer.serialize(builder, mock( - NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.BIG_DECIMAL_TYPE.ordinal(), builder.getIntValueType()); assertEquals("1000000000000000000000000.51616", builder.getValue()); NormalizedNodeMessages.PathArgumentAttribute.Builder builder1 = NormalizedNodeMessages.PathArgumentAttribute.newBuilder(); - ValueSerializer.serialize(builder1, mock( - NormalizedNodeSerializationContext.class), v1); + ValueSerializer.serialize(builder1, mock(QNameSerializationContext.class), v1); assertEquals(ValueType.BIG_DECIMAL_TYPE.ordinal(), builder1.getType()); assertEquals("1000000000000000000000000.51616", builder1.getValue()); @@ -280,7 +262,7 @@ public class ValueSerializerTest{ nodeBuilder.setValue("25"); Object o = ValueSerializer - .deSerialize(mock(NormalizedNodeDeSerializationContext.class), + .deSerialize(mock(QNameDeSerializationContext.class), nodeBuilder.build()); assertTrue(o instanceof Short); @@ -294,7 +276,7 @@ public class ValueSerializerTest{ nodeBuilder.setValue("25"); Object o = ValueSerializer - .deSerialize(mock(NormalizedNodeDeSerializationContext.class), + .deSerialize(mock(QNameDeSerializationContext.class), nodeBuilder.build()); assertTrue(o instanceof Byte); @@ -309,7 +291,7 @@ public class ValueSerializerTest{ nodeBuilder.setValue("25"); Object o = ValueSerializer - .deSerialize(mock(NormalizedNodeDeSerializationContext.class), + .deSerialize(mock(QNameDeSerializationContext.class), nodeBuilder.build()); assertTrue(o instanceof Integer); @@ -324,7 +306,7 @@ public class ValueSerializerTest{ nodeBuilder.setValue("25"); Object o = ValueSerializer - .deSerialize(mock(NormalizedNodeDeSerializationContext.class), + .deSerialize(mock(QNameDeSerializationContext.class), nodeBuilder.build()); assertTrue(o instanceof Long); @@ -339,7 +321,7 @@ public class ValueSerializerTest{ nodeBuilder.setValue("false"); Object o = ValueSerializer - .deSerialize(mock(NormalizedNodeDeSerializationContext.class), + .deSerialize(mock(QNameDeSerializationContext.class), nodeBuilder.build()); assertTrue(o instanceof Boolean); @@ -354,7 +336,7 @@ public class ValueSerializerTest{ nodeBuilder.setValue(TestModel.TEST_QNAME.toString()); Object o = ValueSerializer - .deSerialize(mock(NormalizedNodeDeSerializationContext.class), + .deSerialize(mock(QNameDeSerializationContext.class), nodeBuilder.build()); assertTrue(o instanceof QName); @@ -369,7 +351,7 @@ public class ValueSerializerTest{ nodeBuilder.addAllBitsValue(ImmutableList.of("foo", "bar")); Object o = ValueSerializer - .deSerialize(mock(NormalizedNodeDeSerializationContext.class), + .deSerialize(mock(QNameDeSerializationContext.class), nodeBuilder.build()); assertTrue(o instanceof Set); @@ -384,7 +366,6 @@ public class ValueSerializerTest{ NormalizedNodeMessages.InstanceIdentifier.Builder idBuilder = NormalizedNodeMessages.InstanceIdentifier.newBuilder(); NormalizedNodeMessages.PathArgument.Builder pathBuilder = NormalizedNodeMessages.PathArgument.newBuilder(); - pathBuilder.setValue(TestModel.TEST_QNAME.toString()); pathBuilder.setIntType(PathArgumentType.NODE_IDENTIFIER.ordinal()); idBuilder.addArguments(pathBuilder); @@ -392,9 +373,15 @@ public class ValueSerializerTest{ nodeBuilder.setIntValueType(ValueType.YANG_IDENTIFIER_TYPE.ordinal()); nodeBuilder.setInstanceIdentifierValue(idBuilder); - Object o = ValueSerializer - .deSerialize(mock(NormalizedNodeDeSerializationContext.class), - nodeBuilder.build()); + QNameDeSerializationContext mockContext = mock(QNameDeSerializationContext.class); + Mockito.doReturn(TestModel.TEST_QNAME.getNamespace().toString()).when(mockContext). + getNamespace(Mockito.anyInt()); + Mockito.doReturn(TestModel.TEST_QNAME.getLocalName()).when(mockContext). + getLocalName(Mockito.anyInt()); + Mockito.doReturn(TestModel.TEST_QNAME.getFormattedRevision()).when(mockContext). + getRevision(Mockito.anyInt()); + + Object o = ValueSerializer.deSerialize(mockContext, nodeBuilder.build()); assertTrue(o instanceof YangInstanceIdentifier); assertEquals(TestModel.TEST_PATH, o); @@ -407,8 +394,7 @@ public class ValueSerializerTest{ nodeBuilder.setIntValueType(ValueType.STRING_TYPE.ordinal()); nodeBuilder.setValue("25"); - Object o = ValueSerializer - .deSerialize(mock(NormalizedNodeDeSerializationContext.class), + Object o = ValueSerializer.deSerialize(mock(QNameDeSerializationContext.class), nodeBuilder.build()); assertTrue(o instanceof String); @@ -423,7 +409,7 @@ public class ValueSerializerTest{ nodeBuilder.setValue("25"); Object o = ValueSerializer - .deSerialize(mock(NormalizedNodeDeSerializationContext.class), + .deSerialize(mock(QNameDeSerializationContext.class), nodeBuilder.build()); assertTrue(o instanceof BigInteger); @@ -438,7 +424,7 @@ public class ValueSerializerTest{ nodeBuilder.setValue("25"); Object o = ValueSerializer - .deSerialize(mock(NormalizedNodeDeSerializationContext.class), + .deSerialize(mock(QNameDeSerializationContext.class), nodeBuilder.build()); assertTrue(o instanceof BigDecimal); diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtilsTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtilsTest.java index 136748e341..6cd06e9c1c 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtilsTest.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtilsTest.java @@ -12,10 +12,12 @@ package org.opendaylight.controller.cluster.datastore.util; import org.junit.Assert; import org.junit.Test; +import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameDeSerializationContext; +import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameDeSerializationContextImpl; +import org.opendaylight.controller.cluster.datastore.node.utils.serialization.QNameSerializationContextImpl; import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; - import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -23,139 +25,137 @@ import java.util.List; public class InstanceIdentifierUtilsTest { - private static QName TEST_QNAME = - QName - .create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test"); - private static QName NODE_WITH_VALUE_QNAME = - QName - .create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)value"); - private static QName NODE_WITH_PREDICATES_QNAME = - QName - .create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)pred"); - private static QName NAME_QNAME = - QName - .create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)name"); - - @Test - public void testSerializationOfNodeIdentifier() { - YangInstanceIdentifier.PathArgument p1 = - new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME); - - List arguments = new ArrayList<>(); - - arguments.add(p1); + private static QName TEST_QNAME = QName + .create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test"); + private static QName NODE_WITH_VALUE_QNAME = QName + .create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)value"); + private static QName NODE_WITH_PREDICATES_QNAME = QName + .create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)pred"); + private static QName NAME_QNAME = QName + .create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)name"); - YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); + @Test + public void testSerializationOfNodeIdentifier() { + YangInstanceIdentifier.PathArgument p1 = new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME); - NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = - InstanceIdentifierUtils.toSerializable(expected); + List arguments = new ArrayList<>(); - YangInstanceIdentifier actual = - InstanceIdentifierUtils.fromSerializable(instanceIdentifier); + arguments.add(p1); + YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); - Assert.assertEquals(expected.getLastPathArgument(), - actual.getLastPathArgument()); + NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = + InstanceIdentifierUtils.toSerializable(expected); + YangInstanceIdentifier actual = InstanceIdentifierUtils.fromSerializable(instanceIdentifier); - } + Assert.assertEquals(expected.getLastPathArgument(), actual.getLastPathArgument()); + } - @Test - public void testSerializationOfNodeWithValue() { + @Test + public void testSerializationOfNodeWithValue() { - withValue((short) 1); - withValue((long) 2); - withValue(3); - withValue(true); + withValue((short) 1); + withValue((long) 2); + withValue(3); + withValue(true); - } + } - private void withValue(Object value) { - YangInstanceIdentifier.PathArgument p1 = - new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME); + private void withValue(Object value) { + YangInstanceIdentifier.PathArgument p1 = new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME); - YangInstanceIdentifier.PathArgument p2 = - new YangInstanceIdentifier.NodeWithValue(NODE_WITH_VALUE_QNAME, value); + YangInstanceIdentifier.PathArgument p2 = + new YangInstanceIdentifier.NodeWithValue(NODE_WITH_VALUE_QNAME, value); + List arguments = new ArrayList<>(); - List arguments = new ArrayList<>(); + arguments.add(p1); + arguments.add(p2); - arguments.add(p1); - arguments.add(p2); + YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); - YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); + NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = + InstanceIdentifierUtils.toSerializable(expected); - NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = - InstanceIdentifierUtils.toSerializable(expected); + YangInstanceIdentifier actual = InstanceIdentifierUtils.fromSerializable(instanceIdentifier); - YangInstanceIdentifier actual = - InstanceIdentifierUtils.fromSerializable(instanceIdentifier); + Assert.assertEquals(expected.getLastPathArgument(), actual.getLastPathArgument()); + } + @Test + public void testSerializationOfNodeIdentifierWithPredicates() { - Assert.assertEquals(expected.getLastPathArgument(), - actual.getLastPathArgument()); - } + withPredicates((short) 1); + withPredicates((long) 2); + withPredicates(3); + withPredicates(true); + } - @Test - public void testSerializationOfNodeIdentifierWithPredicates() { + private void withPredicates(Object value) { + YangInstanceIdentifier.PathArgument p1 = new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME); - withPredicates((short) 1); - withPredicates((long) 2); - withPredicates(3); - withPredicates(true); + YangInstanceIdentifier.PathArgument p2 = new YangInstanceIdentifier.NodeIdentifierWithPredicates( + NODE_WITH_PREDICATES_QNAME, NAME_QNAME, value); - } + List arguments = new ArrayList<>(); - private void withPredicates(Object value) { - YangInstanceIdentifier.PathArgument p1 = - new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME); + arguments.add(p1); + arguments.add(p2); - YangInstanceIdentifier.PathArgument p2 = - new YangInstanceIdentifier.NodeIdentifierWithPredicates( - NODE_WITH_PREDICATES_QNAME, NAME_QNAME, value); + YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); + NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = + InstanceIdentifierUtils.toSerializable(expected); - List arguments = new ArrayList<>(); + YangInstanceIdentifier actual = InstanceIdentifierUtils.fromSerializable(instanceIdentifier); - arguments.add(p1); - arguments.add(p2); + Assert.assertEquals(expected.getLastPathArgument(), actual.getLastPathArgument()); + } - YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); + @Test + public void testAugmentationIdentifier() { + YangInstanceIdentifier.PathArgument p1 = new YangInstanceIdentifier.AugmentationIdentifier(new HashSet( + Arrays.asList(TEST_QNAME))); - NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = - InstanceIdentifierUtils.toSerializable(expected); + List arguments = new ArrayList<>(); - YangInstanceIdentifier actual = - InstanceIdentifierUtils.fromSerializable(instanceIdentifier); + arguments.add(p1); + YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); - Assert.assertEquals(expected.getLastPathArgument(), - actual.getLastPathArgument()); - } + NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = + InstanceIdentifierUtils.toSerializable(expected); - @Test - public void testAugmentationIdentifier() { - YangInstanceIdentifier.PathArgument p1 = - new YangInstanceIdentifier.AugmentationIdentifier(new HashSet( - Arrays.asList(TEST_QNAME))); + YangInstanceIdentifier actual = InstanceIdentifierUtils.fromSerializable(instanceIdentifier); - List arguments = new ArrayList<>(); + Assert.assertEquals(expected.getLastPathArgument(), actual.getLastPathArgument()); - arguments.add(p1); + } - YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); + @Test + public void testSerializationWithContext() { + List arguments = + Arrays.asList( + new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME), + new YangInstanceIdentifier.NodeWithValue(NODE_WITH_VALUE_QNAME, 1), + new YangInstanceIdentifier.NodeIdentifierWithPredicates( + NODE_WITH_PREDICATES_QNAME, NAME_QNAME, 2)); - NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = - InstanceIdentifierUtils.toSerializable(expected); + YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); - YangInstanceIdentifier actual = - InstanceIdentifierUtils.fromSerializable(instanceIdentifier); + QNameSerializationContextImpl serializationContext = new QNameSerializationContextImpl(); + NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = + InstanceIdentifierUtils.toSerializable(expected, serializationContext); - Assert.assertEquals(expected.getLastPathArgument(), - actual.getLastPathArgument()); + QNameDeSerializationContext deserializationContext = new QNameDeSerializationContextImpl( + serializationContext.getCodes()); - } + YangInstanceIdentifier actual = InstanceIdentifierUtils.fromSerializable( + instanceIdentifier, deserializationContext); + Assert.assertEquals(expected.getLastPathArgument(), actual.getLastPathArgument()); + } } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/NormalizedNodeXmlConverterTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/NormalizedNodeXmlConverterTest.java deleted file mode 100644 index 853b3e264b..0000000000 --- a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/NormalizedNodeXmlConverterTest.java +++ /dev/null @@ -1,483 +0,0 @@ -/* - * - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - * - */ -package org.opendaylight.controller.cluster.datastore.util; - -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import org.custommonkey.xmlunit.Diff; -import org.custommonkey.xmlunit.XMLUnit; -import org.junit.Test; -import org.opendaylight.controller.protobuff.messages.common.SimpleNormalizedNodeMessage; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapNode; -import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils; -import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory; -import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory; -import org.opendaylight.yangtools.yang.model.api.ChoiceNode; -import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; -import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.Module; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.TransformerFactoryConfigurationError; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringWriter; -import java.net.URI; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Set; - - -/** - * Two of the testcases in the yangtools/yang-data-impl are leveraged (with modification) to create - * the serialization of NormalizedNode using the ProtocolBuffer - * - * @syedbahm - * - */ - - -public class NormalizedNodeXmlConverterTest { - private static final Logger logger = LoggerFactory - .getLogger(NormalizedNodeXmlConverterTest.class); - public static final String NAMESPACE = - "urn:opendaylight:params:xml:ns:yang:controller:test"; - private static Date revision; - private ContainerNode expectedNode; - private ContainerSchemaNode containerNode; - private String xmlPath; - - static { - try { - revision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-03-13"); - } catch (ParseException e) { - throw new RuntimeException(e); - } - } - - public static DataSchemaNode getSchemaNode(final SchemaContext context, - final String moduleName, final String childNodeName) { - for (Module module : context.getModules()) { - if (module.getName().equals(moduleName)) { - DataSchemaNode found = - findChildNode(module.getChildNodes(), childNodeName); - Preconditions.checkState(found != null, "Unable to find %s", - childNodeName); - return found; - } - } - throw new IllegalStateException("Unable to find child node " - + childNodeName); - } - - static DataSchemaNode findChildNode( - final Collection children, final String name) { - List containers = Lists.newArrayList(); - - for (DataSchemaNode dataSchemaNode : children) { - if (dataSchemaNode.getQName().getLocalName().equals(name)) { - return dataSchemaNode; - } - if (dataSchemaNode instanceof DataNodeContainer) { - containers.add((DataNodeContainer) dataSchemaNode); - } else if (dataSchemaNode instanceof ChoiceNode) { - containers.addAll(((ChoiceNode) dataSchemaNode).getCases()); - } - } - - for (DataNodeContainer container : containers) { - DataSchemaNode retVal = findChildNode(container.getChildNodes(), name); - if (retVal != null) { - return retVal; - } - } - - return null; - } - - public static YangInstanceIdentifier.NodeIdentifier getNodeIdentifier( - final String localName) { - return new YangInstanceIdentifier.NodeIdentifier(QName.create( - URI.create(NAMESPACE), revision, localName)); - } - - public static YangInstanceIdentifier.AugmentationIdentifier getAugmentIdentifier( - final String... childNames) { - Set qn = Sets.newHashSet(); - - for (String childName : childNames) { - qn.add(getNodeIdentifier(childName).getNodeType()); - } - - return new YangInstanceIdentifier.AugmentationIdentifier(qn); - } - - - public static ContainerNode augmentChoiceExpectedNode() { - - DataContainerNodeBuilder b = - Builders.containerBuilder(); - b.withNodeIdentifier(getNodeIdentifier("container")); - - b.withChild(Builders - .choiceBuilder() - .withNodeIdentifier(getNodeIdentifier("ch2")) - .withChild( - Builders.leafBuilder() - .withNodeIdentifier(getNodeIdentifier("c2Leaf")).withValue("2") - .build()) - .withChild( - Builders - .choiceBuilder() - .withNodeIdentifier(getNodeIdentifier("c2DeepChoice")) - .withChild( - Builders - .leafBuilder() - .withNodeIdentifier( - getNodeIdentifier("c2DeepChoiceCase1Leaf2")) - .withValue("2").build()).build()).build()); - - b.withChild(Builders - .choiceBuilder() - .withNodeIdentifier(getNodeIdentifier("ch3")) - .withChild( - Builders.leafBuilder() - .withNodeIdentifier(getNodeIdentifier("c3Leaf")).withValue("3") - .build()).build()); - - b.withChild(Builders - .augmentationBuilder() - .withNodeIdentifier(getAugmentIdentifier("augLeaf")) - .withChild( - Builders.leafBuilder() - .withNodeIdentifier(getNodeIdentifier("augLeaf")) - .withValue("augment").build()).build()); - - b.withChild(Builders - .augmentationBuilder() - .withNodeIdentifier(getAugmentIdentifier("ch")) - .withChild( - Builders - .choiceBuilder() - .withNodeIdentifier(getNodeIdentifier("ch")) - .withChild( - Builders.leafBuilder() - .withNodeIdentifier(getNodeIdentifier("c1Leaf")) - .withValue("1").build()) - .withChild( - Builders - .augmentationBuilder() - .withNodeIdentifier( - getAugmentIdentifier("c1Leaf_AnotherAugment", - "deepChoice")) - .withChild( - Builders - .leafBuilder() - .withNodeIdentifier( - getNodeIdentifier("c1Leaf_AnotherAugment")) - .withValue("1").build()) - .withChild( - Builders - .choiceBuilder() - .withNodeIdentifier( - getNodeIdentifier("deepChoice")) - .withChild( - Builders - .leafBuilder() - .withNodeIdentifier( - getNodeIdentifier("deepLeafc1")) - .withValue("1").build()).build()) - .build()).build()).build()); - - return b.build(); - } - - - - public void init(final String yangPath, final String xmlPath, - final ContainerNode expectedNode) throws Exception { - SchemaContext schema = parseTestSchema(yangPath); - this.xmlPath = xmlPath; - this.containerNode = - (ContainerSchemaNode) getSchemaNode(schema, "test", "container"); - this.expectedNode = expectedNode; - } - - SchemaContext parseTestSchema(final String yangPath) throws Exception { - - YangParserImpl yangParserImpl = new YangParserImpl(); - InputStream stream = - NormalizedNodeXmlConverterTest.class.getResourceAsStream(yangPath); - ArrayList al = new ArrayList(); - al.add(stream); - Set modules = yangParserImpl.parseYangModelsFromStreams(al); - return yangParserImpl.resolveSchemaContext(modules); - - } - - - @Test - public void testConversionWithAugmentChoice() throws Exception { - init("/augment_choice.yang", "/augment_choice.xml", - augmentChoiceExpectedNode()); - Document doc = loadDocument(xmlPath); - - ContainerNode built = - DomToNormalizedNodeParserFactory - .getInstance(DomUtils.defaultValueCodecProvider()) - .getContainerNodeParser() - .parse(Collections.singletonList(doc.getDocumentElement()), - containerNode); - - if (expectedNode != null) { - junit.framework.Assert.assertEquals(expectedNode, built); - } - - logger.info("{}", built); - - Iterable els = - DomFromNormalizedNodeSerializerFactory - .getInstance(XmlDocumentUtils.getDocument(), - DomUtils.defaultValueCodecProvider()) - .getContainerNodeSerializer().serialize(containerNode, built); - - Element el = els.iterator().next(); - - XMLUnit.setIgnoreWhitespace(true); - XMLUnit.setIgnoreComments(true); - - System.out.println(toString(doc.getDocumentElement())); - System.out.println(toString(el)); - - new Diff(XMLUnit.buildControlDocument(toString(doc.getDocumentElement())), - XMLUnit.buildTestDocument(toString(el))).similar(); - } - - private static ContainerNode listLeafListWithAttributes() { - DataContainerNodeBuilder b = - Builders.containerBuilder(); - b.withNodeIdentifier(getNodeIdentifier("container")); - - CollectionNodeBuilder listBuilder = - Builders.mapBuilder().withNodeIdentifier(getNodeIdentifier("list")); - - Map predicates = Maps.newHashMap(); - predicates.put(getNodeIdentifier("uint32InList").getNodeType(), 3L); - - DataContainerNodeBuilder list1Builder = - Builders.mapEntryBuilder().withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifierWithPredicates( - getNodeIdentifier("list").getNodeType(), predicates)); - NormalizedNodeBuilder> uint32InListBuilder = - Builders.leafBuilder().withNodeIdentifier( - getNodeIdentifier("uint32InList")); - - list1Builder.withChild(uint32InListBuilder.withValue(3L).build()); - - listBuilder.withChild(list1Builder.build()); - b.withChild(listBuilder.build()); - - NormalizedNodeBuilder> booleanBuilder = - Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("boolean")); - booleanBuilder.withValue(false); - b.withChild(booleanBuilder.build()); - - ListNodeBuilder> leafListBuilder = - Builders.leafSetBuilder().withNodeIdentifier( - getNodeIdentifier("leafList")); - - NormalizedNodeBuilder> leafList1Builder = - Builders.leafSetEntryBuilder().withNodeIdentifier( - new YangInstanceIdentifier.NodeWithValue(getNodeIdentifier( - "leafList").getNodeType(), "a")); - - leafList1Builder.withValue("a"); - - leafListBuilder.withChild(leafList1Builder.build()); - b.withChild(leafListBuilder.build()); - - return b.build(); - } - - - @Test - public void testConversionWithAttributes() throws Exception { - init("/test.yang", "/simple_xml_with_attributes.xml", - listLeafListWithAttributes()); - Document doc = loadDocument(xmlPath); - - ContainerNode built = - DomToNormalizedNodeParserFactory - .getInstance(DomUtils.defaultValueCodecProvider()) - .getContainerNodeParser() - .parse(Collections.singletonList(doc.getDocumentElement()), - containerNode); - - if (expectedNode != null) { - junit.framework.Assert.assertEquals(expectedNode, built); - } - - logger.info("{}", built); - - Iterable els = - DomFromNormalizedNodeSerializerFactory - .getInstance(XmlDocumentUtils.getDocument(), - DomUtils.defaultValueCodecProvider()) - .getContainerNodeSerializer().serialize(containerNode, built); - - Element el = els.iterator().next(); - - XMLUnit.setIgnoreWhitespace(true); - XMLUnit.setIgnoreComments(true); - - System.out.println(toString(doc.getDocumentElement())); - System.out.println(toString(el)); - - new Diff(XMLUnit.buildControlDocument(toString(doc.getDocumentElement())), - XMLUnit.buildTestDocument(toString(el))).similar(); - } - - - private Document loadDocument(final String xmlPath) throws Exception { - InputStream resourceAsStream = - NormalizedNodeXmlConverterTest.class.getResourceAsStream(xmlPath); - - Document currentConfigElement = readXmlToDocument(resourceAsStream); - Preconditions.checkNotNull(currentConfigElement); - return currentConfigElement; - } - - private static final DocumentBuilderFactory BUILDERFACTORY; - - static { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setCoalescing(true); - factory.setIgnoringElementContentWhitespace(true); - factory.setIgnoringComments(true); - BUILDERFACTORY = factory; - } - - private Document readXmlToDocument(final InputStream xmlContent) - throws IOException, SAXException { - DocumentBuilder dBuilder; - try { - dBuilder = BUILDERFACTORY.newDocumentBuilder(); - } catch (ParserConfigurationException e) { - throw new RuntimeException("Failed to parse XML document", e); - } - Document doc = dBuilder.parse(xmlContent); - - doc.getDocumentElement().normalize(); - return doc; - } - - public static String toString(final Element xml) { - try { - Transformer transformer = - TransformerFactory.newInstance().newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - - StreamResult result = new StreamResult(new StringWriter()); - DOMSource source = new DOMSource(xml); - transformer.transform(source, result); - - return result.getWriter().toString(); - } catch (IllegalArgumentException | TransformerFactoryConfigurationError - | TransformerException e) { - throw new RuntimeException("Unable to serialize xml element " + xml, e); - } - } - - @Test - public void testConversionToNormalizedXml() throws Exception { - SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml = - EncoderDecoderUtil.encode(parseTestSchema("/augment_choice.yang"), - augmentChoiceExpectedNode()); - Document expectedDoc = loadDocument("/augment_choice.xml"); - Document convertedDoc = - EncoderDecoderUtil.factory.newDocumentBuilder().parse( - new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8"))); - System.out.println(toString(convertedDoc.getDocumentElement())); - XMLUnit.setIgnoreWhitespace(true); - XMLUnit.setIgnoreComments(true); - new Diff(XMLUnit.buildControlDocument(toString(expectedDoc - .getDocumentElement())), - XMLUnit.buildTestDocument(toString(convertedDoc.getDocumentElement()))) - .similar(); - System.out.println(toString(expectedDoc.getDocumentElement())); - - } - - - @Test - public void testConversionFromXmlToNormalizedNode() throws Exception { - SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml = - EncoderDecoderUtil.encode(parseTestSchema("/test.yang"), - listLeafListWithAttributes()); - Document expectedDoc = loadDocument("/simple_xml_with_attributes.xml"); - Document convertedDoc = - EncoderDecoderUtil.factory.newDocumentBuilder().parse( - new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8"))); - System.out.println(toString(convertedDoc.getDocumentElement())); - XMLUnit.setIgnoreWhitespace(true); - XMLUnit.setIgnoreComments(true); - new Diff(XMLUnit.buildControlDocument(toString(expectedDoc - .getDocumentElement())), - XMLUnit.buildTestDocument(toString(convertedDoc.getDocumentElement()))) - .similar(); - System.out.println(toString(expectedDoc.getDocumentElement())); - - // now we will try to convert xml back to normalize node. - ContainerNode cn = - (ContainerNode) EncoderDecoderUtil.decode( - parseTestSchema("/test.yang"), nnXml); - junit.framework.Assert.assertEquals(listLeafListWithAttributes(), cn); - - } - -} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessagesTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessagesTest.java index c0e91ab0d0..dba8f4f95a 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessagesTest.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessagesTest.java @@ -10,11 +10,8 @@ package org.opendaylight.controller.protobuff.messages.transaction; -import org.junit.Assert; import org.junit.Test; import org.opendaylight.controller.protobuff.messages.AbstractMessagesTest; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; -import org.opendaylight.yangtools.yang.common.QName; /** * This test case is present to ensure that if others have used proper version of protocol buffer @@ -34,29 +31,6 @@ public class ShardTransactionChainMessagesTest extends AbstractMessagesTest { @Override @Test public void verifySerialization() throws Exception { - String testTransactionChainPath = - "/actor/path"; - - ShardTransactionChainMessages.CreateTransactionChainReply.Builder builder = - ShardTransactionChainMessages.CreateTransactionChainReply.newBuilder(); - builder.setTransactionChainPath(testTransactionChainPath); - - writeToFile((com.google.protobuf.GeneratedMessage.Builder) builder); - - // Here we will read the same and check we got back what we had saved - ShardTransactionChainMessages.CreateTransactionChainReply replyNew = - (ShardTransactionChainMessages.CreateTransactionChainReply) readFromFile(ShardTransactionChainMessages.CreateTransactionChainReply.PARSER); - - Assert.assertEquals(replyNew.getTransactionChainPath(),testTransactionChainPath); - - // the following will compare with the version we had shipped - ShardTransactionChainMessages.CreateTransactionChainReply replyOriginal = - (ShardTransactionChainMessages.CreateTransactionChainReply) readFromTestDataFile(ShardTransactionChainMessages.CreateTransactionChainReply.PARSER); - - - Assert.assertEquals(replyOriginal.getTransactionChainPath(), - replyNew.getTransactionChainPath()); - } @Override diff --git a/opendaylight/md-sal/sal-clustering-config/pom.xml b/opendaylight/md-sal/sal-clustering-config/pom.xml index 91c0b5caa1..1c018cade1 100644 --- a/opendaylight/md-sal/sal-clustering-config/pom.xml +++ b/opendaylight/md-sal/sal-clustering-config/pom.xml @@ -12,7 +12,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-clustering-config Configuration files for md-sal clustering diff --git a/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/05-clustering.xml.conf b/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/05-clustering.xml.conf index fbb666a9ca..b57a3f5f0b 100644 --- a/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/05-clustering.xml.conf +++ b/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/05-clustering.xml.conf @@ -29,6 +29,8 @@ operational-dom-store-spi:operational-dom-datastore distributed-operational-store-service + + true diff --git a/opendaylight/md-sal/sal-common-api/pom.xml b/opendaylight/md-sal/sal-common-api/pom.xml index e46fe1fe78..6af20c0fb8 100644 --- a/opendaylight/md-sal/sal-common-api/pom.xml +++ b/opendaylight/md-sal/sal-common-api/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-common-api diff --git a/opendaylight/md-sal/sal-common-impl/pom.xml b/opendaylight/md-sal/sal-common-impl/pom.xml index 82bd716c59..542a1f3905 100644 --- a/opendaylight/md-sal/sal-common-impl/pom.xml +++ b/opendaylight/md-sal/sal-common-impl/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-common-impl bundle diff --git a/opendaylight/md-sal/sal-common-impl/src/test/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizerTest.java b/opendaylight/md-sal/sal-common-impl/src/test/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizerTest.java index 1595288608..3fa8d4e5e9 100644 --- a/opendaylight/md-sal/sal-common-impl/src/test/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizerTest.java +++ b/opendaylight/md-sal/sal-common-impl/src/test/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizerTest.java @@ -119,7 +119,7 @@ public class DataNormalizerTest { static final Short OUTER_LIST_ID = (short) 10; - static final YangInstanceIdentifier OUTER_LIST_PATH_LEGACY = YangInstanceIdentifier.builder(TEST_QNAME) + static final YangInstanceIdentifier OUTER_LIST_PATH_LEGACY = YangInstanceIdentifier.builder(TEST_PATH) .nodeWithKey(OUTER_LIST_QNAME, ID_QNAME, OUTER_LIST_ID).build(); static final YangInstanceIdentifier LEAF_TWO_PATH_LEGACY = YangInstanceIdentifier.builder(OUTER_LIST_PATH_LEGACY) @@ -295,7 +295,7 @@ public class DataNormalizerTest { .withNodeIdentifier(new NodeIdentifier(TEST_QNAME)).withChild(testAnyXmlNode).build(); DataNormalizer normalizer = new DataNormalizer(createTestContext()); - Node legacyNode = normalizer.toLegacy(YangInstanceIdentifier.builder(TEST_QNAME).build(), testContainerNode); + Node legacyNode = normalizer.toLegacy(YangInstanceIdentifier.builder().node(TEST_QNAME).build(), testContainerNode); verifyLegacyNode( legacyNode, @@ -332,7 +332,7 @@ public class DataNormalizerTest { DataNormalizer normalizer = new DataNormalizer(createTestContext()); - Node legacyNode = normalizer.toLegacy(YangInstanceIdentifier.builder(TEST_QNAME).build(), testContainerNode); + Node legacyNode = normalizer.toLegacy(YangInstanceIdentifier.builder().node(TEST_QNAME).build(), testContainerNode); verifyLegacyNode( legacyNode, @@ -359,7 +359,7 @@ public class DataNormalizerTest { DataNormalizer normalizer = new DataNormalizer(createTestContext()); - Node legacyNode = normalizer.toLegacy(YangInstanceIdentifier.builder(TEST_QNAME).build(), testContainerNode); + Node legacyNode = normalizer.toLegacy(YangInstanceIdentifier.builder().node(TEST_QNAME).build(), testContainerNode); verifyLegacyNode( legacyNode, diff --git a/opendaylight/md-sal/sal-common-util/pom.xml b/opendaylight/md-sal/sal-common-util/pom.xml index e42c86a993..b285c991e5 100644 --- a/opendaylight/md-sal/sal-common-util/pom.xml +++ b/opendaylight/md-sal/sal-common-util/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-common-util diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBeanImpl.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBeanImpl.java index 58677103c2..3de49ae296 100644 --- a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBeanImpl.java +++ b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBeanImpl.java @@ -44,25 +44,47 @@ public class ThreadExecutorStatsMXBeanImpl extends AbstractMXBean this.executor = Preconditions.checkNotNull(executor); } + private static ThreadExecutorStatsMXBeanImpl createInternal(final Executor executor, + final String mBeanName, final String mBeanType, final String mBeanCategory) { + if (executor instanceof ThreadPoolExecutor) { + final ThreadExecutorStatsMXBeanImpl ret = new ThreadExecutorStatsMXBeanImpl( + (ThreadPoolExecutor) executor, mBeanName, mBeanType, mBeanCategory); + return ret; + } + + LOG.info("Executor {} is not supported", executor); + return null; + } + /** - * Create a new bean for the statistics, which is already registered. + * Creates a new bean if the backing executor is a ThreadPoolExecutor and registers it. * - * @param executor - * @param mBeanName - * @param mBeanType - * @param mBeanCategory - * @return + * @param executor the backing {@link Executor} + * @param mBeanName Used as the name property in the bean's ObjectName. + * @param mBeanType Used as the type property in the bean's ObjectName. + * @param mBeanCategory Used as the Category property in the bean's ObjectName. + * @return a registered ThreadExecutorStatsMXBeanImpl instance if the backing executor + * is a ThreadPoolExecutor, otherwise null. */ public static ThreadExecutorStatsMXBeanImpl create(final Executor executor, final String mBeanName, final String mBeanType, @Nullable final String mBeanCategory) { - if (executor instanceof ThreadPoolExecutor) { - final ThreadExecutorStatsMXBeanImpl ret = new ThreadExecutorStatsMXBeanImpl((ThreadPoolExecutor) executor, mBeanName, mBeanType, mBeanCategory); + ThreadExecutorStatsMXBeanImpl ret = createInternal(executor, mBeanName, mBeanType, mBeanCategory); + if(ret != null) { ret.registerMBean(); - return ret; } - LOG.info("Executor {} is not supported", executor); - return null; + return ret; + } + + /** + * Creates a new bean if the backing executor is a ThreadPoolExecutor. + * + * @param executor the backing {@link Executor} + * @return a ThreadExecutorStatsMXBeanImpl instance if the backing executor + * is a ThreadPoolExecutor, otherwise null. + */ + public static ThreadExecutorStatsMXBeanImpl create(final Executor executor) { + return createInternal(executor, "", "", null); } @Override diff --git a/opendaylight/md-sal/sal-common/pom.xml b/opendaylight/md-sal/sal-common/pom.xml index f200b5551f..e5450b2487 100644 --- a/opendaylight/md-sal/sal-common/pom.xml +++ b/opendaylight/md-sal/sal-common/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-common diff --git a/opendaylight/md-sal/sal-connector-api/pom.xml b/opendaylight/md-sal/sal-connector-api/pom.xml index 4e7d82dad3..e45e24dd56 100644 --- a/opendaylight/md-sal/sal-connector-api/pom.xml +++ b/opendaylight/md-sal/sal-connector-api/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-connector-api diff --git a/opendaylight/md-sal/sal-distributed-datastore/pom.xml b/opendaylight/md-sal/sal-distributed-datastore/pom.xml index 82998226b6..d7e7d56d49 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/pom.xml +++ b/opendaylight/md-sal/sal-distributed-datastore/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-distributed-datastore bundle @@ -80,7 +80,7 @@ org.opendaylight.controller sal-inmemory-datastore - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT @@ -131,13 +131,13 @@ org.opendaylight.controller sal-clustering-commons - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT org.opendaylight.controller sal-akka-raft - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ClusterWrapper.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ClusterWrapper.java index 2eac2400b5..58d805b2b5 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ClusterWrapper.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ClusterWrapper.java @@ -13,4 +13,5 @@ import akka.actor.ActorRef; public interface ClusterWrapper { void subscribeToMemberEvents(ActorRef actorRef); String getCurrentMemberName(); + String getSelfAddress(); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ClusterWrapperImpl.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ClusterWrapperImpl.java index 8910137ec4..857510ad4b 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ClusterWrapperImpl.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ClusterWrapperImpl.java @@ -17,6 +17,7 @@ import com.google.common.base.Preconditions; public class ClusterWrapperImpl implements ClusterWrapper { private final Cluster cluster; private final String currentMemberName; + private final String selfAddress; public ClusterWrapperImpl(ActorSystem actorSystem){ Preconditions.checkNotNull(actorSystem, "actorSystem should not be null"); @@ -31,6 +32,7 @@ public class ClusterWrapperImpl implements ClusterWrapper { ); currentMemberName = (String) cluster.getSelfRoles().toArray()[0]; + selfAddress = cluster.selfAddress().toString(); } @@ -45,4 +47,8 @@ public class ClusterWrapperImpl implements ClusterWrapper { public String getCurrentMemberName() { return currentMemberName; } + + public String getSelfAddress() { + return selfAddress; + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListener.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListener.java index f1c0df4c3a..a498826e98 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListener.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListener.java @@ -10,10 +10,8 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.Props; import akka.japi.Creator; - import com.google.common.base.Preconditions; import org.opendaylight.controller.cluster.common.actor.AbstractUntypedActor; - import org.opendaylight.controller.cluster.datastore.messages.DataChanged; import org.opendaylight.controller.cluster.datastore.messages.DataChangedReply; import org.opendaylight.controller.cluster.datastore.messages.EnableNotification; @@ -24,7 +22,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; public class DataChangeListener extends AbstractUntypedActor { private final AsyncDataChangeListener> listener; - private volatile boolean notificationsEnabled = false; + private boolean notificationsEnabled = false; public DataChangeListener(AsyncDataChangeListener> listener) { @@ -55,7 +53,9 @@ public class DataChangeListener extends AbstractUntypedActor { change = reply.getChange(); this.listener.onDataChanged(change); - if(getSender() != null){ + // It seems the sender is never null but it doesn't hurt to check. If the caller passes in + // a null sender (ActorRef.noSender()), akka translates that to the deadLetters actor. + if(getSender() != null && !getContext().system().deadLetters().equals(getSender())) { getSender().tell(new DataChangedReply(), getSelf()); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxy.java index a1b6b9252e..1a0ee8c2fa 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxy.java @@ -8,10 +8,9 @@ package org.opendaylight.controller.cluster.datastore; +import akka.actor.ActorRef; import akka.actor.ActorSelection; - import com.google.common.base.Preconditions; - import org.opendaylight.controller.cluster.datastore.messages.DataChanged; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; @@ -33,6 +32,6 @@ public class DataChangeListenerProxy implements AsyncDataChangeListener> change) { - dataChangeListenerActor.tell(new DataChanged(schemaContext, change), null); + dataChangeListenerActor.tell(new DataChanged(schemaContext, change), ActorRef.noSender()); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContext.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContext.java index 1021ddeee7..722e23046e 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContext.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContext.java @@ -8,12 +8,11 @@ package org.opendaylight.controller.cluster.datastore; -import com.google.common.base.Preconditions; - +import org.opendaylight.controller.cluster.raft.ConfigParams; +import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl; import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreConfigProperties; - import scala.concurrent.duration.Duration; - +import scala.concurrent.duration.FiniteDuration; import java.util.concurrent.TimeUnit; /** @@ -27,22 +26,25 @@ public class DatastoreContext { private final Duration shardTransactionIdleTimeout; private final int operationTimeoutInSeconds; private final String dataStoreMXBeanType; + private final ConfigParams shardRaftConfig; + private final int shardTransactionCommitTimeoutInSeconds; + private final int shardTransactionCommitQueueCapacity; - public DatastoreContext() { - this.dataStoreProperties = null; - this.dataStoreMXBeanType = "DistributedDatastore"; - this.shardTransactionIdleTimeout = Duration.create(10, TimeUnit.MINUTES); - this.operationTimeoutInSeconds = 5; - } - - public DatastoreContext(String dataStoreMXBeanType, - InMemoryDOMDataStoreConfigProperties dataStoreProperties, - Duration shardTransactionIdleTimeout, - int operationTimeoutInSeconds) { + private DatastoreContext(InMemoryDOMDataStoreConfigProperties dataStoreProperties, + ConfigParams shardRaftConfig, String dataStoreMXBeanType, int operationTimeoutInSeconds, + Duration shardTransactionIdleTimeout, int shardTransactionCommitTimeoutInSeconds, + int shardTransactionCommitQueueCapacity) { + this.dataStoreProperties = dataStoreProperties; + this.shardRaftConfig = shardRaftConfig; this.dataStoreMXBeanType = dataStoreMXBeanType; - this.dataStoreProperties = Preconditions.checkNotNull(dataStoreProperties); - this.shardTransactionIdleTimeout = shardTransactionIdleTimeout; this.operationTimeoutInSeconds = operationTimeoutInSeconds; + this.shardTransactionIdleTimeout = shardTransactionIdleTimeout; + this.shardTransactionCommitTimeoutInSeconds = shardTransactionCommitTimeoutInSeconds; + this.shardTransactionCommitQueueCapacity = shardTransactionCommitQueueCapacity; + } + + public static Builder newBuilder() { + return new Builder(); } public InMemoryDOMDataStoreConfigProperties getDataStoreProperties() { @@ -60,4 +62,85 @@ public class DatastoreContext { public int getOperationTimeoutInSeconds() { return operationTimeoutInSeconds; } + + public ConfigParams getShardRaftConfig() { + return shardRaftConfig; + } + + public int getShardTransactionCommitTimeoutInSeconds() { + return shardTransactionCommitTimeoutInSeconds; + } + + public int getShardTransactionCommitQueueCapacity() { + return shardTransactionCommitQueueCapacity; + } + + public static class Builder { + private InMemoryDOMDataStoreConfigProperties dataStoreProperties; + private Duration shardTransactionIdleTimeout = Duration.create(10, TimeUnit.MINUTES); + private int operationTimeoutInSeconds = 5; + private String dataStoreMXBeanType; + private int shardTransactionCommitTimeoutInSeconds = 30; + private int shardJournalRecoveryLogBatchSize = 1000; + private int shardSnapshotBatchCount = 20000; + private int shardHeartbeatIntervalInMillis = 500; + private int shardTransactionCommitQueueCapacity = 20000; + + public Builder shardTransactionIdleTimeout(Duration shardTransactionIdleTimeout) { + this.shardTransactionIdleTimeout = shardTransactionIdleTimeout; + return this; + } + + public Builder operationTimeoutInSeconds(int operationTimeoutInSeconds) { + this.operationTimeoutInSeconds = operationTimeoutInSeconds; + return this; + } + + public Builder dataStoreMXBeanType(String dataStoreMXBeanType) { + this.dataStoreMXBeanType = dataStoreMXBeanType; + return this; + } + + public Builder dataStoreProperties(InMemoryDOMDataStoreConfigProperties dataStoreProperties) { + this.dataStoreProperties = dataStoreProperties; + return this; + } + + public Builder shardTransactionCommitTimeoutInSeconds(int shardTransactionCommitTimeoutInSeconds) { + this.shardTransactionCommitTimeoutInSeconds = shardTransactionCommitTimeoutInSeconds; + return this; + } + + public Builder shardJournalRecoveryLogBatchSize(int shardJournalRecoveryLogBatchSize) { + this.shardJournalRecoveryLogBatchSize = shardJournalRecoveryLogBatchSize; + return this; + } + + public Builder shardSnapshotBatchCount(int shardSnapshotBatchCount) { + this.shardSnapshotBatchCount = shardSnapshotBatchCount; + return this; + } + + public Builder shardHeartbeatIntervalInMillis(int shardHeartbeatIntervalInMillis) { + this.shardHeartbeatIntervalInMillis = shardHeartbeatIntervalInMillis; + return this; + } + + public Builder shardTransactionCommitQueueCapacity(int shardTransactionCommitQueueCapacity) { + this.shardTransactionCommitQueueCapacity = shardTransactionCommitQueueCapacity; + return this; + } + + public DatastoreContext build() { + DefaultConfigParamsImpl raftConfig = new DefaultConfigParamsImpl(); + raftConfig.setHeartBeatInterval(new FiniteDuration(shardHeartbeatIntervalInMillis, + TimeUnit.MILLISECONDS)); + raftConfig.setJournalRecoveryLogBatchSize(shardJournalRecoveryLogBatchSize); + raftConfig.setSnapshotBatchCount(shardSnapshotBatchCount); + + return new DatastoreContext(dataStoreProperties, raftConfig, dataStoreMXBeanType, + operationTimeoutInSeconds, shardTransactionIdleTimeout, + shardTransactionCommitTimeoutInSeconds, shardTransactionCommitQueueCapacity); + } + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java index bf541d95de..f6c31aab04 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java @@ -12,6 +12,8 @@ import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.dispatch.OnComplete; import akka.util.Timeout; +import com.google.common.base.Optional; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import org.opendaylight.controller.cluster.datastore.identifiers.ShardManagerIdentifier; import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener; @@ -79,41 +81,41 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, Au LOG.debug("Registering listener: {} for path: {} scope: {}", listener, path, scope); - ActorRef dataChangeListenerActor = actorContext.getActorSystem().actorOf( - DataChangeListener.props(listener )); - String shardName = ShardStrategyFactory.getStrategy(path).findShard(path); - Future future = actorContext.executeLocalShardOperationAsync(shardName, - new RegisterChangeListener(path, dataChangeListenerActor.path(), scope), - new Timeout(actorContext.getOperationDuration().$times( - REGISTER_DATA_CHANGE_LISTENER_TIMEOUT_FACTOR))); + Optional shard = actorContext.findLocalShard(shardName); + + //if shard is NOT local + if (!shard.isPresent()) { + LOG.debug("No local shard for shardName {} was found so returning a noop registration", shardName); + return new NoOpDataChangeListenerRegistration(listener); + } + //if shard is local + ActorRef dataChangeListenerActor = actorContext.getActorSystem().actorOf(DataChangeListener.props(listener)); + Future future = actorContext.executeOperationAsync(shard.get(), + new RegisterChangeListener(path, dataChangeListenerActor.path(), scope), + new Timeout(actorContext.getOperationDuration().$times(REGISTER_DATA_CHANGE_LISTENER_TIMEOUT_FACTOR))); - if (future != null) { - final DataChangeListenerRegistrationProxy listenerRegistrationProxy = + final DataChangeListenerRegistrationProxy listenerRegistrationProxy = new DataChangeListenerRegistrationProxy(listener, dataChangeListenerActor); - future.onComplete(new OnComplete(){ + future.onComplete(new OnComplete() { - @Override public void onComplete(Throwable failure, Object result) + @Override + public void onComplete(Throwable failure, Object result) throws Throwable { - if(failure != null){ - LOG.error("Failed to register listener at path " + path.toString(), failure); - return; - } - RegisterChangeListenerReply reply = (RegisterChangeListenerReply) result; - listenerRegistrationProxy.setListenerRegistrationActor(actorContext - .actorSelection(reply.getListenerRegistrationPath())); + if (failure != null) { + LOG.error("Failed to register listener at path " + path.toString(), failure); + return; } - }, actorContext.getActorSystem().dispatcher()); - return listenerRegistrationProxy; - } + RegisterChangeListenerReply reply = (RegisterChangeListenerReply) result; + listenerRegistrationProxy.setListenerRegistrationActor(actorContext + .actorSelection(reply.getListenerRegistrationPath())); + } + }, actorContext.getActorSystem().dispatcher()); - LOG.debug( - "No local shard for shardName {} was found so returning a noop registration", - shardName); + return listenerRegistrationProxy; - return new NoOpDataChangeListenerRegistration(listener); } @Override @@ -145,4 +147,9 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, Au public void close() throws Exception { actorContext.shutdown(); } + + @VisibleForTesting + ActorContext getActorContext() { + return actorContext; + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java index f3f8b8b193..d0bb3d3b69 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; import akka.actor.ActorSelection; +import akka.actor.Cancellable; import akka.actor.PoisonPill; import akka.actor.Props; import akka.event.Logging; @@ -20,7 +21,7 @@ import akka.serialization.Serialization; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.collect.Lists; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -28,38 +29,41 @@ import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import org.opendaylight.controller.cluster.common.actor.CommonConfig; import org.opendaylight.controller.cluster.common.actor.MeteringBehavior; +import org.opendaylight.controller.cluster.datastore.ShardCommitCoordinator.CohortEntry; import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier; import org.opendaylight.controller.cluster.datastore.identifiers.ShardTransactionIdentifier; import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardMBeanFactory; import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats; +import org.opendaylight.controller.cluster.datastore.messages.AbortTransaction; +import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply; +import org.opendaylight.controller.cluster.datastore.messages.ActorInitialized; +import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction; import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionChain; +import org.opendaylight.controller.cluster.datastore.messages.CommitTransaction; import org.opendaylight.controller.cluster.datastore.messages.CommitTransactionReply; import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction; -import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChainReply; import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionReply; import org.opendaylight.controller.cluster.datastore.messages.EnableNotification; -import org.opendaylight.controller.cluster.datastore.messages.ForwardedCommitTransaction; +import org.opendaylight.controller.cluster.datastore.messages.ForwardedReadyTransaction; import org.opendaylight.controller.cluster.datastore.messages.PeerAddressResolved; import org.opendaylight.controller.cluster.datastore.messages.ReadData; import org.opendaylight.controller.cluster.datastore.messages.ReadDataReply; +import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply; import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener; import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply; import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext; import org.opendaylight.controller.cluster.datastore.modification.Modification; import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification; import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec; -import org.opendaylight.controller.cluster.raft.ConfigParams; -import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl; import org.opendaylight.controller.cluster.raft.RaftActor; import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry; import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply; import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationPayload; +import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory; import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; -import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionFactory; @@ -68,9 +72,12 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import scala.concurrent.duration.Duration; import scala.concurrent.duration.FiniteDuration; +import javax.annotation.Nonnull; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -85,16 +92,15 @@ import java.util.concurrent.TimeUnit; */ public class Shard extends RaftActor { - private static final ConfigParams configParams = new ShardConfigParams(); + private static final Object COMMIT_TRANSACTION_REPLY = new CommitTransactionReply().toSerializable(); + + private static final Object TX_COMMIT_TIMEOUT_CHECK_MESSAGE = "txCommitTimeoutCheck"; public static final String DEFAULT_NAME = "default"; // The state of this Shard private final InMemoryDOMDataStore store; - private final Map - modificationToCohort = new HashMap<>(); - private final LoggingAdapter LOG = Logging.getLogger(getContext().system(), this); @@ -115,11 +121,26 @@ public class Shard extends RaftActor { private ActorRef createSnapshotTransaction; + private int createSnapshotTransactionCounter; + + private final ShardCommitCoordinator commitCoordinator; + + private final long transactionCommitTimeout; + + private Cancellable txCommitTimeoutCheckSchedule; + + /** + * Coordinates persistence recovery on startup. + */ + private ShardRecoveryCoordinator recoveryCoordinator; + private List currentLogRecoveryBatch; + private final Map transactionChains = new HashMap<>(); - private Shard(ShardIdentifier name, Map peerAddresses, + protected Shard(ShardIdentifier name, Map peerAddresses, DatastoreContext datastoreContext, SchemaContext schemaContext) { - super(name.toString(), mapPeerAddresses(peerAddresses), Optional.of(configParams)); + super(name.toString(), mapPeerAddresses(peerAddresses), + Optional.of(datastoreContext.getShardRaftConfig())); this.name = name; this.datastoreContext = datastoreContext; @@ -146,6 +167,12 @@ public class Shard extends RaftActor { if (isMetricsCaptureEnabled()) { getContext().become(new MeteringBehavior(this)); } + + commitCoordinator = new ShardCommitCoordinator(TimeUnit.SECONDS.convert(1, TimeUnit.MINUTES), + datastoreContext.getShardTransactionCommitQueueCapacity()); + + transactionCommitTimeout = TimeUnit.MILLISECONDS.convert( + datastoreContext.getShardTransactionCommitTimeoutInSeconds(), TimeUnit.SECONDS); } private static Map mapPeerAddresses( @@ -171,9 +198,22 @@ public class Shard extends RaftActor { return Props.create(new ShardCreator(name, peerAddresses, datastoreContext, schemaContext)); } - @Override public void onReceiveRecover(Object message) { - LOG.debug("onReceiveRecover: Received message {} from {}", message.getClass().toString(), - getSender()); + @Override + public void postStop() { + super.postStop(); + + if(txCommitTimeoutCheckSchedule != null) { + txCommitTimeoutCheckSchedule.cancel(); + } + } + + @Override + public void onReceiveRecover(Object message) { + if(LOG.isDebugEnabled()) { + LOG.debug("onReceiveRecover: Received message {} from {}", + message.getClass().toString(), + getSender()); + } if (message instanceof RecoveryFailure){ LOG.error(((RecoveryFailure) message).cause(), "Recovery failed because of this cause"); @@ -182,49 +222,241 @@ public class Shard extends RaftActor { } } - @Override public void onReceiveCommand(Object message) { - LOG.debug("onReceiveCommand: Received message {} from {}", message.getClass().toString(), - getSender()); + @Override + public void onReceiveCommand(Object message) { + if(LOG.isDebugEnabled()) { + LOG.debug("onReceiveCommand: Received message {} from {}", message, getSender()); + } if(message.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) { - // This must be for install snapshot. Don't want to open this up and trigger - // deSerialization - self() - .tell(new CaptureSnapshotReply(ReadDataReply.getNormalizedNodeByteString(message)), - self()); - - createSnapshotTransaction = null; - // Send a PoisonPill instead of sending close transaction because we do not really need - // a response - getSender().tell(PoisonPill.getInstance(), self()); - + handleReadDataReply(message); + } else if (message.getClass().equals(CreateTransaction.SERIALIZABLE_CLASS)) { + handleCreateTransaction(message); + } else if(message instanceof ForwardedReadyTransaction) { + handleForwardedReadyTransaction((ForwardedReadyTransaction)message); + } else if(message.getClass().equals(CanCommitTransaction.SERIALIZABLE_CLASS)) { + handleCanCommitTransaction(CanCommitTransaction.fromSerializable(message)); + } else if(message.getClass().equals(CommitTransaction.SERIALIZABLE_CLASS)) { + handleCommitTransaction(CommitTransaction.fromSerializable(message)); + } else if(message.getClass().equals(AbortTransaction.SERIALIZABLE_CLASS)) { + handleAbortTransaction(AbortTransaction.fromSerializable(message)); } else if (message.getClass().equals(CloseTransactionChain.SERIALIZABLE_CLASS)){ closeTransactionChain(CloseTransactionChain.fromSerializable(message)); } else if (message instanceof RegisterChangeListener) { registerChangeListener((RegisterChangeListener) message); } else if (message instanceof UpdateSchemaContext) { updateSchemaContext((UpdateSchemaContext) message); - } else if (message instanceof ForwardedCommitTransaction) { - handleForwardedCommit((ForwardedCommitTransaction) message); - } else if (message.getClass() - .equals(CreateTransaction.SERIALIZABLE_CLASS)) { - if (isLeader()) { - createTransaction(CreateTransaction.fromSerializable(message)); - } else if (getLeader() != null) { - getLeader().forward(message, getContext()); - } else { - getSender().tell(new akka.actor.Status.Failure(new IllegalStateException( - "Could not find leader so transaction cannot be created")), getSelf()); - } } else if (message instanceof PeerAddressResolved) { PeerAddressResolved resolved = (PeerAddressResolved) message; setPeerAddress(resolved.getPeerId().toString(), resolved.getPeerAddress()); + } else if(message.equals(TX_COMMIT_TIMEOUT_CHECK_MESSAGE)) { + handleTransactionCommitTimeoutCheck(); } else { super.onReceiveCommand(message); } } + private void handleTransactionCommitTimeoutCheck() { + CohortEntry cohortEntry = commitCoordinator.getCurrentCohortEntry(); + if(cohortEntry != null) { + long elapsed = System.currentTimeMillis() - cohortEntry.getLastAccessTime(); + if(elapsed > transactionCommitTimeout) { + LOG.warning("Current transaction {} has timed out after {} ms - aborting", + cohortEntry.getTransactionID(), transactionCommitTimeout); + + doAbortTransaction(cohortEntry.getTransactionID(), null); + } + } + } + + private void handleCommitTransaction(CommitTransaction commit) { + final String transactionID = commit.getTransactionID(); + + LOG.debug("Committing transaction {}", transactionID); + + // Get the current in-progress cohort entry in the commitCoordinator if it corresponds to + // this transaction. + final CohortEntry cohortEntry = commitCoordinator.getCohortEntryIfCurrent(transactionID); + if(cohortEntry == null) { + // We're not the current Tx - the Tx was likely expired b/c it took too long in + // between the canCommit and commit messages. + IllegalStateException ex = new IllegalStateException( + String.format("Cannot commit transaction %s - it is not the current transaction", + transactionID)); + LOG.error(ex.getMessage()); + shardMBean.incrementFailedTransactionsCount(); + getSender().tell(new akka.actor.Status.Failure(ex), getSelf()); + return; + } + + // We perform the preCommit phase here atomically with the commit phase. This is an + // optimization to eliminate the overhead of an extra preCommit message. We lose front-end + // coordination of preCommit across shards in case of failure but preCommit should not + // normally fail since we ensure only one concurrent 3-phase commit. + + try { + // We block on the future here so we don't have to worry about possibly accessing our + // state on a different thread outside of our dispatcher. Also, the data store + // currently uses a same thread executor anyway. + cohortEntry.getCohort().preCommit().get(); + + if(persistent) { + Shard.this.persistData(getSender(), transactionID, + new CompositeModificationPayload(cohortEntry.getModification().toSerializable())); + } else { + Shard.this.finishCommit(getSender(), transactionID); + } + } catch (InterruptedException | ExecutionException e) { + LOG.error(e, "An exception occurred while preCommitting transaction {}", + cohortEntry.getTransactionID()); + shardMBean.incrementFailedTransactionsCount(); + getSender().tell(new akka.actor.Status.Failure(e), getSelf()); + } + + cohortEntry.updateLastAccessTime(); + } + + private void finishCommit(@Nonnull final ActorRef sender, final @Nonnull String transactionID) { + // With persistence enabled, this method is called via applyState by the leader strategy + // after the commit has been replicated to a majority of the followers. + + CohortEntry cohortEntry = commitCoordinator.getCohortEntryIfCurrent(transactionID); + if(cohortEntry == null) { + // The transaction is no longer the current commit. This can happen if the transaction + // was aborted prior, most likely due to timeout in the front-end. We need to finish + // committing the transaction though since it was successfully persisted and replicated + // however we can't use the original cohort b/c it was already preCommitted and may + // conflict with the current commit or may have been aborted so we commit with a new + // transaction. + cohortEntry = commitCoordinator.getAndRemoveCohortEntry(transactionID); + if(cohortEntry != null) { + commitWithNewTransaction(cohortEntry.getModification()); + sender.tell(COMMIT_TRANSACTION_REPLY, getSelf()); + } else { + // This really shouldn't happen - it likely means that persistence or replication + // took so long to complete such that the cohort entry was expired from the cache. + IllegalStateException ex = new IllegalStateException( + String.format("Could not finish committing transaction %s - no CohortEntry found", + transactionID)); + LOG.error(ex.getMessage()); + sender.tell(new akka.actor.Status.Failure(ex), getSelf()); + } + + return; + } + + LOG.debug("Finishing commit for transaction {}", cohortEntry.getTransactionID()); + + try { + // We block on the future here so we don't have to worry about possibly accessing our + // state on a different thread outside of our dispatcher. Also, the data store + // currently uses a same thread executor anyway. + cohortEntry.getCohort().commit().get(); + + sender.tell(COMMIT_TRANSACTION_REPLY, getSelf()); + + shardMBean.incrementCommittedTransactionCount(); + shardMBean.setLastCommittedTransactionTime(System.currentTimeMillis()); + + } catch (InterruptedException | ExecutionException e) { + sender.tell(new akka.actor.Status.Failure(e), getSelf()); + + LOG.error(e, "An exception occurred while committing transaction {}", transactionID); + shardMBean.incrementFailedTransactionsCount(); + } + + commitCoordinator.currentTransactionComplete(transactionID, true); + } + + private void handleCanCommitTransaction(CanCommitTransaction canCommit) { + LOG.debug("Can committing transaction {}", canCommit.getTransactionID()); + commitCoordinator.handleCanCommit(canCommit, getSender(), self()); + } + + private void handleForwardedReadyTransaction(ForwardedReadyTransaction ready) { + LOG.debug("Readying transaction {}", ready.getTransactionID()); + + // This message is forwarded by the ShardTransaction on ready. We cache the cohort in the + // commitCoordinator in preparation for the subsequent three phase commit initiated by + // the front-end. + commitCoordinator.transactionReady(ready.getTransactionID(), ready.getCohort(), + ready.getModification()); + + // Return our actor path as we'll handle the three phase commit. + ReadyTransactionReply readyTransactionReply = + new ReadyTransactionReply(Serialization.serializedActorPath(self())); + getSender().tell( + ready.isReturnSerialized() ? readyTransactionReply.toSerializable() : readyTransactionReply, + getSelf()); + } + + private void handleAbortTransaction(AbortTransaction abort) { + doAbortTransaction(abort.getTransactionID(), getSender()); + } + + private void doAbortTransaction(String transactionID, final ActorRef sender) { + final CohortEntry cohortEntry = commitCoordinator.getCohortEntryIfCurrent(transactionID); + if(cohortEntry != null) { + LOG.debug("Aborting transaction {}", transactionID); + + // We don't remove the cached cohort entry here (ie pass false) in case the Tx was + // aborted during replication in which case we may still commit locally if replication + // succeeds. + commitCoordinator.currentTransactionComplete(transactionID, false); + + final ListenableFuture future = cohortEntry.getCohort().abort(); + final ActorRef self = getSelf(); + + Futures.addCallback(future, new FutureCallback() { + @Override + public void onSuccess(Void v) { + shardMBean.incrementAbortTransactionsCount(); + + if(sender != null) { + sender.tell(new AbortTransactionReply().toSerializable(), self); + } + } + + @Override + public void onFailure(Throwable t) { + LOG.error(t, "An exception happened during abort"); + + if(sender != null) { + sender.tell(new akka.actor.Status.Failure(t), self); + } + } + }); + } + } + + private void handleCreateTransaction(Object message) { + if (isLeader()) { + createTransaction(CreateTransaction.fromSerializable(message)); + } else if (getLeader() != null) { + getLeader().forward(message, getContext()); + } else { + getSender().tell(new akka.actor.Status.Failure(new IllegalStateException( + "Could not find shard leader so transaction cannot be created. This typically happens" + + " when system is coming up or recovering and a leader is being elected. Try again" + + " later.")), getSelf()); + } + } + + private void handleReadDataReply(Object message) { + // This must be for install snapshot. Don't want to open this up and trigger + // deSerialization + + self().tell(new CaptureSnapshotReply(ReadDataReply.getNormalizedNodeByteString(message)), + self()); + + createSnapshotTransaction = null; + + // Send a PoisonPill instead of sending close transaction because we do not really need + // a response + getSender().tell(PoisonPill.getInstance(), self()); + } + private void closeTransactionChain(CloseTransactionChain closeTransactionChain) { DOMStoreTransactionChain chain = transactionChains.remove(closeTransactionChain.getTransactionChainId()); @@ -254,33 +486,33 @@ public class Shard extends RaftActor { throw new NullPointerException("schemaContext should not be null"); } - if (transactionType - == TransactionProxy.TransactionType.READ_ONLY.ordinal()) { + if (transactionType == TransactionProxy.TransactionType.READ_ONLY.ordinal()) { shardMBean.incrementReadOnlyTransactionCount(); return getContext().actorOf( ShardTransaction.props(factory.newReadOnlyTransaction(), getSelf(), - schemaContext,datastoreContext, shardMBean), transactionId.toString()); + schemaContext,datastoreContext, shardMBean, + transactionId.getRemoteTransactionId()), transactionId.toString()); - } else if (transactionType - == TransactionProxy.TransactionType.READ_WRITE.ordinal()) { + } else if (transactionType == TransactionProxy.TransactionType.READ_WRITE.ordinal()) { shardMBean.incrementReadWriteTransactionCount(); return getContext().actorOf( ShardTransaction.props(factory.newReadWriteTransaction(), getSelf(), - schemaContext, datastoreContext, shardMBean), transactionId.toString()); + schemaContext, datastoreContext, shardMBean, + transactionId.getRemoteTransactionId()), transactionId.toString()); - } else if (transactionType - == TransactionProxy.TransactionType.WRITE_ONLY.ordinal()) { + } else if (transactionType == TransactionProxy.TransactionType.WRITE_ONLY.ordinal()) { shardMBean.incrementWriteOnlyTransactionCount(); return getContext().actorOf( ShardTransaction.props(factory.newWriteOnlyTransaction(), getSelf(), - schemaContext, datastoreContext, shardMBean), transactionId.toString()); + schemaContext, datastoreContext, shardMBean, + transactionId.getRemoteTransactionId()), transactionId.toString()); } else { throw new IllegalArgumentException( "Shard="+name + ":CreateTransaction message has unidentified transaction type=" @@ -299,7 +531,9 @@ public class Shard extends RaftActor { ShardTransactionIdentifier.builder() .remoteTransactionId(remoteTransactionId) .build(); - LOG.debug("Creating transaction : {} ", transactionId); + if(LOG.isDebugEnabled()) { + LOG.debug("Creating transaction : {} ", transactionId); + } ActorRef transactionActor = createTypedTransactionActor(transactionType, transactionId, transactionChainId); @@ -319,73 +553,16 @@ public class Shard extends RaftActor { commitCohort.commit().get(); } - - private void commit(final ActorRef sender, Object serialized) { - Modification modification = MutableCompositeModification - .fromSerializable(serialized, schemaContext); - DOMStoreThreePhaseCommitCohort cohort = - modificationToCohort.remove(serialized); - if (cohort == null) { - LOG.debug( - "Could not find cohort for modification : {}. Writing modification using a new transaction", - modification); - DOMStoreWriteTransaction transaction = - store.newWriteOnlyTransaction(); - - LOG.debug("Created new transaction {}", transaction.getIdentifier().toString()); - - modification.apply(transaction); - try { - syncCommitTransaction(transaction); - } catch (InterruptedException | ExecutionException e) { - shardMBean.incrementFailedTransactionsCount(); - LOG.error("Failed to commit", e); - return; - } - //we want to just apply the recovery commit and return + private void commitWithNewTransaction(Modification modification) { + DOMStoreWriteTransaction tx = store.newWriteOnlyTransaction(); + modification.apply(tx); + try { + syncCommitTransaction(tx); shardMBean.incrementCommittedTransactionCount(); - return; - } - - - if(sender == null){ - LOG.error("Commit failed. Sender cannot be null"); - return; - } - - final ListenableFuture future = cohort.commit(); - final ActorRef self = getSelf(); - - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(Void v) { - sender.tell(new CommitTransactionReply().toSerializable(), self); - shardMBean.incrementCommittedTransactionCount(); - shardMBean.setLastCommittedTransactionTime(System.currentTimeMillis()); - } - - @Override - public void onFailure(Throwable t) { - LOG.error(t, "An exception happened during commit"); - shardMBean.incrementFailedTransactionsCount(); - sender.tell(new akka.actor.Status.Failure(t), self); - } - }); - - } - - private void handleForwardedCommit(ForwardedCommitTransaction message) { - Object serializedModification = - message.getModification().toSerializable(); - - modificationToCohort - .put(serializedModification, message.getCohort()); - - if (persistent) { - this.persistData(getSender(), "identifier", - new CompositeModificationPayload(serializedModification)); - } else { - this.commit(getSender(), serializedModification); + shardMBean.setLastCommittedTransactionTime(System.currentTimeMillis()); + } catch (InterruptedException | ExecutionException e) { + shardMBean.incrementFailedTransactionsCount(); + LOG.error(e, "Failed to commit"); } } @@ -402,8 +579,10 @@ public class Shard extends RaftActor { private void registerChangeListener( RegisterChangeListener registerChangeListener) { - LOG.debug("registerDataChangeListener for {}", registerChangeListener - .getPath()); + if(LOG.isDebugEnabled()) { + LOG.debug("registerDataChangeListener for {}", registerChangeListener + .getPath()); + } ActorSelection dataChangeListenerPath = getContext() @@ -431,48 +610,133 @@ public class Shard extends RaftActor { getContext().actorOf( DataChangeListenerRegistration.props(registration)); - LOG.debug( - "registerDataChangeListener sending reply, listenerRegistrationPath = {} " - , listenerRegistration.path().toString()); + if(LOG.isDebugEnabled()) { + LOG.debug( + "registerDataChangeListener sending reply, listenerRegistrationPath = {} " + , listenerRegistration.path().toString()); + } getSender() .tell(new RegisterChangeListenerReply(listenerRegistration.path()), getSelf()); } - private void createTransactionChain() { - DOMStoreTransactionChain chain = store.createTransactionChain(); - ActorRef transactionChain = getContext().actorOf( - ShardTransactionChain.props(chain, schemaContext, datastoreContext, shardMBean)); - getSender().tell(new CreateTransactionChainReply(transactionChain.path()).toSerializable(), - getSelf()); - } - private boolean isMetricsCaptureEnabled(){ CommonConfig config = new CommonConfig(getContext().system().settings().config()); return config.isMetricCaptureEnabled(); } - @Override protected void applyState(ActorRef clientActor, String identifier, - Object data) { + @Override + protected + void startLogRecoveryBatch(int maxBatchSize) { + currentLogRecoveryBatch = Lists.newArrayListWithCapacity(maxBatchSize); + + if(LOG.isDebugEnabled()) { + LOG.debug("{} : starting log recovery batch with max size {}", persistenceId(), maxBatchSize); + } + } + @Override + protected void appendRecoveredLogEntry(Payload data) { if (data instanceof CompositeModificationPayload) { - Object modification = - ((CompositeModificationPayload) data).getModification(); + currentLogRecoveryBatch.add(((CompositeModificationPayload) data).getModification()); + } else { + LOG.error("Unknown state received {} during recovery", data); + } + } - if (modification != null) { - commit(clientActor, modification); - } else { - LOG.error( - "modification is null - this is very unexpected, clientActor = {}, identifier = {}", - identifier, clientActor.path().toString()); + @Override + protected void applyRecoverySnapshot(ByteString snapshot) { + if(recoveryCoordinator == null) { + recoveryCoordinator = new ShardRecoveryCoordinator(persistenceId(), schemaContext); + } + + recoveryCoordinator.submit(snapshot, store.newWriteOnlyTransaction()); + + if(LOG.isDebugEnabled()) { + LOG.debug("{} : submitted recovery sbapshot", persistenceId()); + } + } + + @Override + protected void applyCurrentLogRecoveryBatch() { + if(recoveryCoordinator == null) { + recoveryCoordinator = new ShardRecoveryCoordinator(persistenceId(), schemaContext); + } + + recoveryCoordinator.submit(currentLogRecoveryBatch, store.newWriteOnlyTransaction()); + + if(LOG.isDebugEnabled()) { + LOG.debug("{} : submitted log recovery batch with size {}", persistenceId(), + currentLogRecoveryBatch.size()); + } + } + + @Override + protected void onRecoveryComplete() { + if(recoveryCoordinator != null) { + Collection txList = recoveryCoordinator.getTransactions(); + + if(LOG.isDebugEnabled()) { + LOG.debug("{} : recovery complete - committing {} Tx's", persistenceId(), txList.size()); + } + + for(DOMStoreWriteTransaction tx: txList) { + try { + syncCommitTransaction(tx); + shardMBean.incrementCommittedTransactionCount(); + } catch (InterruptedException | ExecutionException e) { + shardMBean.incrementFailedTransactionsCount(); + LOG.error(e, "Failed to commit"); + } } + } + + recoveryCoordinator = null; + currentLogRecoveryBatch = null; + updateJournalStats(); + //notify shard manager + getContext().parent().tell(new ActorInitialized(), getSelf()); + + // Schedule a message to be periodically sent to check if the current in-progress + // transaction should be expired and aborted. + FiniteDuration period = Duration.create(transactionCommitTimeout / 3, TimeUnit.MILLISECONDS); + txCommitTimeoutCheckSchedule = getContext().system().scheduler().schedule( + period, period, getSelf(), + TX_COMMIT_TIMEOUT_CHECK_MESSAGE, getContext().dispatcher(), ActorRef.noSender()); + } + + @Override + protected void applyState(ActorRef clientActor, String identifier, Object data) { + + if (data instanceof CompositeModificationPayload) { + Object modification = ((CompositeModificationPayload) data).getModification(); + + if(modification == null) { + LOG.error( + "modification is null - this is very unexpected, clientActor = {}, identifier = {}", + identifier, clientActor != null ? clientActor.path().toString() : null); + } else if(clientActor == null) { + // There's no clientActor to which to send a commit reply so we must be applying + // replicated state from the leader. + commitWithNewTransaction(MutableCompositeModification.fromSerializable( + modification, schemaContext)); + } else { + // This must be the OK to commit after replication consensus. + finishCommit(clientActor, identifier); + } } else { - LOG.error("Unknown state received {} Class loader = {} CompositeNodeMod.ClassLoader = {}", data, data.getClass().getClassLoader(), CompositeModificationPayload.class.getClassLoader()); + LOG.error("Unknown state received {} Class loader = {} CompositeNodeMod.ClassLoader = {}", + data, data.getClass().getClassLoader(), + CompositeModificationPayload.class.getClassLoader()); } - // Update stats + updateJournalStats(); + + } + + private void updateJournalStats() { ReplicatedLogEntry lastLogEntry = getLastLogEntry(); if (lastLogEntry != null) { @@ -482,17 +746,17 @@ public class Shard extends RaftActor { shardMBean.setCommitIndex(getCommitIndex()); shardMBean.setLastApplied(getLastApplied()); - } - @Override protected void createSnapshot() { + @Override + protected void createSnapshot() { if (createSnapshotTransaction == null) { // Create a transaction. We are really going to treat the transaction as a worker // so that this actor does not get block building the snapshot createSnapshotTransaction = createTransaction( TransactionProxy.TransactionType.READ_ONLY.ordinal(), - "createSnapshot", ""); + "createSnapshot" + ++createSnapshotTransactionCounter, ""); createSnapshotTransaction.tell( new ReadData(YangInstanceIdentifier.builder().build()).toSerializable(), self()); @@ -500,7 +764,9 @@ public class Shard extends RaftActor { } } - @VisibleForTesting @Override protected void applySnapshot(ByteString snapshot) { + @VisibleForTesting + @Override + protected void applySnapshot(ByteString snapshot) { // Since this will be done only on Recovery or when this actor is a Follower // we can safely commit everything in here. We not need to worry about event notifications // as they would have already been disabled on the follower @@ -510,7 +776,7 @@ public class Shard extends RaftActor { DOMStoreWriteTransaction transaction = store.newWriteOnlyTransaction(); NormalizedNodeMessages.Node serializedNode = NormalizedNodeMessages.Node.parseFrom(snapshot); NormalizedNode node = new NormalizedNodeToNodeCodec(schemaContext) - .decode(YangInstanceIdentifier.builder().build(), serializedNode); + .decode(serializedNode); // delete everything first transaction.delete(YangInstanceIdentifier.builder().build()); @@ -531,14 +797,17 @@ public class Shard extends RaftActor { .tell(new EnableNotification(isLeader()), getSelf()); } - shardMBean.setRaftState(getRaftState().name()); shardMBean.setCurrentTerm(getCurrentTerm()); // If this actor is no longer the leader close all the transaction chains if(!isLeader()){ for(Map.Entry entry : transactionChains.entrySet()){ - LOG.debug("onStateChanged: Closing transaction chain {} because shard {} is no longer the leader", entry.getKey(), getId()); + if(LOG.isDebugEnabled()) { + LOG.debug( + "onStateChanged: Closing transaction chain {} because shard {} is no longer the leader", + entry.getKey(), getId()); + } entry.getValue().close(); } @@ -554,16 +823,6 @@ public class Shard extends RaftActor { return this.name.toString(); } - - private static class ShardConfigParams extends DefaultConfigParamsImpl { - public static final FiniteDuration HEART_BEAT_INTERVAL = - new FiniteDuration(500, TimeUnit.MILLISECONDS); - - @Override public FiniteDuration getHeartBeatInterval() { - return HEART_BEAT_INTERVAL; - } - } - private static class ShardCreator implements Creator { private static final long serialVersionUID = 1L; @@ -587,26 +846,13 @@ public class Shard extends RaftActor { } } - @VisibleForTesting NormalizedNode readStore() throws ExecutionException, InterruptedException { - DOMStoreReadTransaction transaction = store.newReadOnlyTransaction(); - - CheckedFuture>, ReadFailedException> future = - transaction.read(YangInstanceIdentifier.builder().build()); - - NormalizedNode node = future.get().get(); - - transaction.close(); - - return node; + @VisibleForTesting + InMemoryDOMDataStore getDataStore() { + return store; } - @VisibleForTesting void writeToStore(YangInstanceIdentifier id, NormalizedNode node) - throws ExecutionException, InterruptedException { - DOMStoreWriteTransaction transaction = store.newWriteOnlyTransaction(); - - transaction.write(id, node); - - syncCommitTransaction(transaction); + @VisibleForTesting + ShardStats getShardMBean() { + return shardMBean; } - } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardCommitCoordinator.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardCommitCoordinator.java new file mode 100644 index 0000000000..f3b4e41640 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardCommitCoordinator.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.cluster.datastore; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction; +import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply; +import org.opendaylight.controller.cluster.datastore.modification.Modification; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import akka.actor.ActorRef; +import akka.actor.Status; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +/** + * Coordinates commits for a shard ensuring only one concurrent 3-phase commit. + * + * @author Thomas Pantelis + */ +public class ShardCommitCoordinator { + + private static final Logger LOG = LoggerFactory.getLogger(ShardCommitCoordinator.class); + + private static final Object CAN_COMMIT_REPLY_TRUE = + new CanCommitTransactionReply(Boolean.TRUE).toSerializable(); + + private static final Object CAN_COMMIT_REPLY_FALSE = + new CanCommitTransactionReply(Boolean.FALSE).toSerializable(); + + private final Cache cohortCache; + + private CohortEntry currentCohortEntry; + + private final Queue queuedCohortEntries; + + private final int queueCapacity; + + public ShardCommitCoordinator(long cacheExpiryTimeoutInSec, int queueCapacity) { + cohortCache = CacheBuilder.newBuilder().expireAfterAccess( + cacheExpiryTimeoutInSec, TimeUnit.SECONDS).build(); + + this.queueCapacity = queueCapacity; + + // We use a LinkedList here to avoid synchronization overhead with concurrent queue impls + // since this should only be accessed on the shard's dispatcher. + queuedCohortEntries = new LinkedList<>(); + } + + /** + * This method caches a cohort entry for the given transactions ID in preparation for the + * subsequent 3-phase commit. + * + * @param transactionID the ID of the transaction + * @param cohort the cohort to participate in the transaction commit + * @param modification the modification made by the transaction + */ + public void transactionReady(String transactionID, DOMStoreThreePhaseCommitCohort cohort, + Modification modification) { + + cohortCache.put(transactionID, new CohortEntry(transactionID, cohort, modification)); + } + + /** + * This method handles the canCommit phase for a transaction. + * + * @param canCommit the CanCommitTransaction message + * @param sender the actor that sent the message + * @param shard the transaction's shard actor + */ + public void handleCanCommit(CanCommitTransaction canCommit, final ActorRef sender, + final ActorRef shard) { + String transactionID = canCommit.getTransactionID(); + if(LOG.isDebugEnabled()) { + LOG.debug("Processing canCommit for transaction {} for shard {}", + transactionID, shard.path()); + } + + // Lookup the cohort entry that was cached previously (or should have been) by + // transactionReady (via the ForwardedReadyTransaction message). + final CohortEntry cohortEntry = cohortCache.getIfPresent(transactionID); + if(cohortEntry == null) { + // Either canCommit was invoked before ready(shouldn't happen) or a long time passed + // between canCommit and ready and the entry was expired from the cache. + IllegalStateException ex = new IllegalStateException( + String.format("No cohort entry found for transaction %s", transactionID)); + LOG.error(ex.getMessage()); + sender.tell(new Status.Failure(ex), shard); + return; + } + + cohortEntry.setCanCommitSender(sender); + cohortEntry.setShard(shard); + + if(currentCohortEntry != null) { + // There's already a Tx commit in progress - attempt to queue this entry to be + // committed after the current Tx completes. + LOG.debug("Transaction {} is already in progress - queueing transaction {}", + currentCohortEntry.getTransactionID(), transactionID); + + if(queuedCohortEntries.size() < queueCapacity) { + queuedCohortEntries.offer(cohortEntry); + } else { + removeCohortEntry(transactionID); + + RuntimeException ex = new RuntimeException( + String.format("Could not enqueue transaction %s - the maximum commit queue"+ + " capacity %d has been reached.", + transactionID, queueCapacity)); + LOG.error(ex.getMessage()); + sender.tell(new Status.Failure(ex), shard); + } + } else { + // No Tx commit currently in progress - make this the current entry and proceed with + // canCommit. + cohortEntry.updateLastAccessTime(); + currentCohortEntry = cohortEntry; + + doCanCommit(cohortEntry); + } + } + + private void doCanCommit(final CohortEntry cohortEntry) { + + try { + // We block on the future here so we don't have to worry about possibly accessing our + // state on a different thread outside of our dispatcher. Also, the data store + // currently uses a same thread executor anyway. + Boolean canCommit = cohortEntry.getCohort().canCommit().get(); + + cohortEntry.getCanCommitSender().tell( + canCommit ? CAN_COMMIT_REPLY_TRUE : CAN_COMMIT_REPLY_FALSE, cohortEntry.getShard()); + + if(!canCommit) { + // Remove the entry from the cache now since the Tx will be aborted. + removeCohortEntry(cohortEntry.getTransactionID()); + } + } catch (InterruptedException | ExecutionException e) { + LOG.debug("An exception occurred during canCommit", e); + + // Remove the entry from the cache now since the Tx will be aborted. + removeCohortEntry(cohortEntry.getTransactionID()); + cohortEntry.getCanCommitSender().tell(new Status.Failure(e), cohortEntry.getShard()); + } + } + + /** + * Returns the cohort entry for the Tx commit currently in progress if the given transaction ID + * matches the current entry. + * + * @param transactionID the ID of the transaction + * @return the current CohortEntry or null if the given transaction ID does not match the + * current entry. + */ + public CohortEntry getCohortEntryIfCurrent(String transactionID) { + if(isCurrentTransaction(transactionID)) { + return currentCohortEntry; + } + + return null; + } + + public CohortEntry getCurrentCohortEntry() { + return currentCohortEntry; + } + + public CohortEntry getAndRemoveCohortEntry(String transactionID) { + CohortEntry cohortEntry = cohortCache.getIfPresent(transactionID); + cohortCache.invalidate(transactionID); + return cohortEntry; + } + + public void removeCohortEntry(String transactionID) { + cohortCache.invalidate(transactionID); + } + + public boolean isCurrentTransaction(String transactionID) { + return currentCohortEntry != null && + currentCohortEntry.getTransactionID().equals(transactionID); + } + + /** + * This method is called when a transaction is complete, successful or not. If the given + * given transaction ID matches the current in-progress transaction, the next cohort entry, + * if any, is dequeued and processed. + * + * @param transactionID the ID of the completed transaction + * @param removeCohortEntry if true the CohortEntry for the transaction is also removed from + * the cache. + */ + public void currentTransactionComplete(String transactionID, boolean removeCohortEntry) { + if(removeCohortEntry) { + removeCohortEntry(transactionID); + } + + if(isCurrentTransaction(transactionID)) { + // Dequeue the next cohort entry waiting in the queue. + currentCohortEntry = queuedCohortEntries.poll(); + if(currentCohortEntry != null) { + doCanCommit(currentCohortEntry); + } + } + } + + static class CohortEntry { + private final String transactionID; + private final DOMStoreThreePhaseCommitCohort cohort; + private final Modification modification; + private ActorRef canCommitSender; + private ActorRef shard; + private long lastAccessTime; + + CohortEntry(String transactionID, DOMStoreThreePhaseCommitCohort cohort, + Modification modification) { + this.transactionID = transactionID; + this.cohort = cohort; + this.modification = modification; + } + + void updateLastAccessTime() { + lastAccessTime = System.currentTimeMillis(); + } + + long getLastAccessTime() { + return lastAccessTime; + } + + String getTransactionID() { + return transactionID; + } + + DOMStoreThreePhaseCommitCohort getCohort() { + return cohort; + } + + Modification getModification() { + return modification; + } + + ActorRef getCanCommitSender() { + return canCommitSender; + } + + void setCanCommitSender(ActorRef canCommitSender) { + this.canCommitSender = canCommitSender; + } + + ActorRef getShard() { + return shard; + } + + void setShard(ActorRef shard) { + this.shard = shard; + } + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java index 13ecaa5619..157f1cb377 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java @@ -15,15 +15,23 @@ import akka.actor.OneForOneStrategy; import akka.actor.Props; import akka.actor.SupervisorStrategy; import akka.cluster.ClusterEvent; +import akka.event.Logging; +import akka.event.LoggingAdapter; import akka.japi.Creator; import akka.japi.Function; +import akka.japi.Procedure; +import akka.persistence.RecoveryCompleted; +import akka.persistence.RecoveryFailure; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; -import org.opendaylight.controller.cluster.common.actor.AbstractUntypedActorWithMetering; - +import com.google.common.base.Supplier; +import org.opendaylight.controller.cluster.common.actor.AbstractUntypedPersistentActorWithMetering; import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier; import org.opendaylight.controller.cluster.datastore.identifiers.ShardManagerIdentifier; import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shardmanager.ShardManagerInfo; import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shardmanager.ShardManagerInfoMBean; +import org.opendaylight.controller.cluster.datastore.messages.ActorInitialized; +import org.opendaylight.controller.cluster.datastore.messages.ActorNotInitialized; import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard; import org.opendaylight.controller.cluster.datastore.messages.FindPrimary; import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound; @@ -32,14 +40,17 @@ import org.opendaylight.controller.cluster.datastore.messages.PeerAddressResolve import org.opendaylight.controller.cluster.datastore.messages.PrimaryFound; import org.opendaylight.controller.cluster.datastore.messages.PrimaryNotFound; import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext; -import org.opendaylight.controller.cluster.datastore.utils.ActorContext; +import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import scala.concurrent.duration.Duration; - +import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; /** * The ShardManager has the following jobs, @@ -50,7 +61,10 @@ import java.util.Map; *
  • Monitor the cluster members and store their addresses *
      */ -public class ShardManager extends AbstractUntypedActorWithMetering { +public class ShardManager extends AbstractUntypedPersistentActorWithMetering { + + protected final LoggingAdapter LOG = + Logging.getLogger(getContext().system(), this); // Stores a mapping between a member name and the address of the member // Member names look like "member-1", "member-2" etc and are as specified @@ -74,11 +88,13 @@ public class ShardManager extends AbstractUntypedActorWithMetering { private final DatastoreContext datastoreContext; + private final Collection knownModules = new HashSet<>(128); + /** * @param type defines the kind of data that goes into shards created by this shard manager. Examples of type would be * configuration or operational */ - private ShardManager(String type, ClusterWrapper cluster, Configuration configuration, + protected ShardManager(String type, ClusterWrapper cluster, Configuration configuration, DatastoreContext datastoreContext) { this.type = Preconditions.checkNotNull(type, "type should not be null"); @@ -89,7 +105,7 @@ public class ShardManager extends AbstractUntypedActorWithMetering { // Subscribe this actor to cluster member events cluster.subscribeToMemberEvents(getSelf()); - //createLocalShards(null); + createLocalShards(); } public static Props props(final String type, @@ -105,14 +121,15 @@ public class ShardManager extends AbstractUntypedActorWithMetering { } @Override - public void handleReceive(Object message) throws Exception { + public void handleCommand(Object message) throws Exception { if (message.getClass().equals(FindPrimary.SERIALIZABLE_CLASS)) { - findPrimary( - FindPrimary.fromSerializable(message)); + findPrimary(FindPrimary.fromSerializable(message)); } else if(message instanceof FindLocalShard){ findLocalShard((FindLocalShard) message); } else if (message instanceof UpdateSchemaContext) { updateSchemaContext(message); + } else if(message instanceof ActorInitialized) { + onActorInitialized(message); } else if (message instanceof ClusterEvent.MemberUp){ memberUp((ClusterEvent.MemberUp) message); } else if(message instanceof ClusterEvent.MemberRemoved) { @@ -125,17 +142,71 @@ public class ShardManager extends AbstractUntypedActorWithMetering { } + private void onActorInitialized(Object message) { + final ActorRef sender = getSender(); + + if (sender == null) { + return; //why is a non-actor sending this message? Just ignore. + } + + String actorName = sender.path().name(); + //find shard name from actor name; actor name is stringified shardId + ShardIdentifier shardId = ShardIdentifier.builder().fromShardIdString(actorName).build(); + + if (shardId.getShardName() == null) { + return; + } + markShardAsInitialized(shardId.getShardName()); + } + + private void markShardAsInitialized(String shardName) { + LOG.debug("Initializing shard [{}]", shardName); + ShardInformation shardInformation = localShards.get(shardName); + if (shardInformation != null) { + shardInformation.setShardInitialized(true); + } + } + + @Override + protected void handleRecover(Object message) throws Exception { + if(message instanceof SchemaContextModules){ + SchemaContextModules msg = (SchemaContextModules) message; + knownModules.clear(); + knownModules.addAll(msg.getModules()); + } else if(message instanceof RecoveryFailure){ + RecoveryFailure failure = (RecoveryFailure) message; + LOG.error(failure.cause(), "Recovery failed"); + } else if(message instanceof RecoveryCompleted){ + LOG.info("Recovery complete : {}", persistenceId()); + + // Delete all the messages from the akka journal except the last one + deleteMessages(lastSequenceNr() - 1); + } + } + private void findLocalShard(FindLocalShard message) { - ShardInformation shardInformation = - localShards.get(message.getShardName()); + final ShardInformation shardInformation = localShards.get(message.getShardName()); - if(shardInformation != null){ - getSender().tell(new LocalShardFound(shardInformation.getActor()), getSelf()); + if(shardInformation == null){ + getSender().tell(new LocalShardNotFound(message.getShardName()), getSelf()); return; } - getSender().tell(new LocalShardNotFound(message.getShardName()), - getSelf()); + sendResponse(shardInformation, new Supplier() { + @Override + public Object get() { + return new LocalShardFound(shardInformation.getActor()); + } + }); + } + + private void sendResponse(ShardInformation shardInformation, Supplier messageSupplier) { + if (shardInformation.getActor() == null || !shardInformation.isShardInitialized()) { + getSender().tell(new ActorNotInitialized(), getSelf()); + return; + } + + getSender().tell(messageSupplier.get(), getSelf()); } private void memberRemoved(ClusterEvent.MemberRemoved message) { @@ -145,7 +216,7 @@ public class ShardManager extends AbstractUntypedActorWithMetering { private void memberUp(ClusterEvent.MemberUp message) { String memberName = message.member().roles().head(); - memberNameToAddress.put(memberName , message.member().address()); + memberNameToAddress.put(memberName, message.member().address()); for(ShardInformation info : localShards.values()){ String shardName = info.getShardName(); @@ -159,41 +230,73 @@ public class ShardManager extends AbstractUntypedActorWithMetering { * * @param message */ - private void updateSchemaContext(Object message) { - SchemaContext schemaContext = ((UpdateSchemaContext) message).getSchemaContext(); + private void updateSchemaContext(final Object message) { + final SchemaContext schemaContext = ((UpdateSchemaContext) message).getSchemaContext(); + + Set allModuleIdentifiers = schemaContext.getAllModuleIdentifiers(); + Set newModules = new HashSet<>(128); + + for(ModuleIdentifier moduleIdentifier : allModuleIdentifiers){ + String s = moduleIdentifier.getNamespace().toString(); + newModules.add(s); + } + + if(newModules.containsAll(knownModules)) { - if(localShards.size() == 0){ - createLocalShards(schemaContext); + LOG.info("New SchemaContext has a super set of current knownModules - persisting info"); + + knownModules.clear(); + knownModules.addAll(newModules); + + persist(new SchemaContextModules(newModules), new Procedure() { + + @Override + public void apply(SchemaContextModules param) throws Exception { + LOG.info("Sending new SchemaContext to Shards"); + for (ShardInformation info : localShards.values()) { + if(info.getActor() == null) { + info.setActor(getContext().actorOf(Shard.props(info.getShardId(), + info.getPeerAddresses(), datastoreContext, schemaContext), + info.getShardId().toString())); + } else { + info.getActor().tell(message, getSelf()); + } + } + } + + }); } else { - for (ShardInformation info : localShards.values()) { - info.getActor().tell(message, getSelf()); - } + LOG.info("Rejecting schema context update because it is not a super set of previously known modules"); } + } private void findPrimary(FindPrimary message) { String shardName = message.getShardName(); // First see if the there is a local replica for the shard - ShardInformation info = localShards.get(shardName); - if(info != null) { - ActorPath shardPath = info.getActorPath(); - if (shardPath != null) { - getSender() - .tell( - new PrimaryFound(shardPath.toString()).toSerializable(), - getSelf()); - return; - } + final ShardInformation info = localShards.get(shardName); + if (info != null) { + sendResponse(info, new Supplier() { + @Override + public Object get() { + return new PrimaryFound(info.getActorPath().toString()).toSerializable(); + } + }); + + return; } - List members = - configuration.getMembersFromShardName(shardName); + List members = configuration.getMembersFromShardName(shardName); if(cluster.getCurrentMemberName() != null) { members.remove(cluster.getCurrentMemberName()); } + /** + * FIXME: Instead of sending remote shard actor path back to sender, + * forward FindPrimary message to remote shard manager + */ // There is no way for us to figure out the primary (for now) so assume // that one of the remote nodes is a primary for(String memberName : members) { @@ -239,7 +342,7 @@ public class ShardManager extends AbstractUntypedActorWithMetering { * runs * */ - private void createLocalShards(SchemaContext schemaContext) { + private void createLocalShards() { String memberName = this.cluster.getCurrentMemberName(); List memberShardNames = this.configuration.getMemberShardNames(memberName); @@ -248,11 +351,8 @@ public class ShardManager extends AbstractUntypedActorWithMetering { for(String shardName : memberShardNames){ ShardIdentifier shardId = getShardIdentifier(memberName, shardName); Map peerAddresses = getPeerAddresses(shardName); - ActorRef actor = getContext() - .actorOf(Shard.props(shardId, peerAddresses, datastoreContext, schemaContext). - withMailbox(ActorContext.MAILBOX), shardId.toString()); localShardActorNames.add(shardId.toString()); - localShards.put(shardName, new ShardInformation(shardName, actor, peerAddresses)); + localShards.put(shardName, new ShardInformation(shardName, shardId, peerAddresses)); } mBean = ShardManagerInfo.createShardManagerMBean("shard-manager-" + this.type, @@ -306,48 +406,80 @@ public class ShardManager extends AbstractUntypedActorWithMetering { } + @Override + public String persistenceId() { + return "shard-manager-" + type; + } + + @VisibleForTesting + Collection getKnownModules() { + return knownModules; + } + private class ShardInformation { + private final ShardIdentifier shardId; private final String shardName; - private final ActorRef actor; - private final ActorPath actorPath; + private ActorRef actor; + private ActorPath actorPath; private final Map peerAddresses; + private boolean shardInitialized = false; // flag that determines if the actor is ready for business - private ShardInformation(String shardName, ActorRef actor, - Map peerAddresses) { + private ShardInformation(String shardName, ShardIdentifier shardId, + Map peerAddresses) { this.shardName = shardName; - this.actor = actor; - this.actorPath = actor.path(); + this.shardId = shardId; this.peerAddresses = peerAddresses; } - public String getShardName() { + String getShardName() { return shardName; } - public ActorRef getActor(){ + ActorRef getActor(){ return actor; } - public ActorPath getActorPath() { + ActorPath getActorPath() { return actorPath; } - public void updatePeerAddress(ShardIdentifier peerId, String peerAddress){ + void setActor(ActorRef actor) { + this.actor = actor; + this.actorPath = actor.path(); + } + + ShardIdentifier getShardId() { + return shardId; + } + + Map getPeerAddresses() { + return peerAddresses; + } + + void updatePeerAddress(ShardIdentifier peerId, String peerAddress){ LOG.info("updatePeerAddress for peer {} with address {}", peerId, peerAddress); if(peerAddresses.containsKey(peerId)){ peerAddresses.put(peerId, peerAddress); - LOG.debug( - "Sending PeerAddressResolved for peer {} with address {} to {}", - peerId, peerAddress, actor.path()); - - actor - .tell(new PeerAddressResolved(peerId, peerAddress), - getSelf()); + if(actor != null) { + if(LOG.isDebugEnabled()) { + LOG.debug("Sending PeerAddressResolved for peer {} with address {} to {}", + peerId, peerAddress, actor.path()); + } + actor.tell(new PeerAddressResolved(peerId, peerAddress), getSelf()); + } } } + + boolean isShardInitialized() { + return shardInitialized; + } + + void setShardInitialized(boolean shardInitialized) { + this.shardInitialized = shardInitialized; + } } private static class ShardManagerCreator implements Creator { @@ -371,6 +503,20 @@ public class ShardManager extends AbstractUntypedActorWithMetering { return new ShardManager(type, cluster, configuration, datastoreContext); } } + + static class SchemaContextModules implements Serializable { + private static final long serialVersionUID = 1L; + + private final Set modules; + + SchemaContextModules(Set modules){ + this.modules = modules; + } + + public Set getModules() { + return modules; + } + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadTransaction.java index 0e9fd113c5..d12e9997bb 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadTransaction.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadTransaction.java @@ -11,7 +11,6 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; - import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats; import org.opendaylight.controller.cluster.datastore.messages.DataExists; import org.opendaylight.controller.cluster.datastore.messages.ReadData; @@ -27,17 +26,25 @@ public class ShardReadTransaction extends ShardTransaction { private final DOMStoreReadTransaction transaction; public ShardReadTransaction(DOMStoreReadTransaction transaction, ActorRef shardActor, - SchemaContext schemaContext, ShardStats shardStats) { - super(shardActor, schemaContext, shardStats); + SchemaContext schemaContext, ShardStats shardStats, String transactionID) { + super(shardActor, schemaContext, shardStats, transactionID); this.transaction = transaction; } @Override public void handleReceive(Object message) throws Exception { - if(ReadData.SERIALIZABLE_CLASS.equals(message.getClass())) { - readData(transaction, ReadData.fromSerializable(message)); + if(message instanceof ReadData) { + readData(transaction, (ReadData) message, !SERIALIZED_REPLY); + + } else if (message instanceof DataExists) { + dataExists(transaction, (DataExists) message, !SERIALIZED_REPLY); + + } else if(ReadData.SERIALIZABLE_CLASS.equals(message.getClass())) { + readData(transaction, ReadData.fromSerializable(message), SERIALIZED_REPLY); + } else if(DataExists.SERIALIZABLE_CLASS.equals(message.getClass())) { - dataExists(transaction, DataExists.fromSerializable(message)); + dataExists(transaction, DataExists.fromSerializable(message), SERIALIZED_REPLY); + } else { super.handleReceive(message); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadWriteTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadWriteTransaction.java index d04ec233ea..b1fd02d217 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadWriteTransaction.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadWriteTransaction.java @@ -14,49 +14,39 @@ import akka.actor.ActorRef; import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats; import org.opendaylight.controller.cluster.datastore.messages.DataExists; -import org.opendaylight.controller.cluster.datastore.messages.DeleteData; -import org.opendaylight.controller.cluster.datastore.messages.MergeData; import org.opendaylight.controller.cluster.datastore.messages.ReadData; -import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction; -import org.opendaylight.controller.cluster.datastore.messages.WriteData; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; -import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction; import org.opendaylight.yangtools.yang.model.api.SchemaContext; /** * @author: syedbahm * Date: 8/6/14 */ -public class ShardReadWriteTransaction extends ShardTransaction { +public class ShardReadWriteTransaction extends ShardWriteTransaction { private final DOMStoreReadWriteTransaction transaction; public ShardReadWriteTransaction(DOMStoreReadWriteTransaction transaction, ActorRef shardActor, - SchemaContext schemaContext, ShardStats shardStats) { - super(shardActor, schemaContext, shardStats); + SchemaContext schemaContext, ShardStats shardStats, String transactionID) { + super(transaction, shardActor, schemaContext, shardStats, transactionID); this.transaction = transaction; } @Override public void handleReceive(Object message) throws Exception { - if(ReadData.SERIALIZABLE_CLASS.equals(message.getClass())) { - readData(transaction, ReadData.fromSerializable(message)); - } else if(WriteData.SERIALIZABLE_CLASS.equals(message.getClass())) { - writeData(transaction, WriteData.fromSerializable(message, schemaContext)); - } else if(MergeData.SERIALIZABLE_CLASS.equals(message.getClass())) { - mergeData(transaction, MergeData.fromSerializable(message, schemaContext)); - } else if(DeleteData.SERIALIZABLE_CLASS.equals(message.getClass())) { - deleteData(transaction, DeleteData.fromSerializable(message)); - } else if(ReadyTransaction.SERIALIZABLE_CLASS.equals(message.getClass())) { - readyTransaction(transaction, new ReadyTransaction()); + if (message instanceof ReadData) { + readData(transaction, (ReadData) message, !SERIALIZED_REPLY); + + } else if (message instanceof DataExists) { + dataExists(transaction, (DataExists) message, !SERIALIZED_REPLY); + + } else if(ReadData.SERIALIZABLE_CLASS.equals(message.getClass())) { + readData(transaction, ReadData.fromSerializable(message), SERIALIZED_REPLY); + } else if(DataExists.SERIALIZABLE_CLASS.equals(message.getClass())) { - dataExists(transaction, DataExists.fromSerializable(message)); + dataExists(transaction, DataExists.fromSerializable(message), SERIALIZED_REPLY); + } else { super.handleReceive(message); } } - - @Override - protected DOMStoreTransaction getDOMStoreTransaction() { - return transaction; - } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardRecoveryCoordinator.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardRecoveryCoordinator.java new file mode 100644 index 0000000000..94fb584102 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardRecoveryCoordinator.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.cluster.datastore; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification; +import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec; +import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.Lists; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; + +/** + * Coordinates persistence recovery of journal log entries and snapshots for a shard. Each snapshot + * and journal log entry batch are de-serialized and applied to their own write transaction + * instance in parallel on a thread pool for faster recovery time. However the transactions are + * committed to the data store in the order the corresponding snapshot or log batch are received + * to preserve data store integrity. + * + * @author Thomas Panetelis + */ +class ShardRecoveryCoordinator { + + private static final int TIME_OUT = 10; + + private static final Logger LOG = LoggerFactory.getLogger(ShardRecoveryCoordinator.class); + + private final List resultingTxList = Lists.newArrayList(); + private final SchemaContext schemaContext; + private final String shardName; + private final ExecutorService executor; + + ShardRecoveryCoordinator(String shardName, SchemaContext schemaContext) { + this.schemaContext = schemaContext; + this.shardName = shardName; + + executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), + new ThreadFactoryBuilder().setDaemon(true) + .setNameFormat("ShardRecovery-" + shardName + "-%d").build()); + } + + /** + * Submits a batch of journal log entries. + * + * @param logEntries the serialized journal log entries + * @param resultingTx the write Tx to which to apply the entries + */ + void submit(List logEntries, DOMStoreWriteTransaction resultingTx) { + LogRecoveryTask task = new LogRecoveryTask(logEntries, resultingTx); + resultingTxList.add(resultingTx); + executor.execute(task); + } + + /** + * Submits a snapshot. + * + * @param snapshot the serialized snapshot + * @param resultingTx the write Tx to which to apply the entries + */ + void submit(ByteString snapshot, DOMStoreWriteTransaction resultingTx) { + SnapshotRecoveryTask task = new SnapshotRecoveryTask(snapshot, resultingTx); + resultingTxList.add(resultingTx); + executor.execute(task); + } + + Collection getTransactions() { + // Shutdown the executor and wait for task completion. + executor.shutdown(); + + try { + if(executor.awaitTermination(TIME_OUT, TimeUnit.MINUTES)) { + return resultingTxList; + } else { + LOG.error("Recovery for shard {} timed out after {} minutes", shardName, TIME_OUT); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + return Collections.emptyList(); + } + + private static abstract class ShardRecoveryTask implements Runnable { + + final DOMStoreWriteTransaction resultingTx; + + ShardRecoveryTask(DOMStoreWriteTransaction resultingTx) { + this.resultingTx = resultingTx; + } + } + + private class LogRecoveryTask extends ShardRecoveryTask { + + private final List logEntries; + + LogRecoveryTask(List logEntries, DOMStoreWriteTransaction resultingTx) { + super(resultingTx); + this.logEntries = logEntries; + } + + @Override + public void run() { + for(int i = 0; i < logEntries.size(); i++) { + MutableCompositeModification.fromSerializable( + logEntries.get(i), schemaContext).apply(resultingTx); + // Null out to GC quicker. + logEntries.set(i, null); + } + } + } + + private class SnapshotRecoveryTask extends ShardRecoveryTask { + + private final ByteString snapshot; + + SnapshotRecoveryTask(ByteString snapshot, DOMStoreWriteTransaction resultingTx) { + super(resultingTx); + this.snapshot = snapshot; + } + + @Override + public void run() { + try { + NormalizedNodeMessages.Node serializedNode = NormalizedNodeMessages.Node.parseFrom(snapshot); + NormalizedNode node = new NormalizedNodeToNodeCodec(schemaContext).decode( + serializedNode); + + // delete everything first + resultingTx.delete(YangInstanceIdentifier.builder().build()); + + // Add everything from the remote node back + resultingTx.write(YangInstanceIdentifier.builder().build(), node); + } catch (InvalidProtocolBufferException e) { + LOG.error("Error deserializing snapshot", e); + } + } + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransaction.java index b810ed9575..5289ad33bf 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransaction.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransaction.java @@ -13,38 +13,20 @@ import akka.actor.PoisonPill; import akka.actor.Props; import akka.actor.ReceiveTimeout; import akka.japi.Creator; - import com.google.common.base.Optional; import com.google.common.util.concurrent.CheckedFuture; import org.opendaylight.controller.cluster.common.actor.AbstractUntypedActor; - - import org.opendaylight.controller.cluster.datastore.exceptions.UnknownMessageException; import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats; import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction; import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionReply; import org.opendaylight.controller.cluster.datastore.messages.DataExists; import org.opendaylight.controller.cluster.datastore.messages.DataExistsReply; -import org.opendaylight.controller.cluster.datastore.messages.DeleteData; -import org.opendaylight.controller.cluster.datastore.messages.DeleteDataReply; -import org.opendaylight.controller.cluster.datastore.messages.MergeData; -import org.opendaylight.controller.cluster.datastore.messages.MergeDataReply; import org.opendaylight.controller.cluster.datastore.messages.ReadData; import org.opendaylight.controller.cluster.datastore.messages.ReadDataReply; -import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction; -import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply; -import org.opendaylight.controller.cluster.datastore.messages.WriteData; -import org.opendaylight.controller.cluster.datastore.messages.WriteDataReply; -import org.opendaylight.controller.cluster.datastore.modification.CompositeModification; -import org.opendaylight.controller.cluster.datastore.modification.DeleteModification; -import org.opendaylight.controller.cluster.datastore.modification.ImmutableCompositeModification; -import org.opendaylight.controller.cluster.datastore.modification.MergeModification; -import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification; -import org.opendaylight.controller.cluster.datastore.modification.WriteModification; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; -import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -76,36 +58,48 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; public abstract class ShardTransaction extends AbstractUntypedActor { private final ActorRef shardActor; - protected final SchemaContext schemaContext; + private final SchemaContext schemaContext; private final ShardStats shardStats; - - private final MutableCompositeModification modification = new MutableCompositeModification(); + private final String transactionID; + protected static final boolean SERIALIZED_REPLY = true; protected ShardTransaction(ActorRef shardActor, SchemaContext schemaContext, - ShardStats shardStats) { + ShardStats shardStats, String transactionID) { this.shardActor = shardActor; this.schemaContext = schemaContext; this.shardStats = shardStats; + this.transactionID = transactionID; } public static Props props(DOMStoreTransaction transaction, ActorRef shardActor, - SchemaContext schemaContext,DatastoreContext datastoreContext, ShardStats shardStats) { + SchemaContext schemaContext,DatastoreContext datastoreContext, ShardStats shardStats, + String transactionID) { return Props.create(new ShardTransactionCreator(transaction, shardActor, schemaContext, - datastoreContext, shardStats)); + datastoreContext, shardStats, transactionID)); } protected abstract DOMStoreTransaction getDOMStoreTransaction(); + protected ActorRef getShardActor() { + return shardActor; + } + + protected String getTransactionID() { + return transactionID; + } + + protected SchemaContext getSchemaContext() { + return schemaContext; + } + @Override public void handleReceive(Object message) throws Exception { if (message.getClass().equals(CloseTransaction.SERIALIZABLE_CLASS)) { closeTransaction(true); - } else if (message instanceof GetCompositedModification) { - // This is here for testing only - getSender().tell(new GetCompositeModificationReply( - new ImmutableCompositeModification(modification)), getSelf()); } else if (message instanceof ReceiveTimeout) { - LOG.debug("Got ReceiveTimeout for inactivity - closing Tx"); + if(LOG.isDebugEnabled()) { + LOG.debug("Got ReceiveTimeout for inactivity - closing Tx"); + } closeTransaction(false); } else { throw new UnknownMessageException(message); @@ -122,23 +116,24 @@ public abstract class ShardTransaction extends AbstractUntypedActor { getSelf().tell(PoisonPill.getInstance(), getSelf()); } - protected void readData(DOMStoreReadTransaction transaction,ReadData message) { + protected void readData(DOMStoreReadTransaction transaction, ReadData message, final boolean returnSerialized) { final ActorRef sender = getSender(); final ActorRef self = getSelf(); final YangInstanceIdentifier path = message.getPath(); final CheckedFuture>, ReadFailedException> future = transaction.read(path); + future.addListener(new Runnable() { @Override public void run() { try { Optional> optional = future.checkedGet(); - if (optional.isPresent()) { - sender.tell(new ReadDataReply(schemaContext,optional.get()).toSerializable(), self); - } else { - sender.tell(new ReadDataReply(schemaContext,null).toSerializable(), self); - } + ReadDataReply readDataReply = new ReadDataReply(schemaContext, optional.orNull()); + + sender.tell((returnSerialized ? readDataReply.toSerializable(): + readDataReply), self); + } catch (Exception e) { shardStats.incrementFailedReadTransactionsCount(); sender.tell(new akka.actor.Status.Failure(e), self); @@ -148,63 +143,21 @@ public abstract class ShardTransaction extends AbstractUntypedActor { }, getContext().dispatcher()); } - protected void dataExists(DOMStoreReadTransaction transaction, DataExists message) { + protected void dataExists(DOMStoreReadTransaction transaction, DataExists message, + final boolean returnSerialized) { final YangInstanceIdentifier path = message.getPath(); try { Boolean exists = transaction.exists(path).checkedGet(); - getSender().tell(new DataExistsReply(exists).toSerializable(), getSelf()); + DataExistsReply dataExistsReply = new DataExistsReply(exists); + getSender().tell(returnSerialized ? dataExistsReply.toSerializable() : + dataExistsReply, getSelf()); } catch (ReadFailedException e) { getSender().tell(new akka.actor.Status.Failure(e),getSelf()); } } - protected void writeData(DOMStoreWriteTransaction transaction, WriteData message) { - modification.addModification( - new WriteModification(message.getPath(), message.getData(),schemaContext)); - LOG.debug("writeData at path : " + message.getPath().toString()); - - try { - transaction.write(message.getPath(), message.getData()); - getSender().tell(new WriteDataReply().toSerializable(), getSelf()); - }catch(Exception e){ - getSender().tell(new akka.actor.Status.Failure(e), getSelf()); - } - } - - protected void mergeData(DOMStoreWriteTransaction transaction, MergeData message) { - modification.addModification( - new MergeModification(message.getPath(), message.getData(), schemaContext)); - LOG.debug("mergeData at path : " + message.getPath().toString()); - try { - transaction.merge(message.getPath(), message.getData()); - getSender().tell(new MergeDataReply().toSerializable(), getSelf()); - }catch(Exception e){ - getSender().tell(new akka.actor.Status.Failure(e), getSelf()); - } - } - - protected void deleteData(DOMStoreWriteTransaction transaction, DeleteData message) { - LOG.debug("deleteData at path : " + message.getPath().toString()); - modification.addModification(new DeleteModification(message.getPath())); - try { - transaction.delete(message.getPath()); - getSender().tell(new DeleteDataReply().toSerializable(), getSelf()); - }catch(Exception e){ - getSender().tell(new akka.actor.Status.Failure(e), getSelf()); - } - } - - protected void readyTransaction(DOMStoreWriteTransaction transaction, ReadyTransaction message) { - DOMStoreThreePhaseCommitCohort cohort = transaction.ready(); - ActorRef cohortActor = getContext().actorOf( - ThreePhaseCommitCohort.props(cohort, shardActor, modification, shardStats), "cohort"); - getSender() - .tell(new ReadyTransactionReply(cohortActor.path()).toSerializable(), getSelf()); - - } - private static class ShardTransactionCreator implements Creator { private static final long serialVersionUID = 1L; @@ -214,15 +167,17 @@ public abstract class ShardTransaction extends AbstractUntypedActor { final SchemaContext schemaContext; final DatastoreContext datastoreContext; final ShardStats shardStats; + final String transactionID; ShardTransactionCreator(DOMStoreTransaction transaction, ActorRef shardActor, SchemaContext schemaContext, DatastoreContext datastoreContext, - ShardStats shardStats) { + ShardStats shardStats, String transactionID) { this.transaction = transaction; this.shardActor = shardActor; this.shardStats = shardStats; this.schemaContext = schemaContext; this.datastoreContext = datastoreContext; + this.transactionID = transactionID; } @Override @@ -230,37 +185,17 @@ public abstract class ShardTransaction extends AbstractUntypedActor { ShardTransaction tx; if(transaction instanceof DOMStoreReadWriteTransaction) { tx = new ShardReadWriteTransaction((DOMStoreReadWriteTransaction)transaction, - shardActor, schemaContext, shardStats); + shardActor, schemaContext, shardStats, transactionID); } else if(transaction instanceof DOMStoreReadTransaction) { tx = new ShardReadTransaction((DOMStoreReadTransaction)transaction, shardActor, - schemaContext, shardStats); + schemaContext, shardStats, transactionID); } else { tx = new ShardWriteTransaction((DOMStoreWriteTransaction)transaction, - shardActor, schemaContext, shardStats); + shardActor, schemaContext, shardStats, transactionID); } tx.getContext().setReceiveTimeout(datastoreContext.getShardTransactionIdleTimeout()); return tx; } } - - // These classes are in here for test purposes only - - static class GetCompositedModification { - } - - - static class GetCompositeModificationReply { - private final CompositeModification modification; - - - GetCompositeModificationReply(CompositeModification modification) { - this.modification = modification; - } - - - public CompositeModification getModification() { - return modification; - } - } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransactionChain.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransactionChain.java index 8fe94cf468..943a82f6f9 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransactionChain.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransactionChain.java @@ -56,23 +56,26 @@ public class ShardTransactionChain extends AbstractUntypedActor { return getContext().parent(); } - private ActorRef createTypedTransactionActor(CreateTransaction createTransaction, - String transactionId) { + private ActorRef createTypedTransactionActor(CreateTransaction createTransaction) { + String transactionName = "shard-" + createTransaction.getTransactionId(); if(createTransaction.getTransactionType() == TransactionProxy.TransactionType.READ_ONLY.ordinal()) { return getContext().actorOf( ShardTransaction.props( chain.newReadOnlyTransaction(), getShardActor(), - schemaContext, datastoreContext, shardStats), transactionId); + schemaContext, datastoreContext, shardStats, + createTransaction.getTransactionId()), transactionName); } else if (createTransaction.getTransactionType() == TransactionProxy.TransactionType.READ_WRITE.ordinal()) { return getContext().actorOf( ShardTransaction.props( chain.newReadWriteTransaction(), getShardActor(), - schemaContext, datastoreContext, shardStats), transactionId); + schemaContext, datastoreContext, shardStats, + createTransaction.getTransactionId()), transactionName); } else if (createTransaction.getTransactionType() == TransactionProxy.TransactionType.WRITE_ONLY.ordinal()) { return getContext().actorOf( ShardTransaction.props( chain.newWriteOnlyTransaction(), getShardActor(), - schemaContext, datastoreContext, shardStats), transactionId); + schemaContext, datastoreContext, shardStats, + createTransaction.getTransactionId()), transactionName); } else { throw new IllegalArgumentException ( "CreateTransaction message has unidentified transaction type=" + @@ -82,10 +85,9 @@ public class ShardTransactionChain extends AbstractUntypedActor { private void createTransaction(CreateTransaction createTransaction) { - ActorRef transactionActor = createTypedTransactionActor(createTransaction, "shard-" + createTransaction.getTransactionId()); - getSender() - .tell(new CreateTransactionReply(transactionActor.path().toString(),createTransaction.getTransactionId()).toSerializable(), - getSelf()); + ActorRef transactionActor = createTypedTransactionActor(createTransaction); + getSender().tell(new CreateTransactionReply(transactionActor.path().toString(), + createTransaction.getTransactionId()).toSerializable(), getSelf()); } public static Props props(DOMStoreTransactionChain chain, SchemaContext schemaContext, diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardWriteTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardWriteTransaction.java index 396b27a042..21c210daf2 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardWriteTransaction.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardWriteTransaction.java @@ -11,12 +11,22 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; - import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats; import org.opendaylight.controller.cluster.datastore.messages.DeleteData; +import org.opendaylight.controller.cluster.datastore.messages.DeleteDataReply; +import org.opendaylight.controller.cluster.datastore.messages.ForwardedReadyTransaction; import org.opendaylight.controller.cluster.datastore.messages.MergeData; +import org.opendaylight.controller.cluster.datastore.messages.MergeDataReply; import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction; import org.opendaylight.controller.cluster.datastore.messages.WriteData; +import org.opendaylight.controller.cluster.datastore.messages.WriteDataReply; +import org.opendaylight.controller.cluster.datastore.modification.CompositeModification; +import org.opendaylight.controller.cluster.datastore.modification.DeleteModification; +import org.opendaylight.controller.cluster.datastore.modification.ImmutableCompositeModification; +import org.opendaylight.controller.cluster.datastore.modification.MergeModification; +import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification; +import org.opendaylight.controller.cluster.datastore.modification.WriteModification; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -26,31 +36,127 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; * Date: 8/6/14 */ public class ShardWriteTransaction extends ShardTransaction { + + private final MutableCompositeModification modification = new MutableCompositeModification(); private final DOMStoreWriteTransaction transaction; public ShardWriteTransaction(DOMStoreWriteTransaction transaction, ActorRef shardActor, - SchemaContext schemaContext, ShardStats shardStats) { - super(shardActor, schemaContext, shardStats); + SchemaContext schemaContext, ShardStats shardStats, String transactionID) { + super(shardActor, schemaContext, shardStats, transactionID); this.transaction = transaction; } + @Override + protected DOMStoreTransaction getDOMStoreTransaction() { + return transaction; + } + @Override public void handleReceive(Object message) throws Exception { - if(WriteData.SERIALIZABLE_CLASS.equals(message.getClass())) { - writeData(transaction, WriteData.fromSerializable(message, schemaContext)); + + if (message instanceof WriteData) { + writeData(transaction, (WriteData) message, !SERIALIZED_REPLY); + + } else if (message instanceof MergeData) { + mergeData(transaction, (MergeData) message, !SERIALIZED_REPLY); + + } else if (message instanceof DeleteData) { + deleteData(transaction, (DeleteData) message, !SERIALIZED_REPLY); + + } else if (message instanceof ReadyTransaction) { + readyTransaction(transaction, new ReadyTransaction(), !SERIALIZED_REPLY); + + } else if(WriteData.SERIALIZABLE_CLASS.equals(message.getClass())) { + writeData(transaction, WriteData.fromSerializable(message, getSchemaContext()), SERIALIZED_REPLY); + } else if(MergeData.SERIALIZABLE_CLASS.equals(message.getClass())) { - mergeData(transaction, MergeData.fromSerializable(message, schemaContext)); + mergeData(transaction, MergeData.fromSerializable(message, getSchemaContext()), SERIALIZED_REPLY); + } else if(DeleteData.SERIALIZABLE_CLASS.equals(message.getClass())) { - deleteData(transaction, DeleteData.fromSerializable(message)); + deleteData(transaction, DeleteData.fromSerializable(message), SERIALIZED_REPLY); + } else if(ReadyTransaction.SERIALIZABLE_CLASS.equals(message.getClass())) { - readyTransaction(transaction, new ReadyTransaction()); + readyTransaction(transaction, new ReadyTransaction(), SERIALIZED_REPLY); + + } else if (message instanceof GetCompositedModification) { + // This is here for testing only + getSender().tell(new GetCompositeModificationReply( + new ImmutableCompositeModification(modification)), getSelf()); } else { super.handleReceive(message); } } - @Override - protected DOMStoreTransaction getDOMStoreTransaction() { - return transaction; + private void writeData(DOMStoreWriteTransaction transaction, WriteData message, boolean returnSerialized) { + modification.addModification( + new WriteModification(message.getPath(), message.getData(), getSchemaContext())); + if(LOG.isDebugEnabled()) { + LOG.debug("writeData at path : " + message.getPath().toString()); + } + try { + transaction.write(message.getPath(), message.getData()); + WriteDataReply writeDataReply = new WriteDataReply(); + getSender().tell(returnSerialized ? writeDataReply.toSerializable() : writeDataReply, + getSelf()); + }catch(Exception e){ + getSender().tell(new akka.actor.Status.Failure(e), getSelf()); + } + } + + private void mergeData(DOMStoreWriteTransaction transaction, MergeData message, boolean returnSerialized) { + modification.addModification( + new MergeModification(message.getPath(), message.getData(), getSchemaContext())); + if(LOG.isDebugEnabled()) { + LOG.debug("mergeData at path : " + message.getPath().toString()); + } + try { + transaction.merge(message.getPath(), message.getData()); + MergeDataReply mergeDataReply = new MergeDataReply(); + getSender().tell(returnSerialized ? mergeDataReply.toSerializable() : mergeDataReply , + getSelf()); + }catch(Exception e){ + getSender().tell(new akka.actor.Status.Failure(e), getSelf()); + } + } + + private void deleteData(DOMStoreWriteTransaction transaction, DeleteData message, boolean returnSerialized) { + if(LOG.isDebugEnabled()) { + LOG.debug("deleteData at path : " + message.getPath().toString()); + } + modification.addModification(new DeleteModification(message.getPath())); + try { + transaction.delete(message.getPath()); + DeleteDataReply deleteDataReply = new DeleteDataReply(); + getSender().tell(returnSerialized ? deleteDataReply.toSerializable() : deleteDataReply, + getSelf()); + }catch(Exception e){ + getSender().tell(new akka.actor.Status.Failure(e), getSelf()); + } + } + + private void readyTransaction(DOMStoreWriteTransaction transaction, ReadyTransaction message, boolean returnSerialized) { + DOMStoreThreePhaseCommitCohort cohort = transaction.ready(); + + getShardActor().forward(new ForwardedReadyTransaction( + getTransactionID(), cohort, modification, returnSerialized), + getContext()); + } + + // These classes are in here for test purposes only + + static class GetCompositedModification { + } + + static class GetCompositeModificationReply { + private final CompositeModification modification; + + + GetCompositeModificationReply(CompositeModification modification) { + this.modification = modification; + } + + public CompositeModification getModification() { + return modification; + } } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TerminationMonitor.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TerminationMonitor.java index e6ac7f8dbc..0c3d33a78c 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TerminationMonitor.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TerminationMonitor.java @@ -25,7 +25,9 @@ public class TerminationMonitor extends UntypedActor{ @Override public void onReceive(Object message) throws Exception { if(message instanceof Terminated){ Terminated terminated = (Terminated) message; - LOG.debug("Actor terminated : {}", terminated.actor()); + if(LOG.isDebugEnabled()) { + LOG.debug("Actor terminated : {}", terminated.actor()); + } } else if(message instanceof Monitor){ Monitor monitor = (Monitor) message; getContext().watch(monitor.getActorRef()); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohort.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohort.java deleted file mode 100644 index e3ae5dac7b..0000000000 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohort.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.cluster.datastore; - -import akka.actor.ActorRef; -import akka.actor.PoisonPill; -import akka.actor.Props; -import akka.event.Logging; -import akka.event.LoggingAdapter; -import akka.japi.Creator; - -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import org.opendaylight.controller.cluster.common.actor.AbstractUntypedActor; - -import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats; -import org.opendaylight.controller.cluster.datastore.messages.AbortTransaction; -import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply; -import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction; -import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply; -import org.opendaylight.controller.cluster.datastore.messages.CommitTransaction; -import org.opendaylight.controller.cluster.datastore.messages.ForwardedCommitTransaction; -import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransaction; -import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransactionReply; -import org.opendaylight.controller.cluster.datastore.modification.CompositeModification; -import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; - -public class ThreePhaseCommitCohort extends AbstractUntypedActor { - private final DOMStoreThreePhaseCommitCohort cohort; - private final ActorRef shardActor; - private final CompositeModification modification; - private final ShardStats shardStats; - - public ThreePhaseCommitCohort(DOMStoreThreePhaseCommitCohort cohort, - ActorRef shardActor, CompositeModification modification, ShardStats shardStats) { - - this.cohort = cohort; - this.shardActor = shardActor; - this.modification = modification; - this.shardStats = shardStats; - } - - private final LoggingAdapter log = - Logging.getLogger(getContext().system(), this); - - public static Props props(final DOMStoreThreePhaseCommitCohort cohort, - final ActorRef shardActor, final CompositeModification modification, - ShardStats shardStats) { - return Props.create(new ThreePhaseCommitCohortCreator(cohort, shardActor, modification, - shardStats)); - } - - @Override - public void handleReceive(Object message) throws Exception { - if (message.getClass() - .equals(CanCommitTransaction.SERIALIZABLE_CLASS)) { - canCommit(new CanCommitTransaction()); - } else if (message.getClass() - .equals(PreCommitTransaction.SERIALIZABLE_CLASS)) { - preCommit(new PreCommitTransaction()); - } else if (message.getClass() - .equals(CommitTransaction.SERIALIZABLE_CLASS)) { - commit(new CommitTransaction()); - } else if (message.getClass() - .equals(AbortTransaction.SERIALIZABLE_CLASS)) { - abort(new AbortTransaction()); - } else { - unknownMessage(message); - } - } - - private void abort(AbortTransaction message) { - final ListenableFuture future = cohort.abort(); - final ActorRef sender = getSender(); - final ActorRef self = getSelf(); - - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(Void v) { - shardStats.incrementAbortTransactionsCount(); - sender - .tell(new AbortTransactionReply().toSerializable(), - self); - } - - @Override - public void onFailure(Throwable t) { - LOG.error(t, "An exception happened during abort"); - sender - .tell(new akka.actor.Status.Failure(t), self); - } - }); - } - - private void commit(CommitTransaction message) { - // Forward the commit to the shard - log.debug("Forward commit transaction to Shard {} ", shardActor); - shardActor.forward(new ForwardedCommitTransaction(cohort, modification), - getContext()); - - getContext().parent().tell(PoisonPill.getInstance(), getSelf()); - - } - - private void preCommit(PreCommitTransaction message) { - final ListenableFuture future = cohort.preCommit(); - final ActorRef sender = getSender(); - final ActorRef self = getSelf(); - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(Void v) { - sender - .tell(new PreCommitTransactionReply().toSerializable(), - self); - } - - @Override - public void onFailure(Throwable t) { - LOG.error(t, "An exception happened during pre-commit"); - sender - .tell(new akka.actor.Status.Failure(t), self); - } - }); - - } - - private void canCommit(CanCommitTransaction message) { - final ListenableFuture future = cohort.canCommit(); - final ActorRef sender = getSender(); - final ActorRef self = getSelf(); - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(Boolean canCommit) { - sender.tell(new CanCommitTransactionReply(canCommit) - .toSerializable(), self); - } - - @Override - public void onFailure(Throwable t) { - LOG.error(t, "An exception happened during canCommit"); - sender - .tell(new akka.actor.Status.Failure(t), self); - } - }); - } - - private static class ThreePhaseCommitCohortCreator implements Creator { - final DOMStoreThreePhaseCommitCohort cohort; - final ActorRef shardActor; - final CompositeModification modification; - final ShardStats shardStats; - - ThreePhaseCommitCohortCreator(DOMStoreThreePhaseCommitCohort cohort, - ActorRef shardActor, CompositeModification modification, ShardStats shardStats) { - this.cohort = cohort; - this.shardActor = shardActor; - this.modification = modification; - this.shardStats = shardStats; - } - - @Override - public ThreePhaseCommitCohort create() throws Exception { - return new ThreePhaseCommitCohort(cohort, shardActor, modification, shardStats); - } - } -} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java index a5be69531d..6e5ba1c90c 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java @@ -8,32 +8,25 @@ package org.opendaylight.controller.cluster.datastore; -import akka.actor.ActorPath; import akka.actor.ActorSelection; import akka.dispatch.Futures; import akka.dispatch.OnComplete; - import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; - import org.opendaylight.controller.cluster.datastore.messages.AbortTransaction; import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply; import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction; import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply; import org.opendaylight.controller.cluster.datastore.messages.CommitTransaction; import org.opendaylight.controller.cluster.datastore.messages.CommitTransactionReply; -import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransaction; -import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransactionReply; import org.opendaylight.controller.cluster.datastore.utils.ActorContext; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import scala.concurrent.Future; import scala.runtime.AbstractFunction1; - import java.util.Collections; import java.util.List; @@ -44,30 +37,34 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho private static final Logger LOG = LoggerFactory.getLogger(ThreePhaseCommitCohortProxy.class); + private static final ListenableFuture IMMEDIATE_SUCCESS = + com.google.common.util.concurrent.Futures.immediateFuture(null); + private final ActorContext actorContext; - private final List> cohortPathFutures; - private volatile List cohortPaths; + private final List> cohortFutures; + private volatile List cohorts; private final String transactionId; public ThreePhaseCommitCohortProxy(ActorContext actorContext, - List> cohortPathFutures, String transactionId) { + List> cohortFutures, String transactionId) { this.actorContext = actorContext; - this.cohortPathFutures = cohortPathFutures; + this.cohortFutures = cohortFutures; this.transactionId = transactionId; } - private Future buildCohortPathsList() { + private Future buildCohortList() { - Future> combinedFutures = Futures.sequence(cohortPathFutures, + Future> combinedFutures = Futures.sequence(cohortFutures, actorContext.getActorSystem().dispatcher()); - return combinedFutures.transform(new AbstractFunction1, Void>() { + return combinedFutures.transform(new AbstractFunction1, Void>() { @Override - public Void apply(Iterable paths) { - cohortPaths = Lists.newArrayList(paths); - - LOG.debug("Tx {} successfully built cohort path list: {}", - transactionId, cohortPaths); + public Void apply(Iterable actorSelections) { + cohorts = Lists.newArrayList(actorSelections); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} successfully built cohort path list: {}", + transactionId, cohorts); + } return null; } }, TransactionProxy.SAME_FAILURE_TRANSFORMER, actorContext.getActorSystem().dispatcher()); @@ -75,8 +72,9 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho @Override public ListenableFuture canCommit() { - LOG.debug("Tx {} canCommit", transactionId); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} canCommit", transactionId); + } final SettableFuture returnFuture = SettableFuture.create(); // The first phase of canCommit is to gather the list of cohort actor paths that will @@ -85,11 +83,13 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho // extracted from ReadyTransactionReply messages by the Futures that were obtained earlier // and passed to us from upstream processing. If any one fails then we'll fail canCommit. - buildCohortPathsList().onComplete(new OnComplete() { + buildCohortList().onComplete(new OnComplete() { @Override public void onComplete(Throwable failure, Void notUsed) throws Throwable { if(failure != null) { - LOG.debug("Tx {}: a cohort path Future failed: {}", transactionId, failure); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {}: a cohort Future failed: {}", transactionId, failure); + } returnFuture.setException(failure); } else { finishCanCommit(returnFuture); @@ -101,20 +101,22 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho } private void finishCanCommit(final SettableFuture returnFuture) { - - LOG.debug("Tx {} finishCanCommit", transactionId); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} finishCanCommit", transactionId); + } // The last phase of canCommit is to invoke all the cohort actors asynchronously to perform // their canCommit processing. If any one fails then we'll fail canCommit. Future> combinedFuture = - invokeCohorts(new CanCommitTransaction().toSerializable()); + invokeCohorts(new CanCommitTransaction(transactionId).toSerializable()); combinedFuture.onComplete(new OnComplete>() { @Override public void onComplete(Throwable failure, Iterable responses) throws Throwable { if(failure != null) { - LOG.debug("Tx {}: a canCommit cohort Future failed: {}", transactionId, failure); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {}: a canCommit cohort Future failed: {}", transactionId, failure); + } returnFuture.setException(failure); return; } @@ -135,23 +137,22 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho return; } } - - LOG.debug("Tx {}: canCommit returning result: {}", transactionId, result); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {}: canCommit returning result: {}", transactionId, result); + } returnFuture.set(Boolean.valueOf(result)); } }, actorContext.getActorSystem().dispatcher()); } private Future> invokeCohorts(Object message) { - List> futureList = Lists.newArrayListWithCapacity(cohortPaths.size()); - for(ActorPath actorPath : cohortPaths) { - - LOG.debug("Tx {}: Sending {} to cohort {}", transactionId, message, actorPath); - - ActorSelection cohort = actorContext.actorSelection(actorPath); + List> futureList = Lists.newArrayListWithCapacity(cohorts.size()); + for(ActorSelection cohort : cohorts) { + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {}: Sending {} to cohort {}", transactionId, message, cohort); + } - futureList.add(actorContext.executeRemoteOperationAsync(cohort, message)); + futureList.add(actorContext.executeOperationAsync(cohort, message)); } return Futures.sequence(futureList, actorContext.getActorSystem().dispatcher()); @@ -159,8 +160,9 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho @Override public ListenableFuture preCommit() { - return voidOperation("preCommit", new PreCommitTransaction().toSerializable(), - PreCommitTransactionReply.SERIALIZABLE_CLASS, true); + // We don't need to do anything here - preCommit is done atomically with the commit phase + // by the shard. + return IMMEDIATE_SUCCESS; } @Override @@ -171,37 +173,39 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho // exception then that exception will supersede and suppress the original exception. But // it's the original exception that is the root cause and of more interest to the client. - return voidOperation("abort", new AbortTransaction().toSerializable(), + return voidOperation("abort", new AbortTransaction(transactionId).toSerializable(), AbortTransactionReply.SERIALIZABLE_CLASS, false); } @Override public ListenableFuture commit() { - return voidOperation("commit", new CommitTransaction().toSerializable(), + return voidOperation("commit", new CommitTransaction(transactionId).toSerializable(), CommitTransactionReply.SERIALIZABLE_CLASS, true); } private ListenableFuture voidOperation(final String operationName, final Object message, final Class expectedResponseClass, final boolean propagateException) { - LOG.debug("Tx {} {}", transactionId, operationName); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} {}", transactionId, operationName); + } final SettableFuture returnFuture = SettableFuture.create(); // The cohort actor list should already be built at this point by the canCommit phase but, // if not for some reason, we'll try to build it here. - if(cohortPaths != null) { + if(cohorts != null) { finishVoidOperation(operationName, message, expectedResponseClass, propagateException, returnFuture); } else { - buildCohortPathsList().onComplete(new OnComplete() { + buildCohortList().onComplete(new OnComplete() { @Override public void onComplete(Throwable failure, Void notUsed) throws Throwable { if(failure != null) { - LOG.debug("Tx {}: a {} cohort path Future failed: {}", transactionId, + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {}: a {} cohort path Future failed: {}", transactionId, operationName, failure); - + } if(propagateException) { returnFuture.setException(failure); } else { @@ -221,9 +225,9 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho private void finishVoidOperation(final String operationName, final Object message, final Class expectedResponseClass, final boolean propagateException, final SettableFuture returnFuture) { - - LOG.debug("Tx {} finish {}", transactionId, operationName); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} finish {}", transactionId, operationName); + } Future> combinedFuture = invokeCohorts(message); combinedFuture.onComplete(new OnComplete>() { @@ -243,9 +247,10 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho } if(exceptionToPropagate != null) { - LOG.debug("Tx {}: a {} cohort Future failed: {}", transactionId, + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {}: a {} cohort Future failed: {}", transactionId, operationName, exceptionToPropagate); - + } if(propagateException) { // We don't log the exception here to avoid redundant logging since we're // propagating to the caller in MD-SAL core who will log it. @@ -254,12 +259,16 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho // Since the caller doesn't want us to propagate the exception we'll also // not log it normally. But it's usually not good to totally silence // exceptions so we'll log it to debug level. - LOG.debug(String.format("%s failed", message.getClass().getSimpleName()), + if(LOG.isDebugEnabled()) { + LOG.debug(String.format("%s failed", message.getClass().getSimpleName()), exceptionToPropagate); + } returnFuture.set(null); } } else { - LOG.debug("Tx {}: {} succeeded", transactionId, operationName); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {}: {} succeeded", transactionId, operationName); + } returnFuture.set(null); } } @@ -267,7 +276,7 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho } @VisibleForTesting - List> getCohortPathFutures() { - return Collections.unmodifiableList(cohortPathFutures); + List> getCohortFutures() { + return Collections.unmodifiableList(cohortFutures); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java index b74c89d727..b467ee4ddb 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java @@ -8,7 +8,7 @@ package org.opendaylight.controller.cluster.datastore; -import akka.actor.ActorPath; +import akka.actor.ActorSelection; import akka.dispatch.Futures; import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionChain; import org.opendaylight.controller.cluster.datastore.utils.ActorContext; @@ -28,7 +28,7 @@ import java.util.List; public class TransactionChainProxy implements DOMStoreTransactionChain{ private final ActorContext actorContext; private final String transactionChainId; - private volatile List> cohortPathFutures = Collections.emptyList(); + private volatile List> cohortFutures = Collections.emptyList(); public TransactionChainProxy(ActorContext actorContext) { this.actorContext = actorContext; @@ -63,14 +63,14 @@ public class TransactionChainProxy implements DOMStoreTransactionChain{ return transactionChainId; } - public void onTransactionReady(List> cohortPathFutures){ - this.cohortPathFutures = cohortPathFutures; + public void onTransactionReady(List> cohortFutures){ + this.cohortFutures = cohortFutures; } public void waitTillCurrentTransactionReady(){ try { Await.result(Futures - .sequence(this.cohortPathFutures, actorContext.getActorSystem().dispatcher()), + .sequence(this.cohortFutures, actorContext.getActorSystem().dispatcher()), actorContext.getOperationDuration()); } catch (Exception e) { throw new IllegalStateException("Failed when waiting for transaction on a chain to become ready", e); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java index 97a9ff0bf3..715f48c349 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java @@ -8,7 +8,6 @@ package org.opendaylight.controller.cluster.datastore; -import akka.actor.ActorPath; import akka.actor.ActorSelection; import akka.dispatch.OnComplete; @@ -22,6 +21,7 @@ import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.SettableFuture; +import org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException; import org.opendaylight.controller.cluster.datastore.identifiers.TransactionIdentifier; import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction; import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction; @@ -156,8 +156,8 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { if(remoteTransactionActorsMB.get()) { for(ActorSelection actor : remoteTransactionActors) { LOG.trace("Sending CloseTransaction to {}", actor); - actorContext.sendRemoteOperationAsync(actor, - new CloseTransaction().toSerializable()); + actorContext.sendOperationAsync(actor, + new CloseTransaction().toSerializable()); } } } @@ -224,8 +224,9 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { new TransactionProxyCleanupPhantomReference(this); phantomReferenceCache.put(cleanup, cleanup); } - - LOG.debug("Created txn {} of type {}", identifier, transactionType); + if(LOG.isDebugEnabled()) { + LOG.debug("Created txn {} of type {}", identifier, transactionType); + } } @Override @@ -235,8 +236,9 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { Preconditions.checkState(transactionType != TransactionType.WRITE_ONLY, "Read operation on write-only transaction is not allowed"); - LOG.debug("Tx {} read {}", identifier, path); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} read {}", identifier, path); + } createTransactionIfMissing(actorContext, path); return transactionContext(path).readData(path); @@ -248,8 +250,9 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { Preconditions.checkState(transactionType != TransactionType.WRITE_ONLY, "Exists operation on write-only transaction is not allowed"); - LOG.debug("Tx {} exists {}", identifier, path); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} exists {}", identifier, path); + } createTransactionIfMissing(actorContext, path); return transactionContext(path).dataExists(path); @@ -267,8 +270,9 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { checkModificationState(); - LOG.debug("Tx {} write {}", identifier, path); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} write {}", identifier, path); + } createTransactionIfMissing(actorContext, path); transactionContext(path).writeData(path, data); @@ -279,8 +283,9 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { checkModificationState(); - LOG.debug("Tx {} merge {}", identifier, path); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} merge {}", identifier, path); + } createTransactionIfMissing(actorContext, path); transactionContext(path).mergeData(path, data); @@ -290,9 +295,9 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { public void delete(YangInstanceIdentifier path) { checkModificationState(); - - LOG.debug("Tx {} delete {}", identifier, path); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} delete {}", identifier, path); + } createTransactionIfMissing(actorContext, path); transactionContext(path).deleteData(path); @@ -305,24 +310,26 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { inReadyState = true; - LOG.debug("Tx {} Trying to get {} transactions ready for commit", identifier, + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} Trying to get {} transactions ready for commit", identifier, remoteTransactionPaths.size()); - - List> cohortPathFutures = Lists.newArrayList(); + } + List> cohortFutures = Lists.newArrayList(); for(TransactionContext transactionContext : remoteTransactionPaths.values()) { - LOG.debug("Tx {} Readying transaction for shard {}", identifier, + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} Readying transaction for shard {}", identifier, transactionContext.getShardName()); - - cohortPathFutures.add(transactionContext.readyTransaction()); + } + cohortFutures.add(transactionContext.readyTransaction()); } if(transactionChainProxy != null){ - transactionChainProxy.onTransactionReady(cohortPathFutures); + transactionChainProxy.onTransactionReady(cohortFutures); } - return new ThreePhaseCommitCohortProxy(actorContext, cohortPathFutures, + return new ThreePhaseCommitCohortProxy(actorContext, cohortFutures, identifier.toString()); } @@ -372,7 +379,12 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { } try { - Object response = actorContext.executeShardOperation(shardName, + Optional primaryShard = actorContext.findPrimaryShard(shardName); + if (!primaryShard.isPresent()) { + throw new PrimaryNotFoundException("Primary could not be found for shard " + shardName); + } + + Object response = actorContext.executeOperation(primaryShard.get(), new CreateTransaction(identifier.toString(), this.transactionType.ordinal(), getTransactionChainId()).toSerializable()); if (response.getClass().equals(CreateTransactionReply.SERIALIZABLE_CLASS)) { @@ -381,8 +393,9 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { String transactionPath = reply.getTransactionPath(); - LOG.debug("Tx {} Received transaction path = {}", identifier, transactionPath); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} Received transaction path = {}", identifier, transactionPath); + } ActorSelection transactionActor = actorContext.actorSelection(transactionPath); if (transactionType == TransactionType.READ_ONLY) { @@ -395,8 +408,12 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { remoteTransactionActorsMB.set(true); } + // TxActor is always created where the leader of the shard is. + // Check if TxActor is created in the same node + boolean isTxActorLocal = actorContext.isLocalPath(transactionPath); + transactionContext = new TransactionContextImpl(shardName, transactionPath, - transactionActor, identifier, actorContext, schemaContext); + transactionActor, identifier, actorContext, schemaContext, isTxActorLocal); remoteTransactionPaths.put(shardName, transactionContext); } else { @@ -404,7 +421,9 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { "Invalid reply type {} for CreateTransaction", response.getClass())); } } catch (Exception e) { - LOG.debug("Tx {} Creating NoOpTransaction because of : {}", identifier, e.getMessage()); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} Creating NoOpTransaction because of : {}", identifier, e.getMessage()); + } remoteTransactionPaths .put(shardName, new NoOpTransactionContext(shardName, e, identifier)); } @@ -423,7 +442,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { void closeTransaction(); - Future readyTransaction(); + Future readyTransaction(); void writeData(YangInstanceIdentifier path, NormalizedNode data); @@ -468,40 +487,42 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { private final SchemaContext schemaContext; private final String actorPath; private final ActorSelection actor; + private final boolean isTxActorLocal; private TransactionContextImpl(String shardName, String actorPath, ActorSelection actor, TransactionIdentifier identifier, ActorContext actorContext, - SchemaContext schemaContext) { + SchemaContext schemaContext, boolean isTxActorLocal) { super(shardName, identifier); this.actorPath = actorPath; this.actor = actor; this.actorContext = actorContext; this.schemaContext = schemaContext; + this.isTxActorLocal = isTxActorLocal; } private ActorSelection getActor() { return actor; } - private String getResolvedCohortPath(String cohortPath) { - return actorContext.resolvePath(actorPath, cohortPath); - } - @Override public void closeTransaction() { - LOG.debug("Tx {} closeTransaction called", identifier); - actorContext.sendRemoteOperationAsync(getActor(), new CloseTransaction().toSerializable()); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} closeTransaction called", identifier); + } + actorContext.sendOperationAsync(getActor(), new CloseTransaction().toSerializable()); } @Override - public Future readyTransaction() { - LOG.debug("Tx {} readyTransaction called with {} previous recorded operations pending", + public Future readyTransaction() { + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} readyTransaction called with {} previous recorded operations pending", identifier, recordedOperationFutures.size()); - + } // Send the ReadyTransaction message to the Tx actor. - final Future replyFuture = actorContext.executeRemoteOperationAsync(getActor(), - new ReadyTransaction().toSerializable()); + ReadyTransaction readyTransaction = new ReadyTransaction(); + final Future replyFuture = actorContext.executeOperationAsync(getActor(), + isTxActorLocal ? readyTransaction : readyTransaction.toSerializable()); // Combine all the previously recorded put/merge/delete operation reply Futures and the // ReadyTransactionReply Future into one Future. If any one fails then the combined @@ -519,13 +540,13 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { // Transform the combined Future into a Future that returns the cohort actor path from // the ReadyTransactionReply. That's the end result of the ready operation. - return combinedFutures.transform(new AbstractFunction1, ActorPath>() { + return combinedFutures.transform(new AbstractFunction1, ActorSelection>() { @Override - public ActorPath apply(Iterable notUsed) { - - LOG.debug("Tx {} readyTransaction: pending recorded operations succeeded", + public ActorSelection apply(Iterable notUsed) { + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} readyTransaction: pending recorded operations succeeded", identifier); - + } // At this point all the Futures succeeded and we need to extract the cohort // actor path from the ReadyTransactionReply. For the recorded operations, they // don't return any data so we're only interested that they completed @@ -535,21 +556,15 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { // Note the Future get call here won't block as it's complete. Object serializedReadyReply = replyFuture.value().get().get(); - if(serializedReadyReply.getClass().equals( - ReadyTransactionReply.SERIALIZABLE_CLASS)) { - ReadyTransactionReply reply = ReadyTransactionReply.fromSerializable( - actorContext.getActorSystem(), serializedReadyReply); - - String resolvedCohortPath = getResolvedCohortPath( - reply.getCohortPath().toString()); + if (serializedReadyReply instanceof ReadyTransactionReply) { + return actorContext.actorSelection(((ReadyTransactionReply)serializedReadyReply).getCohortPath()); - LOG.debug("Tx {} readyTransaction: resolved cohort path {}", - identifier, resolvedCohortPath); + } else if(serializedReadyReply.getClass().equals(ReadyTransactionReply.SERIALIZABLE_CLASS)) { + ReadyTransactionReply reply = ReadyTransactionReply.fromSerializable(serializedReadyReply); + return actorContext.actorSelection(reply.getCohortPath()); - return actorContext.actorFor(resolvedCohortPath); } else { // Throwing an exception here will fail the Future. - throw new IllegalArgumentException(String.format("Invalid reply type {}", serializedReadyReply.getClass())); } @@ -559,31 +574,44 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { @Override public void deleteData(YangInstanceIdentifier path) { - LOG.debug("Tx {} deleteData called path = {}", identifier, path); - recordedOperationFutures.add(actorContext.executeRemoteOperationAsync(getActor(), - new DeleteData(path).toSerializable() )); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} deleteData called path = {}", identifier, path); + } + + DeleteData deleteData = new DeleteData(path); + recordedOperationFutures.add(actorContext.executeOperationAsync(getActor(), + isTxActorLocal ? deleteData : deleteData.toSerializable())); } @Override public void mergeData(YangInstanceIdentifier path, NormalizedNode data) { - LOG.debug("Tx {} mergeData called path = {}", identifier, path); - recordedOperationFutures.add(actorContext.executeRemoteOperationAsync(getActor(), - new MergeData(path, data, schemaContext).toSerializable())); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} mergeData called path = {}", identifier, path); + } + + MergeData mergeData = new MergeData(path, data, schemaContext); + recordedOperationFutures.add(actorContext.executeOperationAsync(getActor(), + isTxActorLocal ? mergeData : mergeData.toSerializable())); } @Override public void writeData(YangInstanceIdentifier path, NormalizedNode data) { - LOG.debug("Tx {} writeData called path = {}", identifier, path); - recordedOperationFutures.add(actorContext.executeRemoteOperationAsync(getActor(), - new WriteData(path, data, schemaContext).toSerializable())); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} writeData called path = {}", identifier, path); + } + + WriteData writeData = new WriteData(path, data, schemaContext); + recordedOperationFutures.add(actorContext.executeOperationAsync(getActor(), + isTxActorLocal ? writeData : writeData.toSerializable())); } @Override public CheckedFuture>, ReadFailedException> readData( final YangInstanceIdentifier path) { - LOG.debug("Tx {} readData called path = {}", identifier, path); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} readData called path = {}", identifier, path); + } final SettableFuture>> returnFuture = SettableFuture.create(); // If there were any previous recorded put/merge/delete operation reply Futures then we @@ -593,9 +621,10 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { if(recordedOperationFutures.isEmpty()) { finishReadData(path, returnFuture); } else { - LOG.debug("Tx {} readData: verifying {} previous recorded operations", + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} readData: verifying {} previous recorded operations", identifier, recordedOperationFutures.size()); - + } // Note: we make a copy of recordedOperationFutures to be on the safe side in case // Futures#sequence accesses the passed List on a different thread, as // recordedOperationFutures is not synchronized. @@ -603,14 +632,16 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { Future> combinedFutures = akka.dispatch.Futures.sequence( Lists.newArrayList(recordedOperationFutures), actorContext.getActorSystem().dispatcher()); + OnComplete> onComplete = new OnComplete>() { @Override public void onComplete(Throwable failure, Iterable notUsed) throws Throwable { if(failure != null) { - LOG.debug("Tx {} readData: a recorded operation failed: {}", + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} readData: a recorded operation failed: {}", identifier, failure); - + } returnFuture.setException(new ReadFailedException( "The read could not be performed because a previous put, merge," + "or delete operation failed", failure)); @@ -629,39 +660,44 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { private void finishReadData(final YangInstanceIdentifier path, final SettableFuture>> returnFuture) { - LOG.debug("Tx {} finishReadData called path = {}", identifier, path); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} finishReadData called path = {}", identifier, path); + } OnComplete onComplete = new OnComplete() { @Override public void onComplete(Throwable failure, Object readResponse) throws Throwable { if(failure != null) { - LOG.debug("Tx {} read operation failed: {}", identifier, failure); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} read operation failed: {}", identifier, failure); + } returnFuture.setException(new ReadFailedException( "Error reading data for path " + path, failure)); } else { - LOG.debug("Tx {} read operation succeeded", identifier, failure); - - if (readResponse.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) { - ReadDataReply reply = ReadDataReply.fromSerializable(schemaContext, - path, readResponse); - if (reply.getNormalizedNode() == null) { - returnFuture.set(Optional.>absent()); - } else { - returnFuture.set(Optional.>of( - reply.getNormalizedNode())); - } + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} read operation succeeded", identifier, failure); + } + + if (readResponse instanceof ReadDataReply) { + ReadDataReply reply = (ReadDataReply) readResponse; + returnFuture.set(Optional.>fromNullable(reply.getNormalizedNode())); + + } else if (readResponse.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) { + ReadDataReply reply = ReadDataReply.fromSerializable(schemaContext, path, readResponse); + returnFuture.set(Optional.>fromNullable(reply.getNormalizedNode())); + } else { returnFuture.setException(new ReadFailedException( - "Invalid response reading data for path " + path)); + "Invalid response reading data for path " + path)); } } } }; - Future readFuture = actorContext.executeRemoteOperationAsync(getActor(), - new ReadData(path).toSerializable()); + ReadData readData = new ReadData(path); + Future readFuture = actorContext.executeOperationAsync(getActor(), + isTxActorLocal ? readData : readData.toSerializable()); + readFuture.onComplete(onComplete, actorContext.getActorSystem().dispatcher()); } @@ -669,8 +705,9 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { public CheckedFuture dataExists( final YangInstanceIdentifier path) { - LOG.debug("Tx {} dataExists called path = {}", identifier, path); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} dataExists called path = {}", identifier, path); + } final SettableFuture returnFuture = SettableFuture.create(); // If there were any previous recorded put/merge/delete operation reply Futures then we @@ -681,9 +718,10 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { if(recordedOperationFutures.isEmpty()) { finishDataExists(path, returnFuture); } else { - LOG.debug("Tx {} dataExists: verifying {} previous recorded operations", + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} dataExists: verifying {} previous recorded operations", identifier, recordedOperationFutures.size()); - + } // Note: we make a copy of recordedOperationFutures to be on the safe side in case // Futures#sequence accesses the passed List on a different thread, as // recordedOperationFutures is not synchronized. @@ -696,9 +734,10 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { public void onComplete(Throwable failure, Iterable notUsed) throws Throwable { if(failure != null) { - LOG.debug("Tx {} dataExists: a recorded operation failed: {}", + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} dataExists: a recorded operation failed: {}", identifier, failure); - + } returnFuture.setException(new ReadFailedException( "The data exists could not be performed because a previous " + "put, merge, or delete operation failed", failure)); @@ -717,22 +756,29 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { private void finishDataExists(final YangInstanceIdentifier path, final SettableFuture returnFuture) { - LOG.debug("Tx {} finishDataExists called path = {}", identifier, path); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} finishDataExists called path = {}", identifier, path); + } OnComplete onComplete = new OnComplete() { @Override public void onComplete(Throwable failure, Object response) throws Throwable { if(failure != null) { - LOG.debug("Tx {} dataExists operation failed: {}", identifier, failure); - + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} dataExists operation failed: {}", identifier, failure); + } returnFuture.setException(new ReadFailedException( "Error checking data exists for path " + path, failure)); } else { - LOG.debug("Tx {} dataExists operation succeeded", identifier, failure); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} dataExists operation succeeded", identifier, failure); + } + + if (response instanceof DataExistsReply) { + returnFuture.set(Boolean.valueOf(((DataExistsReply) response).exists())); + + } else if (response.getClass().equals(DataExistsReply.SERIALIZABLE_CLASS)) { + returnFuture.set(Boolean.valueOf(DataExistsReply.fromSerializable(response).exists())); - if (response.getClass().equals(DataExistsReply.SERIALIZABLE_CLASS)) { - returnFuture.set(Boolean.valueOf(DataExistsReply. - fromSerializable(response).exists())); } else { returnFuture.setException(new ReadFailedException( "Invalid response checking exists for path " + path)); @@ -741,8 +787,10 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { } }; - Future future = actorContext.executeRemoteOperationAsync(getActor(), - new DataExists(path).toSerializable()); + DataExists dataExists = new DataExists(path); + Future future = actorContext.executeOperationAsync(getActor(), + isTxActorLocal ? dataExists : dataExists.toSerializable()); + future.onComplete(onComplete, actorContext.getActorSystem().dispatcher()); } } @@ -761,34 +809,46 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { @Override public void closeTransaction() { - LOG.debug("NoOpTransactionContext {} closeTransaction called", identifier); + if(LOG.isDebugEnabled()) { + LOG.debug("NoOpTransactionContext {} closeTransaction called", identifier); + } } @Override - public Future readyTransaction() { - LOG.debug("Tx {} readyTransaction called", identifier); + public Future readyTransaction() { + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} readyTransaction called", identifier); + } return akka.dispatch.Futures.failed(failure); } @Override public void deleteData(YangInstanceIdentifier path) { - LOG.debug("Tx {} deleteData called path = {}", identifier, path); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} deleteData called path = {}", identifier, path); + } } @Override public void mergeData(YangInstanceIdentifier path, NormalizedNode data) { - LOG.debug("Tx {} mergeData called path = {}", identifier, path); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} mergeData called path = {}", identifier, path); + } } @Override public void writeData(YangInstanceIdentifier path, NormalizedNode data) { - LOG.debug("Tx {} writeData called path = {}", identifier, path); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} writeData called path = {}", identifier, path); + } } @Override public CheckedFuture>, ReadFailedException> readData( YangInstanceIdentifier path) { - LOG.debug("Tx {} readData called path = {}", identifier, path); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} readData called path = {}", identifier, path); + } return Futures.immediateFailedCheckedFuture(new ReadFailedException( "Error reading data for path " + path, failure)); } @@ -796,7 +856,9 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { @Override public CheckedFuture dataExists( YangInstanceIdentifier path) { - LOG.debug("Tx {} dataExists called path = {}", identifier, path); + if(LOG.isDebugEnabled()) { + LOG.debug("Tx {} dataExists called path = {}", identifier, path); + } return Futures.immediateFailedCheckedFuture(new ReadFailedException( "Error checking exists for path " + path, failure)); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/exceptions/NotInitializedException.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/exceptions/NotInitializedException.java new file mode 100644 index 0000000000..302d684322 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/exceptions/NotInitializedException.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.datastore.exceptions; + +public class NotInitializedException extends RuntimeException { + public NotInitializedException(String message) { + super(message); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardIdentifier.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardIdentifier.java index c692881593..d65af61ba3 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardIdentifier.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardIdentifier.java @@ -10,11 +10,17 @@ package org.opendaylight.controller.cluster.datastore.identifiers; import com.google.common.base.Preconditions; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public class ShardIdentifier { private final String shardName; private final String memberName; private final String type; + //format and pattern should be in sync + private final String format = "%s-shard-%s-%s"; + private static final Pattern pattern = Pattern.compile("(\\S+)-shard-(\\S+)-(\\S+)"); public ShardIdentifier(String shardName, String memberName, String type) { @@ -60,15 +66,31 @@ public class ShardIdentifier { } @Override public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(memberName).append("-shard-").append(shardName).append("-").append(type); - return builder.toString(); + //ensure the output of toString matches the pattern above + return new StringBuilder(memberName) + .append("-shard-") + .append(shardName) + .append("-") + .append(type) + .toString(); } public static Builder builder(){ return new Builder(); } + public String getShardName() { + return shardName; + } + + public String getMemberName() { + return memberName; + } + + public String getType() { + return type; + } + public static class Builder { private String shardName; private String memberName; @@ -93,5 +115,15 @@ public class ShardIdentifier { return this; } + public Builder fromShardIdString(String shardId){ + Matcher matcher = pattern.matcher(shardId); + + if (matcher.matches()) { + memberName = matcher.group(1); + shardName = matcher.group(2); + type = matcher.group(3); + } + return this; + } } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardTransactionIdentifier.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardTransactionIdentifier.java index 77e81422e6..dd04afcb0b 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardTransactionIdentifier.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardTransactionIdentifier.java @@ -13,14 +13,19 @@ import com.google.common.base.Preconditions; public class ShardTransactionIdentifier { private final String remoteTransactionId; - public ShardTransactionIdentifier(String remoteTransactionId) { - this.remoteTransactionId = Preconditions.checkNotNull(remoteTransactionId, "remoteTransactionId should not be null"); + private ShardTransactionIdentifier(String remoteTransactionId) { + this.remoteTransactionId = Preconditions.checkNotNull(remoteTransactionId, + "remoteTransactionId should not be null"); } public static Builder builder(){ return new Builder(); } + public String getRemoteTransactionId() { + return remoteTransactionId; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -45,8 +50,7 @@ public class ShardTransactionIdentifier { } @Override public String toString() { - final StringBuilder sb = - new StringBuilder(); + final StringBuilder sb = new StringBuilder(); sb.append("shard-").append(remoteTransactionId); return sb.toString(); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStats.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStats.java index 74a91d08cf..0959c2a959 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStats.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStats.java @@ -74,16 +74,14 @@ public class ShardStats extends AbstractMXBean implements ShardStatsMXBean { } public void setDataStoreExecutor(ExecutorService dsExecutor) { - this.dataStoreExecutorStatsBean = ThreadExecutorStatsMXBeanImpl.create(dsExecutor, - "notification-executor", getMBeanType(), getMBeanCategory()); + this.dataStoreExecutorStatsBean = ThreadExecutorStatsMXBeanImpl.create(dsExecutor); } public void setNotificationManager(QueuedNotificationManager manager) { this.notificationManagerStatsBean = new QueuedNotificationManagerMXBeanImpl(manager, "notification-manager", getMBeanType(), getMBeanCategory()); - this.notificationExecutorStatsBean = ThreadExecutorStatsMXBeanImpl.create(manager.getExecutor(), - "data-store-executor", getMBeanType(), getMBeanCategory()); + this.notificationExecutorStatsBean = ThreadExecutorStatsMXBeanImpl.create(manager.getExecutor()); } @Override @@ -230,7 +228,8 @@ public class ShardStats extends AbstractMXBean implements ShardStatsMXBean { @Override public ThreadExecutorStats getDataStoreExecutorStats() { - return dataStoreExecutorStatsBean.toThreadExecutorStats(); + return dataStoreExecutorStatsBean == null ? null : + dataStoreExecutorStatsBean.toThreadExecutorStats(); } @Override diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/AbortTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/AbortTransaction.java index c639064036..d24e29c9b0 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/AbortTransaction.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/AbortTransaction.java @@ -11,10 +11,27 @@ package org.opendaylight.controller.cluster.datastore.messages; import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages; public class AbortTransaction implements SerializableMessage { - public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.AbortTransaction.class; + public static final Class SERIALIZABLE_CLASS = + ThreePhaseCommitCohortMessages.AbortTransaction.class; - @Override - public Object toSerializable() { - return ThreePhaseCommitCohortMessages.AbortTransaction.newBuilder().build(); - } + private final String transactionID; + + public AbortTransaction(String transactionID) { + this.transactionID = transactionID; + } + + public String getTransactionID() { + return transactionID; + } + + @Override + public Object toSerializable() { + return ThreePhaseCommitCohortMessages.AbortTransaction.newBuilder(). + setTransactionId(transactionID).build(); + } + + public static AbortTransaction fromSerializable(Object message) { + return new AbortTransaction(((ThreePhaseCommitCohortMessages.AbortTransaction)message). + getTransactionId()); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/AbortTransactionReply.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/AbortTransactionReply.java index 88e26401f7..79c6b036fa 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/AbortTransactionReply.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/AbortTransactionReply.java @@ -11,11 +11,11 @@ package org.opendaylight.controller.cluster.datastore.messages; import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages; public class AbortTransactionReply implements SerializableMessage { - public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.AbortTransactionReply.class; + public static final Class SERIALIZABLE_CLASS = + ThreePhaseCommitCohortMessages.AbortTransactionReply.class; - - @Override - public Object toSerializable() { - return ThreePhaseCommitCohortMessages.AbortTransactionReply.newBuilder().build(); - } + @Override + public Object toSerializable() { + return ThreePhaseCommitCohortMessages.AbortTransactionReply.newBuilder().build(); + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/HashMapDataStoreModuleFactory.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ActorInitialized.java similarity index 58% rename from opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/HashMapDataStoreModuleFactory.java rename to opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ActorInitialized.java index 6b5503f794..b034f87d1c 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/HashMapDataStoreModuleFactory.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ActorInitialized.java @@ -5,13 +5,9 @@ * 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.config.yang.md.sal.dom.impl; - -/** -* -*/ -public class HashMapDataStoreModuleFactory extends org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractHashMapDataStoreModuleFactory -{ +package org.opendaylight.controller.cluster.datastore.messages; +import java.io.Serializable; +public class ActorInitialized implements Serializable { } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ActorNotInitialized.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ActorNotInitialized.java new file mode 100644 index 0000000000..de25ef9ecc --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ActorNotInitialized.java @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.datastore.messages; + +import java.io.Serializable; + +public class ActorNotInitialized implements Serializable { +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CanCommitTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CanCommitTransaction.java index 08f81c121f..565345a44f 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CanCommitTransaction.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CanCommitTransaction.java @@ -11,10 +11,26 @@ package org.opendaylight.controller.cluster.datastore.messages; import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages; public class CanCommitTransaction implements SerializableMessage { - public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CanCommitTransaction.class; + public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CanCommitTransaction.class; - @Override - public Object toSerializable() { - return ThreePhaseCommitCohortMessages.CanCommitTransaction.newBuilder().build(); - } + private final String transactionID; + + public CanCommitTransaction(String transactionID) { + this.transactionID = transactionID; + } + + public String getTransactionID() { + return transactionID; + } + + @Override + public Object toSerializable() { + return ThreePhaseCommitCohortMessages.CanCommitTransaction.newBuilder(). + setTransactionId(transactionID).build(); + } + + public static CanCommitTransaction fromSerializable(Object message) { + return new CanCommitTransaction(((ThreePhaseCommitCohortMessages.CanCommitTransaction)message). + getTransactionId()); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CanCommitTransactionReply.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CanCommitTransactionReply.java index bbcd4de03f..9c8909c2dd 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CanCommitTransactionReply.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CanCommitTransactionReply.java @@ -11,24 +11,26 @@ package org.opendaylight.controller.cluster.datastore.messages; import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages; public class CanCommitTransactionReply implements SerializableMessage { - public static Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CanCommitTransactionReply.class; - private final Boolean canCommit; + public static Class SERIALIZABLE_CLASS = + ThreePhaseCommitCohortMessages.CanCommitTransactionReply.class; - public CanCommitTransactionReply(Boolean canCommit) { - this.canCommit = canCommit; - } + private final Boolean canCommit; - public Boolean getCanCommit() { - return canCommit; - } + public CanCommitTransactionReply(Boolean canCommit) { + this.canCommit = canCommit; + } - @Override - public Object toSerializable() { - return ThreePhaseCommitCohortMessages.CanCommitTransactionReply.newBuilder().setCanCommit(canCommit).build(); - } + public Boolean getCanCommit() { + return canCommit; + } + @Override + public Object toSerializable() { + return ThreePhaseCommitCohortMessages.CanCommitTransactionReply.newBuilder().setCanCommit(canCommit).build(); + } - public static CanCommitTransactionReply fromSerializable(Object message) { - return new CanCommitTransactionReply(((ThreePhaseCommitCohortMessages.CanCommitTransactionReply)message).getCanCommit()); - } + public static CanCommitTransactionReply fromSerializable(Object message) { + return new CanCommitTransactionReply( + ((ThreePhaseCommitCohortMessages.CanCommitTransactionReply) message).getCanCommit()); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CommitTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CommitTransaction.java index 92138a769c..d607fe50fe 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CommitTransaction.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CommitTransaction.java @@ -11,10 +11,27 @@ package org.opendaylight.controller.cluster.datastore.messages; import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages; public class CommitTransaction implements SerializableMessage { - public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CommitTransaction.class; + public static final Class SERIALIZABLE_CLASS = + ThreePhaseCommitCohortMessages.CommitTransaction.class; - @Override - public Object toSerializable() { - return ThreePhaseCommitCohortMessages.CommitTransaction.newBuilder().build(); - } + private final String transactionID; + + public CommitTransaction(String transactionID) { + this.transactionID = transactionID; + } + + public String getTransactionID() { + return transactionID; + } + + @Override + public Object toSerializable() { + return ThreePhaseCommitCohortMessages.CommitTransaction.newBuilder().setTransactionId( + transactionID).build(); + } + + public static CommitTransaction fromSerializable(Object message) { + return new CommitTransaction(((ThreePhaseCommitCohortMessages. + CommitTransaction)message).getTransactionId()); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CommitTransactionReply.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CommitTransactionReply.java index 5751b71037..3d4a168450 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CommitTransactionReply.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CommitTransactionReply.java @@ -11,11 +11,11 @@ package org.opendaylight.controller.cluster.datastore.messages; import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages; public class CommitTransactionReply implements SerializableMessage { + public static final Class SERIALIZABLE_CLASS = + ThreePhaseCommitCohortMessages.CommitTransactionReply.class; - public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CommitTransactionReply.class; - - @Override - public Object toSerializable() { - return ThreePhaseCommitCohortMessages.CommitTransactionReply.newBuilder().build(); - } + @Override + public Object toSerializable() { + return ThreePhaseCommitCohortMessages.CommitTransactionReply.newBuilder().build(); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChain.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChain.java deleted file mode 100644 index 8dd04e540e..0000000000 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChain.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.cluster.datastore.messages; - -import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages; - -public class CreateTransactionChain implements SerializableMessage{ - public static final Class SERIALIZABLE_CLASS = ShardTransactionChainMessages.CreateTransactionChain.class; - - @Override - public Object toSerializable() { - return ShardTransactionChainMessages.CreateTransactionChain.newBuilder().build(); - } -} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChainReply.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChainReply.java deleted file mode 100644 index 4a497622fc..0000000000 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChainReply.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.cluster.datastore.messages; - -import akka.actor.ActorPath; -import akka.actor.ActorSystem; -import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages; - -public class CreateTransactionChainReply implements SerializableMessage { - public static final Class SERIALIZABLE_CLASS = ShardTransactionChainMessages.CreateTransactionChainReply.class; - private final ActorPath transactionChainPath; - - public CreateTransactionChainReply(ActorPath transactionChainPath) { - this.transactionChainPath = transactionChainPath; - } - - public ActorPath getTransactionChainPath() { - return transactionChainPath; - } - - @Override - public ShardTransactionChainMessages.CreateTransactionChainReply toSerializable() { - return ShardTransactionChainMessages.CreateTransactionChainReply.newBuilder() - .setTransactionChainPath(transactionChainPath.toString()).build(); - } - - public static CreateTransactionChainReply fromSerializable(ActorSystem actorSystem,Object serializable){ - ShardTransactionChainMessages.CreateTransactionChainReply o = (ShardTransactionChainMessages.CreateTransactionChainReply) serializable; - return new CreateTransactionChainReply( - actorSystem.actorFor(o.getTransactionChainPath()).path()); - } - -} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/DataChanged.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/DataChanged.java index a8827bebf4..5b5f076d43 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/DataChanged.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/DataChanged.java @@ -9,14 +9,13 @@ package org.opendaylight.controller.cluster.datastore.messages; import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec; -import org.opendaylight.controller.cluster.datastore.utils.InstanceIdentifierUtils; +import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; import org.opendaylight.controller.protobuff.messages.datachange.notification.DataChangeListenerMessages; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; - import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -26,8 +25,9 @@ import java.util.Map; import java.util.Set; public class DataChanged implements SerializableMessage { - public static final Class SERIALIZABLE_CLASS = + public static final Class SERIALIZABLE_CLASS = DataChangeListenerMessages.DataChanged.class; + final private SchemaContext schemaContext; private final AsyncDataChangeEvent> change; @@ -50,7 +50,7 @@ public class DataChanged implements SerializableMessage { NormalizedNode normalizedNode) { return new NormalizedNodeToNodeCodec(schemaContext) - .encode(YangInstanceIdentifier.builder().build(), normalizedNode) + .encode(normalizedNode) .getNormalizedNode(); } @@ -62,6 +62,7 @@ public class DataChanged implements SerializableMessage { removedPathInstanceIds.add(InstanceIdentifierUtils.toSerializable(id)); } return new Iterable() { + @Override public Iterator iterator() { return removedPathInstanceIds.iterator(); } @@ -86,7 +87,7 @@ public class DataChanged implements SerializableMessage { builder.setInstanceIdentifierPath(instanceIdentifier) .setNormalizedNode(normalizedNodeToNodeCodec - .encode(entry.getKey(), entry.getValue()) + .encode(entry.getValue()) .getNormalizedNode()); nodeMapBuilder.addMapEntries(builder.build()); } @@ -146,7 +147,6 @@ public class DataChanged implements SerializableMessage { static class DataChangedEvent implements AsyncDataChangeEvent> { - private final SchemaContext schemaContext; private Map> createdData; private final NormalizedNodeToNodeCodec nodeCodec; private Map> updatedData; @@ -156,7 +156,6 @@ public class DataChanged implements SerializableMessage { private Set removedPathIds; DataChangedEvent(SchemaContext schemaContext) { - this.schemaContext = schemaContext; nodeCodec = new NormalizedNodeToNodeCodec(schemaContext); } @@ -183,7 +182,7 @@ public class DataChanged implements SerializableMessage { YangInstanceIdentifier id = InstanceIdentifierUtils .fromSerializable(nodeMapEntry.getInstanceIdentifierPath()); mapEntries.put(id, - nodeCodec.decode(id, nodeMapEntry.getNormalizedNode())); + nodeCodec.decode(nodeMapEntry.getNormalizedNode())); } return mapEntries; } @@ -240,7 +239,7 @@ public class DataChanged implements SerializableMessage { DataChangedEvent setOriginalSubtree(NormalizedNodeMessages.Node node, YangInstanceIdentifier instanceIdentifierPath) { - originalSubTree = nodeCodec.decode(instanceIdentifierPath, node); + originalSubTree = nodeCodec.decode(node); return this; } @@ -251,7 +250,7 @@ public class DataChanged implements SerializableMessage { DataChangedEvent setUpdatedSubtree(NormalizedNodeMessages.Node node, YangInstanceIdentifier instanceIdentifierPath) { - updatedSubTree = nodeCodec.decode(instanceIdentifierPath, node); + updatedSubTree = nodeCodec.decode(node); return this; } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/DeleteData.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/DeleteData.java index 9ae851e76c..6d3051c8c7 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/DeleteData.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/DeleteData.java @@ -8,7 +8,7 @@ package org.opendaylight.controller.cluster.datastore.messages; -import org.opendaylight.controller.cluster.datastore.utils.InstanceIdentifierUtils; +import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils; import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ForwardedCommitTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ForwardedCommitTransaction.java deleted file mode 100644 index 01049930b5..0000000000 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ForwardedCommitTransaction.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.cluster.datastore.messages; - -import org.opendaylight.controller.cluster.datastore.modification.Modification; -import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; - -public class ForwardedCommitTransaction { - private final DOMStoreThreePhaseCommitCohort cohort; - private final Modification modification; - - public ForwardedCommitTransaction(DOMStoreThreePhaseCommitCohort cohort, Modification modification){ - this.cohort = cohort; - this.modification = modification; - } - - public DOMStoreThreePhaseCommitCohort getCohort() { - return cohort; - } - - public Modification getModification() { - return modification; - } -} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ForwardedReadyTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ForwardedReadyTransaction.java new file mode 100644 index 0000000000..180108f218 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ForwardedReadyTransaction.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.cluster.datastore.messages; + +import org.opendaylight.controller.cluster.datastore.modification.Modification; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; + +/** + * Transaction ReadyTransaction message that is forwarded to the local Shard from the ShardTransaction. + * + * @author Thomas Pantelis + */ +public class ForwardedReadyTransaction { + private final String transactionID; + private final DOMStoreThreePhaseCommitCohort cohort; + private final Modification modification; + private final boolean returnSerialized; + + public ForwardedReadyTransaction(String transactionID, DOMStoreThreePhaseCommitCohort cohort, + Modification modification, boolean returnSerialized) { + this.transactionID = transactionID; + this.cohort = cohort; + this.modification = modification; + this.returnSerialized = returnSerialized; + + } + + public String getTransactionID() { + return transactionID; + } + + public DOMStoreThreePhaseCommitCohort getCohort() { + return cohort; + } + + public Modification getModification() { + return modification; + } + + public boolean isReturnSerialized() { + return returnSerialized; + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/MergeData.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/MergeData.java index ba790816c4..eb1f3495bd 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/MergeData.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/MergeData.java @@ -9,8 +9,8 @@ package org.opendaylight.controller.cluster.datastore.messages; import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec; -import org.opendaylight.controller.cluster.datastore.utils.InstanceIdentifierUtils; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; +import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec.Decoded; +import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec.Encoded; import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; @@ -18,31 +18,26 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; public class MergeData extends ModifyData{ - public static final Class SERIALIZABLE_CLASS = ShardTransactionMessages.MergeData.class; + public static final Class SERIALIZABLE_CLASS = + ShardTransactionMessages.MergeData.class; public MergeData(YangInstanceIdentifier path, NormalizedNode data, SchemaContext context) { super(path, data, context); } - @Override public Object toSerializable() { - - NormalizedNodeMessages.Node normalizedNode = - new NormalizedNodeToNodeCodec(schemaContext).encode(path, data) - .getNormalizedNode(); + @Override + public Object toSerializable() { + Encoded encoded = new NormalizedNodeToNodeCodec(schemaContext).encode(path, data); return ShardTransactionMessages.MergeData.newBuilder() - .setInstanceIdentifierPathArguments(InstanceIdentifierUtils.toSerializable(path)) - .setNormalizedNode(normalizedNode).build(); + .setInstanceIdentifierPathArguments(encoded.getEncodedPath()) + .setNormalizedNode(encoded.getEncodedNode().getNormalizedNode()).build(); } public static MergeData fromSerializable(Object serializable, SchemaContext schemaContext){ ShardTransactionMessages.MergeData o = (ShardTransactionMessages.MergeData) serializable; - YangInstanceIdentifier identifier = InstanceIdentifierUtils.fromSerializable(o.getInstanceIdentifierPathArguments()); - - NormalizedNode normalizedNode = - new NormalizedNodeToNodeCodec(schemaContext) - .decode(identifier, o.getNormalizedNode()); - - return new MergeData(identifier, normalizedNode, schemaContext); + Decoded decoded = new NormalizedNodeToNodeCodec(schemaContext).decode( + o.getInstanceIdentifierPathArguments(), o.getNormalizedNode()); + return new MergeData(decoded.getDecodedPath(), decoded.getDecodedNode(), schemaContext); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadData.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadData.java index a698f46347..d743d99fcc 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadData.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadData.java @@ -8,7 +8,7 @@ package org.opendaylight.controller.cluster.datastore.messages; -import org.opendaylight.controller.cluster.datastore.utils.InstanceIdentifierUtils; +import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils; import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadDataReply.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadDataReply.java index fc6bcff64a..43dd81252c 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadDataReply.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadDataReply.java @@ -15,41 +15,44 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -public class ReadDataReply implements SerializableMessage{ - - private final NormalizedNode normalizedNode; - private final SchemaContext schemaContext; - public static final Class SERIALIZABLE_CLASS = ShardTransactionMessages.ReadDataReply.class; - public ReadDataReply(SchemaContext context,NormalizedNode normalizedNode){ - - this.normalizedNode = normalizedNode; - this.schemaContext = context; - } - - public NormalizedNode getNormalizedNode() { - return normalizedNode; - } - - public Object toSerializable(){ - if(normalizedNode != null) { - return ShardTransactionMessages.ReadDataReply.newBuilder() - .setNormalizedNode(new NormalizedNodeToNodeCodec(schemaContext) - .encode(YangInstanceIdentifier.builder().build(), normalizedNode).getNormalizedNode() - ).build(); - }else{ - return ShardTransactionMessages.ReadDataReply.newBuilder().build(); +public class ReadDataReply implements SerializableMessage { + public static final Class SERIALIZABLE_CLASS = + ShardTransactionMessages.ReadDataReply.class; + private final NormalizedNode normalizedNode; + private final SchemaContext schemaContext; + + public ReadDataReply(SchemaContext context,NormalizedNode normalizedNode){ + + this.normalizedNode = normalizedNode; + this.schemaContext = context; + } + + public NormalizedNode getNormalizedNode() { + return normalizedNode; } - } + @Override + public Object toSerializable(){ + if(normalizedNode != null) { + return ShardTransactionMessages.ReadDataReply.newBuilder() + .setNormalizedNode(new NormalizedNodeToNodeCodec(schemaContext) + .encode(normalizedNode).getNormalizedNode()).build(); + } else { + return ShardTransactionMessages.ReadDataReply.newBuilder().build(); - public static ReadDataReply fromSerializable(SchemaContext schemaContext,YangInstanceIdentifier id,Object serializable){ - ShardTransactionMessages.ReadDataReply o = (ShardTransactionMessages.ReadDataReply) serializable; - return new ReadDataReply(schemaContext,new NormalizedNodeToNodeCodec(schemaContext).decode(id, o.getNormalizedNode())); - } + } + } + + public static ReadDataReply fromSerializable(SchemaContext schemaContext, + YangInstanceIdentifier id, Object serializable) { + ShardTransactionMessages.ReadDataReply o = (ShardTransactionMessages.ReadDataReply) serializable; + return new ReadDataReply(schemaContext, new NormalizedNodeToNodeCodec(schemaContext).decode( + o.getNormalizedNode())); + } - public static ByteString getNormalizedNodeByteString(Object serializable){ - ShardTransactionMessages.ReadDataReply o = (ShardTransactionMessages.ReadDataReply) serializable; - return ((ShardTransactionMessages.ReadDataReply) serializable).getNormalizedNode().toByteString(); - } + public static ByteString getNormalizedNodeByteString(Object serializable){ + ShardTransactionMessages.ReadDataReply o = (ShardTransactionMessages.ReadDataReply) serializable; + return ((ShardTransactionMessages.ReadDataReply) serializable).getNormalizedNode().toByteString(); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadyTransactionReply.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadyTransactionReply.java index 5273dc2479..eee489177a 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadyTransactionReply.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadyTransactionReply.java @@ -8,32 +8,33 @@ package org.opendaylight.controller.cluster.datastore.messages; -import akka.actor.ActorPath; -import akka.actor.ActorSystem; import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages; public class ReadyTransactionReply implements SerializableMessage { - public static final Class SERIALIZABLE_CLASS = ShardTransactionMessages.ReadyTransactionReply.class; - private final ActorPath cohortPath; + public static final Class SERIALIZABLE_CLASS = + ShardTransactionMessages.ReadyTransactionReply.class; - public ReadyTransactionReply(ActorPath cohortPath) { + private final String cohortPath; - this.cohortPath = cohortPath; - } + public ReadyTransactionReply(String cohortPath) { - public ActorPath getCohortPath() { - return cohortPath; - } + this.cohortPath = cohortPath; + } - @Override - public ShardTransactionMessages.ReadyTransactionReply toSerializable() { - return ShardTransactionMessages.ReadyTransactionReply.newBuilder() - .setActorPath(cohortPath.toString()).build(); - } + public String getCohortPath() { + return cohortPath; + } - public static ReadyTransactionReply fromSerializable(ActorSystem actorSystem,Object serializable){ - ShardTransactionMessages.ReadyTransactionReply o = (ShardTransactionMessages.ReadyTransactionReply) serializable; - return new ReadyTransactionReply( - actorSystem.actorFor(o.getActorPath()).path()); - } + @Override + public ShardTransactionMessages.ReadyTransactionReply toSerializable() { + return ShardTransactionMessages.ReadyTransactionReply.newBuilder(). + setActorPath(cohortPath).build(); + } + + public static ReadyTransactionReply fromSerializable(Object serializable) { + ShardTransactionMessages.ReadyTransactionReply o = + (ShardTransactionMessages.ReadyTransactionReply) serializable; + + return new ReadyTransactionReply(o.getActorPath()); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/RegisterChangeListener.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/RegisterChangeListener.java index c1ec0a87cb..dea085153b 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/RegisterChangeListener.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/RegisterChangeListener.java @@ -10,13 +10,15 @@ package org.opendaylight.controller.cluster.datastore.messages; import akka.actor.ActorPath; import akka.actor.ActorSystem; -import org.opendaylight.controller.cluster.datastore.utils.InstanceIdentifierUtils; +import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; import org.opendaylight.controller.protobuff.messages.registration.ListenerRegistrationMessages; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; public class RegisterChangeListener implements SerializableMessage { - public static final Class SERIALIZABLE_CLASS = ListenerRegistrationMessages.RegisterChangeListener.class; + public static final Class SERIALIZABLE_CLASS = + ListenerRegistrationMessages.RegisterChangeListener.class; + private final YangInstanceIdentifier path; private final ActorPath dataChangeListenerPath; private final AsyncDataBroker.DataChangeScope scope; diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/WriteData.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/WriteData.java index 87fa010b37..8aa63ef262 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/WriteData.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/WriteData.java @@ -9,41 +9,34 @@ package org.opendaylight.controller.cluster.datastore.messages; import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec; -import org.opendaylight.controller.cluster.datastore.utils.InstanceIdentifierUtils; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; +import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec.Decoded; +import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec.Encoded; import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -public class WriteData extends ModifyData{ +public class WriteData extends ModifyData { - public static final Class SERIALIZABLE_CLASS = ShardTransactionMessages.WriteData.class; + public static final Class SERIALIZABLE_CLASS = + ShardTransactionMessages.WriteData.class; - public WriteData(YangInstanceIdentifier path, NormalizedNode data, SchemaContext schemaContext) { - super(path, data, schemaContext); - } - - @Override public Object toSerializable() { + public WriteData(YangInstanceIdentifier path, NormalizedNode data, SchemaContext schemaContext) { + super(path, data, schemaContext); + } - NormalizedNodeMessages.Node normalizedNode = - new NormalizedNodeToNodeCodec(schemaContext).encode(path, data) - .getNormalizedNode(); + @Override + public Object toSerializable() { + Encoded encoded = new NormalizedNodeToNodeCodec(schemaContext).encode(path, data); return ShardTransactionMessages.WriteData.newBuilder() - .setInstanceIdentifierPathArguments(InstanceIdentifierUtils.toSerializable(path)) - .setNormalizedNode(normalizedNode).build(); - + .setInstanceIdentifierPathArguments(encoded.getEncodedPath()) + .setNormalizedNode(encoded.getEncodedNode().getNormalizedNode()).build(); } public static WriteData fromSerializable(Object serializable, SchemaContext schemaContext){ ShardTransactionMessages.WriteData o = (ShardTransactionMessages.WriteData) serializable; - YangInstanceIdentifier identifier = InstanceIdentifierUtils.fromSerializable(o.getInstanceIdentifierPathArguments()); - - NormalizedNode normalizedNode = - new NormalizedNodeToNodeCodec(schemaContext) - .decode(identifier, o.getNormalizedNode()); - - return new WriteData(identifier, normalizedNode, schemaContext); + Decoded decoded = new NormalizedNodeToNodeCodec(schemaContext).decode( + o.getInstanceIdentifierPathArguments(), o.getNormalizedNode()); + return new WriteData(decoded.getDecodedPath(), decoded.getDecodedNode(), schemaContext); } - } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/AbstractModification.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/AbstractModification.java index 169397bf87..4f4f0fb8f1 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/AbstractModification.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/AbstractModification.java @@ -26,4 +26,8 @@ public abstract class AbstractModification implements Modification, protected AbstractModification(YangInstanceIdentifier path) { this.path = path; } + + public YangInstanceIdentifier getPath() { + return path; + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/DeleteModification.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/DeleteModification.java index 593f458afa..056fe75637 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/DeleteModification.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/DeleteModification.java @@ -8,7 +8,7 @@ package org.opendaylight.controller.cluster.datastore.modification; -import org.opendaylight.controller.cluster.datastore.utils.InstanceIdentifierUtils; +import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils; import org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages; import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -17,23 +17,24 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; * DeleteModification store all the parameters required to delete a path from the data tree */ public class DeleteModification extends AbstractModification { - public DeleteModification(YangInstanceIdentifier path) { - super(path); - } + private static final long serialVersionUID = 1L; - @Override - public void apply(DOMStoreWriteTransaction transaction) { - transaction.delete(path); - } + public DeleteModification(YangInstanceIdentifier path) { + super(path); + } + + @Override + public void apply(DOMStoreWriteTransaction transaction) { + transaction.delete(path); + } - @Override public Object toSerializable() { - return PersistentMessages.Modification.newBuilder() - .setType(this.getClass().toString()) - .setPath(InstanceIdentifierUtils.toSerializable(this.path)) - .build(); + @Override + public Object toSerializable() { + return PersistentMessages.Modification.newBuilder().setType(this.getClass().toString()) + .setPath(InstanceIdentifierUtils.toSerializable(this.path)).build(); } - public static DeleteModification fromSerializable(Object serializable){ + public static DeleteModification fromSerializable(Object serializable) { PersistentMessages.Modification o = (PersistentMessages.Modification) serializable; return new DeleteModification(InstanceIdentifierUtils.fromSerializable(o.getPath())); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/MergeModification.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/MergeModification.java index f06adcf96f..24c4c6c50a 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/MergeModification.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/MergeModification.java @@ -9,8 +9,7 @@ package org.opendaylight.controller.cluster.datastore.modification; import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec; -import org.opendaylight.controller.cluster.datastore.utils.InstanceIdentifierUtils; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; +import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec.Decoded; import org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages; import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -20,16 +19,11 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; /** * MergeModification stores all the parameters required to merge data into the specified path */ -public class MergeModification extends AbstractModification { - private final NormalizedNode data; - private final SchemaContext schemaContext; - +public class MergeModification extends WriteModification { public MergeModification(YangInstanceIdentifier path, NormalizedNode data, SchemaContext schemaContext) { - super(path); - this.data = data; - this.schemaContext = schemaContext; + super(path, data, schemaContext); } @Override @@ -37,29 +31,9 @@ public class MergeModification extends AbstractModification { transaction.merge(path, data); } - @Override public Object toSerializable() { - NormalizedNodeMessages.Container encode = - new NormalizedNodeToNodeCodec(schemaContext).encode( - path, data); - - return PersistentMessages.Modification.newBuilder() - .setType(this.getClass().toString()) - .setPath(InstanceIdentifierUtils.toSerializable(this.path)) - .setData(encode.getNormalizedNode()) - .build(); - - } - - public static MergeModification fromSerializable( - Object serializable, - SchemaContext schemaContext) { + public static MergeModification fromSerializable(Object serializable, SchemaContext schemaContext) { PersistentMessages.Modification o = (PersistentMessages.Modification) serializable; - - YangInstanceIdentifier path = InstanceIdentifierUtils.fromSerializable(o.getPath()); - NormalizedNode data = new NormalizedNodeToNodeCodec(schemaContext).decode( - path, o.getData()); - - return new MergeModification(path, data, schemaContext); + Decoded decoded = new NormalizedNodeToNodeCodec(schemaContext).decode(o.getPath(), o.getData()); + return new MergeModification(decoded.getDecodedPath(), decoded.getDecodedNode(), schemaContext); } - } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/WriteModification.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/WriteModification.java index b4a7dd62d0..53cc35a88b 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/WriteModification.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/modification/WriteModification.java @@ -9,8 +9,8 @@ package org.opendaylight.controller.cluster.datastore.modification; import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec; -import org.opendaylight.controller.cluster.datastore.utils.InstanceIdentifierUtils; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; +import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec.Decoded; +import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec.Encoded; import org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages; import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -22,43 +22,38 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; */ public class WriteModification extends AbstractModification { - private final NormalizedNode data; + protected final NormalizedNode data; private final SchemaContext schemaContext; public WriteModification(YangInstanceIdentifier path, NormalizedNode data, SchemaContext schemaContext) { - super(path); - this.data = data; + super(path); + this.data = data; this.schemaContext = schemaContext; } - @Override - public void apply(DOMStoreWriteTransaction transaction) { - transaction.write(path, data); - } + @Override + public void apply(DOMStoreWriteTransaction transaction) { + transaction.write(path, data); + } - @Override public Object toSerializable() { - NormalizedNodeMessages.Container encode = - new NormalizedNodeToNodeCodec(schemaContext).encode( - path, data); + public NormalizedNode getData() { + return data; + } + @Override + public Object toSerializable() { + Encoded encoded = new NormalizedNodeToNodeCodec(schemaContext).encode(path, data); return PersistentMessages.Modification.newBuilder() - .setType(this.getClass().toString()) - .setPath(InstanceIdentifierUtils.toSerializable(this.path)) - .setData(encode.getNormalizedNode()) - .build(); - + .setType(this.getClass().toString()) + .setPath(encoded.getEncodedPath()) + .setData(encoded.getEncodedNode().getNormalizedNode()) + .build(); } - public static WriteModification fromSerializable( - Object serializable, - SchemaContext schemaContext) { + public static WriteModification fromSerializable(Object serializable, SchemaContext schemaContext) { PersistentMessages.Modification o = (PersistentMessages.Modification) serializable; - - YangInstanceIdentifier path = InstanceIdentifierUtils.fromSerializable(o.getPath()); - NormalizedNode data = new NormalizedNodeToNodeCodec(schemaContext).decode( - path, o.getData()); - - return new WriteModification(path, data, schemaContext); + Decoded decoded = new NormalizedNodeToNodeCodec(schemaContext).decode(o.getPath(), o.getData()); + return new WriteModification(decoded.getDecodedPath(), decoded.getDecodedNode(), schemaContext); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java index 7b5588cb19..314ae916de 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java @@ -13,12 +13,14 @@ import akka.actor.ActorRef; import akka.actor.ActorSelection; import akka.actor.ActorSystem; import akka.actor.PoisonPill; -import akka.pattern.Patterns; import akka.util.Timeout; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; import org.opendaylight.controller.cluster.datastore.ClusterWrapper; import org.opendaylight.controller.cluster.datastore.Configuration; -import org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException; +import org.opendaylight.controller.cluster.datastore.exceptions.NotInitializedException; import org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException; +import org.opendaylight.controller.cluster.datastore.messages.ActorNotInitialized; import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard; import org.opendaylight.controller.cluster.datastore.messages.FindPrimary; import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound; @@ -31,9 +33,7 @@ import scala.concurrent.Await; import scala.concurrent.Future; import scala.concurrent.duration.Duration; import scala.concurrent.duration.FiniteDuration; - import java.util.concurrent.TimeUnit; - import static akka.pattern.Patterns.ask; /** @@ -101,14 +101,17 @@ public class ActorContext { } /** - * Finds the primary for a given shard + * Finds the primary shard for the given shard name * * @param shardName * @return */ - public ActorSelection findPrimary(String shardName) { - String path = findPrimaryPath(shardName); - return actorSystem.actorSelection(path); + public Optional findPrimaryShard(String shardName) { + String path = findPrimaryPathOrNull(shardName); + if (path == null){ + return Optional.absent(); + } + return Optional.of(actorSystem.actorSelection(path)); } /** @@ -118,34 +121,36 @@ public class ActorContext { * @return a reference to a local shard actor which represents the shard * specified by the shardName */ - public ActorRef findLocalShard(String shardName) { - Object result = executeLocalOperation(shardManager, - new FindLocalShard(shardName)); + public Optional findLocalShard(String shardName) { + Object result = executeOperation(shardManager, new FindLocalShard(shardName)); if (result instanceof LocalShardFound) { LocalShardFound found = (LocalShardFound) result; - LOG.debug("Local shard found {}", found.getPath()); - - return found.getPath(); + return Optional.of(found.getPath()); } - return null; + return Optional.absent(); } - public String findPrimaryPath(String shardName) { - Object result = executeLocalOperation(shardManager, - new FindPrimary(shardName).toSerializable()); + private String findPrimaryPathOrNull(String shardName) { + Object result = executeOperation(shardManager, new FindPrimary(shardName).toSerializable()); if (result.getClass().equals(PrimaryFound.SERIALIZABLE_CLASS)) { PrimaryFound found = PrimaryFound.fromSerializable(result); LOG.debug("Primary found {}", found.getPrimaryPath()); - return found.getPrimaryPath(); + + } else if (result.getClass().equals(ActorNotInitialized.class)){ + throw new NotInitializedException( + String.format("Found primary shard[%s] but its not initialized yet. Please try again later", shardName) + ); + + } else { + return null; } - throw new PrimaryNotFoundException("Could not find primary for shardName " + shardName); } @@ -156,16 +161,25 @@ public class ActorContext { * @param message * @return The response of the operation */ - public Object executeLocalOperation(ActorRef actor, Object message) { - Future future = ask(actor, message, operationTimeout); + public Object executeOperation(ActorRef actor, Object message) { + Future future = executeOperationAsync(actor, message, operationTimeout); try { return Await.result(future, operationDuration); } catch (Exception e) { - throw new TimeoutException("Sending message " + message.getClass().toString() + " to actor " + actor.toString() + " failed" , e); + throw new TimeoutException("Sending message " + message.getClass().toString() + + " to actor " + actor.toString() + " failed. Try again later.", e); } } + public Future executeOperationAsync(ActorRef actor, Object message, Timeout timeout) { + Preconditions.checkArgument(actor != null, "actor must not be null"); + Preconditions.checkArgument(message != null, "message must not be null"); + + LOG.debug("Sending message {} to {}", message.getClass().toString(), actor.toString()); + return ask(actor, message, timeout); + } + /** * Execute an operation on a remote actor and wait for it's response * @@ -173,18 +187,14 @@ public class ActorContext { * @param message * @return */ - public Object executeRemoteOperation(ActorSelection actor, Object message) { - - LOG.debug("Sending remote message {} to {}", message.getClass().toString(), - actor.toString()); - - Future future = ask(actor, message, operationTimeout); + public Object executeOperation(ActorSelection actor, Object message) { + Future future = executeOperationAsync(actor, message); try { return Await.result(future, operationDuration); } catch (Exception e) { throw new TimeoutException("Sending message " + message.getClass().toString() + - " to actor " + actor.toString() + " failed" , e); + " to actor " + actor.toString() + " failed. Try again later.", e); } } @@ -195,9 +205,11 @@ public class ActorContext { * @param message the message to send * @return a Future containing the eventual result */ - public Future executeRemoteOperationAsync(ActorSelection actor, Object message) { + public Future executeOperationAsync(ActorSelection actor, Object message) { + Preconditions.checkArgument(actor != null, "actor must not be null"); + Preconditions.checkArgument(message != null, "message must not be null"); - LOG.debug("Sending remote message {} to {}", message.getClass().toString(), actor.toString()); + LOG.debug("Sending message {} to {}", message.getClass().toString(), actor.toString()); return ask(actor, message, operationTimeout); } @@ -209,117 +221,22 @@ public class ActorContext { * @param actor the ActorSelection * @param message the message to send */ - public void sendRemoteOperationAsync(ActorSelection actor, Object message) { - actor.tell(message, ActorRef.noSender()); - } - - public void sendShardOperationAsync(String shardName, Object message) { - ActorSelection primary = findPrimary(shardName); + public void sendOperationAsync(ActorSelection actor, Object message) { + Preconditions.checkArgument(actor != null, "actor must not be null"); + Preconditions.checkArgument(message != null, "message must not be null"); - primary.tell(message, ActorRef.noSender()); - } - - - /** - * Execute an operation on the primary for a given shard - *

      - * This method first finds the primary for a given shard ,then sends - * the message to the remote shard and waits for a response - *

      - * - * @param shardName - * @param message - * @return - * @throws org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException if the message to the remote shard times out - * @throws org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException if the primary shard is not found - */ - public Object executeShardOperation(String shardName, Object message) { - ActorSelection primary = findPrimary(shardName); - - return executeRemoteOperation(primary, message); - } - - /** - * Execute an operation on the the local shard only - *

      - * This method first finds the address of the local shard if any. It then - * executes the operation on it. - *

      - * - * @param shardName the name of the shard on which the operation needs to be executed - * @param message the message that needs to be sent to the shard - * @return the message that was returned by the local actor on which the - * the operation was executed. If a local shard was not found then - * null is returned - * @throws org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException - * if the operation does not complete in a specified time duration - */ - public Object executeLocalShardOperation(String shardName, Object message) { - ActorRef local = findLocalShard(shardName); - - if(local != null) { - return executeLocalOperation(local, message); - } + LOG.debug("Sending message {} to {}", message.getClass().toString(), actor.toString()); - return null; - } - - - /** - * Execute an operation on the the local shard only asynchronously - * - *

      - * This method first finds the address of the local shard if any. It then - * executes the operation on it. - *

      - * - * @param shardName the name of the shard on which the operation needs to be executed - * @param message the message that needs to be sent to the shard - * @param timeout the amount of time that this method should wait for a response before timing out - * @return null if the shard could not be located else a future on which the caller can wait - * - */ - public Future executeLocalShardOperationAsync(String shardName, Object message, Timeout timeout) { - ActorRef local = findLocalShard(shardName); - if(local == null){ - return null; - } - return Patterns.ask(local, message, timeout); + actor.tell(message, ActorRef.noSender()); } - - public void shutdown() { shardManager.tell(PoisonPill.getInstance(), null); actorSystem.shutdown(); } - /** - * @deprecated Need to stop using this method. There are ways to send a - * remote ActorRef as a string which should be used instead of this hack - * - * @param primaryPath - * @param localPathOfRemoteActor - * @return - */ - @Deprecated - public String resolvePath(final String primaryPath, - final String localPathOfRemoteActor) { - StringBuilder builder = new StringBuilder(); - String[] primaryPathElements = primaryPath.split("/"); - builder.append(primaryPathElements[0]).append("//") - .append(primaryPathElements[1]).append(primaryPathElements[2]); - String[] remotePathElements = localPathOfRemoteActor.split("/"); - for (int i = 3; i < remotePathElements.length; i++) { - builder.append("/").append(remotePathElements[i]); - } - - return builder.toString(); - - } - - public ActorPath actorFor(String path){ - return actorSystem.actorFor(path).path(); + public ClusterWrapper getClusterWrapper() { + return clusterWrapper; } public String getCurrentMemberName(){ @@ -333,10 +250,13 @@ public class ActorContext { */ public void broadcast(Object message){ for(String shardName : configuration.getAllShardNames()){ - try { - sendShardOperationAsync(shardName, message); - } catch(Exception e){ - LOG.warn("broadcast failed to send message " + message.getClass().getSimpleName() + " to shard " + shardName, e); + + Optional primary = findPrimaryShard(shardName); + if (primary.isPresent()) { + primary.get().tell(message, ActorRef.noSender()); + } else { + LOG.warn("broadcast failed to send message {} to shard {}. Primary not found", + message.getClass().getSimpleName(), shardName); } } } @@ -344,4 +264,30 @@ public class ActorContext { public FiniteDuration getOperationDuration() { return operationDuration; } + + public boolean isLocalPath(String path) { + String selfAddress = clusterWrapper.getSelfAddress(); + if (path == null || selfAddress == null) { + return false; + } + + int atIndex1 = path.indexOf("@"); + int atIndex2 = selfAddress.indexOf("@"); + + if (atIndex1 == -1 || atIndex2 == -1) { + return false; + } + + int slashIndex1 = path.indexOf("/", atIndex1); + int slashIndex2 = selfAddress.indexOf("/", atIndex2); + + if (slashIndex1 == -1 || slashIndex2 == -1) { + return false; + } + + String hostPort1 = path.substring(atIndex1, slashIndex1); + String hostPort2 = selfAddress.substring(atIndex2, slashIndex2); + + return hostPort1.equals(hostPort2); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/InstanceIdentifierUtils.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/InstanceIdentifierUtils.java deleted file mode 100644 index c154b81e35..0000000000 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/InstanceIdentifierUtils.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.opendaylight.controller.cluster.datastore.utils; - -import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author: syedbahm - */ -public class InstanceIdentifierUtils { - - protected static final Logger logger = LoggerFactory - .getLogger(InstanceIdentifierUtils.class); - - public static String getParentPath(String currentElementPath) { - - StringBuilder parentPath = new StringBuilder(); - - if (currentElementPath != null) { - String[] parentPaths = currentElementPath.split("/"); - if (parentPaths.length > 2) { - for (int i = 0; i < parentPaths.length - 1; i++) { - if (parentPaths[i].length() > 0) { - parentPath.append( "/"); - parentPath.append( parentPaths[i]); - } - } - } - } - return parentPath.toString(); - } - - @Deprecated - public static YangInstanceIdentifier from(String path) { - String[] ids = path.split("/"); - - List pathArguments = - new ArrayList<>(); - for (String nodeId : ids) { - if (!"".equals(nodeId)) { - pathArguments - .add(NodeIdentifierFactory.getArgument(nodeId)); - } - } - final YangInstanceIdentifier instanceIdentifier = - YangInstanceIdentifier.create(pathArguments); - return instanceIdentifier; - } - - /** - * @deprecated Use {@link org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils} instead - * @param path - * @return - */ - @Deprecated - public static NormalizedNodeMessages.InstanceIdentifier toSerializable(YangInstanceIdentifier path){ - return org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils.toSerializable(path); - } - - /** - * @deprecated Use {@link org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils} instead - * @param path - * @return - */ - @Deprecated - public static YangInstanceIdentifier fromSerializable(NormalizedNodeMessages.InstanceIdentifier path){ - return org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils.fromSerializable(path); - } -} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedConfigDataStoreProviderModule.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedConfigDataStoreProviderModule.java index e7a7aab406..de33f55b96 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedConfigDataStoreProviderModule.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedConfigDataStoreProviderModule.java @@ -40,15 +40,25 @@ public class DistributedConfigDataStoreProviderModule extends props = new ConfigProperties(); } - DatastoreContext datastoreContext = new DatastoreContext("DistributedConfigDatastore", - InMemoryDOMDataStoreConfigProperties.create( - props.getMaxShardDataChangeExecutorPoolSize().getValue(), - props.getMaxShardDataChangeExecutorQueueSize().getValue(), - props.getMaxShardDataChangeListenerQueueSize().getValue(), - props.getMaxShardDataStoreExecutorQueueSize().getValue()), - Duration.create(props.getShardTransactionIdleTimeoutInMinutes().getValue(), - TimeUnit.MINUTES), - props.getOperationTimeoutInSeconds().getValue()); + DatastoreContext datastoreContext = DatastoreContext.newBuilder() + .dataStoreMXBeanType("DistributedConfigDatastore") + .dataStoreProperties(InMemoryDOMDataStoreConfigProperties.create( + props.getMaxShardDataChangeExecutorPoolSize().getValue().intValue(), + props.getMaxShardDataChangeExecutorQueueSize().getValue().intValue(), + props.getMaxShardDataChangeListenerQueueSize().getValue().intValue(), + props.getMaxShardDataStoreExecutorQueueSize().getValue().intValue())) + .shardTransactionIdleTimeout(Duration.create( + props.getShardTransactionIdleTimeoutInMinutes().getValue(), TimeUnit.MINUTES)) + .operationTimeoutInSeconds(props.getOperationTimeoutInSeconds().getValue()) + .shardJournalRecoveryLogBatchSize(props.getShardJournalRecoveryLogBatchSize(). + getValue().intValue()) + .shardSnapshotBatchCount(props.getShardSnapshotBatchCount().getValue().intValue()) + .shardHeartbeatIntervalInMillis(props.getShardHearbeatIntervalInMillis().getValue()) + .shardTransactionCommitTimeoutInSeconds( + props.getShardTransactionCommitTimeoutInSeconds().getValue().intValue()) + .shardTransactionCommitQueueCapacity( + props.getShardTransactionCommitQueueCapacity().getValue().intValue()) + .build(); return DistributedDataStoreFactory.createInstance("config", getConfigSchemaServiceDependency(), datastoreContext, bundleContext); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedOperationalDataStoreProviderModule.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedOperationalDataStoreProviderModule.java index 814e6f606a..ee1859d9ca 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedOperationalDataStoreProviderModule.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedOperationalDataStoreProviderModule.java @@ -40,15 +40,25 @@ public class DistributedOperationalDataStoreProviderModule extends props = new OperationalProperties(); } - DatastoreContext datastoreContext = new DatastoreContext("DistributedOperationalDatastore", - InMemoryDOMDataStoreConfigProperties.create( - props.getMaxShardDataChangeExecutorPoolSize().getValue(), - props.getMaxShardDataChangeExecutorQueueSize().getValue(), - props.getMaxShardDataChangeListenerQueueSize().getValue(), - props.getMaxShardDataStoreExecutorQueueSize().getValue()), - Duration.create(props.getShardTransactionIdleTimeoutInMinutes().getValue(), - TimeUnit.MINUTES), - props.getOperationTimeoutInSeconds().getValue()); + DatastoreContext datastoreContext = DatastoreContext.newBuilder() + .dataStoreMXBeanType("DistributedOperationalDatastore") + .dataStoreProperties(InMemoryDOMDataStoreConfigProperties.create( + props.getMaxShardDataChangeExecutorPoolSize().getValue().intValue(), + props.getMaxShardDataChangeExecutorQueueSize().getValue().intValue(), + props.getMaxShardDataChangeListenerQueueSize().getValue().intValue(), + props.getMaxShardDataStoreExecutorQueueSize().getValue().intValue())) + .shardTransactionIdleTimeout(Duration.create( + props.getShardTransactionIdleTimeoutInMinutes().getValue(), TimeUnit.MINUTES)) + .operationTimeoutInSeconds(props.getOperationTimeoutInSeconds().getValue()) + .shardJournalRecoveryLogBatchSize(props.getShardJournalRecoveryLogBatchSize(). + getValue().intValue()) + .shardSnapshotBatchCount(props.getShardSnapshotBatchCount().getValue().intValue()) + .shardHeartbeatIntervalInMillis(props.getShardHearbeatIntervalInMillis().getValue()) + .shardTransactionCommitTimeoutInSeconds( + props.getShardTransactionCommitTimeoutInSeconds().getValue().intValue()) + .shardTransactionCommitQueueCapacity( + props.getShardTransactionCommitQueueCapacity().getValue().intValue()) + .build(); return DistributedDataStoreFactory.createInstance("operational", getOperationalSchemaServiceDependency(), datastoreContext, bundleContext); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/yang/distributed-datastore-provider.yang b/opendaylight/md-sal/sal-distributed-datastore/src/main/yang/distributed-datastore-provider.yang index e19a76703f..167d530d18 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/yang/distributed-datastore-provider.yang +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/yang/distributed-datastore-provider.yang @@ -36,8 +36,8 @@ module distributed-datastore-provider { config:java-name-prefix DistributedOperationalDataStoreProvider; } - typedef non-zero-uint16-type { - type uint16 { + typedef non-zero-uint32-type { + type uint32 { range "1..max"; } } @@ -48,43 +48,79 @@ module distributed-datastore-provider { } } + typedef heartbeat-interval-type { + type uint16 { + range "100..max"; + } + } + grouping data-store-properties { leaf max-shard-data-change-executor-queue-size { default 1000; - type non-zero-uint16-type; + type non-zero-uint32-type; description "The maximum queue size for each shard's data store data change notification executor."; } leaf max-shard-data-change-executor-pool-size { default 20; - type non-zero-uint16-type; + type non-zero-uint32-type; description "The maximum thread pool size for each shard's data store data change notification executor."; } leaf max-shard-data-change-listener-queue-size { default 1000; - type non-zero-uint16-type; - description "The maximum queue size for each shard's data store data change listeners."; + type non-zero-uint32-type; + description "The maximum queue size for each shard's data store data change listener."; } leaf max-shard-data-store-executor-queue-size { default 5000; - type non-zero-uint16-type; + type non-zero-uint32-type; description "The maximum queue size for each shard's data store executor."; } leaf shard-transaction-idle-timeout-in-minutes { default 10; - type non-zero-uint16-type; + type non-zero-uint32-type; description "The maximum amount of time a shard transaction can be idle without receiving any messages before it self-destructs."; } + leaf shard-snapshot-batch-count { + default 20000; + type non-zero-uint32-type; + description "The minimum number of entries to be present in the in-memory journal log before a snapshot to be taken."; + } + + leaf shard-hearbeat-interval-in-millis { + default 500; + type heartbeat-interval-type; + description "The interval at which a shard will send a heart beat message to its remote shard."; + } + leaf operation-timeout-in-seconds { default 5; type operation-timeout-type; description "The maximum amount of time for akka operations (remote or local) to complete before failing."; } + leaf shard-journal-recovery-log-batch-size { + default 5000; + type non-zero-uint32-type; + description "The maximum number of journal log entries to batch on recovery for a shard before committing to the data store."; + } + + leaf shard-transaction-commit-timeout-in-seconds { + default 30; + type non-zero-uint32-type; + description "The maximum amount of time a shard transaction three-phase commit can be idle without receiving the next messages before it aborts the transaction"; + } + + leaf shard-transaction-commit-queue-capacity { + default 20000; + type non-zero-uint32-type; + description "The maximum allowed capacity for each shard's transaction commit queue."; + } + leaf enable-metric-capture { default false; type boolean; @@ -93,7 +129,7 @@ module distributed-datastore-provider { leaf bounded-mailbox-capacity { default 1000; - type non-zero-uint16-type; + type non-zero-uint32-type; description "Max queue size that an actor's mailbox can reach"; } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/AbstractActorTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/AbstractActorTest.java index 022ef9bbaf..fae21f2709 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/AbstractActorTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/AbstractActorTest.java @@ -10,11 +10,10 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorSystem; import akka.testkit.JavaTestKit; -import org.apache.commons.io.FileUtils; + import org.junit.AfterClass; import org.junit.BeforeClass; -import java.io.File; import java.io.IOException; public abstract class AbstractActorTest { @@ -25,35 +24,15 @@ public abstract class AbstractActorTest { System.setProperty("shard.persistent", "false"); system = ActorSystem.create("test"); - - deletePersistenceFiles(); } @AfterClass public static void tearDownClass() throws IOException { JavaTestKit.shutdownActorSystem(system); system = null; - - deletePersistenceFiles(); - } - - protected static void deletePersistenceFiles() throws IOException { - File journal = new File("journal"); - - if(journal.exists()) { - FileUtils.deleteDirectory(journal); - } - - File snapshots = new File("snapshots"); - - if(snapshots.exists()){ - FileUtils.deleteDirectory(snapshots); - } - } protected ActorSystem getSystem() { return system; } - } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/BasicIntegrationTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/BasicIntegrationTest.java deleted file mode 100644 index 7b826302f5..0000000000 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/BasicIntegrationTest.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.cluster.datastore; - -import akka.actor.ActorPath; -import akka.actor.ActorRef; -import akka.actor.ActorSelection; -import akka.actor.Props; -import akka.event.Logging; -import akka.testkit.JavaTestKit; -import org.junit.Test; -import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier; -import org.opendaylight.controller.cluster.datastore.messages.CommitTransaction; -import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction; -import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionReply; -import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransaction; -import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransactionReply; -import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction; -import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply; -import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext; -import org.opendaylight.controller.cluster.datastore.messages.WriteData; -import org.opendaylight.controller.cluster.datastore.messages.WriteDataReply; -import org.opendaylight.controller.md.cluster.datastore.model.TestModel; -import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import scala.concurrent.Await; -import scala.concurrent.Future; -import scala.concurrent.duration.FiniteDuration; - -import java.util.Collections; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertTrue; -import static org.junit.Assert.assertNotNull; - -public class BasicIntegrationTest extends AbstractActorTest { - - @Test - public void integrationTest() throws Exception{ - // System.setProperty("shard.persistent", "true"); - // This test will - // - create a Shard - // - initiate a transaction - // - write something - // - read the transaction for commit - // - commit the transaction - - - new JavaTestKit(getSystem()) {{ - final ShardIdentifier identifier = - ShardIdentifier.builder().memberName("member-1") - .shardName("inventory").type("config").build(); - - final SchemaContext schemaContext = TestModel.createTestContext(); - DatastoreContext datastoreContext = new DatastoreContext(); - - final Props props = Shard.props(identifier, Collections.EMPTY_MAP, datastoreContext, TestModel.createTestContext()); - final ActorRef shard = getSystem().actorOf(props); - - new Within(duration("10 seconds")) { - @Override - protected void run() { - shard.tell(new UpdateSchemaContext(schemaContext), getRef()); - - - // Wait for a specific log message to show up - final boolean result = - new JavaTestKit.EventFilter(Logging.Info.class - ) { - @Override - protected Boolean run() { - return true; - } - }.from(shard.path().toString()) - .message("Switching from state Candidate to Leader") - .occurrences(1).exec(); - - assertEquals(true, result); - - // Create a transaction on the shard - shard.tell(new CreateTransaction("txn-1", TransactionProxy.TransactionType.WRITE_ONLY.ordinal() ).toSerializable(), getRef()); - - final ActorSelection transaction = - new ExpectMsg(duration("3 seconds"), "CreateTransactionReply") { - @Override - protected ActorSelection match(Object in) { - if (CreateTransactionReply.SERIALIZABLE_CLASS.equals(in.getClass())) { - CreateTransactionReply reply = CreateTransactionReply.fromSerializable(in); - return getSystem() - .actorSelection(reply - .getTransactionPath()); - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertNotNull(transaction); - - System.out.println("Successfully created transaction"); - - // 3. Write some data - transaction.tell(new WriteData(TestModel.TEST_PATH, - ImmutableNodes.containerNode(TestModel.TEST_QNAME), schemaContext).toSerializable(), - getRef()); - - Boolean writeDone = new ExpectMsg(duration("3 seconds"), "WriteDataReply") { - @Override - protected Boolean match(Object in) { - if (in.getClass().equals(WriteDataReply.SERIALIZABLE_CLASS)) { - return true; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertTrue(writeDone); - - System.out.println("Successfully wrote data"); - - // 4. Ready the transaction for commit - - transaction.tell(new ReadyTransaction().toSerializable(), getRef()); - - final ActorSelection cohort = - new ExpectMsg(duration("3 seconds"), "ReadyTransactionReply") { - @Override - protected ActorSelection match(Object in) { - if (in.getClass().equals(ReadyTransactionReply.SERIALIZABLE_CLASS)) { - ActorPath cohortPath = - ReadyTransactionReply.fromSerializable(getSystem(),in) - .getCohortPath(); - return getSystem() - .actorSelection(cohortPath); - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertNotNull(cohort); - - System.out.println("Successfully readied the transaction"); - - // 5. PreCommit the transaction - - cohort.tell(new PreCommitTransaction().toSerializable(), getRef()); - - Boolean preCommitDone = - new ExpectMsg(duration("3 seconds"), "PreCommitTransactionReply") { - @Override - protected Boolean match(Object in) { - if (in.getClass().equals(PreCommitTransactionReply.SERIALIZABLE_CLASS)) { - return true; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertTrue(preCommitDone); - - System.out.println("Successfully pre-committed the transaction"); - - // 6. Commit the transaction - cohort.tell(new CommitTransaction().toSerializable(), getRef()); - - // FIXME : Add assertions that the commit worked and that the cohort and transaction actors were terminated - - System.out.println("TODO : Check Successfully committed the transaction"); - } - - - }; - } - - private ActorRef watchActor(ActorSelection actor) { - Future future = actor - .resolveOne(FiniteDuration.apply(100, "milliseconds")); - - try { - ActorRef actorRef = Await.result(future, - FiniteDuration.apply(100, "milliseconds")); - - watch(actorRef); - - return actorRef; - } catch (Exception e) { - throw new RuntimeException(e); - } - - } - }; - - - } -} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxyTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxyTest.java index 2ed11cfbda..c79d762035 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxyTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxyTest.java @@ -82,7 +82,7 @@ public class DataChangeListenerProxyTest extends AbstractActorTest { ActorContext testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)), new MockClusterWrapper(), new MockConfiguration()); Object messages = testContext - .executeLocalOperation(actorRef, "messages"); + .executeOperation(actorRef, "messages"); Assert.assertNotNull(messages); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationProxyTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationProxyTest.java index ab3ff795d3..aaf080bdf7 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationProxyTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationProxyTest.java @@ -66,7 +66,7 @@ public class DataChangeListenerRegistrationProxyTest extends AbstractActorTest{ ActorContext testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)),new MockClusterWrapper(), new MockConfiguration()); Object messages = testContext - .executeLocalOperation(actorRef, "messages"); + .executeOperation(actorRef, "messages"); assertNotNull(messages); @@ -95,7 +95,7 @@ public class DataChangeListenerRegistrationProxyTest extends AbstractActorTest{ ActorContext testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)),new MockClusterWrapper(), new MockConfiguration()); Object messages = testContext - .executeLocalOperation(actorRef, "messages"); + .executeOperation(actorRef, "messages"); assertNotNull(messages); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerTest.java index b39cc84cef..101a73782b 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerTest.java @@ -1,150 +1,85 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; +import akka.actor.DeadLetter; import akka.actor.Props; import akka.testkit.JavaTestKit; import org.junit.Test; +import org.mockito.Mockito; import org.opendaylight.controller.cluster.datastore.messages.DataChanged; import org.opendaylight.controller.cluster.datastore.messages.DataChangedReply; import org.opendaylight.controller.cluster.datastore.messages.EnableNotification; import org.opendaylight.controller.md.cluster.datastore.model.CompositeModel; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; public class DataChangeListenerTest extends AbstractActorTest { - private static class MockDataChangedEvent implements AsyncDataChangeEvent> { - Map> createdData = new HashMap<>(); - Map> updatedData = new HashMap<>(); - Map> originalData = new HashMap<>(); - - - - @Override - public Map> getCreatedData() { - createdData.put(CompositeModel.FAMILY_PATH, CompositeModel.createFamily()); - return createdData; - } - - @Override - public Map> getUpdatedData() { - updatedData.put(CompositeModel.FAMILY_PATH, CompositeModel.createFamily()); - return updatedData; - - } - - @Override - public Set getRemovedPaths() { - Setids = new HashSet(); - ids.add( CompositeModel.TEST_PATH); - return ids; - } - - @Override - public Map> getOriginalData() { - originalData.put(CompositeModel.FAMILY_PATH, CompositeModel.createFamily()); - return originalData; - } - - @Override public NormalizedNode getOriginalSubtree() { - - - return originalData.put(CompositeModel.FAMILY_PATH, CompositeModel.createFamily()); - } - - @Override public NormalizedNode getUpdatedSubtree() { + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void testDataChangedWhenNotificationsAreEnabled(){ + new JavaTestKit(getSystem()) {{ + final AsyncDataChangeEvent mockChangeEvent = Mockito.mock(AsyncDataChangeEvent.class); + final AsyncDataChangeListener mockListener = Mockito.mock(AsyncDataChangeListener.class); + final Props props = DataChangeListener.props(mockListener); + final ActorRef subject = getSystem().actorOf(props, "testDataChangedNotificationsEnabled"); - //fixme: need to have some valid data here - return originalData.put(CompositeModel.FAMILY_PATH, CompositeModel.createFamily()); - } - } + // Let the DataChangeListener know that notifications should be enabled + subject.tell(new EnableNotification(true), getRef()); - private class MockDataChangeListener implements AsyncDataChangeListener> { - private boolean gotIt = false; - private AsyncDataChangeEvent> change; + subject.tell(new DataChanged(CompositeModel.createTestContext(), mockChangeEvent), + getRef()); - @Override public void onDataChanged( - AsyncDataChangeEvent> change) { - gotIt = true;this.change=change; - } + expectMsgClass(DataChangedReply.class); - public boolean gotIt() { - return gotIt; - } - public AsyncDataChangeEvent> getChange(){ - return change; - } + Mockito.verify(mockListener).onDataChanged(mockChangeEvent); + }}; } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Test - public void testDataChangedWhenNotificationsAreEnabled(){ + public void testDataChangedWhenNotificationsAreDisabled(){ new JavaTestKit(getSystem()) {{ - final MockDataChangeListener listener = new MockDataChangeListener(); - final Props props = DataChangeListener.props(listener); + final AsyncDataChangeEvent mockChangeEvent = Mockito.mock(AsyncDataChangeEvent.class); + final AsyncDataChangeListener mockListener = Mockito.mock(AsyncDataChangeListener.class); + final Props props = DataChangeListener.props(mockListener); final ActorRef subject = - getSystem().actorOf(props, "testDataChangedNotificationsEnabled"); + getSystem().actorOf(props, "testDataChangedNotificationsDisabled"); + + subject.tell(new DataChanged(CompositeModel.createTestContext(), mockChangeEvent), + getRef()); new Within(duration("1 seconds")) { @Override protected void run() { - - // Let the DataChangeListener know that notifications should - // be enabled - subject.tell(new EnableNotification(true), getRef()); - - subject.tell( - new DataChanged(CompositeModel.createTestContext(),new MockDataChangedEvent()), - getRef()); - - final Boolean out = new ExpectMsg(duration("800 millis"), "dataChanged") { - // do not put code outside this method, will run afterwards - @Override - protected Boolean match(Object in) { - if (in != null && in.getClass().equals(DataChangedReply.class)) { - - return true; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertTrue(out); - assertTrue(listener.gotIt()); - assertNotNull(listener.getChange().getCreatedData()); - expectNoMsg(); + + Mockito.verify(mockListener, Mockito.never()).onDataChanged( + Mockito.any(AsyncDataChangeEvent.class)); } }; }}; } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Test - public void testDataChangedWhenNotificationsAreDisabled(){ + public void testDataChangedWithNoSender(){ new JavaTestKit(getSystem()) {{ - final MockDataChangeListener listener = new MockDataChangeListener(); - final Props props = DataChangeListener.props(listener); - final ActorRef subject = - getSystem().actorOf(props, "testDataChangedNotificationsDisabled"); + final AsyncDataChangeEvent mockChangeEvent = Mockito.mock(AsyncDataChangeEvent.class); + final AsyncDataChangeListener mockListener = Mockito.mock(AsyncDataChangeListener.class); + final Props props = DataChangeListener.props(mockListener); + final ActorRef subject = getSystem().actorOf(props, "testDataChangedWithNoSender"); + // Let the DataChangeListener know that notifications should be enabled + subject.tell(new EnableNotification(true), ActorRef.noSender()); + + subject.tell(new DataChanged(CompositeModel.createTestContext(), mockChangeEvent), + ActorRef.noSender()); + + getSystem().eventStream().subscribe(getRef(), DeadLetter.class); new Within(duration("1 seconds")) { @Override protected void run() { - - subject.tell( - new DataChanged(CompositeModel.createTestContext(),new MockDataChangedEvent()), - getRef()); - expectNoMsg(); } }; diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreIntegrationTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreIntegrationTest.java index ec8aee2b09..395021d361 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreIntegrationTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreIntegrationTest.java @@ -1,17 +1,12 @@ package org.opendaylight.controller.cluster.datastore; +import akka.actor.ActorRef; import akka.actor.ActorSystem; -import akka.event.Logging; -import akka.testkit.JavaTestKit; - +import akka.actor.PoisonPill; import com.google.common.base.Optional; -import com.google.common.util.concurrent.ListenableFuture; - -import junit.framework.Assert; - -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Before; +import com.google.common.util.concurrent.Uninterruptibles; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import org.junit.Test; import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory; import org.opendaylight.controller.cluster.datastore.utils.MockClusterWrapper; @@ -19,292 +14,268 @@ import org.opendaylight.controller.md.cluster.datastore.model.CarsModel; import org.opendaylight.controller.md.cluster.datastore.model.PeopleModel; import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper; import org.opendaylight.controller.md.cluster.datastore.model.TestModel; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; - -import java.io.File; -import java.io.IOException; -import java.util.concurrent.ExecutionException; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertTrue; -import static junit.framework.Assert.fail; +public class DistributedDataStoreIntegrationTest extends AbstractActorTest { -public class DistributedDataStoreIntegrationTest { + @Test + public void testWriteTransactionWithSingleShard() throws Exception{ + System.setProperty("shard.persistent", "true"); + new IntegrationTestKit(getSystem()) {{ + DistributedDataStore dataStore = + setupDistributedDataStore("transactionIntegrationTest", "test-1"); - private static ActorSystem system; + testWriteTransaction(dataStore, TestModel.TEST_PATH, + ImmutableNodes.containerNode(TestModel.TEST_QNAME)); - @Before - public void setUp() throws IOException { - File journal = new File("journal"); + testWriteTransaction(dataStore, TestModel.OUTER_LIST_PATH, + ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build()); - if(journal.exists()) { - FileUtils.deleteDirectory(journal); - } + cleanup(dataStore); + }}; + } + @Test + public void testWriteTransactionWithMultipleShards() throws Exception{ + System.setProperty("shard.persistent", "true"); + new IntegrationTestKit(getSystem()) {{ + DistributedDataStore dataStore = + setupDistributedDataStore("testWriteTransactionWithMultipleShards", "cars-1", "people-1"); - System.setProperty("shard.persistent", "false"); - system = ActorSystem.create("test"); - } + DOMStoreWriteTransaction writeTx = dataStore.newWriteOnlyTransaction(); + assertNotNull("newWriteOnlyTransaction returned null", writeTx); - @After - public void tearDown() { - JavaTestKit.shutdownActorSystem(system); - system = null; - } + YangInstanceIdentifier nodePath1 = CarsModel.BASE_PATH; + NormalizedNode nodeToWrite1 = CarsModel.emptyContainer(); + writeTx.write(nodePath1, nodeToWrite1); - protected ActorSystem getSystem() { - return system; - } + YangInstanceIdentifier nodePath2 = PeopleModel.BASE_PATH; + NormalizedNode nodeToWrite2 = PeopleModel.emptyContainer(); + writeTx.write(nodePath2, nodeToWrite2); - @Test - public void integrationTest() throws Exception { - final Configuration configuration = new ConfigurationImpl("module-shards.conf", "modules.conf"); - ShardStrategyFactory.setConfiguration(configuration); + DOMStoreThreePhaseCommitCohort cohort = writeTx.ready(); + Boolean canCommit = cohort.canCommit().get(5, TimeUnit.SECONDS); + assertEquals("canCommit", true, canCommit); + cohort.preCommit().get(5, TimeUnit.SECONDS); + cohort.commit().get(5, TimeUnit.SECONDS); + // 5. Verify the data in the store - new JavaTestKit(getSystem()) { - { + DOMStoreReadTransaction readTx = dataStore.newReadOnlyTransaction(); - new Within(duration("10 seconds")) { - @Override - protected void run() { - try { - final DistributedDataStore distributedDataStore = - new DistributedDataStore(getSystem(), "config", - new MockClusterWrapper(), configuration, - new DatastoreContext()); + Optional> optional = readTx.read(nodePath1).get(); + assertEquals("isPresent", true, optional.isPresent()); + assertEquals("Data node", nodeToWrite1, optional.get()); - distributedDataStore.onGlobalContextUpdated(TestModel.createTestContext()); + optional = readTx.read(nodePath2).get(); + assertEquals("isPresent", true, optional.isPresent()); + assertEquals("Data node", nodeToWrite2, optional.get()); - // Wait for a specific log message to show up - final boolean result = - new JavaTestKit.EventFilter(Logging.Info.class - ) { - @Override - protected Boolean run() { - return true; - } - }.from("akka://test/user/shardmanager-config/member-1-shard-test-1-config") - .message("Switching from state Candidate to Leader") - .occurrences(1).exec(); + cleanup(dataStore); + }}; + } - assertEquals(true, result); + @Test + public void testReadWriteTransaction() throws Exception{ + System.setProperty("shard.persistent", "true"); + new IntegrationTestKit(getSystem()) {{ + DistributedDataStore dataStore = + setupDistributedDataStore("testReadWriteTransaction", "test-1"); - DOMStoreReadWriteTransaction transaction = - distributedDataStore.newReadWriteTransaction(); + // 1. Create a read-write Tx - transaction - .write(TestModel.TEST_PATH, ImmutableNodes - .containerNode(TestModel.TEST_QNAME)); + DOMStoreReadWriteTransaction readWriteTx = dataStore.newReadWriteTransaction(); + assertNotNull("newReadWriteTransaction returned null", readWriteTx); - ListenableFuture>> - future = - transaction.read(TestModel.TEST_PATH); + // 2. Write some data - Optional> optional = - future.get(); + YangInstanceIdentifier nodePath = TestModel.TEST_PATH; + NormalizedNode nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME); + readWriteTx.write(nodePath, nodeToWrite ); - Assert.assertTrue("Node not found", optional.isPresent()); + // 3. Read the data from Tx - NormalizedNode normalizedNode = - optional.get(); + Boolean exists = readWriteTx.exists(nodePath).checkedGet(5, TimeUnit.SECONDS); + assertEquals("exists", true, exists); - assertEquals(TestModel.TEST_QNAME, - normalizedNode.getNodeType()); + Optional> optional = readWriteTx.read(nodePath).get(5, TimeUnit.SECONDS); + assertEquals("isPresent", true, optional.isPresent()); + assertEquals("Data node", nodeToWrite, optional.get()); - DOMStoreThreePhaseCommitCohort ready = - transaction.ready(); + // 4. Ready the Tx for commit - ListenableFuture canCommit = - ready.canCommit(); + DOMStoreThreePhaseCommitCohort cohort = readWriteTx.ready(); - assertTrue(canCommit.get(5, TimeUnit.SECONDS)); + // 5. Commit the Tx - ListenableFuture preCommit = - ready.preCommit(); + Boolean canCommit = cohort.canCommit().get(5, TimeUnit.SECONDS); + assertEquals("canCommit", true, canCommit); + cohort.preCommit().get(5, TimeUnit.SECONDS); + cohort.commit().get(5, TimeUnit.SECONDS); - preCommit.get(5, TimeUnit.SECONDS); + // 6. Verify the data in the store - ListenableFuture commit = ready.commit(); + DOMStoreReadTransaction readTx = dataStore.newReadOnlyTransaction(); - commit.get(5, TimeUnit.SECONDS); - } catch (ExecutionException | TimeoutException | InterruptedException e){ - fail(e.getMessage()); - } - } - }; - } - }; + optional = readTx.read(nodePath).get(5, TimeUnit.SECONDS); + assertEquals("isPresent", true, optional.isPresent()); + assertEquals("Data node", nodeToWrite, optional.get()); + cleanup(dataStore); + }}; } @Test - public void transactionChainIntegrationTest() throws Exception { - final Configuration configuration = new ConfigurationImpl("module-shards.conf", "modules.conf"); - ShardStrategyFactory.setConfiguration(configuration); + public void testTransactionAbort() throws Exception{ + System.setProperty("shard.persistent", "true"); + new IntegrationTestKit(getSystem()) {{ + DistributedDataStore dataStore = + setupDistributedDataStore("transactionAbortIntegrationTest", "test-1"); + DOMStoreWriteTransaction writeTx = dataStore.newWriteOnlyTransaction(); + assertNotNull("newWriteOnlyTransaction returned null", writeTx); + writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); - new JavaTestKit(getSystem()) { - { + DOMStoreThreePhaseCommitCohort cohort = writeTx.ready(); - new Within(duration("10 seconds")) { - @Override - protected void run() { - try { - final DistributedDataStore distributedDataStore = - new DistributedDataStore(getSystem(), "config", - new MockClusterWrapper(), configuration, - new DatastoreContext()); + cohort.canCommit().get(5, TimeUnit.SECONDS); - distributedDataStore.onGlobalContextUpdated(TestModel.createTestContext()); + cohort.abort().get(5, TimeUnit.SECONDS); - // Wait for a specific log message to show up - final boolean result = - new JavaTestKit.EventFilter(Logging.Info.class - ) { - @Override - protected Boolean run() { - return true; - } - }.from("akka://test/user/shardmanager-config/member-1-shard-test-1-config") - .message("Switching from state Candidate to Leader") - .occurrences(1).exec(); + testWriteTransaction(dataStore, TestModel.TEST_PATH, + ImmutableNodes.containerNode(TestModel.TEST_QNAME)); - assertEquals(true, result); - - DOMStoreTransactionChain transactionChain = - distributedDataStore.createTransactionChain(); - - DOMStoreReadWriteTransaction transaction = - transactionChain.newReadWriteTransaction(); + cleanup(dataStore); + }}; + } - transaction - .write(TestModel.TEST_PATH, ImmutableNodes - .containerNode(TestModel.TEST_QNAME)); + @Test + public void testTransactionChain() throws Exception{ + System.setProperty("shard.persistent", "true"); + new IntegrationTestKit(getSystem()) {{ + DistributedDataStore dataStore = + setupDistributedDataStore("transactionChainIntegrationTest", "test-1"); - ListenableFuture>> - future = - transaction.read(TestModel.TEST_PATH); + // 1. Create a Tx chain and write-only Tx - Optional> optional = - future.get(); + DOMStoreTransactionChain txChain = dataStore.createTransactionChain(); - Assert.assertTrue("Node not found", optional.isPresent()); + DOMStoreWriteTransaction writeTx = txChain.newWriteOnlyTransaction(); + assertNotNull("newWriteOnlyTransaction returned null", writeTx); - NormalizedNode normalizedNode = - optional.get(); + // 2. Write some data - assertEquals(TestModel.TEST_QNAME, - normalizedNode.getNodeType()); + NormalizedNode containerNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME); + writeTx.write(TestModel.TEST_PATH, containerNode); - DOMStoreThreePhaseCommitCohort ready = - transaction.ready(); + // 3. Ready the Tx for commit - ListenableFuture canCommit = - ready.canCommit(); + DOMStoreThreePhaseCommitCohort cohort = writeTx.ready(); - assertTrue(canCommit.get(5, TimeUnit.SECONDS)); + // 4. Commit the Tx - ListenableFuture preCommit = - ready.preCommit(); + Boolean canCommit = cohort.canCommit().get(5, TimeUnit.SECONDS); + assertEquals("canCommit", true, canCommit); + cohort.preCommit().get(5, TimeUnit.SECONDS); + cohort.commit().get(5, TimeUnit.SECONDS); - preCommit.get(5, TimeUnit.SECONDS); + // 5. Verify the data in the store - ListenableFuture commit = ready.commit(); + DOMStoreReadTransaction readTx = txChain.newReadOnlyTransaction(); - commit.get(5, TimeUnit.SECONDS); + Optional> optional = readTx.read(TestModel.TEST_PATH).get(5, TimeUnit.SECONDS); + assertEquals("isPresent", true, optional.isPresent()); + assertEquals("Data node", containerNode, optional.get()); - transactionChain.close(); - } catch (ExecutionException | TimeoutException | InterruptedException e){ - fail(e.getMessage()); - } - } - }; - } - }; + txChain.close(); + cleanup(dataStore); + }}; } + class IntegrationTestKit extends ShardTestKit { - //FIXME : Disabling test because it's flaky - //@Test - public void integrationTestWithMultiShardConfiguration() - throws ExecutionException, InterruptedException, TimeoutException { - final Configuration configuration = new ConfigurationImpl("module-shards.conf", "modules.conf"); - - ShardStrategyFactory.setConfiguration(configuration); - - new JavaTestKit(getSystem()) { - { + IntegrationTestKit(ActorSystem actorSystem) { + super(actorSystem); + } - new Within(duration("10 seconds")) { - @Override - protected void run() { - try { - final DistributedDataStore distributedDataStore = - new DistributedDataStore(getSystem(), "config", - new MockClusterWrapper(), configuration, null); + DistributedDataStore setupDistributedDataStore(String typeName, String... shardNames) { + MockClusterWrapper cluster = new MockClusterWrapper(); + Configuration config = new ConfigurationImpl("module-shards.conf", "modules.conf"); + ShardStrategyFactory.setConfiguration(config); + + DatastoreContext datastoreContext = DatastoreContext.newBuilder().build(); + DistributedDataStore dataStore = new DistributedDataStore(getSystem(), typeName, cluster, + config, datastoreContext); + + SchemaContext schemaContext = SchemaContextHelper.full(); + dataStore.onGlobalContextUpdated(schemaContext); + + for(String shardName: shardNames) { + ActorRef shard = null; + for(int i = 0; i < 20 * 5 && shard == null; i++) { + Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS); + Optional shardReply = dataStore.getActorContext().findLocalShard(shardName); + if(shardReply.isPresent()) { + shard = shardReply.get(); + } + } - distributedDataStore.onGlobalContextUpdated( - SchemaContextHelper.full()); + assertNotNull("Shard was not created", shard); - // Wait for a specific log message to show up - final boolean result = - new JavaTestKit.EventFilter( - Logging.Info.class - ) { - @Override - protected Boolean run() { - return true; - } - }.from( - "akka://test/user/shardmanager-config/member-1-shard-cars-1-config") - .message( - "Switching from state Candidate to Leader") - .occurrences(1) - .exec(); + System.out.println("!!!!!!shard: "+shard.path().toString()); + waitUntilLeader(shard); + } - Thread.sleep(1000); + return dataStore; + } + void testWriteTransaction(DistributedDataStore dataStore, YangInstanceIdentifier nodePath, + NormalizedNode nodeToWrite) throws Exception { - DOMStoreReadWriteTransaction transaction = - distributedDataStore.newReadWriteTransaction(); + // 1. Create a write-only Tx - transaction.write(CarsModel.BASE_PATH, CarsModel.emptyContainer()); - transaction.write(PeopleModel.BASE_PATH, PeopleModel.emptyContainer()); + DOMStoreWriteTransaction writeTx = dataStore.newWriteOnlyTransaction(); + assertNotNull("newWriteOnlyTransaction returned null", writeTx); - DOMStoreThreePhaseCommitCohort ready = transaction.ready(); + // 2. Write some data - ListenableFuture canCommit = ready.canCommit(); + writeTx.write(nodePath, nodeToWrite); - assertTrue(canCommit.get(5, TimeUnit.SECONDS)); + // 3. Ready the Tx for commit - ListenableFuture preCommit = ready.preCommit(); + DOMStoreThreePhaseCommitCohort cohort = writeTx.ready(); - preCommit.get(5, TimeUnit.SECONDS); + // 4. Commit the Tx - ListenableFuture commit = ready.commit(); + Boolean canCommit = cohort.canCommit().get(5, TimeUnit.SECONDS); + assertEquals("canCommit", true, canCommit); + cohort.preCommit().get(5, TimeUnit.SECONDS); + cohort.commit().get(5, TimeUnit.SECONDS); - commit.get(5, TimeUnit.SECONDS); + // 5. Verify the data in the store - assertEquals(true, result); - } catch(ExecutionException | TimeoutException | InterruptedException e){ - fail(e.getMessage()); - } - } - }; - } - }; + DOMStoreReadTransaction readTx = dataStore.newReadOnlyTransaction(); + Optional> optional = readTx.read(nodePath).get(5, TimeUnit.SECONDS); + assertEquals("isPresent", true, optional.isPresent()); + assertEquals("Data node", nodeToWrite, optional.get()); + } + void cleanup(DistributedDataStore dataStore) { + dataStore.getActorContext().getShardManager().tell(PoisonPill.getInstance(), null); + } } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java index 08c3ea9602..00243ea5d1 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java @@ -8,6 +8,7 @@ import akka.actor.Props; import akka.dispatch.ExecutionContexts; import akka.dispatch.Futures; import akka.util.Timeout; +import com.google.common.base.Optional; import com.google.common.util.concurrent.MoreExecutors; import org.junit.After; import org.junit.Before; @@ -33,9 +34,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import scala.concurrent.ExecutionContextExecutor; import scala.concurrent.Future; import scala.concurrent.duration.FiniteDuration; - import java.util.concurrent.TimeUnit; - import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertNull; import static org.junit.Assert.assertNotNull; @@ -87,7 +86,7 @@ public class DistributedDataStoreTest extends AbstractActorTest{ new DistributedDataStore(actorSystem, "config", mock(ClusterWrapper.class), mock(Configuration.class), - new DatastoreContext()); + DatastoreContext.newBuilder().build()); verify(actorSystem).actorOf(any(Props.class), eq("shardmanager-config")); } @@ -97,11 +96,11 @@ public class DistributedDataStoreTest extends AbstractActorTest{ ListenerRegistration registration = distributedDataStore.registerChangeListener(TestModel.TEST_PATH, new AsyncDataChangeListener>() { - @Override - public void onDataChanged(AsyncDataChangeEvent> change) { - throw new UnsupportedOperationException("onDataChanged"); - } - }, AsyncDataBroker.DataChangeScope.BASE); + @Override + public void onDataChanged(AsyncDataChangeEvent> change) { + throw new UnsupportedOperationException("onDataChanged"); + } + }, AsyncDataBroker.DataChangeScope.BASE); // Since we do not expect the shard to be local registration will return a NoOpRegistration assertTrue(registration instanceof NoOpDataChangeListenerRegistration); @@ -119,8 +118,9 @@ public class DistributedDataStoreTest extends AbstractActorTest{ Future future = mock(Future.class); when(actorContext.getOperationDuration()).thenReturn(FiniteDuration.apply(5, TimeUnit.SECONDS)); when(actorContext.getActorSystem()).thenReturn(getSystem()); + when(actorContext.findLocalShard(anyString())).thenReturn(Optional.of(doNothingActorRef)); when(actorContext - .executeLocalShardOperationAsync(anyString(), anyObject(), any(Timeout.class))).thenReturn(future); + .executeOperationAsync(eq(doNothingActorRef), anyObject(), any(Timeout.class))).thenReturn(future); ListenerRegistration registration = distributedDataStore.registerChangeListener(TestModel.TEST_PATH, @@ -153,8 +153,9 @@ public class DistributedDataStoreTest extends AbstractActorTest{ when(actorSystem.dispatcher()).thenReturn(executor); when(actorSystem.actorOf(any(Props.class))).thenReturn(doNothingActorRef); when(actorContext.getActorSystem()).thenReturn(actorSystem); + when(actorContext.findLocalShard(anyString())).thenReturn(Optional.of(doNothingActorRef)); when(actorContext - .executeLocalShardOperationAsync(anyString(), anyObject(), any(Timeout.class))).thenReturn(f); + .executeOperationAsync(eq(doNothingActorRef), anyObject(), any(Timeout.class))).thenReturn(f); when(actorContext.actorSelection(any(ActorPath.class))).thenReturn(actorSelection); ListenerRegistration registration = @@ -195,8 +196,9 @@ public class DistributedDataStoreTest extends AbstractActorTest{ when(actorSystem.dispatcher()).thenReturn(executor); when(actorSystem.actorOf(any(Props.class))).thenReturn(doNothingActorRef); when(actorContext.getActorSystem()).thenReturn(actorSystem); + when(actorContext.findLocalShard(anyString())).thenReturn(Optional.of(doNothingActorRef)); when(actorContext - .executeLocalShardOperationAsync(anyString(), anyObject(), any(Timeout.class))).thenReturn(f); + .executeOperationAsync(eq(doNothingActorRef), anyObject(), any(Timeout.class))).thenReturn(f); when(actorContext.actorSelection(any(ActorPath.class))).thenReturn(actorSelection); ListenerRegistration registration = diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardManagerTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardManagerTest.java index 02201f7cd1..5022d97997 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardManagerTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardManagerTest.java @@ -1,14 +1,20 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; +import akka.persistence.RecoveryCompleted; import akka.testkit.JavaTestKit; import akka.testkit.TestActorRef; -import junit.framework.Assert; -import org.junit.AfterClass; -import org.junit.BeforeClass; +import akka.japi.Creator; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Uninterruptibles; +import org.junit.After; +import org.junit.Before; import org.junit.Test; +import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier; +import org.opendaylight.controller.cluster.datastore.messages.ActorInitialized; +import org.opendaylight.controller.cluster.datastore.messages.ActorNotInitialized; import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard; import org.opendaylight.controller.cluster.datastore.messages.FindPrimary; import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound; @@ -16,226 +22,328 @@ import org.opendaylight.controller.cluster.datastore.messages.LocalShardNotFound import org.opendaylight.controller.cluster.datastore.messages.PrimaryFound; import org.opendaylight.controller.cluster.datastore.messages.PrimaryNotFound; import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext; +import org.opendaylight.controller.cluster.datastore.utils.DoNothingActor; +import org.opendaylight.controller.cluster.datastore.utils.InMemoryJournal; import org.opendaylight.controller.cluster.datastore.utils.MockClusterWrapper; import org.opendaylight.controller.cluster.datastore.utils.MockConfiguration; import org.opendaylight.controller.md.cluster.datastore.model.TestModel; -import scala.concurrent.duration.Duration; - -import static junit.framework.Assert.assertEquals; +import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import java.net.URI; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ShardManagerTest extends AbstractActorTest { + private static int ID_COUNTER = 1; + + private final String shardMrgIDSuffix = "config" + ID_COUNTER++; + private final String shardMgrID = "shard-manager-" + shardMrgIDSuffix; + + private static ActorRef mockShardActor; + + @Before + public void setUp() { + InMemoryJournal.clear(); -public class ShardManagerTest { - private static ActorSystem system; + if(mockShardActor == null) { + String name = new ShardIdentifier(Shard.DEFAULT_NAME, "member-1","config").toString(); + mockShardActor = getSystem().actorOf(Props.create(DoNothingActor.class), name); + } + } - @BeforeClass - public static void setUp() { - system = ActorSystem.create("test"); + @After + public void tearDown() { + InMemoryJournal.clear(); } - @AfterClass - public static void tearDown() { - JavaTestKit.shutdownActorSystem(system); - system = null; + private Props newShardMgrProps() { + return ShardManager.props(shardMrgIDSuffix, new MockClusterWrapper(), new MockConfiguration(), + DatastoreContext.newBuilder().build()); } @Test public void testOnReceiveFindPrimaryForNonExistentShard() throws Exception { + new JavaTestKit(getSystem()) {{ + final ActorRef shardManager = getSystem().actorOf(newShardMgrProps()); - new JavaTestKit(system) {{ - final Props props = ShardManager - .props("config", new MockClusterWrapper(), - new MockConfiguration(), new DatastoreContext()); - final TestActorRef subject = - TestActorRef.create(system, props); - - new Within(duration("10 seconds")) { - @Override - protected void run() { - - subject.tell(new FindPrimary("inventory").toSerializable(), getRef()); + shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef()); - expectMsgEquals(Duration.Zero(), - new PrimaryNotFound("inventory").toSerializable()); + shardManager.tell(new FindPrimary("non-existent").toSerializable(), getRef()); - expectNoMsg(); - } - }; + expectMsgEquals(duration("5 seconds"), + new PrimaryNotFound("non-existent").toSerializable()); }}; } @Test public void testOnReceiveFindPrimaryForExistentShard() throws Exception { + new JavaTestKit(getSystem()) {{ + final ActorRef shardManager = getSystem().actorOf(newShardMgrProps()); - new JavaTestKit(system) {{ - final Props props = ShardManager - .props("config", new MockClusterWrapper(), - new MockConfiguration(), new DatastoreContext()); - final TestActorRef subject = - TestActorRef.create(system, props); + shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef()); + shardManager.tell(new ActorInitialized(), mockShardActor); - subject.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef()); + shardManager.tell(new FindPrimary(Shard.DEFAULT_NAME).toSerializable(), getRef()); - new Within(duration("10 seconds")) { - @Override - protected void run() { + expectMsgClass(duration("5 seconds"), PrimaryFound.SERIALIZABLE_CLASS); + }}; + } - subject.tell(new FindPrimary(Shard.DEFAULT_NAME).toSerializable(), getRef()); + @Test + public void testOnReceiveFindPrimaryForNotInitialzedShard() throws Exception { + new JavaTestKit(getSystem()) {{ + final ActorRef shardManager = getSystem().actorOf(newShardMgrProps()); - expectMsgClass(duration("1 seconds"), PrimaryFound.SERIALIZABLE_CLASS); + shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef()); - expectNoMsg(); - } - }; + shardManager.tell(new FindPrimary(Shard.DEFAULT_NAME).toSerializable(), getRef()); + + expectMsgClass(duration("5 seconds"), ActorNotInitialized.class); }}; } @Test public void testOnReceiveFindLocalShardForNonExistentShard() throws Exception { + new JavaTestKit(getSystem()) {{ + final ActorRef shardManager = getSystem().actorOf(newShardMgrProps()); - new JavaTestKit(system) {{ - final Props props = ShardManager - .props("config", new MockClusterWrapper(), - new MockConfiguration(), new DatastoreContext()); - final TestActorRef subject = - TestActorRef.create(system, props); - - new Within(duration("10 seconds")) { - @Override - protected void run() { - - subject.tell(new FindLocalShard("inventory"), getRef()); - - final String out = new ExpectMsg(duration("10 seconds"), "find local") { - @Override - protected String match(Object in) { - if (in instanceof LocalShardNotFound) { - return ((LocalShardNotFound) in).getShardName(); - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertEquals("inventory", out); - - expectNoMsg(); - } - }; + shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef()); + + shardManager.tell(new FindLocalShard("non-existent"), getRef()); + + LocalShardNotFound notFound = expectMsgClass(duration("5 seconds"), LocalShardNotFound.class); + + assertEquals("getShardName", "non-existent", notFound.getShardName()); }}; } @Test public void testOnReceiveFindLocalShardForExistentShard() throws Exception { + new JavaTestKit(getSystem()) {{ + final ActorRef shardManager = getSystem().actorOf(newShardMgrProps()); - final MockClusterWrapper mockClusterWrapper = new MockClusterWrapper(); - - new JavaTestKit(system) {{ - final Props props = ShardManager - .props("config", mockClusterWrapper, - new MockConfiguration(), new DatastoreContext()); - final TestActorRef subject = - TestActorRef.create(system, props); + shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef()); + shardManager.tell(new ActorInitialized(), mockShardActor); - subject.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef()); + shardManager.tell(new FindLocalShard(Shard.DEFAULT_NAME), getRef()); - new Within(duration("10 seconds")) { - @Override - protected void run() { + LocalShardFound found = expectMsgClass(duration("5 seconds"), LocalShardFound.class); - subject.tell(new FindLocalShard(Shard.DEFAULT_NAME), getRef()); + assertTrue("Found path contains " + found.getPath().path().toString(), + found.getPath().path().toString().contains("member-1-shard-default-config")); + }}; + } - final ActorRef out = new ExpectMsg(duration("10 seconds"), "find local") { - @Override - protected ActorRef match(Object in) { - if (in instanceof LocalShardFound) { - return ((LocalShardFound) in).getPath(); - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message + @Test + public void testOnReceiveFindLocalShardForNotInitializedShard() throws Exception { + new JavaTestKit(getSystem()) {{ + final ActorRef shardManager = getSystem().actorOf(newShardMgrProps()); - assertTrue(out.path().toString(), out.path().toString().contains("member-1-shard-default-config")); + shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef()); + //shardManager.tell(new ActorInitialized(), mockShardActor); + shardManager.tell(new FindLocalShard(Shard.DEFAULT_NAME), getRef()); - expectNoMsg(); - } - }; + expectMsgClass(duration("5 seconds"), ActorNotInitialized.class); }}; } @Test public void testOnReceiveMemberUp() throws Exception { + new JavaTestKit(getSystem()) {{ + final ActorRef shardManager = getSystem().actorOf(newShardMgrProps()); - new JavaTestKit(system) {{ - final Props props = ShardManager - .props("config", new MockClusterWrapper(), - new MockConfiguration(), new DatastoreContext()); - final TestActorRef subject = - TestActorRef.create(system, props); - - // the run() method needs to finish within 3 seconds - new Within(duration("10 seconds")) { - @Override - protected void run() { - - MockClusterWrapper.sendMemberUp(subject, "member-2", getRef().path().toString()); - - subject.tell(new FindPrimary("astronauts").toSerializable(), getRef()); - - final String out = new ExpectMsg(duration("1 seconds"), "primary found") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - if (in.getClass().equals(PrimaryFound.SERIALIZABLE_CLASS)) { - PrimaryFound f = PrimaryFound.fromSerializable(in); - return f.getPrimaryPath(); - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - Assert.assertTrue(out, out.contains("member-2-shard-astronauts-config")); - - expectNoMsg(); - } - }; + MockClusterWrapper.sendMemberUp(shardManager, "member-2", getRef().path().toString()); + + shardManager.tell(new FindPrimary("astronauts").toSerializable(), getRef()); + + PrimaryFound found = PrimaryFound.fromSerializable(expectMsgClass(duration("5 seconds"), + PrimaryFound.SERIALIZABLE_CLASS)); + String path = found.getPrimaryPath(); + assertTrue("Found path contains " + path, path.contains("member-2-shard-astronauts-config")); }}; } @Test public void testOnReceiveMemberDown() throws Exception { - new JavaTestKit(system) {{ - final Props props = ShardManager - .props("config", new MockClusterWrapper(), - new MockConfiguration(), new DatastoreContext()); - final TestActorRef subject = - TestActorRef.create(system, props); + new JavaTestKit(getSystem()) {{ + final ActorRef shardManager = getSystem().actorOf(newShardMgrProps()); - // the run() method needs to finish within 3 seconds - new Within(duration("10 seconds")) { - @Override - protected void run() { + MockClusterWrapper.sendMemberUp(shardManager, "member-2", getRef().path().toString()); - MockClusterWrapper.sendMemberUp(subject, "member-2", getRef().path().toString()); + shardManager.tell(new FindPrimary("astronauts").toSerializable(), getRef()); - subject.tell(new FindPrimary("astronauts").toSerializable(), getRef()); + expectMsgClass(duration("5 seconds"), PrimaryFound.SERIALIZABLE_CLASS); - expectMsgClass(duration("1 seconds"), PrimaryFound.SERIALIZABLE_CLASS); + MockClusterWrapper.sendMemberRemoved(shardManager, "member-2", getRef().path().toString()); - MockClusterWrapper.sendMemberRemoved(subject, "member-2", getRef().path().toString()); + shardManager.tell(new FindPrimary("astronauts").toSerializable(), getRef()); - subject.tell(new FindPrimary("astronauts").toSerializable(), getRef()); + expectMsgClass(duration("5 seconds"), PrimaryNotFound.SERIALIZABLE_CLASS); + }}; + } - expectMsgClass(duration("1 seconds"), PrimaryNotFound.SERIALIZABLE_CLASS); + @Test + public void testOnRecoveryJournalIsCleaned() { + InMemoryJournal.addEntry(shardMgrID, 1L, new ShardManager.SchemaContextModules( + ImmutableSet.of("foo"))); + InMemoryJournal.addEntry(shardMgrID, 2L, new ShardManager.SchemaContextModules( + ImmutableSet.of("bar"))); + InMemoryJournal.addDeleteMessagesCompleteLatch(shardMgrID); + + new JavaTestKit(getSystem()) {{ + TestActorRef shardManager = TestActorRef.create(getSystem(), + Props.create(new TestShardManagerCreator(shardMrgIDSuffix))); + + shardManager.underlyingActor().waitForRecoveryComplete(); + InMemoryJournal.waitForDeleteMessagesComplete(shardMgrID); + + // Journal entries up to the last one should've been deleted + Map journal = InMemoryJournal.get(shardMgrID); + synchronized (journal) { + assertEquals("Journal size", 1, journal.size()); + assertEquals("Journal entry seq #", Long.valueOf(2), journal.keySet().iterator().next()); + } + }}; + } - expectNoMsg(); - } - }; + @Test + public void testOnRecoveryPreviouslyKnownModulesAreDiscovered() throws Exception { + final ImmutableSet persistedModules = ImmutableSet.of("foo", "bar"); + InMemoryJournal.addEntry(shardMgrID, 1L, new ShardManager.SchemaContextModules( + persistedModules)); + new JavaTestKit(getSystem()) {{ + TestActorRef shardManager = TestActorRef.create(getSystem(), + Props.create(new TestShardManagerCreator(shardMrgIDSuffix))); + + shardManager.underlyingActor().waitForRecoveryComplete(); + + Collection knownModules = shardManager.underlyingActor().getKnownModules(); + + assertEquals("getKnownModules", persistedModules, Sets.newHashSet(knownModules)); }}; } + @Test + public void testOnUpdateSchemaContextUpdateKnownModulesIfTheyContainASuperSetOfTheKnownModules() + throws Exception { + new JavaTestKit(getSystem()) {{ + final TestActorRef shardManager = + TestActorRef.create(getSystem(), newShardMgrProps()); + + assertEquals("getKnownModules size", 0, shardManager.underlyingActor().getKnownModules().size()); + ModuleIdentifier foo = mock(ModuleIdentifier.class); + when(foo.getNamespace()).thenReturn(new URI("foo")); + + Set moduleIdentifierSet = new HashSet<>(); + moduleIdentifierSet.add(foo); + + SchemaContext schemaContext = mock(SchemaContext.class); + when(schemaContext.getAllModuleIdentifiers()).thenReturn(moduleIdentifierSet); + + shardManager.underlyingActor().onReceiveCommand(new UpdateSchemaContext(schemaContext)); + + assertEquals("getKnownModules", Sets.newHashSet("foo"), + Sets.newHashSet(shardManager.underlyingActor().getKnownModules())); + + ModuleIdentifier bar = mock(ModuleIdentifier.class); + when(bar.getNamespace()).thenReturn(new URI("bar")); + + moduleIdentifierSet.add(bar); + + shardManager.underlyingActor().onReceiveCommand(new UpdateSchemaContext(schemaContext)); + + assertEquals("getKnownModules", Sets.newHashSet("foo", "bar"), + Sets.newHashSet(shardManager.underlyingActor().getKnownModules())); + }}; + } + + @Test + public void testOnUpdateSchemaContextDoNotUpdateKnownModulesIfTheyDoNotContainASuperSetOfKnownModules() + throws Exception { + new JavaTestKit(getSystem()) {{ + final TestActorRef shardManager = + TestActorRef.create(getSystem(), newShardMgrProps()); + + SchemaContext schemaContext = mock(SchemaContext.class); + Set moduleIdentifierSet = new HashSet<>(); + + ModuleIdentifier foo = mock(ModuleIdentifier.class); + when(foo.getNamespace()).thenReturn(new URI("foo")); + + moduleIdentifierSet.add(foo); + + when(schemaContext.getAllModuleIdentifiers()).thenReturn(moduleIdentifierSet); + + shardManager.underlyingActor().onReceiveCommand(new UpdateSchemaContext(schemaContext)); + + assertEquals("getKnownModules", Sets.newHashSet("foo"), + Sets.newHashSet(shardManager.underlyingActor().getKnownModules())); + + //Create a completely different SchemaContext with only the bar module in it + //schemaContext = mock(SchemaContext.class); + moduleIdentifierSet.clear(); + ModuleIdentifier bar = mock(ModuleIdentifier.class); + when(bar.getNamespace()).thenReturn(new URI("bar")); + + moduleIdentifierSet.add(bar); + + shardManager.underlyingActor().onReceiveCommand(new UpdateSchemaContext(schemaContext)); + + assertEquals("getKnownModules", Sets.newHashSet("foo"), + Sets.newHashSet(shardManager.underlyingActor().getKnownModules())); + + }}; + } + + + private static class TestShardManager extends ShardManager { + private final CountDownLatch recoveryComplete = new CountDownLatch(1); + + TestShardManager(String shardMrgIDSuffix) { + super(shardMrgIDSuffix, new MockClusterWrapper(), new MockConfiguration(), + DatastoreContext.newBuilder().build()); + } + + @Override + public void handleRecover(Object message) throws Exception { + try { + super.handleRecover(message); + } finally { + if(message instanceof RecoveryCompleted) { + recoveryComplete.countDown(); + } + } + } + + void waitForRecoveryComplete() { + assertEquals("Recovery complete", true, + Uninterruptibles.awaitUninterruptibly(recoveryComplete, 5, TimeUnit.SECONDS)); + } + } + + @SuppressWarnings("serial") + static class TestShardManagerCreator implements Creator { + String shardMrgIDSuffix; + + TestShardManagerCreator(String shardMrgIDSuffix) { + this.shardMrgIDSuffix = shardMrgIDSuffix; + } + + @Override + public TestShardManager create() throws Exception { + return new TestShardManager(shardMrgIDSuffix); + } + + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java index deb71c2df4..f183bb319e 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java @@ -1,26 +1,57 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; -import akka.event.Logging; +import akka.dispatch.Dispatchers; +import akka.dispatch.OnComplete; +import akka.japi.Creator; +import akka.pattern.Patterns; import akka.testkit.JavaTestKit; import akka.testkit.TestActorRef; +import akka.util.Timeout; +import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; -import org.junit.Assert; +import org.junit.After; +import org.junit.Before; import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier; +import org.opendaylight.controller.cluster.datastore.messages.AbortTransaction; +import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply; +import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction; +import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply; +import org.opendaylight.controller.cluster.datastore.messages.CommitTransaction; +import org.opendaylight.controller.cluster.datastore.messages.CommitTransactionReply; import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction; import org.opendaylight.controller.cluster.datastore.messages.EnableNotification; +import org.opendaylight.controller.cluster.datastore.messages.ForwardedReadyTransaction; import org.opendaylight.controller.cluster.datastore.messages.PeerAddressResolved; +import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply; import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener; import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply; import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext; +import org.opendaylight.controller.cluster.datastore.modification.MergeModification; +import org.opendaylight.controller.cluster.datastore.modification.Modification; +import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification; +import org.opendaylight.controller.cluster.datastore.modification.WriteModification; import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec; +import org.opendaylight.controller.cluster.datastore.utils.InMemoryJournal; +import org.opendaylight.controller.cluster.datastore.utils.InMemorySnapshotStore; +import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry; +import org.opendaylight.controller.cluster.raft.ReplicatedLogImplEntry; +import org.opendaylight.controller.cluster.raft.Snapshot; +import org.opendaylight.controller.cluster.raft.base.messages.ApplyLogEntries; +import org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot; +import org.opendaylight.controller.cluster.raft.base.messages.ApplyState; import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot; +import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationPayload; +import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload; import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper; import org.opendaylight.controller.md.cluster.datastore.model.TestModel; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; @@ -28,144 +59,158 @@ import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; +import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory; import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages.CreateTransactionReply; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; - +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.FiniteDuration; import java.io.IOException; import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; - +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.inOrder; public class ShardTest extends AbstractActorTest { - private static final DatastoreContext DATA_STORE_CONTEXT = new DatastoreContext(); + private static final SchemaContext SCHEMA_CONTEXT = TestModel.createTestContext(); + + private static final ShardIdentifier IDENTIFIER = ShardIdentifier.builder().memberName("member-1") + .shardName("inventory").type("config").build(); + + private static final AtomicInteger NEXT_SHARD_NUM = new AtomicInteger(); + + private static String shardName() { + return "shard" + NEXT_SHARD_NUM.getAndIncrement(); + } + + private DatastoreContext dataStoreContext = DatastoreContext.newBuilder(). + shardJournalRecoveryLogBatchSize(3).shardSnapshotBatchCount(5000).build(); + + @Before + public void setUp() { + System.setProperty("shard.persistent", "false"); + + InMemorySnapshotStore.clear(); + InMemoryJournal.clear(); + } + + @After + public void tearDown() { + InMemorySnapshotStore.clear(); + InMemoryJournal.clear(); + } + + private Props newShardProps() { + return Shard.props(IDENTIFIER, Collections.emptyMap(), + dataStoreContext, SCHEMA_CONTEXT); + } @Test public void testOnReceiveRegisterListener() throws Exception { new JavaTestKit(getSystem()) {{ - final ShardIdentifier identifier = - ShardIdentifier.builder().memberName("member-1") - .shardName("inventory").type("config").build(); + ActorRef subject = getSystem().actorOf(newShardProps(), "testRegisterChangeListener"); - final Props props = Shard.props(identifier, Collections.EMPTY_MAP, DATA_STORE_CONTEXT, TestModel.createTestContext()); - final ActorRef subject = - getSystem().actorOf(props, "testRegisterChangeListener"); + subject.tell(new UpdateSchemaContext(SchemaContextHelper.full()), getRef()); - new Within(duration("3 seconds")) { - @Override - protected void run() { + subject.tell(new RegisterChangeListener(TestModel.TEST_PATH, + getRef().path(), AsyncDataBroker.DataChangeScope.BASE), getRef()); - subject.tell( - new UpdateSchemaContext(SchemaContextHelper.full()), - getRef()); + EnableNotification enable = expectMsgClass(duration("3 seconds"), EnableNotification.class); + assertEquals("isEnabled", false, enable.isEnabled()); - subject.tell(new RegisterChangeListener(TestModel.TEST_PATH, - getRef().path(), AsyncDataBroker.DataChangeScope.BASE), - getRef()); + RegisterChangeListenerReply reply = expectMsgClass(duration("3 seconds"), + RegisterChangeListenerReply.class); + assertTrue(reply.getListenerRegistrationPath().toString().matches( + "akka:\\/\\/test\\/user\\/testRegisterChangeListener\\/\\$.*")); + }}; + } - final Boolean notificationEnabled = new ExpectMsg( - duration("3 seconds"), "enable notification") { - // do not put code outside this method, will run afterwards - @Override - protected Boolean match(Object in) { - if(in instanceof EnableNotification){ - return ((EnableNotification) in).isEnabled(); - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message + @Test + public void testCreateTransaction(){ + new ShardTestKit(getSystem()) {{ + ActorRef subject = getSystem().actorOf(newShardProps(), "testCreateTransaction"); - assertFalse(notificationEnabled); + waitUntilLeader(subject); - final String out = new ExpectMsg(duration("3 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - if (in.getClass().equals(RegisterChangeListenerReply.class)) { - RegisterChangeListenerReply reply = - (RegisterChangeListenerReply) in; - return reply.getListenerRegistrationPath() - .toString(); - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message + subject.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef()); - assertTrue(out.matches( - "akka:\\/\\/test\\/user\\/testRegisterChangeListener\\/\\$.*")); - } + subject.tell(new CreateTransaction("txn-1", + TransactionProxy.TransactionType.READ_ONLY.ordinal() ).toSerializable(), getRef()); + CreateTransactionReply reply = expectMsgClass(duration("3 seconds"), + CreateTransactionReply.class); - }; + String path = reply.getTransactionActorPath().toString(); + assertTrue("Unexpected transaction path " + path, + path.contains("akka://test/user/testCreateTransaction/shard-txn-1")); + expectNoMsg(); }}; } @Test - public void testCreateTransaction(){ + public void testCreateTransactionOnChain(){ + new ShardTestKit(getSystem()) {{ + final ActorRef subject = getSystem().actorOf(newShardProps(), "testCreateTransactionOnChain"); + + waitUntilLeader(subject); + + subject.tell(new CreateTransaction("txn-1", + TransactionProxy.TransactionType.READ_ONLY.ordinal() , "foobar").toSerializable(), + getRef()); + + CreateTransactionReply reply = expectMsgClass(duration("3 seconds"), + CreateTransactionReply.class); + + String path = reply.getTransactionActorPath().toString(); + assertTrue("Unexpected transaction path " + path, + path.contains("akka://test/user/testCreateTransactionOnChain/shard-txn-1")); + expectNoMsg(); + }}; + } + + @Test + public void testPeerAddressResolved(){ new JavaTestKit(getSystem()) {{ final ShardIdentifier identifier = ShardIdentifier.builder().memberName("member-1") .shardName("inventory").type("config").build(); - final Props props = Shard.props(identifier, Collections.EMPTY_MAP, DATA_STORE_CONTEXT, TestModel.createTestContext()); - final ActorRef subject = - getSystem().actorOf(props, "testCreateTransaction"); - - // Wait for a specific log message to show up - final boolean result = - new JavaTestKit.EventFilter(Logging.Info.class - ) { - @Override - protected Boolean run() { - return true; - } - }.from(subject.path().toString()) - .message("Switching from state Candidate to Leader") - .occurrences(1).exec(); - - Assert.assertEquals(true, result); + Props props = Shard.props(identifier, + Collections.singletonMap(identifier, null), + dataStoreContext, SCHEMA_CONTEXT); + final ActorRef subject = getSystem().actorOf(props, "testPeerAddressResolved"); new Within(duration("3 seconds")) { @Override protected void run() { subject.tell( - new UpdateSchemaContext(TestModel.createTestContext()), - getRef()); - - subject.tell(new CreateTransaction("txn-1", TransactionProxy.TransactionType.READ_ONLY.ordinal() ).toSerializable(), + new PeerAddressResolved(identifier, "akka://foobar"), getRef()); - final String out = new ExpectMsg(duration("3 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - if (in instanceof CreateTransactionReply) { - CreateTransactionReply reply = - (CreateTransactionReply) in; - return reply.getTransactionActorPath() - .toString(); - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertTrue("Unexpected transaction path " + out, - out.contains("akka://test/user/testCreateTransaction/shard-txn-1")); expectNoMsg(); } }; @@ -173,187 +218,838 @@ public class ShardTest extends AbstractActorTest { } @Test - public void testCreateTransactionOnChain(){ - new JavaTestKit(getSystem()) {{ - final ShardIdentifier identifier = - ShardIdentifier.builder().memberName("member-1") - .shardName("inventory").type("config").build(); + public void testApplySnapshot() throws ExecutionException, InterruptedException { + TestActorRef ref = TestActorRef.create(getSystem(), newShardProps()); + + NormalizedNodeToNodeCodec codec = + new NormalizedNodeToNodeCodec(SCHEMA_CONTEXT); + + writeToStore(ref, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); + + YangInstanceIdentifier root = YangInstanceIdentifier.builder().build(); + NormalizedNode expected = readStore(ref, root); + + NormalizedNodeMessages.Container encode = codec.encode(expected); + + ApplySnapshot applySnapshot = new ApplySnapshot(Snapshot.create( + encode.getNormalizedNode().toByteString().toByteArray(), + Collections.emptyList(), 1, 2, 3, 4)); + + ref.underlyingActor().onReceiveCommand(applySnapshot); + + NormalizedNode actual = readStore(ref, root); + + assertEquals(expected, actual); + } + + @Test + public void testApplyState() throws Exception { + + TestActorRef shard = TestActorRef.create(getSystem(), newShardProps()); + + NormalizedNode node = ImmutableNodes.containerNode(TestModel.TEST_QNAME); + + MutableCompositeModification compMod = new MutableCompositeModification(); + compMod.addModification(new WriteModification(TestModel.TEST_PATH, node, SCHEMA_CONTEXT)); + Payload payload = new CompositeModificationPayload(compMod.toSerializable()); + ApplyState applyState = new ApplyState(null, "test", + new ReplicatedLogImplEntry(1, 2, payload)); + + shard.underlyingActor().onReceiveCommand(applyState); + + NormalizedNode actual = readStore(shard, TestModel.TEST_PATH); + assertEquals("Applied state", node, actual); + } + + @SuppressWarnings("serial") + @Test + public void testRecovery() throws Exception { + + // Set up the InMemorySnapshotStore. + + InMemoryDOMDataStore testStore = InMemoryDOMDataStoreFactory.create("Test", null, null); + testStore.onGlobalContextUpdated(SCHEMA_CONTEXT); + + DOMStoreWriteTransaction writeTx = testStore.newWriteOnlyTransaction(); + writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); + DOMStoreThreePhaseCommitCohort commitCohort = writeTx.ready(); + commitCohort.preCommit().get(); + commitCohort.commit().get(); + + DOMStoreReadTransaction readTx = testStore.newReadOnlyTransaction(); + NormalizedNode root = readTx.read(YangInstanceIdentifier.builder().build()).get().get(); + + InMemorySnapshotStore.addSnapshot(IDENTIFIER.toString(), Snapshot.create( + new NormalizedNodeToNodeCodec(SCHEMA_CONTEXT).encode( + root). + getNormalizedNode().toByteString().toByteArray(), + Collections.emptyList(), 0, 1, -1, -1)); + + // Set up the InMemoryJournal. + + InMemoryJournal.addEntry(IDENTIFIER.toString(), 0, new ReplicatedLogImplEntry(0, 1, newPayload( + new WriteModification(TestModel.OUTER_LIST_PATH, + ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build(), + SCHEMA_CONTEXT)))); + + int nListEntries = 11; + Set listEntryKeys = new HashSet<>(); + for(int i = 1; i <= nListEntries; i++) { + listEntryKeys.add(Integer.valueOf(i)); + YangInstanceIdentifier path = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH) + .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, i).build(); + Modification mod = new MergeModification(path, + ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, i), + SCHEMA_CONTEXT); + InMemoryJournal.addEntry(IDENTIFIER.toString(), i, new ReplicatedLogImplEntry(i, 1, + newPayload(mod))); + } + + InMemoryJournal.addEntry(IDENTIFIER.toString(), nListEntries + 1, + new ApplyLogEntries(nListEntries)); - final Props props = Shard.props(identifier, Collections.EMPTY_MAP, DATA_STORE_CONTEXT, TestModel.createTestContext()); - final ActorRef subject = - getSystem().actorOf(props, "testCreateTransactionOnChain"); + // Create the actor and wait for recovery complete. - // Wait for a specific log message to show up - final boolean result = - new JavaTestKit.EventFilter(Logging.Info.class - ) { + final CountDownLatch recoveryComplete = new CountDownLatch(1); + + Creator creator = new Creator() { + @Override + public Shard create() throws Exception { + return new Shard(IDENTIFIER, Collections.emptyMap(), + dataStoreContext, SCHEMA_CONTEXT) { @Override - protected Boolean run() { - return true; + protected void onRecoveryComplete() { + try { + super.onRecoveryComplete(); + } finally { + recoveryComplete.countDown(); + } } - }.from(subject.path().toString()) - .message("Switching from state Candidate to Leader") - .occurrences(1).exec(); + }; + } + }; - Assert.assertEquals(true, result); + TestActorRef shard = TestActorRef.create(getSystem(), + Props.create(new DelegatingShardCreator(creator)), "testRecovery"); + + assertEquals("Recovery complete", true, recoveryComplete.await(5, TimeUnit.SECONDS)); + + // Verify data in the data store. + + NormalizedNode outerList = readStore(shard, TestModel.OUTER_LIST_PATH); + assertNotNull(TestModel.OUTER_LIST_QNAME.getLocalName() + " not found", outerList); + assertTrue(TestModel.OUTER_LIST_QNAME.getLocalName() + " value is not Iterable", + outerList.getValue() instanceof Iterable); + for(Object entry: (Iterable) outerList.getValue()) { + assertTrue(TestModel.OUTER_LIST_QNAME.getLocalName() + " entry is not MapEntryNode", + entry instanceof MapEntryNode); + MapEntryNode mapEntry = (MapEntryNode)entry; + Optional> idLeaf = + mapEntry.getChild(new YangInstanceIdentifier.NodeIdentifier(TestModel.ID_QNAME)); + assertTrue("Missing leaf " + TestModel.ID_QNAME.getLocalName(), idLeaf.isPresent()); + Object value = idLeaf.get().getValue(); + assertTrue("Unexpected value for leaf "+ TestModel.ID_QNAME.getLocalName() + ": " + value, + listEntryKeys.remove(value)); + } - new Within(duration("3 seconds")) { - @Override - protected void run() { + if(!listEntryKeys.isEmpty()) { + fail("Missing " + TestModel.OUTER_LIST_QNAME.getLocalName() + " entries with keys: " + + listEntryKeys); + } - subject.tell( - new UpdateSchemaContext(TestModel.createTestContext()), - getRef()); + assertEquals("Last log index", nListEntries, + shard.underlyingActor().getShardMBean().getLastLogIndex()); + assertEquals("Commit index", nListEntries, + shard.underlyingActor().getShardMBean().getCommitIndex()); + assertEquals("Last applied", nListEntries, + shard.underlyingActor().getShardMBean().getLastApplied()); + } - subject.tell(new CreateTransaction("txn-1", TransactionProxy.TransactionType.READ_ONLY.ordinal() , "foobar").toSerializable(), - getRef()); + private CompositeModificationPayload newPayload(Modification... mods) { + MutableCompositeModification compMod = new MutableCompositeModification(); + for(Modification mod: mods) { + compMod.addModification(mod); + } - final String out = new ExpectMsg(duration("3 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - if (in instanceof CreateTransactionReply) { - CreateTransactionReply reply = - (CreateTransactionReply) in; - return reply.getTransactionActorPath() - .toString(); - } else { - throw noMatch(); - } + return new CompositeModificationPayload(compMod.toSerializable()); + } + + private DOMStoreThreePhaseCommitCohort setupMockWriteTransaction(String cohortName, + InMemoryDOMDataStore dataStore, YangInstanceIdentifier path, NormalizedNode data, + MutableCompositeModification modification) { + return setupMockWriteTransaction(cohortName, dataStore, path, data, modification, null); + } + + private DOMStoreThreePhaseCommitCohort setupMockWriteTransaction(String cohortName, + InMemoryDOMDataStore dataStore, YangInstanceIdentifier path, NormalizedNode data, + MutableCompositeModification modification, + final Function> preCommit) { + + DOMStoreWriteTransaction tx = dataStore.newWriteOnlyTransaction(); + tx.write(path, data); + final DOMStoreThreePhaseCommitCohort realCohort = tx.ready(); + DOMStoreThreePhaseCommitCohort cohort = mock(DOMStoreThreePhaseCommitCohort.class, cohortName); + + doAnswer(new Answer>() { + @Override + public ListenableFuture answer(InvocationOnMock invocation) { + return realCohort.canCommit(); + } + }).when(cohort).canCommit(); + + doAnswer(new Answer>() { + @Override + public ListenableFuture answer(InvocationOnMock invocation) throws Throwable { + if(preCommit != null) { + return preCommit.apply(realCohort); + } else { + return realCohort.preCommit(); + } + } + }).when(cohort).preCommit(); + + doAnswer(new Answer>() { + @Override + public ListenableFuture answer(InvocationOnMock invocation) throws Throwable { + return realCohort.commit(); + } + }).when(cohort).commit(); + + doAnswer(new Answer>() { + @Override + public ListenableFuture answer(InvocationOnMock invocation) throws Throwable { + return realCohort.abort(); + } + }).when(cohort).abort(); + + modification.addModification(new WriteModification(path, data, SCHEMA_CONTEXT)); + + return cohort; + } + + @SuppressWarnings({ "unchecked" }) + @Test + public void testConcurrentThreePhaseCommits() throws Throwable { + System.setProperty("shard.persistent", "true"); + new ShardTestKit(getSystem()) {{ + final TestActorRef shard = TestActorRef.create(getSystem(), + newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName()); + + waitUntilLeader(shard); + + // Setup 3 simulated transactions with mock cohorts backed by real cohorts. + + InMemoryDOMDataStore dataStore = shard.underlyingActor().getDataStore(); + + String transactionID1 = "tx1"; + MutableCompositeModification modification1 = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort1 = setupMockWriteTransaction("cohort1", dataStore, + TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), modification1); + + String transactionID2 = "tx2"; + MutableCompositeModification modification2 = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort2 = setupMockWriteTransaction("cohort2", dataStore, + TestModel.OUTER_LIST_PATH, + ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build(), + modification2); + + String transactionID3 = "tx3"; + MutableCompositeModification modification3 = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort3 = setupMockWriteTransaction("cohort3", dataStore, + YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH) + .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1).build(), + ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1), + modification3); + + long timeoutSec = 5; + final FiniteDuration duration = FiniteDuration.create(timeoutSec, TimeUnit.SECONDS); + final Timeout timeout = new Timeout(duration); + + // Simulate the ForwardedReadyTransaction message for the first Tx that would be sent + // by the ShardTransaction. + + shard.tell(new ForwardedReadyTransaction(transactionID1, cohort1, modification1, true), getRef()); + ReadyTransactionReply readyReply = ReadyTransactionReply.fromSerializable( + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS)); + assertEquals("Cohort path", shard.path().toString(), readyReply.getCohortPath()); + + // Send the CanCommitTransaction message for the first Tx. + + shard.tell(new CanCommitTransaction(transactionID1).toSerializable(), getRef()); + CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable( + expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS)); + assertEquals("Can commit", true, canCommitReply.getCanCommit()); + + // Send the ForwardedReadyTransaction for the next 2 Tx's. + + shard.tell(new ForwardedReadyTransaction(transactionID2, cohort2, modification2, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); + + shard.tell(new ForwardedReadyTransaction(transactionID3, cohort3, modification3, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); + + // Send the CanCommitTransaction message for the next 2 Tx's. These should get queued and + // processed after the first Tx completes. + + Future canCommitFuture1 = Patterns.ask(shard, + new CanCommitTransaction(transactionID2).toSerializable(), timeout); + + Future canCommitFuture2 = Patterns.ask(shard, + new CanCommitTransaction(transactionID3).toSerializable(), timeout); + + // Send the CommitTransaction message for the first Tx. After it completes, it should + // trigger the 2nd Tx to proceed which should in turn then trigger the 3rd. + + shard.tell(new CommitTransaction(transactionID1).toSerializable(), getRef()); + expectMsgClass(duration, CommitTransactionReply.SERIALIZABLE_CLASS); + + // Wait for the next 2 Tx's to complete. + + final AtomicReference caughtEx = new AtomicReference<>(); + final CountDownLatch commitLatch = new CountDownLatch(2); + + class OnFutureComplete extends OnComplete { + private final Class expRespType; + + OnFutureComplete(Class expRespType) { + this.expRespType = expRespType; + } + + @Override + public void onComplete(Throwable error, Object resp) { + if(error != null) { + System.out.println(new java.util.Date()+": "+getClass().getSimpleName() + " failure: "+error); + caughtEx.set(new AssertionError(getClass().getSimpleName() + " failure", error)); + } else { + try { + assertEquals("Commit response type", expRespType, resp.getClass()); + onSuccess(resp); + } catch (Exception e) { + caughtEx.set(e); } - }.get(); // this extracts the received message + } + } - assertTrue("Unexpected transaction path " + out, - out.contains("akka://test/user/testCreateTransactionOnChain/shard-txn-1")); - expectNoMsg(); + void onSuccess(Object resp) throws Exception { } - }; + } + + class OnCommitFutureComplete extends OnFutureComplete { + OnCommitFutureComplete() { + super(CommitTransactionReply.SERIALIZABLE_CLASS); + } + + @Override + public void onComplete(Throwable error, Object resp) { + super.onComplete(error, resp); + commitLatch.countDown(); + } + } + + class OnCanCommitFutureComplete extends OnFutureComplete { + private final String transactionID; + + OnCanCommitFutureComplete(String transactionID) { + super(CanCommitTransactionReply.SERIALIZABLE_CLASS); + this.transactionID = transactionID; + } + + @Override + void onSuccess(Object resp) throws Exception { + CanCommitTransactionReply canCommitReply = + CanCommitTransactionReply.fromSerializable(resp); + assertEquals("Can commit", true, canCommitReply.getCanCommit()); + + Future commitFuture = Patterns.ask(shard, + new CommitTransaction(transactionID).toSerializable(), timeout); + commitFuture.onComplete(new OnCommitFutureComplete(), getSystem().dispatcher()); + } + } + + canCommitFuture1.onComplete(new OnCanCommitFutureComplete(transactionID2), + getSystem().dispatcher()); + + canCommitFuture2.onComplete(new OnCanCommitFutureComplete(transactionID3), + getSystem().dispatcher()); + + boolean done = commitLatch.await(timeoutSec, TimeUnit.SECONDS); + + if(caughtEx.get() != null) { + throw caughtEx.get(); + } + + assertEquals("Commits complete", true, done); + + InOrder inOrder = inOrder(cohort1, cohort2, cohort3); + inOrder.verify(cohort1).canCommit(); + inOrder.verify(cohort1).preCommit(); + inOrder.verify(cohort1).commit(); + inOrder.verify(cohort2).canCommit(); + inOrder.verify(cohort2).preCommit(); + inOrder.verify(cohort2).commit(); + inOrder.verify(cohort3).canCommit(); + inOrder.verify(cohort3).preCommit(); + inOrder.verify(cohort3).commit(); + + // Verify data in the data store. + + NormalizedNode outerList = readStore(shard, TestModel.OUTER_LIST_PATH); + assertNotNull(TestModel.OUTER_LIST_QNAME.getLocalName() + " not found", outerList); + assertTrue(TestModel.OUTER_LIST_QNAME.getLocalName() + " value is not Iterable", + outerList.getValue() instanceof Iterable); + Object entry = ((Iterable)outerList.getValue()).iterator().next(); + assertTrue(TestModel.OUTER_LIST_QNAME.getLocalName() + " entry is not MapEntryNode", + entry instanceof MapEntryNode); + MapEntryNode mapEntry = (MapEntryNode)entry; + Optional> idLeaf = + mapEntry.getChild(new YangInstanceIdentifier.NodeIdentifier(TestModel.ID_QNAME)); + assertTrue("Missing leaf " + TestModel.ID_QNAME.getLocalName(), idLeaf.isPresent()); + assertEquals(TestModel.ID_QNAME.getLocalName() + " value", 1, idLeaf.get().getValue()); + + assertEquals("Last log index", 2, shard.underlyingActor().getShardMBean().getLastLogIndex()); }}; } @Test - public void testPeerAddressResolved(){ - new JavaTestKit(getSystem()) {{ - Map peerAddresses = new HashMap<>(); + public void testCommitPhaseFailure() throws Throwable { + new ShardTestKit(getSystem()) {{ + final TestActorRef shard = TestActorRef.create(getSystem(), + newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName()); - final ShardIdentifier identifier = - ShardIdentifier.builder().memberName("member-1") - .shardName("inventory").type("config").build(); + waitUntilLeader(shard); - peerAddresses.put(identifier, null); - final Props props = Shard.props(identifier, peerAddresses, DATA_STORE_CONTEXT, TestModel.createTestContext()); - final ActorRef subject = - getSystem().actorOf(props, "testPeerAddressResolved"); + // Setup 2 simulated transactions with mock cohorts. The first one fails in the + // commit phase. - new Within(duration("3 seconds")) { + String transactionID1 = "tx1"; + MutableCompositeModification modification1 = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort1 = mock(DOMStoreThreePhaseCommitCohort.class, "cohort1"); + doReturn(Futures.immediateFuture(Boolean.TRUE)).when(cohort1).canCommit(); + doReturn(Futures.immediateFuture(null)).when(cohort1).preCommit(); + doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock"))).when(cohort1).commit(); + + String transactionID2 = "tx2"; + MutableCompositeModification modification2 = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort2 = mock(DOMStoreThreePhaseCommitCohort.class, "cohort2"); + doReturn(Futures.immediateFuture(Boolean.TRUE)).when(cohort2).canCommit(); + + FiniteDuration duration = duration("5 seconds"); + final Timeout timeout = new Timeout(duration); + + // Simulate the ForwardedReadyTransaction messages that would be sent + // by the ShardTransaction. + + shard.tell(new ForwardedReadyTransaction(transactionID1, cohort1, modification1, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); + + shard.tell(new ForwardedReadyTransaction(transactionID2, cohort2, modification2, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); + + // Send the CanCommitTransaction message for the first Tx. + + shard.tell(new CanCommitTransaction(transactionID1).toSerializable(), getRef()); + CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable( + expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS)); + assertEquals("Can commit", true, canCommitReply.getCanCommit()); + + // Send the CanCommitTransaction message for the 2nd Tx. This should get queued and + // processed after the first Tx completes. + + Future canCommitFuture = Patterns.ask(shard, + new CanCommitTransaction(transactionID2).toSerializable(), timeout); + + // Send the CommitTransaction message for the first Tx. This should send back an error + // and trigger the 2nd Tx to proceed. + + shard.tell(new CommitTransaction(transactionID1).toSerializable(), getRef()); + expectMsgClass(duration, akka.actor.Status.Failure.class); + + // Wait for the 2nd Tx to complete the canCommit phase. + + final CountDownLatch latch = new CountDownLatch(1); + canCommitFuture.onComplete(new OnComplete() { @Override - protected void run() { + public void onComplete(Throwable t, Object resp) { + latch.countDown(); + } + }, getSystem().dispatcher()); - subject.tell( - new PeerAddressResolved(identifier, "akka://foobar"), - getRef()); + assertEquals("2nd CanCommit complete", true, latch.await(5, TimeUnit.SECONDS)); - expectNoMsg(); + InOrder inOrder = inOrder(cohort1, cohort2); + inOrder.verify(cohort1).canCommit(); + inOrder.verify(cohort1).preCommit(); + inOrder.verify(cohort1).commit(); + inOrder.verify(cohort2).canCommit(); + }}; + } + + @Test + public void testPreCommitPhaseFailure() throws Throwable { + new ShardTestKit(getSystem()) {{ + final TestActorRef shard = TestActorRef.create(getSystem(), + newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName()); + + waitUntilLeader(shard); + + String transactionID = "tx1"; + MutableCompositeModification modification = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort = mock(DOMStoreThreePhaseCommitCohort.class, "cohort1"); + doReturn(Futures.immediateFuture(Boolean.TRUE)).when(cohort).canCommit(); + doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock"))).when(cohort).preCommit(); + + FiniteDuration duration = duration("5 seconds"); + + // Simulate the ForwardedReadyTransaction messages that would be sent + // by the ShardTransaction. + + shard.tell(new ForwardedReadyTransaction(transactionID, cohort, modification, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); + + // Send the CanCommitTransaction message. + + shard.tell(new CanCommitTransaction(transactionID).toSerializable(), getRef()); + CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable( + expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS)); + assertEquals("Can commit", true, canCommitReply.getCanCommit()); + + // Send the CommitTransaction message. This should send back an error + // for preCommit failure. + + shard.tell(new CommitTransaction(transactionID).toSerializable(), getRef()); + expectMsgClass(duration, akka.actor.Status.Failure.class); + + InOrder inOrder = inOrder(cohort); + inOrder.verify(cohort).canCommit(); + inOrder.verify(cohort).preCommit(); + }}; + } + + @Test + public void testCanCommitPhaseFailure() throws Throwable { + new ShardTestKit(getSystem()) {{ + final TestActorRef shard = TestActorRef.create(getSystem(), + newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName()); + + waitUntilLeader(shard); + + final FiniteDuration duration = duration("5 seconds"); + + String transactionID = "tx1"; + MutableCompositeModification modification = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort = mock(DOMStoreThreePhaseCommitCohort.class, "cohort1"); + doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock"))).when(cohort).canCommit(); + + // Simulate the ForwardedReadyTransaction messages that would be sent + // by the ShardTransaction. + + shard.tell(new ForwardedReadyTransaction(transactionID, cohort, modification, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); + + // Send the CanCommitTransaction message. + + shard.tell(new CanCommitTransaction(transactionID).toSerializable(), getRef()); + expectMsgClass(duration, akka.actor.Status.Failure.class); + }}; + } + + @Test + public void testAbortBeforeFinishCommit() throws Throwable { + System.setProperty("shard.persistent", "true"); + new ShardTestKit(getSystem()) {{ + final TestActorRef shard = TestActorRef.create(getSystem(), + newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName()); + + waitUntilLeader(shard); + + final FiniteDuration duration = duration("5 seconds"); + final Timeout timeout = new Timeout(duration); + + InMemoryDOMDataStore dataStore = shard.underlyingActor().getDataStore(); + + final String transactionID = "tx1"; + final CountDownLatch abortComplete = new CountDownLatch(1); + Function> preCommit = + new Function>() { + @Override + public ListenableFuture apply(final DOMStoreThreePhaseCommitCohort cohort) { + ListenableFuture preCommitFuture = cohort.preCommit(); + + Future abortFuture = Patterns.ask(shard, + new AbortTransaction(transactionID).toSerializable(), timeout); + abortFuture.onComplete(new OnComplete() { + @Override + public void onComplete(Throwable e, Object resp) { + abortComplete.countDown(); + } + }, getSystem().dispatcher()); + + return preCommitFuture; } }; + + MutableCompositeModification modification = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort = setupMockWriteTransaction("cohort1", dataStore, + TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), + modification, preCommit); + + shard.tell(new ForwardedReadyTransaction(transactionID, cohort, modification, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); + + shard.tell(new CanCommitTransaction(transactionID).toSerializable(), getRef()); + CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable( + expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS)); + assertEquals("Can commit", true, canCommitReply.getCanCommit()); + + Future commitFuture = Patterns.ask(shard, + new CommitTransaction(transactionID).toSerializable(), timeout); + + assertEquals("Abort complete", true, abortComplete.await(5, TimeUnit.SECONDS)); + + Await.result(commitFuture, duration); + + NormalizedNode node = readStore(shard, TestModel.TEST_PATH); + assertNotNull(TestModel.TEST_QNAME.getLocalName() + " not found", node); }}; } @Test - public void testApplySnapshot() throws ExecutionException, InterruptedException { - Map peerAddresses = new HashMap<>(); + public void testTransactionCommitTimeout() throws Throwable { + dataStoreContext = DatastoreContext.newBuilder().shardTransactionCommitTimeoutInSeconds(1).build(); - final ShardIdentifier identifier = - ShardIdentifier.builder().memberName("member-1") - .shardName("inventory").type("config").build(); + new ShardTestKit(getSystem()) {{ + final TestActorRef shard = TestActorRef.create(getSystem(), + newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName()); - peerAddresses.put(identifier, null); - final Props props = Shard.props(identifier, peerAddresses, DATA_STORE_CONTEXT, TestModel.createTestContext()); + waitUntilLeader(shard); - TestActorRef ref = TestActorRef.create(getSystem(), props); + final FiniteDuration duration = duration("5 seconds"); - ref.underlyingActor().updateSchemaContext(TestModel.createTestContext()); + InMemoryDOMDataStore dataStore = shard.underlyingActor().getDataStore(); - NormalizedNodeToNodeCodec codec = - new NormalizedNodeToNodeCodec(TestModel.createTestContext()); + writeToStore(shard, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); + writeToStore(shard, TestModel.OUTER_LIST_PATH, + ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build()); - ref.underlyingActor().writeToStore(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); + // Create 1st Tx - will timeout - NormalizedNode expected = ref.underlyingActor().readStore(); + String transactionID1 = "tx1"; + MutableCompositeModification modification1 = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort1 = setupMockWriteTransaction("cohort1", dataStore, + YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH) + .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1).build(), + ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1), + modification1); - NormalizedNodeMessages.Container encode = codec - .encode(YangInstanceIdentifier.builder().build(), expected); + // Create 2nd Tx + String transactionID2 = "tx3"; + MutableCompositeModification modification2 = new MutableCompositeModification(); + YangInstanceIdentifier listNodePath = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH) + .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2).build(); + DOMStoreThreePhaseCommitCohort cohort2 = setupMockWriteTransaction("cohort3", dataStore, + listNodePath, + ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2), + modification2); - ref.underlyingActor().applySnapshot(encode.getNormalizedNode().toByteString()); + // Ready the Tx's - NormalizedNode actual = ref.underlyingActor().readStore(); + shard.tell(new ForwardedReadyTransaction(transactionID1, cohort1, modification1, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); - assertEquals(expected, actual); + shard.tell(new ForwardedReadyTransaction(transactionID2, cohort2, modification2, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); + + // canCommit 1st Tx. We don't send the commit so it should timeout. + + shard.tell(new CanCommitTransaction(transactionID1).toSerializable(), getRef()); + expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS); + + // canCommit the 2nd Tx - it should complete after the 1st Tx times out. + + shard.tell(new CanCommitTransaction(transactionID2).toSerializable(), getRef()); + expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS); + + // Commit the 2nd Tx. + + shard.tell(new CommitTransaction(transactionID2).toSerializable(), getRef()); + expectMsgClass(duration, CommitTransactionReply.SERIALIZABLE_CLASS); + + NormalizedNode node = readStore(shard, listNodePath); + assertNotNull(listNodePath + " not found", node); + }}; } - private static class ShardTestKit extends JavaTestKit { + @Test + public void testTransactionCommitQueueCapacityExceeded() throws Throwable { + dataStoreContext = DatastoreContext.newBuilder().shardTransactionCommitQueueCapacity(1).build(); - private ShardTestKit(ActorSystem actorSystem) { - super(actorSystem); - } + new ShardTestKit(getSystem()) {{ + final TestActorRef shard = TestActorRef.create(getSystem(), + newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName()); - protected void waitForLogMessage(final Class logLevel, ActorRef subject, String logMessage){ - // Wait for a specific log message to show up - final boolean result = - new JavaTestKit.EventFilter(logLevel - ) { - @Override - protected Boolean run() { - return true; - } - }.from(subject.path().toString()) - .message(logMessage) - .occurrences(1).exec(); + waitUntilLeader(shard); - Assert.assertEquals(true, result); + final FiniteDuration duration = duration("5 seconds"); - } + InMemoryDOMDataStore dataStore = shard.underlyingActor().getDataStore(); + + String transactionID1 = "tx1"; + MutableCompositeModification modification1 = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort1 = setupMockWriteTransaction("cohort1", dataStore, + TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), modification1); + + String transactionID2 = "tx2"; + MutableCompositeModification modification2 = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort2 = setupMockWriteTransaction("cohort2", dataStore, + TestModel.OUTER_LIST_PATH, + ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build(), + modification2); + + String transactionID3 = "tx3"; + MutableCompositeModification modification3 = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort3 = setupMockWriteTransaction("cohort3", dataStore, + TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), modification3); + + // Ready the Tx's + + shard.tell(new ForwardedReadyTransaction(transactionID1, cohort1, modification1, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); + + shard.tell(new ForwardedReadyTransaction(transactionID2, cohort2, modification2, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); + + shard.tell(new ForwardedReadyTransaction(transactionID3, cohort3, modification3, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); + + // canCommit 1st Tx. + + shard.tell(new CanCommitTransaction(transactionID1).toSerializable(), getRef()); + expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS); + // canCommit the 2nd Tx - it should get queued. + + shard.tell(new CanCommitTransaction(transactionID2).toSerializable(), getRef()); + + // canCommit the 3rd Tx - should exceed queue capacity and fail. + + shard.tell(new CanCommitTransaction(transactionID3).toSerializable(), getRef()); + expectMsgClass(duration, akka.actor.Status.Failure.class); + }}; } @Test - public void testCreateSnapshot() throws IOException, InterruptedException { + public void testCanCommitBeforeReadyFailure() throws Throwable { new ShardTestKit(getSystem()) {{ - final ShardIdentifier identifier = - ShardIdentifier.builder().memberName("member-1") - .shardName("inventory").type("config").build(); + final TestActorRef shard = TestActorRef.create(getSystem(), + newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName()); - final Props props = Shard.props(identifier, Collections.EMPTY_MAP, DATA_STORE_CONTEXT, TestModel.createTestContext()); - final ActorRef subject = - getSystem().actorOf(props, "testCreateSnapshot"); + shard.tell(new CanCommitTransaction("tx").toSerializable(), getRef()); + expectMsgClass(duration("5 seconds"), akka.actor.Status.Failure.class); + }}; + } - // Wait for a specific log message to show up - this.waitForLogMessage(Logging.Info.class, subject, "Switching from state Candidate to Leader"); + @Test + public void testAbortTransaction() throws Throwable { + new ShardTestKit(getSystem()) {{ + final TestActorRef shard = TestActorRef.create(getSystem(), + newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName()); + waitUntilLeader(shard); - new Within(duration("3 seconds")) { - @Override - protected void run() { + // Setup 2 simulated transactions with mock cohorts. The first one will be aborted. - subject.tell( - new UpdateSchemaContext(TestModel.createTestContext()), - getRef()); + String transactionID1 = "tx1"; + MutableCompositeModification modification1 = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort1 = mock(DOMStoreThreePhaseCommitCohort.class, "cohort1"); + doReturn(Futures.immediateFuture(Boolean.TRUE)).when(cohort1).canCommit(); + doReturn(Futures.immediateFuture(null)).when(cohort1).abort(); - subject.tell(new CaptureSnapshot(-1,-1,-1,-1), - getRef()); + String transactionID2 = "tx2"; + MutableCompositeModification modification2 = new MutableCompositeModification(); + DOMStoreThreePhaseCommitCohort cohort2 = mock(DOMStoreThreePhaseCommitCohort.class, "cohort2"); + doReturn(Futures.immediateFuture(Boolean.TRUE)).when(cohort2).canCommit(); - waitForLogMessage(Logging.Info.class, subject, "CaptureSnapshotReply received by actor"); + FiniteDuration duration = duration("5 seconds"); + final Timeout timeout = new Timeout(duration); - subject.tell(new CaptureSnapshot(-1,-1,-1,-1), - getRef()); + // Simulate the ForwardedReadyTransaction messages that would be sent + // by the ShardTransaction. + + shard.tell(new ForwardedReadyTransaction(transactionID1, cohort1, modification1, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); + + shard.tell(new ForwardedReadyTransaction(transactionID2, cohort2, modification2, true), getRef()); + expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS); - waitForLogMessage(Logging.Info.class, subject, "CaptureSnapshotReply received by actor"); + // Send the CanCommitTransaction message for the first Tx. + shard.tell(new CanCommitTransaction(transactionID1).toSerializable(), getRef()); + CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable( + expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS)); + assertEquals("Can commit", true, canCommitReply.getCanCommit()); + + // Send the CanCommitTransaction message for the 2nd Tx. This should get queued and + // processed after the first Tx completes. + + Future canCommitFuture = Patterns.ask(shard, + new CanCommitTransaction(transactionID2).toSerializable(), timeout); + + // Send the AbortTransaction message for the first Tx. This should trigger the 2nd + // Tx to proceed. + + shard.tell(new AbortTransaction(transactionID1).toSerializable(), getRef()); + expectMsgClass(duration, AbortTransactionReply.SERIALIZABLE_CLASS); + + // Wait for the 2nd Tx to complete the canCommit phase. + + final CountDownLatch latch = new CountDownLatch(1); + canCommitFuture.onComplete(new OnComplete() { + @Override + public void onComplete(Throwable t, Object resp) { + latch.countDown(); + } + }, getSystem().dispatcher()); + + assertEquals("2nd CanCommit complete", true, latch.await(5, TimeUnit.SECONDS)); + + InOrder inOrder = inOrder(cohort1, cohort2); + inOrder.verify(cohort1).canCommit(); + inOrder.verify(cohort2).canCommit(); + }}; + } + + @Test + public void testCreateSnapshot() throws IOException, InterruptedException { + new ShardTestKit(getSystem()) {{ + final AtomicReference latch = new AtomicReference<>(new CountDownLatch(1)); + Creator creator = new Creator() { + @Override + public Shard create() throws Exception { + return new Shard(IDENTIFIER, Collections.emptyMap(), + dataStoreContext, SCHEMA_CONTEXT) { + @Override + public void saveSnapshot(Object snapshot) { + super.saveSnapshot(snapshot); + latch.get().countDown(); + } + }; } }; - deletePersistenceFiles(); + TestActorRef shard = TestActorRef.create(getSystem(), + Props.create(new DelegatingShardCreator(creator)), "testCreateSnapshot"); + + waitUntilLeader(shard); + + shard.tell(new CaptureSnapshot(-1,-1,-1,-1), getRef()); + + assertEquals("Snapshot saved", true, latch.get().await(5, TimeUnit.SECONDS)); + + latch.set(new CountDownLatch(1)); + shard.tell(new CaptureSnapshot(-1,-1,-1,-1), getRef()); + + assertEquals("Snapshot saved", true, latch.get().await(5, TimeUnit.SECONDS)); }}; } @@ -366,7 +1062,7 @@ public class ShardTest extends AbstractActorTest { InMemoryDOMDataStore store = new InMemoryDOMDataStore("test", MoreExecutors.listeningDecorator( MoreExecutors.sameThreadExecutor()), MoreExecutors.sameThreadExecutor()); - store.onGlobalContextUpdated(TestModel.createTestContext()); + store.onGlobalContextUpdated(SCHEMA_CONTEXT); DOMStoreWriteTransaction putTransaction = store.newWriteOnlyTransaction(); putTransaction.write(TestModel.TEST_PATH, @@ -424,4 +1120,43 @@ public class ShardTest extends AbstractActorTest { } }; } + + private NormalizedNode readStore(TestActorRef shard, YangInstanceIdentifier id) + throws ExecutionException, InterruptedException { + DOMStoreReadTransaction transaction = shard.underlyingActor().getDataStore().newReadOnlyTransaction(); + + CheckedFuture>, ReadFailedException> future = + transaction.read(id); + + Optional> optional = future.get(); + NormalizedNode node = optional.isPresent()? optional.get() : null; + + transaction.close(); + + return node; + } + + private void writeToStore(TestActorRef shard, YangInstanceIdentifier id, NormalizedNode node) + throws ExecutionException, InterruptedException { + DOMStoreWriteTransaction transaction = shard.underlyingActor().getDataStore().newWriteOnlyTransaction(); + + transaction.write(id, node); + + DOMStoreThreePhaseCommitCohort commitCohort = transaction.ready(); + commitCohort.preCommit().get(); + commitCohort.commit().get(); + } + + private static final class DelegatingShardCreator implements Creator { + private final Creator delegate; + + DelegatingShardCreator(Creator delegate) { + this.delegate = delegate; + } + + @Override + public Shard create() throws Exception { + return delegate.create(); + } + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTestKit.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTestKit.java new file mode 100644 index 0000000000..9a0e8f9e18 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTestKit.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.cluster.datastore; + +import java.util.concurrent.TimeUnit; +import org.junit.Assert; +import org.opendaylight.controller.cluster.raft.client.messages.FindLeader; +import org.opendaylight.controller.cluster.raft.client.messages.FindLeaderReply; +import com.google.common.util.concurrent.Uninterruptibles; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.pattern.Patterns; +import akka.testkit.JavaTestKit; +import akka.util.Timeout; + +class ShardTestKit extends JavaTestKit { + + ShardTestKit(ActorSystem actorSystem) { + super(actorSystem); + } + + protected void waitForLogMessage(final Class logLevel, ActorRef subject, String logMessage){ + // Wait for a specific log message to show up + final boolean result = + new JavaTestKit.EventFilter(logLevel + ) { + @Override + protected Boolean run() { + return true; + } + }.from(subject.path().toString()) + .message(logMessage) + .occurrences(1).exec(); + + Assert.assertEquals(true, result); + + } + + protected void waitUntilLeader(ActorRef shard) { + for(int i = 0; i < 20 * 5; i++) { + Future future = Patterns.ask(shard, new FindLeader(), new Timeout(5, TimeUnit.SECONDS)); + try { + FindLeaderReply resp = (FindLeaderReply)Await.result(future, Duration.create(5, TimeUnit.SECONDS)); + if(resp.getLeaderActor() != null) { + return; + } + } catch (Exception e) { + e.printStackTrace(); + } + + Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS); + } + + Assert.fail("Leader not found for shard " + shard.path()); + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionFailureTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionFailureTest.java index 869f475787..17731de5cd 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionFailureTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionFailureTest.java @@ -13,10 +13,8 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; import akka.actor.Props; import akka.testkit.TestActorRef; - import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; - import org.junit.BeforeClass; import org.junit.Test; import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier; @@ -30,11 +28,9 @@ import org.opendaylight.controller.protobuff.messages.transaction.ShardTransacti import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.impl.schema.Builders; import org.opendaylight.yangtools.yang.model.api.SchemaContext; - import scala.concurrent.Await; import scala.concurrent.Future; import scala.concurrent.duration.Duration; - import java.util.Collections; import java.util.concurrent.TimeUnit; @@ -58,7 +54,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest { ShardIdentifier.builder().memberName("member-1") .shardName("inventory").type("operational").build(); - private final DatastoreContext datastoreContext = new DatastoreContext(); + private final DatastoreContext datastoreContext = DatastoreContext.newBuilder().build(); private final ShardStats shardStats = new ShardStats(SHARD_IDENTIFIER.toString(), "DataStore"); @@ -68,7 +64,8 @@ public class ShardTransactionFailureTest extends AbstractActorTest { } private ActorRef createShard(){ - return getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new DatastoreContext(), TestModel.createTestContext())); + return getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, datastoreContext, + TestModel.createTestContext())); } @Test(expected = ReadFailedException.class) @@ -77,7 +74,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest { final ActorRef shard = createShard(); final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final TestActorRef subject = TestActorRef .create(getSystem(), props, @@ -106,7 +103,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest { final ActorRef shard = createShard(); final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final TestActorRef subject = TestActorRef .create(getSystem(), props, @@ -135,7 +132,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest { final ActorRef shard = createShard(); final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final TestActorRef subject = TestActorRef .create(getSystem(), props, @@ -164,7 +161,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest { final ActorRef shard = createShard(); final Props props = ShardTransaction.props(store.newWriteOnlyTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final TestActorRef subject = TestActorRef .create(getSystem(), props, @@ -196,7 +193,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest { final ActorRef shard = createShard(); final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final TestActorRef subject = TestActorRef .create(getSystem(), props, @@ -233,7 +230,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest { final ActorRef shard = createShard(); final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final TestActorRef subject = TestActorRef .create(getSystem(), props, "testNegativeMergeTransactionReady"); @@ -265,7 +262,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest { final ActorRef shard = createShard(); final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final TestActorRef subject = TestActorRef .create(getSystem(), props, diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionTest.java index 0beb00b435..711f3d7a72 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionTest.java @@ -5,12 +5,11 @@ import akka.actor.Props; import akka.actor.Terminated; import akka.testkit.JavaTestKit; import akka.testkit.TestActorRef; - import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; - import org.junit.BeforeClass; import org.junit.Test; +import org.opendaylight.controller.cluster.datastore.ShardWriteTransaction.GetCompositeModificationReply; import org.opendaylight.controller.cluster.datastore.exceptions.UnknownMessageException; import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier; import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats; @@ -35,17 +34,16 @@ import org.opendaylight.controller.cluster.datastore.modification.Modification; import org.opendaylight.controller.cluster.datastore.modification.WriteModification; import org.opendaylight.controller.md.cluster.datastore.model.TestModel; import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; -import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreConfigProperties; +import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; import org.opendaylight.yangtools.yang.model.api.SchemaContext; - import scala.concurrent.duration.Duration; - import java.util.Collections; import java.util.concurrent.TimeUnit; - import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; public class ShardTransactionTest extends AbstractActorTest { @@ -61,7 +59,7 @@ public class ShardTransactionTest extends AbstractActorTest { ShardIdentifier.builder().memberName("member-1") .shardName("inventory").type("config").build(); - private DatastoreContext datastoreContext = new DatastoreContext(); + private DatastoreContext datastoreContext = DatastoreContext.newBuilder().build(); private final ShardStats shardStats = new ShardStats(SHARD_IDENTIFIER.toString(), "DataStore"); @@ -72,48 +70,42 @@ public class ShardTransactionTest extends AbstractActorTest { private ActorRef createShard(){ return getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, - Collections.EMPTY_MAP, new DatastoreContext(), TestModel.createTestContext())); + Collections.EMPTY_MAP, datastoreContext, TestModel.createTestContext())); } @Test public void testOnReceiveReadData() throws Exception { new JavaTestKit(getSystem()) {{ final ActorRef shard = createShard(); - final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); - final ActorRef subject = getSystem().actorOf(props, "testReadData"); + Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard, + testSchemaContext, datastoreContext, shardStats, "txn"); - new Within(duration("1 seconds")) { - @Override - protected void run() { - - subject.tell( - new ReadData(YangInstanceIdentifier.builder().build()).toSerializable(), - getRef()); - - final String out = new ExpectMsg(duration("1 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - if (in.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) { - if (ReadDataReply.fromSerializable(testSchemaContext,YangInstanceIdentifier.builder().build(), in) - .getNormalizedNode()!= null) { - return "match"; - } - return null; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertEquals("match", out); - - expectNoMsg(); - } + testOnReceiveReadData(getSystem().actorOf(props, "testReadDataRO")); + + props = ShardTransaction.props(store.newReadWriteTransaction(), shard, + testSchemaContext, datastoreContext, shardStats, "txn"); + + testOnReceiveReadData(getSystem().actorOf(props, "testReadDataRW")); + } + private void testOnReceiveReadData(final ActorRef subject) { + //serialized read + subject.tell(new ReadData(YangInstanceIdentifier.builder().build()).toSerializable(), + getRef()); - }; + ShardTransactionMessages.ReadDataReply replySerialized = + expectMsgClass(duration("5 seconds"), ReadDataReply.SERIALIZABLE_CLASS); + + assertNotNull(ReadDataReply.fromSerializable( + testSchemaContext,YangInstanceIdentifier.builder().build(), replySerialized) + .getNormalizedNode()); + + // unserialized read + subject.tell(new ReadData(YangInstanceIdentifier.builder().build()),getRef()); + + ReadDataReply reply = expectMsgClass(duration("5 seconds"), ReadDataReply.class); + + assertNotNull(reply.getNormalizedNode()); }}; } @@ -121,42 +113,35 @@ public class ShardTransactionTest extends AbstractActorTest { public void testOnReceiveReadDataWhenDataNotFound() throws Exception { new JavaTestKit(getSystem()) {{ final ActorRef shard = createShard(); - final Props props = ShardTransaction.props( store.newReadOnlyTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); - final ActorRef subject = getSystem().actorOf(props, "testReadDataWhenDataNotFound"); + Props props = ShardTransaction.props( store.newReadOnlyTransaction(), shard, + testSchemaContext, datastoreContext, shardStats, "txn"); - new Within(duration("1 seconds")) { - @Override - protected void run() { - - subject.tell( - new ReadData(TestModel.TEST_PATH).toSerializable(), - getRef()); - - final String out = new ExpectMsg(duration("1 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - if (in.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) { - if (ReadDataReply.fromSerializable(testSchemaContext,TestModel.TEST_PATH, in) - .getNormalizedNode() - == null) { - return "match"; - } - return null; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertEquals("match", out); - - expectNoMsg(); - } + testOnReceiveReadDataWhenDataNotFound(getSystem().actorOf( + props, "testReadDataWhenDataNotFoundRO")); + + props = ShardTransaction.props( store.newReadWriteTransaction(), shard, + testSchemaContext, datastoreContext, shardStats, "txn"); + + testOnReceiveReadDataWhenDataNotFound(getSystem().actorOf( + props, "testReadDataWhenDataNotFoundRW")); + } + private void testOnReceiveReadDataWhenDataNotFound(final ActorRef subject) { + // serialized read + subject.tell(new ReadData(TestModel.TEST_PATH).toSerializable(), getRef()); - }; + ShardTransactionMessages.ReadDataReply replySerialized = + expectMsgClass(duration("5 seconds"), ReadDataReply.SERIALIZABLE_CLASS); + + assertTrue(ReadDataReply.fromSerializable( + testSchemaContext, TestModel.TEST_PATH, replySerialized).getNormalizedNode() == null); + + // unserialized read + subject.tell(new ReadData(TestModel.TEST_PATH),getRef()); + + ReadDataReply reply = expectMsgClass(duration("5 seconds"), ReadDataReply.class); + + assertTrue(reply.getNormalizedNode() == null); }}; } @@ -164,41 +149,32 @@ public class ShardTransactionTest extends AbstractActorTest { public void testOnReceiveDataExistsPositive() throws Exception { new JavaTestKit(getSystem()) {{ final ActorRef shard = createShard(); - final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); - final ActorRef subject = getSystem().actorOf(props, "testDataExistsPositive"); + Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard, + testSchemaContext, datastoreContext, shardStats, "txn"); - new Within(duration("1 seconds")) { - @Override - protected void run() { - - subject.tell( - new DataExists(YangInstanceIdentifier.builder().build()).toSerializable(), - getRef()); - - final String out = new ExpectMsg(duration("1 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - if (in.getClass().equals(DataExistsReply.SERIALIZABLE_CLASS)) { - if (DataExistsReply.fromSerializable(in) - .exists()) { - return "match"; - } - return null; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertEquals("match", out); - - expectNoMsg(); - } + testOnReceiveDataExistsPositive(getSystem().actorOf(props, "testDataExistsPositiveRO")); + + props = ShardTransaction.props(store.newReadWriteTransaction(), shard, + testSchemaContext, datastoreContext, shardStats, "txn"); + + testOnReceiveDataExistsPositive(getSystem().actorOf(props, "testDataExistsPositiveRW")); + } + private void testOnReceiveDataExistsPositive(final ActorRef subject) { + subject.tell(new DataExists(YangInstanceIdentifier.builder().build()).toSerializable(), + getRef()); - }; + ShardTransactionMessages.DataExistsReply replySerialized = + expectMsgClass(duration("5 seconds"), ShardTransactionMessages.DataExistsReply.class); + + assertTrue(DataExistsReply.fromSerializable(replySerialized).exists()); + + // unserialized read + subject.tell(new DataExists(YangInstanceIdentifier.builder().build()),getRef()); + + DataExistsReply reply = expectMsgClass(duration("5 seconds"), DataExistsReply.class); + + assertTrue(reply.exists()); }}; } @@ -206,76 +182,44 @@ public class ShardTransactionTest extends AbstractActorTest { public void testOnReceiveDataExistsNegative() throws Exception { new JavaTestKit(getSystem()) {{ final ActorRef shard = createShard(); - final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); - final ActorRef subject = getSystem().actorOf(props, "testDataExistsNegative"); + Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard, + testSchemaContext, datastoreContext, shardStats, "txn"); - new Within(duration("1 seconds")) { - @Override - protected void run() { - - subject.tell( - new DataExists(TestModel.TEST_PATH).toSerializable(), - getRef()); - - final String out = new ExpectMsg(duration("1 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - if (in.getClass().equals(DataExistsReply.SERIALIZABLE_CLASS)) { - if (!DataExistsReply.fromSerializable(in) - .exists()) { - return "match"; - } - return null; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertEquals("match", out); - - expectNoMsg(); - } + testOnReceiveDataExistsNegative(getSystem().actorOf(props, "testDataExistsNegativeRO")); + + props = ShardTransaction.props(store.newReadWriteTransaction(), shard, + testSchemaContext, datastoreContext, shardStats, "txn"); + + testOnReceiveDataExistsNegative(getSystem().actorOf(props, "testDataExistsNegativeRW")); + } + private void testOnReceiveDataExistsNegative(final ActorRef subject) { + subject.tell(new DataExists(TestModel.TEST_PATH).toSerializable(), getRef()); - }; + ShardTransactionMessages.DataExistsReply replySerialized = + expectMsgClass(duration("5 seconds"), ShardTransactionMessages.DataExistsReply.class); + + assertFalse(DataExistsReply.fromSerializable(replySerialized).exists()); + + // unserialized read + subject.tell(new DataExists(TestModel.TEST_PATH),getRef()); + + DataExistsReply reply = expectMsgClass(duration("5 seconds"), DataExistsReply.class); + + assertFalse(reply.exists()); }}; } private void assertModification(final ActorRef subject, final Class modificationType) { new JavaTestKit(getSystem()) {{ - new Within(duration("1 seconds")) { - @Override - protected void run() { - subject - .tell(new ShardTransaction.GetCompositedModification(), - getRef()); - - final CompositeModification compositeModification = - new ExpectMsg(duration("1 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected CompositeModification match(Object in) { - if (in instanceof ShardTransaction.GetCompositeModificationReply) { - return ((ShardTransaction.GetCompositeModificationReply) in) - .getModification(); - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertTrue( - compositeModification.getModifications().size() == 1); - assertEquals(modificationType, - compositeModification.getModifications().get(0) - .getClass()); + subject.tell(new ShardWriteTransaction.GetCompositedModification(), getRef()); - } - }; + CompositeModification compositeModification = expectMsgClass(duration("3 seconds"), + GetCompositeModificationReply.class).getModification(); + + assertTrue(compositeModification.getModifications().size() == 1); + assertEquals(modificationType, compositeModification.getModifications().get(0).getClass()); }}; } @@ -284,38 +228,26 @@ public class ShardTransactionTest extends AbstractActorTest { new JavaTestKit(getSystem()) {{ final ActorRef shard = createShard(); final Props props = ShardTransaction.props(store.newWriteOnlyTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final ActorRef subject = getSystem().actorOf(props, "testWriteData"); - new Within(duration("1 seconds")) { - @Override - protected void run() { - - subject.tell(new WriteData(TestModel.TEST_PATH, - ImmutableNodes.containerNode(TestModel.TEST_QNAME), TestModel.createTestContext()).toSerializable(), - getRef()); - - final String out = new ExpectMsg(duration("1 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - if (in.getClass().equals(WriteDataReply.SERIALIZABLE_CLASS)) { - return "match"; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertEquals("match", out); - - assertModification(subject, WriteModification.class); - expectNoMsg(); - } + subject.tell(new WriteData(TestModel.TEST_PATH, + ImmutableNodes.containerNode(TestModel.TEST_QNAME), TestModel.createTestContext()).toSerializable(), + getRef()); + ShardTransactionMessages.WriteDataReply replySerialized = + expectMsgClass(duration("5 seconds"), ShardTransactionMessages.WriteDataReply.class); - }; + assertModification(subject, WriteModification.class); + + //unserialized write + subject.tell(new WriteData(TestModel.TEST_PATH, + ImmutableNodes.containerNode(TestModel.TEST_QNAME), + TestModel.createTestContext()), + getRef()); + + expectMsgClass(duration("5 seconds"), WriteDataReply.class); }}; } @@ -324,39 +256,25 @@ public class ShardTransactionTest extends AbstractActorTest { new JavaTestKit(getSystem()) {{ final ActorRef shard = createShard(); final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final ActorRef subject = getSystem().actorOf(props, "testMergeData"); - new Within(duration("1 seconds")) { - @Override - protected void run() { - - subject.tell(new MergeData(TestModel.TEST_PATH, - ImmutableNodes.containerNode(TestModel.TEST_QNAME), testSchemaContext).toSerializable(), - getRef()); + subject.tell(new MergeData(TestModel.TEST_PATH, + ImmutableNodes.containerNode(TestModel.TEST_QNAME), testSchemaContext).toSerializable(), + getRef()); - final String out = new ExpectMsg(duration("500 milliseconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - if (in.getClass().equals(MergeDataReply.SERIALIZABLE_CLASS)) { - return "match"; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message + ShardTransactionMessages.MergeDataReply replySerialized = + expectMsgClass(duration("5 seconds"), ShardTransactionMessages.MergeDataReply.class); - assertEquals("match", out); + assertModification(subject, MergeModification.class); - assertModification(subject, MergeModification.class); + //unserialized merge + subject.tell(new MergeData(TestModel.TEST_PATH, + ImmutableNodes.containerNode(TestModel.TEST_QNAME), testSchemaContext), + getRef()); - expectNoMsg(); - } - - - }; + expectMsgClass(duration("5 seconds"), MergeDataReply.class); }}; } @@ -365,36 +283,21 @@ public class ShardTransactionTest extends AbstractActorTest { new JavaTestKit(getSystem()) {{ final ActorRef shard = createShard(); final Props props = ShardTransaction.props( store.newWriteOnlyTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final ActorRef subject = getSystem().actorOf(props, "testDeleteData"); - new Within(duration("1 seconds")) { - @Override - protected void run() { - - subject.tell(new DeleteData(TestModel.TEST_PATH).toSerializable(), getRef()); - - final String out = new ExpectMsg(duration("1 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - if (in.getClass().equals(DeleteDataReply.SERIALIZABLE_CLASS)) { - return "match"; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertEquals("match", out); - - assertModification(subject, DeleteModification.class); - expectNoMsg(); - } + subject.tell(new DeleteData(TestModel.TEST_PATH).toSerializable(), getRef()); + + ShardTransactionMessages.DeleteDataReply replySerialized = + expectMsgClass(duration("5 seconds"), ShardTransactionMessages.DeleteDataReply.class); + assertModification(subject, DeleteModification.class); - }; + //unserialized merge + subject.tell(new DeleteData(TestModel.TEST_PATH), getRef()); + + expectMsgClass(duration("5 seconds"), DeleteDataReply.class); }}; } @@ -404,87 +307,45 @@ public class ShardTransactionTest extends AbstractActorTest { new JavaTestKit(getSystem()) {{ final ActorRef shard = createShard(); final Props props = ShardTransaction.props( store.newReadWriteTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final ActorRef subject = getSystem().actorOf(props, "testReadyTransaction"); - new Within(duration("1 seconds")) { - @Override - protected void run() { - - subject.tell(new ReadyTransaction().toSerializable(), getRef()); - - final String out = new ExpectMsg(duration("1 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - if (in.getClass().equals(ReadyTransactionReply.SERIALIZABLE_CLASS)) { - return "match"; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message + subject.tell(new ReadyTransaction().toSerializable(), getRef()); - assertEquals("match", out); + expectMsgClass(duration("5 seconds"), ReadyTransactionReply.SERIALIZABLE_CLASS); + }}; - expectNoMsg(); - } + // test + new JavaTestKit(getSystem()) {{ + final ActorRef shard = createShard(); + final Props props = ShardTransaction.props( store.newReadWriteTransaction(), shard, + testSchemaContext, datastoreContext, shardStats, "txn"); + final ActorRef subject = + getSystem().actorOf(props, "testReadyTransaction2"); + subject.tell(new ReadyTransaction(), getRef()); - }; + expectMsgClass(duration("5 seconds"), ReadyTransactionReply.class); }}; } + @SuppressWarnings("unchecked") @Test public void testOnReceiveCloseTransaction() throws Exception { new JavaTestKit(getSystem()) {{ final ActorRef shard = createShard(); final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); - final ActorRef subject = - getSystem().actorOf(props, "testCloseTransaction"); + testSchemaContext, datastoreContext, shardStats, "txn"); + final ActorRef subject = getSystem().actorOf(props, "testCloseTransaction"); watch(subject); - new Within(duration("6 seconds")) { - @Override - protected void run() { - - subject.tell(new CloseTransaction().toSerializable(), getRef()); - - final String out = new ExpectMsg(duration("3 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - System.out.println("!!!IN match 1: "+(in!=null?in.getClass():"NULL")); - if (in.getClass().equals(CloseTransactionReply.SERIALIZABLE_CLASS)) { - return "match"; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertEquals("match", out); - - final String termination = new ExpectMsg(duration("3 seconds"), "match hint") { - // do not put code outside this method, will run afterwards - @Override - protected String match(Object in) { - System.out.println("!!!IN match 2: "+(in!=null?in.getClass():"NULL")); - if (in instanceof Terminated) { - return "match"; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - assertEquals("match", termination); - } - }; + subject.tell(new CloseTransaction().toSerializable(), getRef()); + + expectMsgClass(duration("3 seconds"), CloseTransactionReply.SERIALIZABLE_CLASS); + expectMsgClass(duration("3 seconds"), Terminated.class); }}; } @@ -492,7 +353,7 @@ public class ShardTransactionTest extends AbstractActorTest { public void testNegativePerformingWriteOperationOnReadTransaction() throws Exception { final ActorRef shard = createShard(); final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final TestActorRef subject = TestActorRef.apply(props,getSystem()); subject.receive(new DeleteData(TestModel.TEST_PATH).toSerializable(), ActorRef.noSender()); @@ -501,14 +362,13 @@ public class ShardTransactionTest extends AbstractActorTest { @Test public void testShardTransactionInactivity() { - datastoreContext = new DatastoreContext("Test", - InMemoryDOMDataStoreConfigProperties.getDefault(), - Duration.create(500, TimeUnit.MILLISECONDS), 5); + datastoreContext = DatastoreContext.newBuilder().shardTransactionIdleTimeout( + Duration.create(500, TimeUnit.MILLISECONDS)).build(); new JavaTestKit(getSystem()) {{ final ActorRef shard = createShard(); final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard, - testSchemaContext, datastoreContext, shardStats); + testSchemaContext, datastoreContext, shardStats, "txn"); final ActorRef subject = getSystem().actorOf(props, "testShardTransactionInactivity"); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortFailureTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortFailureTest.java deleted file mode 100644 index 4e4c34bcbc..0000000000 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortFailureTest.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - * - */ - -package org.opendaylight.controller.cluster.datastore; - -import akka.actor.ActorRef; -import akka.actor.Props; -import akka.testkit.TestActorRef; -import akka.util.Timeout; - -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mockito; -import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier; -import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats; -import org.opendaylight.controller.cluster.datastore.messages.ForwardedCommitTransaction; -import org.opendaylight.controller.cluster.datastore.modification.CompositeModification; -import org.opendaylight.controller.cluster.datastore.modification.Modification; -import org.opendaylight.controller.md.cluster.datastore.model.TestModel; -import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException; -import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; -import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; -import org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages; -import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages; -import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; - -import scala.concurrent.Await; -import scala.concurrent.Future; -import scala.concurrent.duration.Duration; -import scala.concurrent.duration.FiniteDuration; - -import java.util.Collections; -import java.util.concurrent.TimeUnit; - -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.when; - - -public class ThreePhaseCommitCohortFailureTest extends AbstractActorTest { - - private static ListeningExecutorService storeExecutor = - MoreExecutors.listeningDecorator(MoreExecutors.sameThreadExecutor()); - - private static final InMemoryDOMDataStore store = - new InMemoryDOMDataStore("OPER", storeExecutor, - MoreExecutors.sameThreadExecutor()); - - private static final SchemaContext testSchemaContext = - TestModel.createTestContext(); - - private static final ShardIdentifier SHARD_IDENTIFIER = - ShardIdentifier.builder().memberName("member-1") - .shardName("inventory").type("config").build(); - - private final DatastoreContext datastoreContext = new DatastoreContext(); - - private final ShardStats shardStats = new ShardStats(SHARD_IDENTIFIER.toString(), "DataStore"); - - @BeforeClass - public static void staticSetup() { - store.onGlobalContextUpdated(testSchemaContext); - } - - private final FiniteDuration ASK_RESULT_DURATION = Duration.create(5000, TimeUnit.MILLISECONDS); - - private ActorRef createShard(){ - return getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, datastoreContext, TestModel.createTestContext())); - } - - @Test(expected = TestException.class) - public void testNegativeAbortResultsInException() throws Exception { - - final ActorRef shard = createShard(); - final DOMStoreThreePhaseCommitCohort mockCohort = Mockito - .mock(DOMStoreThreePhaseCommitCohort.class); - final CompositeModification mockComposite = - Mockito.mock(CompositeModification.class); - final Props props = - ThreePhaseCommitCohort.props(mockCohort, shard, mockComposite, shardStats); - - final TestActorRef subject = TestActorRef - .create(getSystem(), props, - "testNegativeAbortResultsInException"); - - when(mockCohort.abort()).thenReturn( - Futures.immediateFailedFuture(new TestException())); - - Future future = - akka.pattern.Patterns.ask(subject, - ThreePhaseCommitCohortMessages.AbortTransaction.newBuilder() - .build(), 3000); - assertTrue(future.isCompleted()); - - Await.result(future, ASK_RESULT_DURATION); - } - - - @Test(expected = OptimisticLockFailedException.class) - public void testNegativeCanCommitResultsInException() throws Exception { - - final ActorRef shard = createShard(); - final DOMStoreThreePhaseCommitCohort mockCohort = Mockito - .mock(DOMStoreThreePhaseCommitCohort.class); - final CompositeModification mockComposite = - Mockito.mock(CompositeModification.class); - final Props props = - ThreePhaseCommitCohort.props(mockCohort, shard, mockComposite, shardStats); - - final TestActorRef subject = TestActorRef - .create(getSystem(), props, - "testNegativeCanCommitResultsInException"); - - when(mockCohort.canCommit()).thenReturn( - Futures - .immediateFailedFuture( - new OptimisticLockFailedException("some exception"))); - - Future future = - akka.pattern.Patterns.ask(subject, - ThreePhaseCommitCohortMessages.CanCommitTransaction.newBuilder() - .build(), 3000); - - - Await.result(future, ASK_RESULT_DURATION); - - } - - - @Test(expected = TestException.class) - public void testNegativePreCommitResultsInException() throws Exception { - - final ActorRef shard = createShard(); - final DOMStoreThreePhaseCommitCohort mockCohort = Mockito - .mock(DOMStoreThreePhaseCommitCohort.class); - final CompositeModification mockComposite = - Mockito.mock(CompositeModification.class); - final Props props = - ThreePhaseCommitCohort.props(mockCohort, shard, mockComposite, shardStats); - - final TestActorRef subject = TestActorRef - .create(getSystem(), props, - "testNegativePreCommitResultsInException"); - - when(mockCohort.preCommit()).thenReturn( - Futures - .immediateFailedFuture( - new TestException())); - - Future future = - akka.pattern.Patterns.ask(subject, - ThreePhaseCommitCohortMessages.PreCommitTransaction.newBuilder() - .build(), 3000); - - Await.result(future, ASK_RESULT_DURATION); - - } - - @Test(expected = TestException.class) - public void testNegativeCommitResultsInException() throws Exception { - - final TestActorRef subject = TestActorRef.create(getSystem(), - Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, datastoreContext, TestModel.createTestContext()), - "testNegativeCommitResultsInException"); - - final ActorRef shardTransaction = - getSystem().actorOf(ShardTransaction.props(store.newReadWriteTransaction(), subject, - testSchemaContext, datastoreContext, shardStats)); - - ShardTransactionMessages.WriteData writeData = - ShardTransactionMessages.WriteData.newBuilder() - .setInstanceIdentifierPathArguments( - NormalizedNodeMessages.InstanceIdentifier.newBuilder() - .build()).setNormalizedNode( - NormalizedNodeMessages.Node.newBuilder().build() - - ).build(); - - Timeout askTimeout = new Timeout(ASK_RESULT_DURATION); - - //This is done so that Modification list is updated which is used during commit - Future future = akka.pattern.Patterns.ask(shardTransaction, writeData, askTimeout); - - //ready transaction creates the cohort so that we get into the - //block where in commmit is done - ShardTransactionMessages.ReadyTransaction readyTransaction = - ShardTransactionMessages.ReadyTransaction.newBuilder().build(); - - future = akka.pattern.Patterns.ask(shardTransaction, readyTransaction, askTimeout); - - //but when the message is sent it will have the MockCommit object - //so that we can simulate throwing of exception - ForwardedCommitTransaction mockForwardCommitTransaction = - Mockito.mock(ForwardedCommitTransaction.class); - DOMStoreThreePhaseCommitCohort mockThreePhaseCommitTransaction = - Mockito.mock(DOMStoreThreePhaseCommitCohort.class); - when(mockForwardCommitTransaction.getCohort()) - .thenReturn(mockThreePhaseCommitTransaction); - when(mockThreePhaseCommitTransaction.commit()).thenReturn(Futures - .immediateFailedFuture( - new TestException())); - Modification mockModification = Mockito.mock( - Modification.class); - when(mockForwardCommitTransaction.getModification()) - .thenReturn(mockModification); - - when(mockModification.toSerializable()).thenReturn( - PersistentMessages.CompositeModification.newBuilder().build()); - - future = akka.pattern.Patterns.ask(subject, mockForwardCommitTransaction, askTimeout); - Await.result(future, ASK_RESULT_DURATION); - } - - private class TestException extends Exception { - } -} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxyTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxyTest.java index 1cd0f85fa1..46060dda2a 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxyTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxyTest.java @@ -4,19 +4,8 @@ import akka.actor.ActorPath; import akka.actor.ActorSelection; import akka.actor.Props; import akka.dispatch.Futures; - import com.google.common.collect.Lists; import com.google.common.util.concurrent.ListenableFuture; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.isA; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.times; - import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -33,13 +22,20 @@ import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransacti import org.opendaylight.controller.cluster.datastore.messages.SerializableMessage; import org.opendaylight.controller.cluster.datastore.utils.ActorContext; import org.opendaylight.controller.cluster.datastore.utils.DoNothingActor; - import scala.concurrent.Future; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.isA; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest { @SuppressWarnings("serial") @@ -56,28 +52,28 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest { doReturn(getSystem()).when(actorContext).getActorSystem(); } - private Future newCohortPath() { + private Future newCohort() { ActorPath path = getSystem().actorOf(Props.create(DoNothingActor.class)).path(); - doReturn(mock(ActorSelection.class)).when(actorContext).actorSelection(path); - return Futures.successful(path); + ActorSelection actorSelection = getSystem().actorSelection(path); + return Futures.successful(actorSelection); } private final ThreePhaseCommitCohortProxy setupProxy(int nCohorts) throws Exception { - List> cohortPathFutures = Lists.newArrayList(); + List> cohortFutures = Lists.newArrayList(); for(int i = 1; i <= nCohorts; i++) { - cohortPathFutures.add(newCohortPath()); + cohortFutures.add(newCohort()); } - return new ThreePhaseCommitCohortProxy(actorContext, cohortPathFutures, "txn-1"); + return new ThreePhaseCommitCohortProxy(actorContext, cohortFutures, "txn-1"); } private ThreePhaseCommitCohortProxy setupProxyWithFailedCohortPath() throws Exception { - List> cohortPathFutures = Lists.newArrayList(); - cohortPathFutures.add(newCohortPath()); - cohortPathFutures.add(Futures.failed(new TestException())); + List> cohortFutures = Lists.newArrayList(); + cohortFutures.add(newCohort()); + cohortFutures.add(Futures.failed(new TestException())); - return new ThreePhaseCommitCohortProxy(actorContext, cohortPathFutures, "txn-1"); + return new ThreePhaseCommitCohortProxy(actorContext, cohortFutures, "txn-1"); } private void setupMockActorContext(Class requestType, Object... responses) { @@ -91,12 +87,12 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest { .successful(((SerializableMessage) responses[i]).toSerializable())); } - stubber.when(actorContext).executeRemoteOperationAsync(any(ActorSelection.class), + stubber.when(actorContext).executeOperationAsync(any(ActorSelection.class), isA(requestType)); } private void verifyCohortInvocations(int nCohorts, Class requestType) { - verify(actorContext, times(nCohorts)).executeRemoteOperationAsync( + verify(actorContext, times(nCohorts)).executeOperationAsync( any(ActorSelection.class), isA(requestType)); } @@ -198,24 +194,13 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest { @Test public void testPreCommit() throws Exception { + // Precommit is currently a no-op ThreePhaseCommitCohortProxy proxy = setupProxy(1); setupMockActorContext(PreCommitTransaction.SERIALIZABLE_CLASS, new PreCommitTransactionReply()); proxy.preCommit().get(5, TimeUnit.SECONDS); - - verifyCohortInvocations(1, PreCommitTransaction.SERIALIZABLE_CLASS); - } - - @Test(expected = ExecutionException.class) - public void testPreCommitWithFailure() throws Exception { - ThreePhaseCommitCohortProxy proxy = setupProxy(2); - - setupMockActorContext(PreCommitTransaction.SERIALIZABLE_CLASS, - new PreCommitTransactionReply(), new RuntimeException("mock")); - - proxy.preCommit().get(5, TimeUnit.SECONDS); } @Test @@ -317,7 +302,6 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest { proxy.commit().get(5, TimeUnit.SECONDS); verifyCohortInvocations(2, CanCommitTransaction.SERIALIZABLE_CLASS); - verifyCohortInvocations(2, PreCommitTransaction.SERIALIZABLE_CLASS); verifyCohortInvocations(2, CommitTransaction.SERIALIZABLE_CLASS); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java index e5392e0251..f2b849122a 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java @@ -1,28 +1,17 @@ package org.opendaylight.controller.cluster.datastore; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; -import akka.actor.ActorPath; import akka.actor.ActorRef; import akka.actor.ActorSelection; +import akka.actor.ActorSystem; import akka.actor.Props; import akka.dispatch.Futures; - import com.google.common.base.Optional; import com.google.common.util.concurrent.CheckedFuture; - import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; - -import static org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType.READ_ONLY; -import static org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType.WRITE_ONLY; -import static org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType.READ_WRITE; - import org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType; import org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException; import org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException; @@ -52,22 +41,27 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCoh import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; import org.opendaylight.yangtools.yang.model.api.SchemaContext; - import scala.concurrent.Await; import scala.concurrent.Future; import scala.concurrent.duration.Duration; import java.util.List; import java.util.concurrent.TimeUnit; - +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.isA; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType.READ_ONLY; +import static org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType.READ_WRITE; +import static org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType.WRITE_ONLY; @SuppressWarnings("resource") public class TransactionProxyTest extends AbstractActorTest { @@ -87,6 +81,9 @@ public class TransactionProxyTest extends AbstractActorTest { private SchemaContext schemaContext; + @Mock + private ClusterWrapper mockClusterWrapper; + String memberName = "mock-member"; @Before @@ -98,6 +95,7 @@ public class TransactionProxyTest extends AbstractActorTest { doReturn(getSystem()).when(mockActorContext).getActorSystem(); doReturn(memberName).when(mockActorContext).getCurrentMemberName(); doReturn(schemaContext).when(mockActorContext).getSchemaContext(); + doReturn(mockClusterWrapper).when(mockActorContext).getClusterWrapper(); ShardStrategyFactory.setConfiguration(configuration); } @@ -116,7 +114,7 @@ public class TransactionProxyTest extends AbstractActorTest { return argThat(matcher); } - private DataExists eqDataExists() { + private DataExists eqSerializedDataExists() { ArgumentMatcher matcher = new ArgumentMatcher() { @Override public boolean matches(Object argument) { @@ -128,7 +126,19 @@ public class TransactionProxyTest extends AbstractActorTest { return argThat(matcher); } - private ReadData eqReadData() { + private DataExists eqDataExists() { + ArgumentMatcher matcher = new ArgumentMatcher() { + @Override + public boolean matches(Object argument) { + return (argument instanceof DataExists) && + ((DataExists)argument).getPath().equals(TestModel.TEST_PATH); + } + }; + + return argThat(matcher); + } + + private ReadData eqSerializedReadData() { ArgumentMatcher matcher = new ArgumentMatcher() { @Override public boolean matches(Object argument) { @@ -140,7 +150,19 @@ public class TransactionProxyTest extends AbstractActorTest { return argThat(matcher); } - private WriteData eqWriteData(final NormalizedNode nodeToWrite) { + private ReadData eqReadData() { + ArgumentMatcher matcher = new ArgumentMatcher() { + @Override + public boolean matches(Object argument) { + return (argument instanceof ReadData) && + ((ReadData)argument).getPath().equals(TestModel.TEST_PATH); + } + }; + + return argThat(matcher); + } + + private WriteData eqSerializedWriteData(final NormalizedNode nodeToWrite) { ArgumentMatcher matcher = new ArgumentMatcher() { @Override public boolean matches(Object argument) { @@ -157,7 +179,23 @@ public class TransactionProxyTest extends AbstractActorTest { return argThat(matcher); } - private MergeData eqMergeData(final NormalizedNode nodeToWrite) { + private WriteData eqWriteData(final NormalizedNode nodeToWrite) { + ArgumentMatcher matcher = new ArgumentMatcher() { + @Override + public boolean matches(Object argument) { + if(argument instanceof WriteData) { + WriteData obj = (WriteData) argument; + return obj.getPath().equals(TestModel.TEST_PATH) && + obj.getData().equals(nodeToWrite); + } + return false; + } + }; + + return argThat(matcher); + } + + private MergeData eqSerializedMergeData(final NormalizedNode nodeToWrite) { ArgumentMatcher matcher = new ArgumentMatcher() { @Override public boolean matches(Object argument) { @@ -174,7 +212,24 @@ public class TransactionProxyTest extends AbstractActorTest { return argThat(matcher); } - private DeleteData eqDeleteData() { + private MergeData eqMergeData(final NormalizedNode nodeToWrite) { + ArgumentMatcher matcher = new ArgumentMatcher() { + @Override + public boolean matches(Object argument) { + if(argument instanceof MergeData) { + MergeData obj = ((MergeData) argument); + return obj.getPath().equals(TestModel.TEST_PATH) && + obj.getData().equals(nodeToWrite); + } + + return false; + } + }; + + return argThat(matcher); + } + + private DeleteData eqSerializedDeleteData() { ArgumentMatcher matcher = new ArgumentMatcher() { @Override public boolean matches(Object argument) { @@ -186,30 +241,67 @@ public class TransactionProxyTest extends AbstractActorTest { return argThat(matcher); } - private Future readyTxReply(ActorPath path) { + private DeleteData eqDeleteData() { + ArgumentMatcher matcher = new ArgumentMatcher() { + @Override + public boolean matches(Object argument) { + return argument instanceof DeleteData && + ((DeleteData)argument).getPath().equals(TestModel.TEST_PATH); + } + }; + + return argThat(matcher); + } + + private Future readySerializedTxReply(String path) { return Futures.successful((Object)new ReadyTransactionReply(path).toSerializable()); } - private Future readDataReply(NormalizedNode data) { + private Future readyTxReply(String path) { + return Futures.successful((Object)new ReadyTransactionReply(path)); + } + + + private Future readSerializedDataReply(NormalizedNode data) { return Futures.successful(new ReadDataReply(schemaContext, data).toSerializable()); } - private Future dataExistsReply(boolean exists) { + private Future readDataReply(NormalizedNode data) { + return Futures.successful(new ReadDataReply(schemaContext, data)); + } + + private Future dataExistsSerializedReply(boolean exists) { return Futures.successful(new DataExistsReply(exists).toSerializable()); } - private Future writeDataReply() { + private Future dataExistsReply(boolean exists) { + return Futures.successful(new DataExistsReply(exists)); + } + + private Future writeSerializedDataReply() { return Futures.successful(new WriteDataReply().toSerializable()); } - private Future mergeDataReply() { + private Future writeDataReply() { + return Futures.successful(new WriteDataReply()); + } + + private Future mergeSerializedDataReply() { return Futures.successful(new MergeDataReply().toSerializable()); } - private Future deleteDataReply() { + private Future mergeDataReply() { + return Futures.successful(new MergeDataReply()); + } + + private Future deleteSerializedDataReply() { return Futures.successful(new DeleteDataReply().toSerializable()); } + private Future deleteDataReply() { + return Futures.successful(new DeleteDataReply()); + } + private ActorSelection actorSelection(ActorRef actorRef) { return getSystem().actorSelection(actorRef.path()); } @@ -220,16 +312,19 @@ public class TransactionProxyTest extends AbstractActorTest { .setTransactionId("txn-1").build(); } - private ActorRef setupActorContextWithInitialCreateTransaction(TransactionType type) { - ActorRef actorRef = getSystem().actorOf(Props.create(DoNothingActor.class)); - doReturn(getSystem().actorSelection(actorRef.path())). + private ActorRef setupActorContextWithInitialCreateTransaction(ActorSystem actorSystem, TransactionType type) { + ActorRef actorRef = actorSystem.actorOf(Props.create(DoNothingActor.class)); + doReturn(actorSystem.actorSelection(actorRef.path())). when(mockActorContext).actorSelection(actorRef.path().toString()); + + doReturn(Optional.of(actorSystem.actorSelection(actorRef.path()))). + when(mockActorContext).findPrimaryShard(eq(DefaultShardStrategy.DEFAULT_SHARD)); + doReturn(createTransactionReply(actorRef)).when(mockActorContext). - executeShardOperation(eq(DefaultShardStrategy.DEFAULT_SHARD), + executeOperation(eq(actorSystem.actorSelection(actorRef.path())), eqCreateTransaction(memberName, type)); - doReturn(actorRef.path().toString()).when(mockActorContext).resolvePath( - anyString(), eq(actorRef.path().toString())); - doReturn(actorRef.path()).when(mockActorContext).actorFor(actorRef.path().toString()); + + doReturn(false).when(mockActorContext).isLocalPath(actorRef.path().toString()); return actorRef; } @@ -247,13 +342,13 @@ public class TransactionProxyTest extends AbstractActorTest { @Test public void testRead() throws Exception { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_ONLY); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_ONLY); - doReturn(readDataReply(null)).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqReadData()); + doReturn(readSerializedDataReply(null)).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedReadData()); Optional> readOptional = transactionProxy.read( TestModel.TEST_PATH).get(5, TimeUnit.SECONDS); @@ -262,8 +357,8 @@ public class TransactionProxyTest extends AbstractActorTest { NormalizedNode expectedNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME); - doReturn(readDataReply(expectedNode)).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqReadData()); + doReturn(readSerializedDataReply(expectedNode)).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedReadData()); readOptional = transactionProxy.read(TestModel.TEST_PATH).get(5, TimeUnit.SECONDS); @@ -274,10 +369,10 @@ public class TransactionProxyTest extends AbstractActorTest { @Test(expected = ReadFailedException.class) public void testReadWithInvalidReplyMessageType() throws Exception { - setupActorContextWithInitialCreateTransaction(READ_ONLY); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY); doReturn(Futures.successful(new Object())).when(mockActorContext). - executeRemoteOperationAsync(any(ActorSelection.class), any()); + executeOperationAsync(any(ActorSelection.class), any()); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_ONLY); @@ -287,10 +382,10 @@ public class TransactionProxyTest extends AbstractActorTest { @Test(expected = TestException.class) public void testReadWithAsyncRemoteOperatonFailure() throws Throwable { - setupActorContextWithInitialCreateTransaction(READ_ONLY); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY); doReturn(Futures.failed(new TestException())).when(mockActorContext). - executeRemoteOperationAsync(any(ActorSelection.class), any()); + executeOperationAsync(any(ActorSelection.class), any()); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_ONLY); @@ -300,12 +395,17 @@ public class TransactionProxyTest extends AbstractActorTest { private void testExceptionOnInitialCreateTransaction(Exception exToThrow, Invoker invoker) throws Throwable { + ActorRef actorRef = getSystem().actorOf(Props.create(DoNothingActor.class)); - doThrow(exToThrow).when(mockActorContext).executeShardOperation( - anyString(), any()); + if (exToThrow instanceof PrimaryNotFoundException) { + doReturn(Optional.absent()).when(mockActorContext).findPrimaryShard(anyString()); + } else { + doReturn(Optional.of(getSystem().actorSelection(actorRef.path()))). + when(mockActorContext).findPrimaryShard(anyString()); + } + doThrow(exToThrow).when(mockActorContext).executeOperation(any(ActorSelection.class), any()); - TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, - READ_ONLY); + TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_ONLY); propagateReadFailedExceptionCause(invoker.invoke(transactionProxy)); } @@ -337,18 +437,18 @@ public class TransactionProxyTest extends AbstractActorTest { @Test(expected = TestException.class) public void testReadWithPriorRecordingOperationFailure() throws Throwable { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_WRITE); NormalizedNode nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME); - doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqWriteData(nodeToWrite)); + doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite)); doReturn(Futures.failed(new TestException())).when(mockActorContext). - executeRemoteOperationAsync(eq(actorSelection(actorRef)), eqDeleteData()); + executeOperationAsync(eq(actorSelection(actorRef)), eqSerializedDeleteData()); - doReturn(readDataReply(null)).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqReadData()); + doReturn(readSerializedDataReply(null)).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedReadData()); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_WRITE); @@ -360,22 +460,22 @@ public class TransactionProxyTest extends AbstractActorTest { try { propagateReadFailedExceptionCause(transactionProxy.read(TestModel.TEST_PATH)); } finally { - verify(mockActorContext, times(0)).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqReadData()); + verify(mockActorContext, times(0)).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedReadData()); } } @Test public void testReadWithPriorRecordingOperationSuccessful() throws Throwable { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_WRITE); NormalizedNode expectedNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME); - doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqWriteData(expectedNode)); + doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedWriteData(expectedNode)); - doReturn(readDataReply(expectedNode)).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqReadData()); + doReturn(readSerializedDataReply(expectedNode)).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedReadData()); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_WRITE); @@ -401,20 +501,20 @@ public class TransactionProxyTest extends AbstractActorTest { @Test public void testExists() throws Exception { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_ONLY); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_ONLY); - doReturn(dataExistsReply(false)).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqDataExists()); + doReturn(dataExistsSerializedReply(false)).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedDataExists()); Boolean exists = transactionProxy.exists(TestModel.TEST_PATH).checkedGet(); assertEquals("Exists response", false, exists); - doReturn(dataExistsReply(true)).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqDataExists()); + doReturn(dataExistsSerializedReply(true)).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedDataExists()); exists = transactionProxy.exists(TestModel.TEST_PATH).checkedGet(); @@ -433,10 +533,10 @@ public class TransactionProxyTest extends AbstractActorTest { @Test(expected = ReadFailedException.class) public void testExistsWithInvalidReplyMessageType() throws Exception { - setupActorContextWithInitialCreateTransaction(READ_ONLY); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY); doReturn(Futures.successful(new Object())).when(mockActorContext). - executeRemoteOperationAsync(any(ActorSelection.class), any()); + executeOperationAsync(any(ActorSelection.class), any()); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_ONLY); @@ -446,10 +546,10 @@ public class TransactionProxyTest extends AbstractActorTest { @Test(expected = TestException.class) public void testExistsWithAsyncRemoteOperatonFailure() throws Throwable { - setupActorContextWithInitialCreateTransaction(READ_ONLY); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY); doReturn(Futures.failed(new TestException())).when(mockActorContext). - executeRemoteOperationAsync(any(ActorSelection.class), any()); + executeOperationAsync(any(ActorSelection.class), any()); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_ONLY); @@ -459,18 +559,18 @@ public class TransactionProxyTest extends AbstractActorTest { @Test(expected = TestException.class) public void testExistsWithPriorRecordingOperationFailure() throws Throwable { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_WRITE); NormalizedNode nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME); - doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqWriteData(nodeToWrite)); + doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite)); doReturn(Futures.failed(new TestException())).when(mockActorContext). - executeRemoteOperationAsync(eq(actorSelection(actorRef)), eqDeleteData()); + executeOperationAsync(eq(actorSelection(actorRef)), eqSerializedDeleteData()); - doReturn(dataExistsReply(false)).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqDataExists()); + doReturn(dataExistsSerializedReply(false)).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedDataExists()); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_WRITE); @@ -482,22 +582,22 @@ public class TransactionProxyTest extends AbstractActorTest { try { propagateReadFailedExceptionCause(transactionProxy.exists(TestModel.TEST_PATH)); } finally { - verify(mockActorContext, times(0)).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqDataExists()); + verify(mockActorContext, times(0)).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedDataExists()); } } @Test public void testExistsWithPriorRecordingOperationSuccessful() throws Throwable { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_WRITE); NormalizedNode nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME); - doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqWriteData(nodeToWrite)); + doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite)); - doReturn(dataExistsReply(true)).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqDataExists()); + doReturn(dataExistsSerializedReply(true)).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedDataExists()); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_WRITE); @@ -543,20 +643,20 @@ public class TransactionProxyTest extends AbstractActorTest { @Test public void testWrite() throws Exception { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), WRITE_ONLY); NormalizedNode nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME); - doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqWriteData(nodeToWrite)); + doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite)); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, WRITE_ONLY); transactionProxy.write(TestModel.TEST_PATH, nodeToWrite); - verify(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqWriteData(nodeToWrite)); + verify(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite)); verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(), WriteDataReply.SERIALIZABLE_CLASS); @@ -586,20 +686,20 @@ public class TransactionProxyTest extends AbstractActorTest { @Test public void testMerge() throws Exception { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), WRITE_ONLY); NormalizedNode nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME); - doReturn(mergeDataReply()).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqMergeData(nodeToWrite)); + doReturn(mergeSerializedDataReply()).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedMergeData(nodeToWrite)); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, WRITE_ONLY); transactionProxy.merge(TestModel.TEST_PATH, nodeToWrite); - verify(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqMergeData(nodeToWrite)); + verify(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedMergeData(nodeToWrite)); verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(), MergeDataReply.SERIALIZABLE_CLASS); @@ -607,35 +707,35 @@ public class TransactionProxyTest extends AbstractActorTest { @Test public void testDelete() throws Exception { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), WRITE_ONLY); - doReturn(deleteDataReply()).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqDeleteData()); + doReturn(deleteSerializedDataReply()).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedDeleteData()); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, WRITE_ONLY); transactionProxy.delete(TestModel.TEST_PATH); - verify(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqDeleteData()); + verify(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedDeleteData()); verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(), DeleteDataReply.SERIALIZABLE_CLASS); } - private void verifyCohortPathFutures(ThreePhaseCommitCohortProxy proxy, - Object... expReplies) throws Exception { + private void verifyCohortFutures(ThreePhaseCommitCohortProxy proxy, + Object... expReplies) throws Exception { assertEquals("getReadyOperationFutures size", expReplies.length, - proxy.getCohortPathFutures().size()); + proxy.getCohortFutures().size()); int i = 0; - for( Future future: proxy.getCohortPathFutures()) { + for( Future future: proxy.getCohortFutures()) { assertNotNull("Ready operation Future is null", future); Object expReply = expReplies[i++]; - if(expReply instanceof ActorPath) { - ActorPath actual = Await.result(future, Duration.create(5, TimeUnit.SECONDS)); + if(expReply instanceof ActorSelection) { + ActorSelection actual = Await.result(future, Duration.create(5, TimeUnit.SECONDS)); assertEquals("Cohort actor path", expReply, actual); } else { // Expecting exception. @@ -652,17 +752,17 @@ public class TransactionProxyTest extends AbstractActorTest { @SuppressWarnings("unchecked") @Test public void testReady() throws Exception { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_WRITE); NormalizedNode nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME); - doReturn(readDataReply(null)).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqReadData()); + doReturn(readSerializedDataReply(null)).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedReadData()); - doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqWriteData(nodeToWrite)); + doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite)); - doReturn(readyTxReply(actorRef.path())).when(mockActorContext).executeRemoteOperationAsync( + doReturn(readySerializedTxReply(actorRef.path().toString())).when(mockActorContext).executeOperationAsync( eq(actorSelection(actorRef)), isA(ReadyTransaction.SERIALIZABLE_CLASS)); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, @@ -681,25 +781,27 @@ public class TransactionProxyTest extends AbstractActorTest { verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(), WriteDataReply.SERIALIZABLE_CLASS); - verifyCohortPathFutures(proxy, actorRef.path()); + verifyCohortFutures(proxy, getSystem().actorSelection(actorRef.path())); } @SuppressWarnings("unchecked") @Test public void testReadyWithRecordingOperationFailure() throws Exception { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), WRITE_ONLY); NormalizedNode nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME); - doReturn(mergeDataReply()).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqMergeData(nodeToWrite)); + doReturn(mergeSerializedDataReply()).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedMergeData(nodeToWrite)); doReturn(Futures.failed(new TestException())).when(mockActorContext). - executeRemoteOperationAsync(eq(actorSelection(actorRef)), eqWriteData(nodeToWrite)); + executeOperationAsync(eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite)); - doReturn(readyTxReply(actorRef.path())).when(mockActorContext).executeRemoteOperationAsync( + doReturn(readySerializedTxReply(actorRef.path().toString())).when(mockActorContext).executeOperationAsync( eq(actorSelection(actorRef)), isA(ReadyTransaction.SERIALIZABLE_CLASS)); + doReturn(false).when(mockActorContext).isLocalPath(actorRef.path().toString()); + TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, WRITE_ONLY); @@ -716,21 +818,21 @@ public class TransactionProxyTest extends AbstractActorTest { verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(), MergeDataReply.SERIALIZABLE_CLASS, TestException.class); - verifyCohortPathFutures(proxy, TestException.class); + verifyCohortFutures(proxy, TestException.class); } @SuppressWarnings("unchecked") @Test public void testReadyWithReplyFailure() throws Exception { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), WRITE_ONLY); NormalizedNode nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME); - doReturn(mergeDataReply()).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqMergeData(nodeToWrite)); + doReturn(mergeSerializedDataReply()).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedMergeData(nodeToWrite)); doReturn(Futures.failed(new TestException())).when(mockActorContext). - executeRemoteOperationAsync(eq(actorSelection(actorRef)), + executeOperationAsync(eq(actorSelection(actorRef)), isA(ReadyTransaction.SERIALIZABLE_CLASS)); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, @@ -747,14 +849,15 @@ public class TransactionProxyTest extends AbstractActorTest { verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(), MergeDataReply.SERIALIZABLE_CLASS); - verifyCohortPathFutures(proxy, TestException.class); + verifyCohortFutures(proxy, TestException.class); } @Test public void testReadyWithInitialCreateTransactionFailure() throws Exception { - doThrow(new PrimaryNotFoundException("mock")).when(mockActorContext).executeShardOperation( - anyString(), any()); + doReturn(Optional.absent()).when(mockActorContext).findPrimaryShard(anyString()); +// doThrow(new PrimaryNotFoundException("mock")).when(mockActorContext).executeShardOperation( +// anyString(), any()); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, WRITE_ONLY); @@ -773,21 +876,21 @@ public class TransactionProxyTest extends AbstractActorTest { ThreePhaseCommitCohortProxy proxy = (ThreePhaseCommitCohortProxy) ready; - verifyCohortPathFutures(proxy, PrimaryNotFoundException.class); + verifyCohortFutures(proxy, PrimaryNotFoundException.class); } @SuppressWarnings("unchecked") @Test public void testReadyWithInvalidReplyMessageType() throws Exception { - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), WRITE_ONLY); NormalizedNode nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME); - doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqWriteData(nodeToWrite)); + doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite)); doReturn(Futures.successful(new Object())).when(mockActorContext). - executeRemoteOperationAsync(eq(actorSelection(actorRef)), + executeOperationAsync(eq(actorSelection(actorRef)), isA(ReadyTransaction.SERIALIZABLE_CLASS)); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, @@ -801,12 +904,12 @@ public class TransactionProxyTest extends AbstractActorTest { ThreePhaseCommitCohortProxy proxy = (ThreePhaseCommitCohortProxy) ready; - verifyCohortPathFutures(proxy, IllegalArgumentException.class); + verifyCohortFutures(proxy, IllegalArgumentException.class); } @Test public void testGetIdentifier() { - setupActorContextWithInitialCreateTransaction(READ_ONLY); + setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, TransactionProxy.TransactionType.READ_ONLY); @@ -818,10 +921,10 @@ public class TransactionProxyTest extends AbstractActorTest { @SuppressWarnings("unchecked") @Test public void testClose() throws Exception{ - ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE); + ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_WRITE); - doReturn(readDataReply(null)).when(mockActorContext).executeRemoteOperationAsync( - eq(actorSelection(actorRef)), eqReadData()); + doReturn(readSerializedDataReply(null)).when(mockActorContext).executeOperationAsync( + eq(actorSelection(actorRef)), eqSerializedReadData()); TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_WRITE); @@ -830,7 +933,143 @@ public class TransactionProxyTest extends AbstractActorTest { transactionProxy.close(); - verify(mockActorContext).sendRemoteOperationAsync( + verify(mockActorContext).sendOperationAsync( eq(actorSelection(actorRef)), isA(CloseTransaction.SERIALIZABLE_CLASS)); } + + + /** + * Method to test a local Tx actor. The Tx paths are matched to decide if the + * Tx actor is local or not. This is done by mocking the Tx actor path + * and the caller paths and ensuring that the paths have the remote-address format + * + * Note: Since the default akka provider for test is not a RemoteActorRefProvider, + * the paths returned for the actors for all the tests are not qualified remote paths. + * Hence are treated as non-local/remote actors. In short, all tests except + * few below run for remote actors + * + * @throws Exception + */ + @Test + public void testLocalTxActorRead() throws Exception { + ActorSystem actorSystem = getSystem(); + ActorRef shardActorRef = actorSystem.actorOf(Props.create(DoNothingActor.class)); + + doReturn(actorSystem.actorSelection(shardActorRef.path())). + when(mockActorContext).actorSelection(shardActorRef.path().toString()); + + doReturn(Optional.of(actorSystem.actorSelection(shardActorRef.path()))). + when(mockActorContext).findPrimaryShard(eq(DefaultShardStrategy.DEFAULT_SHARD)); + + String actorPath = "akka.tcp://system@127.0.0.1:2550/user/tx-actor"; + CreateTransactionReply createTransactionReply = CreateTransactionReply.newBuilder() + .setTransactionId("txn-1") + .setTransactionActorPath(actorPath) + .build(); + + doReturn(createTransactionReply).when(mockActorContext). + executeOperation(eq(actorSystem.actorSelection(shardActorRef.path())), + eqCreateTransaction(memberName, READ_ONLY)); + + doReturn(true).when(mockActorContext).isLocalPath(actorPath); + + TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,READ_ONLY); + + // negative test case with null as the reply + doReturn(readDataReply(null)).when(mockActorContext).executeOperationAsync( + any(ActorSelection.class), eqReadData()); + + Optional> readOptional = transactionProxy.read( + TestModel.TEST_PATH).get(5, TimeUnit.SECONDS); + + assertEquals("NormalizedNode isPresent", false, readOptional.isPresent()); + + // test case with node as read data reply + NormalizedNode expectedNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME); + + doReturn(readDataReply(expectedNode)).when(mockActorContext).executeOperationAsync( + any(ActorSelection.class), eqReadData()); + + readOptional = transactionProxy.read(TestModel.TEST_PATH).get(5, TimeUnit.SECONDS); + + assertEquals("NormalizedNode isPresent", true, readOptional.isPresent()); + + assertEquals("Response NormalizedNode", expectedNode, readOptional.get()); + + // test for local data exists + doReturn(dataExistsReply(true)).when(mockActorContext).executeOperationAsync( + any(ActorSelection.class), eqDataExists()); + + boolean exists = transactionProxy.exists(TestModel.TEST_PATH).checkedGet(); + + assertEquals("Exists response", true, exists); + } + + @Test + public void testLocalTxActorWrite() throws Exception { + ActorSystem actorSystem = getSystem(); + ActorRef shardActorRef = actorSystem.actorOf(Props.create(DoNothingActor.class)); + + doReturn(actorSystem.actorSelection(shardActorRef.path())). + when(mockActorContext).actorSelection(shardActorRef.path().toString()); + + doReturn(Optional.of(actorSystem.actorSelection(shardActorRef.path()))). + when(mockActorContext).findPrimaryShard(eq(DefaultShardStrategy.DEFAULT_SHARD)); + + String actorPath = "akka.tcp://system@127.0.0.1:2550/user/tx-actor"; + CreateTransactionReply createTransactionReply = CreateTransactionReply.newBuilder() + .setTransactionId("txn-1") + .setTransactionActorPath(actorPath) + .build(); + + doReturn(createTransactionReply).when(mockActorContext). + executeOperation(eq(actorSystem.actorSelection(shardActorRef.path())), + eqCreateTransaction(memberName, WRITE_ONLY)); + + doReturn(true).when(mockActorContext).isLocalPath(actorPath); + + NormalizedNode nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME); + + doReturn(writeDataReply()).when(mockActorContext).executeOperationAsync( + any(ActorSelection.class), eqWriteData(nodeToWrite)); + + TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, WRITE_ONLY); + transactionProxy.write(TestModel.TEST_PATH, nodeToWrite); + + verify(mockActorContext).executeOperationAsync( + any(ActorSelection.class), eqWriteData(nodeToWrite)); + + //testing local merge + doReturn(mergeDataReply()).when(mockActorContext).executeOperationAsync( + any(ActorSelection.class), eqMergeData(nodeToWrite)); + + transactionProxy.merge(TestModel.TEST_PATH, nodeToWrite); + + verify(mockActorContext).executeOperationAsync( + any(ActorSelection.class), eqMergeData(nodeToWrite)); + + + //testing local delete + doReturn(deleteDataReply()).when(mockActorContext).executeOperationAsync( + any(ActorSelection.class), eqDeleteData()); + + transactionProxy.delete(TestModel.TEST_PATH); + + verify(mockActorContext).executeOperationAsync(any(ActorSelection.class), eqDeleteData()); + + verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(), + WriteDataReply.class, MergeDataReply.class, DeleteDataReply.class); + + // testing ready + doReturn(readyTxReply(shardActorRef.path().toString())).when(mockActorContext).executeOperationAsync( + any(ActorSelection.class), isA(ReadyTransaction.class)); + + DOMStoreThreePhaseCommitCohort ready = transactionProxy.ready(); + + assertTrue(ready instanceof ThreePhaseCommitCohortProxy); + + ThreePhaseCommitCohortProxy proxy = (ThreePhaseCommitCohortProxy) ready; + + verifyCohortFutures(proxy, getSystem().actorSelection(shardActorRef.path())); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardIdentifierTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardIdentifierTest.java index afcd045434..0b5e7132c7 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardIdentifierTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardIdentifierTest.java @@ -14,5 +14,14 @@ public class ShardIdentifierTest { assertEquals("member-1-shard-inventory-config", id.toString()); } + @Test + public void testFromShardIdString(){ + String shardIdStr = "member-1-shard-inventory-config"; + + ShardIdentifier id = ShardIdentifier.builder().fromShardIdString(shardIdStr).build(); + assertEquals("member-1", id.getMemberName()); + assertEquals("inventory", id.getShardName()); + assertEquals("config", id.getType()); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/messages/MergeDataTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/messages/MergeDataTest.java index 75128e6a25..8f3ca9c535 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/messages/MergeDataTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/messages/MergeDataTest.java @@ -1,47 +1,21 @@ package org.opendaylight.controller.cluster.datastore.messages; -import junit.framework.Assert; +import org.junit.Assert; import org.junit.Test; -import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec; import org.opendaylight.controller.md.cluster.datastore.model.TestModel; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; public class MergeDataTest { @Test - public void testBasic(){ - MergeData mergeData = new MergeData(TestModel.TEST_PATH, ImmutableNodes - .containerNode(TestModel.TEST_QNAME), - TestModel.createTestContext()); - - MergeData output = MergeData - .fromSerializable(mergeData.toSerializable(), - TestModel.createTestContext()); - - } - - @Test - public void testNormalizedNodeEncodeDecode(){ - NormalizedNode expected = - ImmutableNodes.containerNode(TestModel.TEST_QNAME); - - - NormalizedNodeMessages.Container node = - new NormalizedNodeToNodeCodec(TestModel.createTestContext()) - .encode(TestModel.TEST_PATH, - expected); - - String parentPath = node.getParentPath(); - - NormalizedNodeMessages.Node normalizedNode = - node.getNormalizedNode(); - - NormalizedNode actual = new NormalizedNodeToNodeCodec(TestModel.createTestContext()).decode(TestModel.TEST_PATH, - normalizedNode); - - - Assert.assertEquals(expected, actual); + public void testSerialization() { + SchemaContext schemaContext = TestModel.createTestContext(); + MergeData expected = new MergeData(TestModel.TEST_PATH, ImmutableNodes + .containerNode(TestModel.TEST_QNAME), schemaContext); + + MergeData actual = MergeData.fromSerializable(expected.toSerializable(), schemaContext); + Assert.assertEquals("getPath", expected.getPath(), actual.getPath()); + Assert.assertEquals("getData", expected.getData(), actual.getData()); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/messages/WriteDataTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/messages/WriteDataTest.java new file mode 100644 index 0000000000..6a5d65f8da --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/messages/WriteDataTest.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.cluster.datastore.messages; + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.md.cluster.datastore.model.TestModel; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * Unit tests for WriteData. + * + * @author Thomas Pantelis + */ +public class WriteDataTest { + + @Test + public void testSerialization() { + SchemaContext schemaContext = TestModel.createTestContext(); + WriteData expected = new WriteData(TestModel.TEST_PATH, ImmutableNodes + .containerNode(TestModel.TEST_QNAME), schemaContext); + + WriteData actual = WriteData.fromSerializable(expected.toSerializable(), schemaContext); + Assert.assertEquals("getPath", expected.getPath(), actual.getPath()); + Assert.assertEquals("getData", expected.getData(), actual.getData()); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/modification/MergeModificationTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/modification/MergeModificationTest.java index 9af3439ae1..5d2021167b 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/modification/MergeModificationTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/modification/MergeModificationTest.java @@ -7,22 +7,38 @@ import org.opendaylight.controller.md.cluster.datastore.model.TestModel; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; public class MergeModificationTest extends AbstractModificationTest{ - @Test - public void testApply() throws Exception { - //TODO : Need to write a better test for this + @Test + public void testApply() throws Exception { + //TODO : Need to write a better test for this - //Write something into the datastore - DOMStoreReadWriteTransaction writeTransaction = store.newReadWriteTransaction(); - MergeModification writeModification = new MergeModification(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), TestModel.createTestContext()); - writeModification.apply(writeTransaction); - commitTransaction(writeTransaction); + //Write something into the datastore + DOMStoreReadWriteTransaction writeTransaction = store.newReadWriteTransaction(); + MergeModification writeModification = new MergeModification(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), TestModel.createTestContext()); + writeModification.apply(writeTransaction); + commitTransaction(writeTransaction); - //Check if it's in the datastore - Optional> data = readData(TestModel.TEST_PATH); - Assert.assertTrue(data.isPresent()); + //Check if it's in the datastore + Optional> data = readData(TestModel.TEST_PATH); + Assert.assertTrue(data.isPresent()); - } + } + + @Test + public void testSerialization() { + SchemaContext schemaContext = TestModel.createTestContext(); + NormalizedNode node = ImmutableNodes.containerNode(TestModel.TEST_QNAME); + MergeModification mergeModification = new MergeModification(TestModel.TEST_PATH, + node, schemaContext); + + Object serialized = mergeModification.toSerializable(); + + MergeModification newModification = MergeModification.fromSerializable(serialized, schemaContext); + + Assert.assertEquals("getPath", TestModel.TEST_PATH, newModification.getPath()); + Assert.assertEquals("getData", node, newModification.getData()); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/modification/MutableCompositeModificationTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/modification/MutableCompositeModificationTest.java index 03aaace0e3..f8116aa78d 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/modification/MutableCompositeModificationTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/modification/MutableCompositeModificationTest.java @@ -35,8 +35,9 @@ public class MutableCompositeModificationTest extends AbstractModificationTest { MutableCompositeModification compositeModification = new MutableCompositeModification(); compositeModification.addModification(new WriteModification(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), TestModel.createTestContext())); - - assertNotEquals(compositeModification.toSerializable(), compositeModification.toSerializable()); - + Object one = compositeModification.toSerializable(); + try{Thread.sleep(10);}catch(Exception err){} + Object two = compositeModification.toSerializable(); + assertNotEquals(one,two); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/modification/WriteModificationTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/modification/WriteModificationTest.java index 75d8c00db8..3a82fffccb 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/modification/WriteModificationTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/modification/WriteModificationTest.java @@ -7,20 +7,36 @@ import org.opendaylight.controller.md.cluster.datastore.model.TestModel; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; public class WriteModificationTest extends AbstractModificationTest{ - @Test - public void testApply() throws Exception { - //Write something into the datastore - DOMStoreReadWriteTransaction writeTransaction = store.newReadWriteTransaction(); - WriteModification writeModification = new WriteModification(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), TestModel.createTestContext()); - writeModification.apply(writeTransaction); - commitTransaction(writeTransaction); + @Test + public void testApply() throws Exception { + //Write something into the datastore + DOMStoreReadWriteTransaction writeTransaction = store.newReadWriteTransaction(); + WriteModification writeModification = new WriteModification(TestModel.TEST_PATH, + ImmutableNodes.containerNode(TestModel.TEST_QNAME), TestModel.createTestContext()); + writeModification.apply(writeTransaction); + commitTransaction(writeTransaction); - //Check if it's in the datastore - Optional> data = readData(TestModel.TEST_PATH); - Assert.assertTrue(data.isPresent()); + //Check if it's in the datastore + Optional> data = readData(TestModel.TEST_PATH); + Assert.assertTrue(data.isPresent()); + } - } + @Test + public void testSerialization() { + SchemaContext schemaContext = TestModel.createTestContext(); + NormalizedNode node = ImmutableNodes.containerNode(TestModel.TEST_QNAME); + WriteModification writeModification = new WriteModification(TestModel.TEST_PATH, + node, schemaContext); + + Object serialized = writeModification.toSerializable(); + + WriteModification newModification = WriteModification.fromSerializable(serialized, schemaContext); + + Assert.assertEquals("getPath", TestModel.TEST_PATH, newModification.getPath()); + Assert.assertEquals("getData", node, newModification.getData()); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java index 5d8fb8393d..60f9a2d9dc 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java @@ -1,14 +1,12 @@ package org.opendaylight.controller.cluster.datastore.utils; -import java.util.concurrent.TimeUnit; import akka.actor.ActorRef; import akka.actor.ActorSelection; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.japi.Creator; import akka.testkit.JavaTestKit; - +import com.google.common.base.Optional; import org.junit.Test; import org.opendaylight.controller.cluster.datastore.AbstractActorTest; import org.opendaylight.controller.cluster.datastore.ClusterWrapper; @@ -16,49 +14,15 @@ import org.opendaylight.controller.cluster.datastore.Configuration; import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard; import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound; import org.opendaylight.controller.cluster.datastore.messages.LocalShardNotFound; - import scala.concurrent.Await; import scala.concurrent.Future; import scala.concurrent.duration.Duration; +import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; public class ActorContextTest extends AbstractActorTest{ - @Test - public void testResolvePathForRemoteActor(){ - ActorContext actorContext = - new ActorContext(mock(ActorSystem.class), mock(ActorRef.class),mock( - ClusterWrapper.class), - mock(Configuration.class)); - - String actual = actorContext.resolvePath( - "akka.tcp://system@127.0.0.1:2550/user/shardmanager/shard", - "akka://system/user/shardmanager/shard/transaction"); - - String expected = "akka.tcp://system@127.0.0.1:2550/user/shardmanager/shard/transaction"; - - assertEquals(expected, actual); - } - - @Test - public void testResolvePathForLocalActor(){ - ActorContext actorContext = - new ActorContext(getSystem(), mock(ActorRef.class), mock(ClusterWrapper.class), - mock(Configuration.class)); - - String actual = actorContext.resolvePath( - "akka://system/user/shardmanager/shard", - "akka://system/user/shardmanager/shard/transaction"); - - String expected = "akka://system/user/shardmanager/shard/transaction"; - - assertEquals(expected, actual); - - System.out.println(actorContext - .actorFor("akka://system/user/shardmanager/shard/transaction")); - } - private static class MockShardManager extends UntypedActor { @@ -101,7 +65,7 @@ public class ActorContextTest extends AbstractActorTest{ } @Test - public void testExecuteLocalShardOperationWithShardFound(){ + public void testFindLocalShardWithShardFound(){ new JavaTestKit(getSystem()) {{ new Within(duration("1 seconds")) { @@ -117,9 +81,9 @@ public class ActorContextTest extends AbstractActorTest{ new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), mock(Configuration.class)); - Object out = actorContext.executeLocalShardOperation("default", "hello"); + Optional out = actorContext.findLocalShard("default"); - assertEquals("hello", out); + assertEquals(shardActorRef, out.get()); expectNoMsg(); @@ -130,149 +94,92 @@ public class ActorContextTest extends AbstractActorTest{ } @Test - public void testExecuteLocalShardOperationWithShardNotFound(){ + public void testFindLocalShardWithShardNotFound(){ new JavaTestKit(getSystem()) {{ + ActorRef shardManagerActorRef = getSystem() + .actorOf(MockShardManager.props(false, null)); - new Within(duration("1 seconds")) { - @Override - protected void run() { - - ActorRef shardManagerActorRef = getSystem() - .actorOf(MockShardManager.props(false, null)); - - ActorContext actorContext = - new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), + ActorContext actorContext = + new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), mock(Configuration.class)); - Object out = actorContext.executeLocalShardOperation("default", "hello"); - - assertNull(out); - - - expectNoMsg(); - } - }; + Optional out = actorContext.findLocalShard("default"); + assertTrue(!out.isPresent()); }}; } - @Test - public void testFindLocalShardWithShardFound(){ - new JavaTestKit(getSystem()) {{ - - new Within(duration("1 seconds")) { - @Override - protected void run() { - - ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class)); - - ActorRef shardManagerActorRef = getSystem() - .actorOf(MockShardManager.props(true, shardActorRef)); - - ActorContext actorContext = - new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), - mock(Configuration.class)); - - Object out = actorContext.findLocalShard("default"); - - assertEquals(shardActorRef, out); - - - expectNoMsg(); - } - }; - }}; - - } - - @Test - public void testFindLocalShardWithShardNotFound(){ + public void testExecuteRemoteOperation() { new JavaTestKit(getSystem()) {{ + ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class)); - new Within(duration("1 seconds")) { - @Override - protected void run() { + ActorRef shardManagerActorRef = getSystem() + .actorOf(MockShardManager.props(true, shardActorRef)); - ActorRef shardManagerActorRef = getSystem() - .actorOf(MockShardManager.props(false, null)); - - ActorContext actorContext = - new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), + ActorContext actorContext = + new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), mock(Configuration.class)); - Object out = actorContext.findLocalShard("default"); - - assertNull(out); + ActorSelection actor = actorContext.actorSelection(shardActorRef.path()); + Object out = actorContext.executeOperation(actor, "hello"); - expectNoMsg(); - } - }; + assertEquals("hello", out); }}; - } @Test - public void testExecuteRemoteOperation() { + public void testExecuteRemoteOperationAsync() { new JavaTestKit(getSystem()) {{ + ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class)); - new Within(duration("3 seconds")) { - @Override - protected void run() { - - ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class)); - - ActorRef shardManagerActorRef = getSystem() - .actorOf(MockShardManager.props(true, shardActorRef)); + ActorRef shardManagerActorRef = getSystem() + .actorOf(MockShardManager.props(true, shardActorRef)); - ActorContext actorContext = - new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), + ActorContext actorContext = + new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), mock(Configuration.class)); - ActorSelection actor = actorContext.actorSelection(shardActorRef.path()); - - Object out = actorContext.executeRemoteOperation(actor, "hello"); + ActorSelection actor = actorContext.actorSelection(shardActorRef.path()); - assertEquals("hello", out); + Future future = actorContext.executeOperationAsync(actor, "hello"); - expectNoMsg(); - } - }; + try { + Object result = Await.result(future, Duration.create(3, TimeUnit.SECONDS)); + assertEquals("Result", "hello", result); + } catch(Exception e) { + throw new AssertionError(e); + } }}; } @Test - public void testExecuteRemoteOperationAsync() { - new JavaTestKit(getSystem()) {{ - - new Within(duration("3 seconds")) { - @Override - protected void run() { + public void testIsLocalPath() { + MockClusterWrapper clusterWrapper = new MockClusterWrapper(); + ActorContext actorContext = + new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); - ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class)); + clusterWrapper.setSelfAddress(""); + assertEquals(false, actorContext.isLocalPath(null)); + assertEquals(false, actorContext.isLocalPath("")); - ActorRef shardManagerActorRef = getSystem() - .actorOf(MockShardManager.props(true, shardActorRef)); + clusterWrapper.setSelfAddress(null); + assertEquals(false, actorContext.isLocalPath("")); - ActorContext actorContext = - new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), - mock(Configuration.class)); + clusterWrapper.setSelfAddress("akka://test/user/$b"); + assertEquals(false, actorContext.isLocalPath("akka://test/user/$a")); - ActorSelection actor = actorContext.actorSelection(shardActorRef.path()); + clusterWrapper.setSelfAddress("akka.tcp://system@127.0.0.1:2550/"); + assertEquals(true, actorContext.isLocalPath("akka.tcp://system@127.0.0.1:2550/")); - Future future = actorContext.executeRemoteOperationAsync(actor, "hello"); + clusterWrapper.setSelfAddress("akka.tcp://system@127.0.0.1:2550"); + assertEquals(false, actorContext.isLocalPath("akka.tcp://system@127.0.0.1:2550/")); - try { - Object result = Await.result(future, Duration.create(3, TimeUnit.SECONDS)); - assertEquals("Result", "hello", result); - } catch(Exception e) { - throw new AssertionError(e); - } + clusterWrapper.setSelfAddress("akka.tcp://system@128.0.0.1:2550/"); + assertEquals(false, actorContext.isLocalPath("akka.tcp://system@127.0.0.1:2550/")); - expectNoMsg(); - } - }; - }}; + clusterWrapper.setSelfAddress("akka.tcp://system@127.0.0.1:2551/"); + assertEquals(false, actorContext.isLocalPath("akka.tcp://system@127.0.0.1:2550/")); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/InMemoryJournal.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/InMemoryJournal.java new file mode 100644 index 0000000000..3486753082 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/InMemoryJournal.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.cluster.datastore.utils; + +import static org.junit.Assert.assertEquals; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import com.google.common.collect.Maps; +import com.google.common.util.concurrent.Uninterruptibles; +import scala.concurrent.Future; +import akka.dispatch.Futures; +import akka.japi.Procedure; +import akka.persistence.PersistentConfirmation; +import akka.persistence.PersistentId; +import akka.persistence.PersistentImpl; +import akka.persistence.PersistentRepr; +import akka.persistence.journal.japi.AsyncWriteJournal; + +public class InMemoryJournal extends AsyncWriteJournal { + + private static final Map> journals = new ConcurrentHashMap<>(); + + private static final Map deleteMessagesCompleteLatches = new ConcurrentHashMap<>(); + + public static void addEntry(String persistenceId, long sequenceNr, Object data) { + Map journal = journals.get(persistenceId); + if(journal == null) { + journal = Maps.newLinkedHashMap(); + journals.put(persistenceId, journal); + } + + synchronized (journal) { + journal.put(sequenceNr, data); + } + } + + public static void clear() { + journals.clear(); + } + + public static Map get(String persistenceId) { + Map journal = journals.get(persistenceId); + return journal != null ? journal : Collections.emptyMap(); + } + + public static void waitForDeleteMessagesComplete(String persistenceId) { + assertEquals("Recovery complete", true, Uninterruptibles.awaitUninterruptibly( + deleteMessagesCompleteLatches.get(persistenceId), 5, TimeUnit.SECONDS)); + } + + public static void addDeleteMessagesCompleteLatch(String persistenceId) { + deleteMessagesCompleteLatches.put(persistenceId, new CountDownLatch(1)); + } + + @Override + public Future doAsyncReplayMessages(final String persistenceId, long fromSequenceNr, + long toSequenceNr, long max, final Procedure replayCallback) { + return Futures.future(new Callable() { + @Override + public Void call() throws Exception { + Map journal = journals.get(persistenceId); + if(journal == null) { + return null; + } + + synchronized (journal) { + for (Map.Entry entry : journal.entrySet()) { + PersistentRepr persistentMessage = + new PersistentImpl(entry.getValue(), entry.getKey(), persistenceId, + false, null, null); + replayCallback.apply(persistentMessage); + } + } + + return null; + } + }, context().dispatcher()); + } + + @Override + public Future doAsyncReadHighestSequenceNr(String persistenceId, long fromSequenceNr) { + return Futures.successful(-1L); + } + + @Override + public Future doAsyncWriteMessages(final Iterable messages) { + return Futures.future(new Callable() { + @Override + public Void call() throws Exception { + for (PersistentRepr repr : messages) { + Map journal = journals.get(repr.persistenceId()); + if(journal == null) { + journal = Maps.newLinkedHashMap(); + journals.put(repr.persistenceId(), journal); + } + + synchronized (journal) { + journal.put(repr.sequenceNr(), repr.payload()); + } + } + return null; + } + }, context().dispatcher()); + } + + @Override + public Future doAsyncWriteConfirmations(Iterable confirmations) { + return Futures.successful(null); + } + + @Override + public Future doAsyncDeleteMessages(Iterable messageIds, boolean permanent) { + return Futures.successful(null); + } + + @Override + public Future doAsyncDeleteMessagesTo(String persistenceId, long toSequenceNr, boolean permanent) { + Map journal = journals.get(persistenceId); + if(journal != null) { + synchronized (journal) { + Iterator iter = journal.keySet().iterator(); + while(iter.hasNext()) { + Long n = iter.next(); + if(n <= toSequenceNr) { + iter.remove(); + } + } + } + } + + CountDownLatch latch = deleteMessagesCompleteLatches.get(persistenceId); + if(latch != null) { + latch.countDown(); + } + + return Futures.successful(null); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/InMemorySnapshotStore.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/InMemorySnapshotStore.java index 0e492f0fbb..22e522b760 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/InMemorySnapshotStore.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/InMemorySnapshotStore.java @@ -16,46 +16,66 @@ import akka.persistence.SnapshotSelectionCriteria; import akka.persistence.snapshot.japi.SnapshotStore; import com.google.common.collect.Iterables; import scala.concurrent.Future; - import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.opendaylight.controller.cluster.raft.Snapshot; public class InMemorySnapshotStore extends SnapshotStore { - Map> snapshots = new HashMap<>(); + private static Map> snapshots = new ConcurrentHashMap<>(); + + public static void addSnapshot(String persistentId, Snapshot snapshot) { + List snapshotList = snapshots.get(persistentId); + + if(snapshotList == null) { + snapshotList = new ArrayList<>(); + snapshots.put(persistentId, snapshotList); + } + + snapshotList.add(new StoredSnapshot(new SnapshotMetadata(persistentId, snapshotList.size(), + System.currentTimeMillis()), snapshot)); + } + + public static void clear() { + snapshots.clear(); + } - @Override public Future> doLoadAsync(String s, + @Override + public Future> doLoadAsync(String s, SnapshotSelectionCriteria snapshotSelectionCriteria) { - List snapshotList = snapshots.get(s); + List snapshotList = snapshots.get(s); if(snapshotList == null){ return Futures.successful(Option.none()); } - Snapshot snapshot = Iterables.getLast(snapshotList); + StoredSnapshot snapshot = Iterables.getLast(snapshotList); SelectedSnapshot selectedSnapshot = new SelectedSnapshot(snapshot.getMetadata(), snapshot.getData()); return Futures.successful(Option.some(selectedSnapshot)); } - @Override public Future doSaveAsync(SnapshotMetadata snapshotMetadata, Object o) { - List snapshotList = snapshots.get(snapshotMetadata.persistenceId()); + @Override + public Future doSaveAsync(SnapshotMetadata snapshotMetadata, Object o) { + List snapshotList = snapshots.get(snapshotMetadata.persistenceId()); if(snapshotList == null){ snapshotList = new ArrayList<>(); snapshots.put(snapshotMetadata.persistenceId(), snapshotList); } - snapshotList.add(new Snapshot(snapshotMetadata, o)); + snapshotList.add(new StoredSnapshot(snapshotMetadata, o)); return Futures.successful(null); } - @Override public void onSaved(SnapshotMetadata snapshotMetadata) throws Exception { + @Override + public void onSaved(SnapshotMetadata snapshotMetadata) throws Exception { } - @Override public void doDelete(SnapshotMetadata snapshotMetadata) throws Exception { - List snapshotList = snapshots.get(snapshotMetadata.persistenceId()); + @Override + public void doDelete(SnapshotMetadata snapshotMetadata) throws Exception { + List snapshotList = snapshots.get(snapshotMetadata.persistenceId()); if(snapshotList == null){ return; @@ -64,7 +84,7 @@ public class InMemorySnapshotStore extends SnapshotStore { int deleteIndex = -1; for(int i=0;i snapshotList = snapshots.get(s); + List snapshotList = snapshots.get(s); if(snapshotList == null){ return; @@ -90,11 +111,11 @@ public class InMemorySnapshotStore extends SnapshotStore { snapshots.remove(s); } - private static class Snapshot { + private static class StoredSnapshot { private final SnapshotMetadata metadata; private final Object data; - private Snapshot(SnapshotMetadata metadata, Object data) { + private StoredSnapshot(SnapshotMetadata metadata, Object data) { this.metadata = metadata; this.data = data; } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockActorContext.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockActorContext.java index 8fa3a17f90..81b6bccaf0 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockActorContext.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockActorContext.java @@ -12,6 +12,7 @@ import static org.junit.Assert.assertNotNull; import akka.actor.ActorRef; import akka.actor.ActorSelection; import akka.actor.ActorSystem; +import com.google.common.base.Optional; public class MockActorContext extends ActorContext { @@ -30,19 +31,13 @@ public class MockActorContext extends ActorContext { super(actorSystem, shardManager, new MockClusterWrapper(), new MockConfiguration()); } - - @Override public Object executeShardOperation(String shardName, - Object message) { - return executeShardOperationResponse; - } - - @Override public Object executeRemoteOperation(ActorSelection actor, - Object message) { + @Override public Object executeOperation(ActorSelection actor, + Object message) { return executeRemoteOperationResponse; } - @Override public ActorSelection findPrimary(String shardName) { - return null; + @Override public Optional findPrimaryShard(String shardName) { + return Optional.absent(); } public void setExecuteShardOperationResponse(Object response){ @@ -74,14 +69,9 @@ public class MockActorContext extends ActorContext { } @Override - public Object executeLocalOperation(ActorRef actor, - Object message) { + public Object executeOperation(ActorRef actor, + Object message) { return this.executeLocalOperationResponse; } - @Override - public Object executeLocalShardOperation(String shardName, - Object message) { - return this.executeLocalShardOperationResponse; - } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockClusterWrapper.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockClusterWrapper.java index 803aa03b7c..b80506d17d 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockClusterWrapper.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockClusterWrapper.java @@ -15,19 +15,31 @@ import akka.cluster.MemberStatus; import akka.cluster.UniqueAddress; import org.opendaylight.controller.cluster.datastore.ClusterWrapper; import scala.collection.JavaConversions; - import java.util.HashSet; import java.util.Set; public class MockClusterWrapper implements ClusterWrapper{ - @Override public void subscribeToMemberEvents(ActorRef actorRef) { + private String selfAddress = "akka.tcp://test@127.0.0.1:2550/user/member-1-shard-test-config"; + + @Override + public void subscribeToMemberEvents(ActorRef actorRef) { } - @Override public String getCurrentMemberName() { + @Override + public String getCurrentMemberName() { return "member-1"; } + @Override + public String getSelfAddress() { + return selfAddress; + } + + public void setSelfAddress(String selfAddress) { + this.selfAddress = selfAddress; + } + public static void sendMemberUp(ActorRef to, String memberName, String address){ to.tell(createMemberUp(memberName, address), null); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/TestUtils.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/TestUtils.java index 4ddba2f1b9..3bad468950 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/TestUtils.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/TestUtils.java @@ -21,7 +21,7 @@ public class TestUtils { ActorContext testContext = new ActorContext(actorSystem, actorSystem.actorOf( Props.create(DoNothingActor.class)), new MockClusterWrapper(), new MockConfiguration()); Object messages = testContext - .executeLocalOperation(actorRef, "messages"); + .executeOperation(actorRef, "messages"); Assert.assertNotNull(messages); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/CompositeModel.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/CompositeModel.java index ece312752d..1f3732e362 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/CompositeModel.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/CompositeModel.java @@ -293,7 +293,7 @@ public class CompositeModel { Set childAugmentations = new HashSet<>(); childAugmentations.add(AUG_QNAME); final YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier = - new YangInstanceIdentifier.AugmentationIdentifier(null, childAugmentations); + new YangInstanceIdentifier.AugmentationIdentifier(childAugmentations); final AugmentationNode augmentationNode = Builders.augmentationBuilder() .withNodeIdentifier(augmentationIdentifier) diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/SampleModelsTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/SampleModelsTest.java index be8713c702..2300f9d130 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/SampleModelsTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/SampleModelsTest.java @@ -12,7 +12,6 @@ import junit.framework.Assert; import org.junit.Test; import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec; import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; public class SampleModelsTest { @@ -23,14 +22,12 @@ public class SampleModelsTest { final NormalizedNodeMessages.Container node = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()) - .encode(YangInstanceIdentifier.of(PeopleModel.BASE_QNAME), - expected); + .encode(expected); final NormalizedNodeMessages.Node normalizedNode = node.getNormalizedNode(); - final NormalizedNode actual = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()).decode(YangInstanceIdentifier.of(PeopleModel.BASE_QNAME), - normalizedNode); + final NormalizedNode actual = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()).decode(normalizedNode); Assert.assertEquals(expected, actual); @@ -45,14 +42,12 @@ public class SampleModelsTest { final NormalizedNodeMessages.Container node = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()) - .encode(YangInstanceIdentifier.of(CarsModel.BASE_QNAME), - expected); + .encode(expected); final NormalizedNodeMessages.Node normalizedNode = node.getNormalizedNode(); final NormalizedNode actual = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()).decode( - YangInstanceIdentifier.of(CarsModel.BASE_QNAME), normalizedNode); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/application.conf b/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/application.conf index f0dadc618b..3a37dd9376 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/application.conf +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/application.conf @@ -1,5 +1,6 @@ akka { persistence.snapshot-store.plugin = "in-memory-snapshot-store" + persistence.journal.plugin = "in-memory-journal" loggers = ["akka.testkit.TestEventListener", "akka.event.slf4j.Slf4jLogger"] @@ -17,6 +18,10 @@ akka { } } +in-memory-journal { + class = "org.opendaylight.controller.cluster.datastore.utils.InMemoryJournal" +} + in-memory-snapshot-store { # Class name of the plugin. class = "org.opendaylight.controller.cluster.datastore.utils.InMemorySnapshotStore" diff --git a/opendaylight/md-sal/sal-dom-api/pom.xml b/opendaylight/md-sal/sal-dom-api/pom.xml index ab392a06f8..0302a7d920 100644 --- a/opendaylight/md-sal/sal-dom-api/pom.xml +++ b/opendaylight/md-sal/sal-dom-api/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-core-api bundle diff --git a/opendaylight/md-sal/sal-dom-broker/pom.xml b/opendaylight/md-sal/sal-dom-broker/pom.xml index 96e353b80e..dc20296ff5 100644 --- a/opendaylight/md-sal/sal-dom-broker/pom.xml +++ b/opendaylight/md-sal/sal-dom-broker/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-broker-impl bundle @@ -45,7 +45,7 @@ org.opendaylight.controller sal-inmemory-datastore - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomInmemoryDataBrokerModule.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomInmemoryDataBrokerModule.java index ac62974d29..8f01a393c6 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomInmemoryDataBrokerModule.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomInmemoryDataBrokerModule.java @@ -8,18 +8,24 @@ package org.opendaylight.controller.config.yang.md.sal.dom.impl; import java.util.EnumMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitDeadlockException; import org.opendaylight.controller.md.sal.common.util.jmx.AbstractMXBean; import org.opendaylight.controller.md.sal.common.util.jmx.ThreadExecutorStatsMXBeanImpl; +import org.opendaylight.controller.md.sal.dom.broker.impl.DOMConcurrentDataCommitCoordinator; import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl; +import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataCommitCoordinatorImpl; +import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataCommitExecutor; import org.opendaylight.controller.md.sal.dom.broker.impl.jmx.CommitStatsMXBeanImpl; import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory; import org.opendaylight.controller.sal.core.spi.data.DOMStore; +import org.opendaylight.yangtools.util.DurationStatisticsTracker; import org.opendaylight.yangtools.util.concurrent.DeadlockDetectingListeningExecutorService; import org.opendaylight.yangtools.util.concurrent.SpecialExecutors; +import com.google.common.collect.Lists; /** * @@ -65,17 +71,6 @@ public final class DomInmemoryDataBrokerModule extends datastores.put(LogicalDatastoreType.OPERATIONAL, operStore); datastores.put(LogicalDatastoreType.CONFIGURATION, configStore); - /* - * We use a single-threaded executor for commits with a bounded queue capacity. If the - * queue capacity is reached, subsequent commit tasks will be rejected and the commits will - * fail. This is done to relieve back pressure. This should be an extreme scenario - either - * there's deadlock(s) somewhere and the controller is unstable or some rogue component is - * continuously hammering commits too fast or the controller is just over-capacity for the - * system it's running on. - */ - ExecutorService commitExecutor = SpecialExecutors.newBoundedSingleThreadExecutor( - getMaxDataBrokerCommitQueueSize(), "WriteTxCommit"); - /* * We use an executor for commit ListenableFuture callbacks that favors reusing available * threads over creating new threads at the expense of execution time. The assumption is @@ -88,31 +83,65 @@ public final class DomInmemoryDataBrokerModule extends getMaxDataBrokerFutureCallbackPoolSize(), getMaxDataBrokerFutureCallbackQueueSize(), "CommitFutures"); - DOMDataBrokerImpl newDataBroker = new DOMDataBrokerImpl(datastores, - new DeadlockDetectingListeningExecutorService(commitExecutor, - TransactionCommitDeadlockException.DEADLOCK_EXCEPTION_SUPPLIER, - listenableFutureExecutor)); + final List mBeans = Lists.newArrayList(); + + DOMDataCommitExecutor commitCoordinator; + DurationStatisticsTracker commitStatsTracker = null; + + if(getAllowConcurrentCommits()) { + DOMConcurrentDataCommitCoordinator coordinator = + new DOMConcurrentDataCommitCoordinator(listenableFutureExecutor); + commitStatsTracker = coordinator.getCommitStatsTracker(); + commitCoordinator = coordinator; + } else { + /* + * We use a single-threaded executor for commits with a bounded queue capacity. If the + * queue capacity is reached, subsequent commit tasks will be rejected and the commits will + * fail. This is done to relieve back pressure. This should be an extreme scenario - either + * there's deadlock(s) somewhere and the controller is unstable or some rogue component is + * continuously hammering commits too fast or the controller is just over-capacity for the + * system it's running on. + */ + ExecutorService commitExecutor = SpecialExecutors.newBoundedSingleThreadExecutor( + getMaxDataBrokerCommitQueueSize(), "WriteTxCommit"); + + DOMDataCommitCoordinatorImpl coordinator = new DOMDataCommitCoordinatorImpl( + new DeadlockDetectingListeningExecutorService(commitExecutor, + TransactionCommitDeadlockException.DEADLOCK_EXCEPTION_SUPPLIER, + listenableFutureExecutor)); + + commitStatsTracker = coordinator.getCommitStatsTracker(); + commitCoordinator = coordinator; + + final AbstractMXBean commitExecutorStatsMXBean = + ThreadExecutorStatsMXBeanImpl.create(commitExecutor, "CommitExecutorStats", + JMX_BEAN_TYPE, null); + if(commitExecutorStatsMXBean != null) { + mBeans.add(commitExecutorStatsMXBean); + } + } - final CommitStatsMXBeanImpl commitStatsMXBean = new CommitStatsMXBeanImpl( - newDataBroker.getCommitStatsTracker(), JMX_BEAN_TYPE); - commitStatsMXBean.registerMBean(); + DOMDataBrokerImpl newDataBroker = new DOMDataBrokerImpl(datastores, commitCoordinator); + + if(commitStatsTracker != null) { + final CommitStatsMXBeanImpl commitStatsMXBean = new CommitStatsMXBeanImpl( + commitStatsTracker, JMX_BEAN_TYPE); + commitStatsMXBean.registerMBean(); + mBeans.add(commitStatsMXBean); + } - final AbstractMXBean commitExecutorStatsMXBean = - ThreadExecutorStatsMXBeanImpl.create(commitExecutor, "CommitExecutorStats", - JMX_BEAN_TYPE, null); final AbstractMXBean commitFutureStatsMXBean = ThreadExecutorStatsMXBeanImpl.create(listenableFutureExecutor, "CommitFutureExecutorStats", JMX_BEAN_TYPE, null); + if(commitFutureStatsMXBean != null) { + mBeans.add(commitFutureStatsMXBean); + } newDataBroker.setCloseable(new AutoCloseable() { @Override public void close() { - commitStatsMXBean.unregisterMBean(); - if (commitExecutorStatsMXBean != null) { - commitExecutorStatsMXBean.unregisterMBean(); - } - if (commitFutureStatsMXBean != null) { - commitFutureStatsMXBean.unregisterMBean(); + for(AbstractMXBean mBean: mBeans) { + mBean.unregisterMBean(); } } }); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/HashMapDataStoreModule.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/HashMapDataStoreModule.java deleted file mode 100644 index df1b5a3403..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/HashMapDataStoreModule.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.config.yang.md.sal.dom.impl; - -import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore; - -/** -* -*/ -public final class HashMapDataStoreModule extends org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractHashMapDataStoreModule -{ - - public HashMapDataStoreModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { - super(identifier, dependencyResolver); - } - - public HashMapDataStoreModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, HashMapDataStoreModule oldModule, java.lang.AutoCloseable oldInstance) { - super(identifier, dependencyResolver, oldModule, oldInstance); - } - - @Override - public void validate(){ - super.validate(); - // Add custom validation for module attributes here. - } - - @Override - public java.lang.AutoCloseable createInstance() { - HashMapDataStore store = new HashMapDataStore(); - return store; - } -} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMConcurrentDataCommitCoordinator.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMConcurrentDataCommitCoordinator.java new file mode 100644 index 0000000000..605d71d81e --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMConcurrentDataCommitCoordinator.java @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.md.sal.dom.broker.impl; + +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; +import org.opendaylight.yangtools.util.DurationStatisticsTracker; +import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; +import com.google.common.util.concurrent.AbstractFuture; +import com.google.common.util.concurrent.AbstractListeningExecutorService; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +/** + * Implementation of DOMDataCommitExecutor that coordinates transaction commits concurrently. The 3 + * commit phases (canCommit, preCommit, and commit) are performed serially and non-blocking + * (ie async) per transaction but multiple transaction commits can run concurrent. + * + * @author Thomas Pantelis + */ +public class DOMConcurrentDataCommitCoordinator implements DOMDataCommitExecutor { + + private static final String CAN_COMMIT = "CAN_COMMIT"; + private static final String PRE_COMMIT = "PRE_COMMIT"; + private static final String COMMIT = "COMMIT"; + + private static final Logger LOG = LoggerFactory.getLogger(DOMConcurrentDataCommitCoordinator.class); + + private final DurationStatisticsTracker commitStatsTracker = DurationStatisticsTracker.createConcurrent(); + + /** + * This executor is used to execute Future listener callback Runnables async. + */ + private final ExecutorService clientFutureCallbackExecutor; + + /** + * This executor is re-used internally in calls to Futures#addCallback to avoid the overhead + * of Futures#addCallback creating a MoreExecutors#sameThreadExecutor for each call. + */ + private final ExecutorService internalFutureCallbackExecutor = new SimpleSameThreadExecutor(); + + public DOMConcurrentDataCommitCoordinator(ExecutorService listenableFutureExecutor) { + this.clientFutureCallbackExecutor = Preconditions.checkNotNull(listenableFutureExecutor); + } + + public DurationStatisticsTracker getCommitStatsTracker() { + return commitStatsTracker; + } + + @Override + public CheckedFuture submit(DOMDataWriteTransaction transaction, + Iterable cohorts) { + + Preconditions.checkArgument(transaction != null, "Transaction must not be null."); + Preconditions.checkArgument(cohorts != null, "Cohorts must not be null."); + LOG.debug("Tx: {} is submitted for execution.", transaction.getIdentifier()); + + final int cohortSize = Iterables.size(cohorts); + final AsyncNotifyingSettableFuture clientSubmitFuture = + new AsyncNotifyingSettableFuture(clientFutureCallbackExecutor); + + doCanCommit(clientSubmitFuture, transaction, cohorts, cohortSize); + + return MappingCheckedFuture.create(clientSubmitFuture, + TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER); + } + + private void doCanCommit(final AsyncNotifyingSettableFuture clientSubmitFuture, + final DOMDataWriteTransaction transaction, + final Iterable cohorts, final int cohortSize) { + + final long startTime = System.nanoTime(); + + // Not using Futures.allAsList here to avoid its internal overhead. + final AtomicInteger remaining = new AtomicInteger(cohortSize); + FutureCallback futureCallback = new FutureCallback() { + @Override + public void onSuccess(Boolean result) { + if (result == null || !result) { + handleException(clientSubmitFuture, transaction, cohorts, cohortSize, + CAN_COMMIT, new TransactionCommitFailedException( + "Can Commit failed, no detailed cause available.")); + } else { + if(remaining.decrementAndGet() == 0) { + // All cohorts completed successfully - we can move on to the preCommit phase + doPreCommit(startTime, clientSubmitFuture, transaction, cohorts, cohortSize); + } + } + } + + @Override + public void onFailure(Throwable t) { + handleException(clientSubmitFuture, transaction, cohorts, cohortSize, CAN_COMMIT, t); + } + }; + + for(DOMStoreThreePhaseCommitCohort cohort: cohorts) { + ListenableFuture canCommitFuture = cohort.canCommit(); + Futures.addCallback(canCommitFuture, futureCallback, internalFutureCallbackExecutor); + } + } + + private void doPreCommit(final long startTime, final AsyncNotifyingSettableFuture clientSubmitFuture, + final DOMDataWriteTransaction transaction, + final Iterable cohorts, final int cohortSize) { + + // Not using Futures.allAsList here to avoid its internal overhead. + final AtomicInteger remaining = new AtomicInteger(cohortSize); + FutureCallback futureCallback = new FutureCallback() { + @Override + public void onSuccess(Void notUsed) { + if(remaining.decrementAndGet() == 0) { + // All cohorts completed successfully - we can move on to the commit phase + doCommit(startTime, clientSubmitFuture, transaction, cohorts, cohortSize); + } + } + + @Override + public void onFailure(Throwable t) { + handleException(clientSubmitFuture, transaction, cohorts, cohortSize, CAN_COMMIT, t); + } + }; + + for(DOMStoreThreePhaseCommitCohort cohort: cohorts) { + ListenableFuture preCommitFuture = cohort.preCommit(); + Futures.addCallback(preCommitFuture, futureCallback, internalFutureCallbackExecutor); + } + } + + private void doCommit(final long startTime, final AsyncNotifyingSettableFuture clientSubmitFuture, + final DOMDataWriteTransaction transaction, + final Iterable cohorts, final int cohortSize) { + + // Not using Futures.allAsList here to avoid its internal overhead. + final AtomicInteger remaining = new AtomicInteger(cohortSize); + FutureCallback futureCallback = new FutureCallback() { + @Override + public void onSuccess(Void notUsed) { + if(remaining.decrementAndGet() == 0) { + // All cohorts completed successfully - we're done. + commitStatsTracker.addDuration(System.nanoTime() - startTime); + + clientSubmitFuture.set(); + } + } + + @Override + public void onFailure(Throwable t) { + handleException(clientSubmitFuture, transaction, cohorts, cohortSize, CAN_COMMIT, t); + } + }; + + for(DOMStoreThreePhaseCommitCohort cohort: cohorts) { + ListenableFuture commitFuture = cohort.commit(); + Futures.addCallback(commitFuture, futureCallback, internalFutureCallbackExecutor); + } + } + + private void handleException(final AsyncNotifyingSettableFuture clientSubmitFuture, + final DOMDataWriteTransaction transaction, + final Iterable cohorts, int cohortSize, + final String phase, final Throwable t) { + + if(clientSubmitFuture.isDone()) { + // We must have had failures from multiple cohorts. + return; + } + + LOG.warn("Tx: {} Error during phase {}, starting Abort", transaction.getIdentifier(), phase, t); + Exception e; + if(t instanceof Exception) { + e = (Exception)t; + } else { + e = new RuntimeException("Unexpected error occurred", t); + } + + final TransactionCommitFailedException clientException = + TransactionCommitFailedExceptionMapper.CAN_COMMIT_ERROR_MAPPER.apply(e); + + // Transaction failed - tell all cohorts to abort. + + @SuppressWarnings("unchecked") + ListenableFuture[] canCommitFutures = new ListenableFuture[cohortSize]; + int i = 0; + for(DOMStoreThreePhaseCommitCohort cohort: cohorts) { + canCommitFutures[i++] = cohort.abort(); + } + + ListenableFuture> combinedFuture = Futures.allAsList(canCommitFutures); + Futures.addCallback(combinedFuture, new FutureCallback>() { + @Override + public void onSuccess(List notUsed) { + // Propagate the original exception to the client. + clientSubmitFuture.setException(clientException); + } + + @Override + public void onFailure(Throwable t) { + LOG.error("Tx: {} Error during Abort.", transaction.getIdentifier(), t); + + // Propagate the original exception as that is what caused the Tx to fail and is + // what's interesting to the client. + clientSubmitFuture.setException(clientException); + } + }, internalFutureCallbackExecutor); + } + + /** + * A settable future that uses an {@link Executor} to execute listener callback Runnables, + * registered via {@link #addListener}, asynchronously when this future completes. This is + * done to guarantee listener executions are off-loaded onto another thread to avoid blocking + * the thread that completed this future, as a common use case is to pass an executor that runs + * tasks in the same thread as the caller (ie MoreExecutors#sameThreadExecutor) + * to {@link #addListener}. + * + * FIXME: This class should probably be moved to yangtools common utils for re-usability and + * unified with AsyncNotifyingListenableFutureTask. + */ + private static class AsyncNotifyingSettableFuture extends AbstractFuture { + + /** + * ThreadLocal used to detect if the task completion thread is running the future listener Runnables. + */ + private static final ThreadLocal ON_TASK_COMPLETION_THREAD_TL = new ThreadLocal(); + + private final ExecutorService listenerExecutor; + + AsyncNotifyingSettableFuture(ExecutorService listenerExecutor) { + this.listenerExecutor = listenerExecutor; + } + + @Override + public void addListener(final Runnable listener, final Executor executor) { + // Wrap the listener Runnable in a DelegatingRunnable. If the specified executor is one + // that runs tasks in the same thread as the caller submitting the task + // (e.g. {@link com.google.common.util.concurrent.MoreExecutors#sameThreadExecutor}) and + // the listener is executed from the #set methods, then the DelegatingRunnable will detect + // this via the ThreadLocal and submit the listener Runnable to the listenerExecutor. + // + // On the other hand, if this task is already complete, the call to ExecutionList#add in + // superclass will execute the listener Runnable immediately and, since the ThreadLocal + // won't be set, the DelegatingRunnable will run the listener Runnable inline. + super.addListener(new DelegatingRunnable(listener, listenerExecutor), executor); + } + + boolean set() { + ON_TASK_COMPLETION_THREAD_TL.set(Boolean.TRUE); + try { + return super.set(null); + } finally { + ON_TASK_COMPLETION_THREAD_TL.set(null); + } + } + + @Override + protected boolean setException(Throwable throwable) { + ON_TASK_COMPLETION_THREAD_TL.set(Boolean.TRUE); + try { + return super.setException(throwable); + } finally { + ON_TASK_COMPLETION_THREAD_TL.set(null); + } + } + + private static final class DelegatingRunnable implements Runnable { + private final Runnable delegate; + private final Executor executor; + + DelegatingRunnable(final Runnable delegate, final Executor executor) { + this.delegate = Preconditions.checkNotNull(delegate); + this.executor = Preconditions.checkNotNull(executor); + } + + @Override + public void run() { + if (ON_TASK_COMPLETION_THREAD_TL.get() != null) { + // We're running on the task completion thread so off-load to the executor. + LOG.trace("Submitting ListenenableFuture Runnable from thread {} to executor {}", + Thread.currentThread().getName(), executor); + executor.execute(delegate); + } else { + // We're not running on the task completion thread so run the delegate inline. + LOG.trace("Executing ListenenableFuture Runnable on this thread: {}", + Thread.currentThread().getName()); + delegate.run(); + } + } + } + } + + /** + * A simple same-thread executor without the internal locking overhead that + * MoreExecutors#sameThreadExecutor has. The #execute method is the only one of concern - we + * don't shutdown the executor so the other methods irrelevant. + */ + private static class SimpleSameThreadExecutor extends AbstractListeningExecutorService { + + @Override + public void execute(Runnable command) { + command.run(); + } + + @Override + public boolean awaitTermination(long arg0, TimeUnit arg1) throws InterruptedException { + return true; + } + + @Override + public boolean isShutdown() { + return false; + } + + @Override + public boolean isTerminated() { + return false; + } + + @Override + public void shutdown() { + } + + @Override + public List shutdownNow() { + return null; + } + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java index 8ed5206132..3f7db01c6b 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java @@ -8,7 +8,7 @@ package org.opendaylight.controller.md.sal.dom.broker.impl; import static com.google.common.base.Preconditions.checkState; -import com.google.common.base.Optional; +import com.google.common.base.Preconditions; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.ListeningExecutorService; import java.util.EnumMap; @@ -26,7 +26,6 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStore; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.util.DurationStatsTracker; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,25 +35,26 @@ public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory datastores, final ListeningExecutorService executor) { + this(datastores, new DOMDataCommitCoordinatorImpl(executor)); + } + + public DOMDataBrokerImpl(final Map datastores, + final DOMDataCommitExecutor coordinator) { super(datastores); - this.coordinator = new DOMDataCommitCoordinatorImpl(executor); + this.coordinator = Preconditions.checkNotNull(coordinator); } public void setCloseable(final AutoCloseable closeable) { this.closeable = closeable; } - public DurationStatsTracker getCommitStatsTracker() { - return coordinator.getCommitStatsTracker(); - } - @Override public void close() { super.close(); @@ -102,6 +102,6 @@ public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory submit(final DOMDataWriteTransaction transaction, final Iterable cohorts) { LOG.debug("Transaction: {} submitted with cohorts {}.", transaction.getIdentifier(), cohorts); - return coordinator.submit(transaction, cohorts, Optional. absent()); + return coordinator.submit(transaction, cohorts); } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java index 7cd6afa466..0b1dd1c5e0 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java @@ -6,11 +6,14 @@ */ package org.opendaylight.controller.md.sal.dom.broker.impl; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; import java.util.Map; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; @@ -27,16 +30,27 @@ import org.slf4j.LoggerFactory; * {@link org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType} type. * */ -public class DOMDataBrokerTransactionChainImpl extends AbstractDOMForwardedTransactionFactory - implements DOMTransactionChain, DOMDataCommitErrorListener { +final class DOMDataBrokerTransactionChainImpl extends AbstractDOMForwardedTransactionFactory + implements DOMTransactionChain { + private static enum State { + RUNNING, + CLOSING, + CLOSED, + FAILED, + } + private static final AtomicIntegerFieldUpdater COUNTER_UPDATER = + AtomicIntegerFieldUpdater.newUpdater(DOMDataBrokerTransactionChainImpl.class, "counter"); + private static final AtomicReferenceFieldUpdater STATE_UPDATER = + AtomicReferenceFieldUpdater.newUpdater(DOMDataBrokerTransactionChainImpl.class, State.class, "state"); private static final Logger LOG = LoggerFactory.getLogger(DOMDataBrokerTransactionChainImpl.class); private final AtomicLong txNum = new AtomicLong(); private final DOMDataCommitExecutor coordinator; private final TransactionChainListener listener; private final long chainId; - private volatile boolean failed = false; + private volatile State state = State.RUNNING; + private volatile int counter = 0; /** * @@ -62,37 +76,70 @@ public class DOMDataBrokerTransactionChainImpl extends AbstractDOMForwardedTrans this.listener = Preconditions.checkNotNull(listener); } + private void checkNotFailed() { + Preconditions.checkState(state != State.FAILED, "Transaction chain has failed"); + } + @Override protected Object newTransactionIdentifier() { return "DOM-CHAIN-" + chainId + "-" + txNum.getAndIncrement(); } @Override - public CheckedFuture submit( + public CheckedFuture submit( final DOMDataWriteTransaction transaction, final Iterable cohorts) { + checkNotFailed(); checkNotClosed(); - return coordinator.submit(transaction, cohorts, Optional. of(this)); + final CheckedFuture ret = coordinator.submit(transaction, cohorts); + + COUNTER_UPDATER.incrementAndGet(this); + Futures.addCallback(ret, new FutureCallback() { + @Override + public void onSuccess(final Void result) { + transactionCompleted(); + } + + @Override + public void onFailure(final Throwable t) { + transactionFailed(transaction, t); + } + }); + + return ret; } @Override public void close() { - super.close(); + final boolean success = STATE_UPDATER.compareAndSet(this, State.RUNNING, State.CLOSING); + if (!success) { + LOG.debug("Chain {} is no longer running", this); + return; + } + super.close(); for (DOMStoreTransactionChain subChain : getTxFactories().values()) { subChain.close(); } - if (!failed) { - LOG.debug("Transaction chain {} successfully finished.", this); - // FIXME: this event should be emitted once all operations complete - listener.onTransactionChainSuccessful(this); + if (counter == 0) { + finishClose(); } } - @Override - public void onCommitFailed(final DOMDataWriteTransaction tx, final Throwable cause) { - failed = true; + private void finishClose() { + state = State.CLOSED; + listener.onTransactionChainSuccessful(this); + } + + private void transactionCompleted() { + if (COUNTER_UPDATER.decrementAndGet(this) == 0 && state == State.CLOSING) { + finishClose(); + } + } + + private void transactionFailed(final DOMDataWriteTransaction tx, final Throwable cause) { + state = State.FAILED; LOG.debug("Transaction chain {} failed.", this, cause); listener.onTransactionChainFailed(this, tx, cause); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java index 77cf105ed6..c1ecaa67df 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java @@ -6,7 +6,6 @@ */ package org.opendaylight.controller.md.sal.dom.broker.impl; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; import com.google.common.collect.Iterables; @@ -21,7 +20,7 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; -import org.opendaylight.yangtools.util.DurationStatsTracker; +import org.opendaylight.yangtools.util.DurationStatisticsTracker; import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,7 +42,7 @@ import org.slf4j.LoggerFactory; public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor { private static final Logger LOG = LoggerFactory.getLogger(DOMDataCommitCoordinatorImpl.class); - private final DurationStatsTracker commitStatsTracker = new DurationStatsTracker(); + private final DurationStatisticsTracker commitStatsTracker = DurationStatisticsTracker.createConcurrent(); private final ListeningExecutorService executor; /** @@ -57,22 +56,21 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor { this.executor = Preconditions.checkNotNull(executor, "executor must not be null."); } - public DurationStatsTracker getCommitStatsTracker() { + public DurationStatisticsTracker getCommitStatsTracker() { return commitStatsTracker; } @Override public CheckedFuture submit(final DOMDataWriteTransaction transaction, - final Iterable cohorts, final Optional listener) { + final Iterable cohorts) { Preconditions.checkArgument(transaction != null, "Transaction must not be null."); Preconditions.checkArgument(cohorts != null, "Cohorts must not be null."); - Preconditions.checkArgument(listener != null, "Listener must not be null"); LOG.debug("Tx: {} is submitted for execution.", transaction.getIdentifier()); ListenableFuture commitFuture = null; try { commitFuture = executor.submit(new CommitCoordinationTask(transaction, cohorts, - listener, commitStatsTracker)); + commitStatsTracker)); } catch(RejectedExecutionException e) { LOG.error("The commit executor's queue is full - submit task was rejected. \n" + executor, e); @@ -81,10 +79,6 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor { "Could not submit the commit task - the commit queue capacity has been exceeded.", e)); } - if (listener.isPresent()) { - Futures.addCallback(commitFuture, new DOMDataCommitErrorInvoker(transaction, listener.get())); - } - return MappingCheckedFuture.create(commitFuture, TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER); } @@ -135,17 +129,16 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor { AtomicReferenceFieldUpdater.newUpdater(CommitCoordinationTask.class, CommitPhase.class, "currentPhase"); private final DOMDataWriteTransaction tx; private final Iterable cohorts; - private final DurationStatsTracker commitStatTracker; + private final DurationStatisticsTracker commitStatTracker; private final int cohortSize; private volatile CommitPhase currentPhase = CommitPhase.SUBMITTED; public CommitCoordinationTask(final DOMDataWriteTransaction transaction, final Iterable cohorts, - final Optional listener, - final DurationStatsTracker commitStatTracker) { + final DurationStatisticsTracker commitStatsTracker) { this.tx = Preconditions.checkNotNull(transaction, "transaction must not be null"); this.cohorts = Preconditions.checkNotNull(cohorts, "cohorts must not be null"); - this.commitStatTracker = commitStatTracker; + this.commitStatTracker = commitStatsTracker; this.cohortSize = Iterables.size(cohorts); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorInvoker.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorInvoker.java deleted file mode 100644 index 5ce9241dd2..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorInvoker.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.sal.dom.broker.impl; - -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.FutureCallback; - -/** - * - * Utility implemetation of {@link FutureCallback} which is responsible - * for invoking {@link DOMDataCommitErrorListener} on TransactionCommit failed. - * - * When {@link #onFailure(Throwable)} is invoked, supplied {@link DOMDataCommitErrorListener} - * callback is invoked with associated transaction and throwable is invoked on listener. - * - */ -class DOMDataCommitErrorInvoker implements FutureCallback { - - private final DOMDataWriteTransaction tx; - private final DOMDataCommitErrorListener listener; - - - /** - * - * Construct new DOMDataCommitErrorInvoker. - * - * @param transaction Transaction which should be passed as argument to {@link DOMDataCommitErrorListener#onCommitFailed(DOMDataWriteTransaction, Throwable)} - * @param listener Listener which should be invoked on error. - */ - public DOMDataCommitErrorInvoker(DOMDataWriteTransaction transaction, DOMDataCommitErrorListener listener) { - this.tx = Preconditions.checkNotNull(transaction, "Transaction must not be null"); - this.listener = Preconditions.checkNotNull(listener, "Listener must not be null"); - } - - @Override - public void onFailure(Throwable t) { - listener.onCommitFailed(tx, t); - } - - @Override - public void onSuccess(Void result) { - // NOOP - } -} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorListener.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorListener.java deleted file mode 100644 index 80bc6696f0..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorListener.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.sal.dom.broker.impl; - -import java.util.EventListener; - -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; - -/** - * - * Listener on transaction failure which may be passed to - * {@link DOMDataCommitExecutor}. This listener is notified during transaction - * processing, before result is delivered to other client code outside MD-SAL. - * This allows implementors to update their internal state before transaction - * failure is visible to client code. - * - * This is internal API for MD-SAL implementations, for consumer facing error - * listeners see {@link org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener}. - * - */ -interface DOMDataCommitErrorListener extends EventListener { - - /** - * - * Callback which is invoked on transaction failure during three phase - * commit in {@link DOMDataCommitExecutor}. - * - * - * Implementation of this callback MUST NOT do any blocking calls or any - * calls to MD-SAL, since this callback is invoked synchronously on MD-SAL - * Broker coordination thread. - * - * @param tx - * Transaction which failed - * @param cause - * Failure reason - */ - void onCommitFailed(DOMDataWriteTransaction tx, Throwable cause); - -} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitExecutor.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitExecutor.java index 234758ca75..dae14b5128 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitExecutor.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitExecutor.java @@ -7,11 +7,10 @@ */ package org.opendaylight.controller.md.sal.dom.broker.impl; +import com.google.common.util.concurrent.CheckedFuture; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; /** * Executor of Three Phase Commit coordination for @@ -22,7 +21,7 @@ import com.google.common.util.concurrent.CheckedFuture; * * */ -interface DOMDataCommitExecutor { +public interface DOMDataCommitExecutor { /** * Submits supplied transaction to be executed in context of provided @@ -35,15 +34,13 @@ interface DOMDataCommitExecutor { * Transaction to be used as context for reporting * @param cohort * DOM Store cohorts representing provided transaction, its - * subtransactoins. - * @param listener - * Error listener which should be notified if transaction failed. + * subtransactions. * @return a CheckedFuture. if commit coordination on cohorts finished successfully, * nothing is returned from the Future, On failure, * the Future fails with a {@link TransactionCommitFailedException}. * */ CheckedFuture submit(DOMDataWriteTransaction tx, - Iterable cohort, Optional listener); + Iterable cohort); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImpl.java index f67f6b0148..0d5306faf7 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImpl.java @@ -9,9 +9,8 @@ package org.opendaylight.controller.md.sal.dom.broker.impl.jmx; import javax.annotation.Nonnull; - import org.opendaylight.controller.md.sal.common.util.jmx.AbstractMXBean; -import org.opendaylight.yangtools.util.DurationStatsTracker; +import org.opendaylight.yangtools.util.DurationStatisticsTracker; /** * Implementation of the CommitStatsMXBean interface. @@ -20,7 +19,7 @@ import org.opendaylight.yangtools.util.DurationStatsTracker; */ public class CommitStatsMXBeanImpl extends AbstractMXBean implements CommitStatsMXBean { - private final DurationStatsTracker commitStatsTracker; + private final DurationStatisticsTracker commitStatsTracker; /** * Constructor. @@ -28,7 +27,7 @@ public class CommitStatsMXBeanImpl extends AbstractMXBean implements CommitStats * @param commitStatsTracker the DurationStatsTracker used to obtain the stats. * @param mBeanType mBeanType Used as the type property in the bean's ObjectName. */ - public CommitStatsMXBeanImpl(@Nonnull DurationStatsTracker commitStatsTracker, + public CommitStatsMXBeanImpl(@Nonnull DurationStatisticsTracker commitStatsTracker, @Nonnull String mBeanType) { super("CommitStats", mBeanType, null); this.commitStatsTracker = commitStatsTracker; diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.java deleted file mode 100644 index 1f82bd71b4..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.sal.dom.broker.impl; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; -import org.opendaylight.controller.md.sal.common.api.data.DataModification; -import org.opendaylight.controller.sal.core.api.data.DataStore; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.common.RpcResultBuilder; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class HashMapDataStore implements DataStore, AutoCloseable { - private static final Logger LOG = LoggerFactory - .getLogger(HashMapDataStore.class); - - private final Map configuration = new ConcurrentHashMap(); - private final Map operational = new ConcurrentHashMap(); - - @Override - public boolean containsConfigurationPath(final YangInstanceIdentifier path) { - return configuration.containsKey(path); - } - - @Override - public boolean containsOperationalPath(final YangInstanceIdentifier path) { - return operational.containsKey(path); - } - - @Override - public Iterable getStoredConfigurationPaths() { - return configuration.keySet(); - } - - @Override - public Iterable getStoredOperationalPaths() { - return operational.keySet(); - } - - @Override - public CompositeNode readConfigurationData(final YangInstanceIdentifier path) { - LOG.trace("Reading configuration path {}", path); - return configuration.get(path); - } - - @Override - public CompositeNode readOperationalData(YangInstanceIdentifier path) { - LOG.trace("Reading operational path {}", path); - return operational.get(path); - } - - @Override - public DataCommitHandler.DataCommitTransaction requestCommit( - final DataModification modification) { - return new HashMapDataStoreTransaction(modification, this); - } - - public RpcResult rollback(HashMapDataStoreTransaction transaction) { - return RpcResultBuilder. success().build(); - } - - public RpcResult finish(HashMapDataStoreTransaction transaction) { - final DataModification modification = transaction - .getModification(); - for (final YangInstanceIdentifier removal : modification - .getRemovedConfigurationData()) { - LOG.trace("Removing configuration path {}", removal); - remove(configuration, removal); - } - for (final YangInstanceIdentifier removal : modification - .getRemovedOperationalData()) { - LOG.trace("Removing operational path {}", removal); - remove(operational, removal); - } - if (LOG.isTraceEnabled()) { - for (final YangInstanceIdentifier a : modification - .getUpdatedConfigurationData().keySet()) { - LOG.trace("Adding configuration path {}", a); - } - for (final YangInstanceIdentifier a : modification - .getUpdatedOperationalData().keySet()) { - LOG.trace("Adding operational path {}", a); - } - } - configuration.putAll(modification.getUpdatedConfigurationData()); - operational.putAll(modification.getUpdatedOperationalData()); - - return RpcResultBuilder. success().build(); - } - - public void remove(final Map map, - final YangInstanceIdentifier identifier) { - Set affected = new HashSet(); - for (final YangInstanceIdentifier path : map.keySet()) { - if (identifier.contains(path)) { - affected.add(path); - } - } - for (final YangInstanceIdentifier pathToRemove : affected) { - LOG.trace("Removed path {}", pathToRemove); - map.remove(pathToRemove); - } - } - - @Override - public void close() { - // NOOP - } -} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStoreTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStoreTransaction.java deleted file mode 100644 index ee026b6006..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStoreTransaction.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.sal.dom.broker.impl; - -import org.opendaylight.controller.md.sal.common.api.data.DataModification; -import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; - -public class HashMapDataStoreTransaction implements - DataCommitTransaction { - private final DataModification modification; - private final HashMapDataStore datastore; - - HashMapDataStoreTransaction( - final DataModification modify, - final HashMapDataStore store) { - modification = modify; - datastore = store; - } - - @Override - public RpcResult finish() throws IllegalStateException { - return datastore.finish(this); - } - - @Override - public DataModification getModification() { - return this.modification; - } - - @Override - public RpcResult rollback() throws IllegalStateException { - return datastore.rollback(this); - } -} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang b/opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang index b1df7efcdb..fa6d496193 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang +++ b/opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang @@ -32,12 +32,6 @@ module opendaylight-sal-dom-broker-impl { config:provided-service sal:dom-async-data-broker; } - identity hash-map-data-store { - base config:module-type; - config:provided-service sal:dom-data-store; - config:java-name-prefix HashMapDataStore; - } - identity schema-service-singleton { base config:module-type; config:provided-service sal:schema-service; @@ -126,12 +120,14 @@ module opendaylight-sal-dom-broker-impl { type uint16; description "The maximum queue size for the data broker's commit executor."; } - } - } - - augment "/config:modules/config:module/config:state" { - case hash-map-data-store { - when "/config:modules/config:module/config:type = 'hash-map-data-store'"; + + leaf allow-concurrent-commits { + default false; + type boolean; + description "Specifies whether or not to allow 3-phrase commits to run concurrently. + Use with caution. If set to true, the data store implementations must be prepared + to handle concurrent commits. The default is false"; + } } } @@ -149,4 +145,4 @@ module opendaylight-sal-dom-broker-impl { } } } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMConcurrentDataCommitCoordinatorTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMConcurrentDataCommitCoordinatorTest.java new file mode 100644 index 0000000000..25d7df17d1 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMConcurrentDataCommitCoordinatorTest.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.md.sal.dom.broker.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.inOrder; +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.SettableFuture; +import com.google.common.util.concurrent.Uninterruptibles; + +/** + * Unit tests for DOMConcurrentDataCommitCoordinator. + * + * @author Thomas Pantelis + */ +public class DOMConcurrentDataCommitCoordinatorTest { + + private final DOMDataWriteTransaction transaction = mock(DOMDataWriteTransaction.class); + private final DOMStoreThreePhaseCommitCohort mockCohort1 = mock(DOMStoreThreePhaseCommitCohort.class); + private final DOMStoreThreePhaseCommitCohort mockCohort2 = mock(DOMStoreThreePhaseCommitCohort.class); + private final ThreadPoolExecutor futureExecutor = + new ThreadPoolExecutor(0, 1, 5, TimeUnit.SECONDS, new SynchronousQueue()); + private final DOMConcurrentDataCommitCoordinator coordinator = + new DOMConcurrentDataCommitCoordinator(futureExecutor); + + @Before + public void setup() { + doReturn("tx").when(transaction).getIdentifier(); + } + + @After + public void tearDown() { + futureExecutor.shutdownNow(); + } + + @Test + public void testSuccessfulSubmitAsync() throws Throwable { + testSuccessfulSubmit(true); + } + + @Test + public void testSuccessfulSubmitSync() throws Throwable { + testSuccessfulSubmit(false); + } + + private void testSuccessfulSubmit(final boolean doAsync) throws Throwable { + final CountDownLatch asyncCanCommitContinue = new CountDownLatch(1); + Answer> asyncCanCommit = new Answer>() { + @Override + public ListenableFuture answer(InvocationOnMock invocation) { + final SettableFuture future = SettableFuture.create(); + if(doAsync) { + new Thread() { + @Override + public void run() { + Uninterruptibles.awaitUninterruptibly(asyncCanCommitContinue, + 10, TimeUnit.SECONDS); + future.set(true); + } + }.start(); + } else { + future.set(true); + } + + return future; + } + }; + + doAnswer(asyncCanCommit).when(mockCohort1).canCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort1).preCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort1).commit(); + + doReturn(Futures.immediateFuture(true)).when(mockCohort2).canCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort2).preCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort2).commit(); + + CheckedFuture future = coordinator.submit( + transaction, Arrays.asList(mockCohort1, mockCohort2)); + + final CountDownLatch doneLatch = new CountDownLatch(1); + final AtomicReference caughtEx = new AtomicReference<>(); + Futures.addCallback(future, new FutureCallback() { + @Override + public void onSuccess(Void result) { + doneLatch.countDown(); + } + + @Override + public void onFailure(Throwable t) { + caughtEx.set(t); + doneLatch.countDown(); + } + }); + + asyncCanCommitContinue.countDown(); + + assertEquals("Submit complete", true, doneLatch.await(5, TimeUnit.SECONDS)); + + if(caughtEx.get() != null) { + throw caughtEx.get(); + } + + assertEquals("Task count", doAsync ? 1 : 0, futureExecutor.getTaskCount()); + + InOrder inOrder = inOrder(mockCohort1, mockCohort2); + inOrder.verify(mockCohort1).canCommit(); + inOrder.verify(mockCohort2).canCommit(); + inOrder.verify(mockCohort1).preCommit(); + inOrder.verify(mockCohort2).preCommit(); + inOrder.verify(mockCohort1).commit(); + inOrder.verify(mockCohort2).commit(); + } + + @Test + public void testSubmitWithNegativeCanCommitResponse() throws Exception { + doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort(); + + doReturn(Futures.immediateFuture(false)).when(mockCohort2).canCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort(); + + DOMStoreThreePhaseCommitCohort mockCohort3 = mock(DOMStoreThreePhaseCommitCohort.class); + doReturn(Futures.immediateFuture(false)).when(mockCohort3).canCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort3).abort(); + + CheckedFuture future = coordinator.submit( + transaction, Arrays.asList(mockCohort1, mockCohort2, mockCohort3)); + + assertFailure(future, null, mockCohort1, mockCohort2, mockCohort3); + } + + private void assertFailure(CheckedFuture future, + Exception expCause, DOMStoreThreePhaseCommitCohort... mockCohorts) + throws Exception { + try { + future.checkedGet(5, TimeUnit.SECONDS); + fail("Expected TransactionCommitFailedException"); + } catch (TransactionCommitFailedException e) { + if(expCause != null) { + assertSame("Expected cause", expCause, e.getCause()); + } + + InOrder inOrder = inOrder((Object[])mockCohorts); + for(DOMStoreThreePhaseCommitCohort c: mockCohorts) { + inOrder.verify(c).abort(); + } + } catch (TimeoutException e) { + throw e; + } + } + + @Test + public void testSubmitWithCanCommitException() throws Exception { + doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort(); + + IllegalStateException cause = new IllegalStateException("mock"); + doReturn(Futures.immediateFailedFuture(cause)).when(mockCohort2).canCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort(); + + CheckedFuture future = coordinator.submit( + transaction, Arrays.asList(mockCohort1, mockCohort2)); + + assertFailure(future, cause, mockCohort1, mockCohort2); + } + + @Test + public void testSubmitWithPreCommitException() throws Exception { + doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort1).preCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort(); + + doReturn(Futures.immediateFuture(true)).when(mockCohort2).canCommit(); + IllegalStateException cause = new IllegalStateException("mock"); + doReturn(Futures.immediateFailedFuture(cause)).when(mockCohort2).preCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort(); + + DOMStoreThreePhaseCommitCohort mockCohort3 = mock(DOMStoreThreePhaseCommitCohort.class); + doReturn(Futures.immediateFuture(true)).when(mockCohort3).canCommit(); + doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock2"))). + when(mockCohort3).preCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort3).abort(); + + CheckedFuture future = coordinator.submit( + transaction, Arrays.asList(mockCohort1, mockCohort2, mockCohort3)); + + assertFailure(future, cause, mockCohort1, mockCohort2, mockCohort3); + } + + @Test + public void testSubmitWithCommitException() throws Exception { + doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort1).preCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort1).commit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort(); + + doReturn(Futures.immediateFuture(true)).when(mockCohort2).canCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort2).preCommit(); + IllegalStateException cause = new IllegalStateException("mock"); + doReturn(Futures.immediateFailedFuture(cause)).when(mockCohort2).commit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort(); + + DOMStoreThreePhaseCommitCohort mockCohort3 = mock(DOMStoreThreePhaseCommitCohort.class); + doReturn(Futures.immediateFuture(true)).when(mockCohort3).canCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort3).preCommit(); + doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock2"))). + when(mockCohort3).commit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort3).abort(); + + CheckedFuture future = coordinator.submit( + transaction, Arrays.asList(mockCohort1, mockCohort2, mockCohort3)); + + assertFailure(future, cause, mockCohort1, mockCohort2, mockCohort3); + } + + @Test + public void testSubmitWithAbortException() throws Exception { + doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit(); + doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock abort error"))). + when(mockCohort1).abort(); + + IllegalStateException cause = new IllegalStateException("mock canCommit error"); + doReturn(Futures.immediateFailedFuture(cause)).when(mockCohort2).canCommit(); + doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort(); + + CheckedFuture future = coordinator.submit( + transaction, Arrays.asList(mockCohort1, mockCohort2)); + + assertFailure(future, cause, mockCohort1, mockCohort2); + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManagerTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManagerTest.java index 4d239a93f7..05c4793218 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManagerTest.java +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManagerTest.java @@ -48,7 +48,7 @@ public class BackwardsCompatibleMountPointManagerTest { private BackwardsCompatibleMountPointManager compatibleMountPointManager; static final QName qName = QName.create("namespace", "12-12-1212", "mount"); - static final YangInstanceIdentifier id = YangInstanceIdentifier.builder(qName).build(); + static final YangInstanceIdentifier id = YangInstanceIdentifier.of(qName); @Before public void setUp() throws Exception { diff --git a/opendaylight/md-sal/sal-dom-spi/pom.xml b/opendaylight/md-sal/sal-dom-spi/pom.xml index 88ac86a45e..6cc721e68d 100644 --- a/opendaylight/md-sal/sal-dom-spi/pom.xml +++ b/opendaylight/md-sal/sal-dom-spi/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-core-spi bundle diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/broker/spi/rpc/RpcRoutingStrategy.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/broker/spi/rpc/RpcRoutingStrategy.java index 81203c55fe..6c8f37b66b 100644 --- a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/broker/spi/rpc/RpcRoutingStrategy.java +++ b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/broker/spi/rpc/RpcRoutingStrategy.java @@ -7,6 +7,8 @@ */ package org.opendaylight.controller.md.sal.dom.broker.spi.rpc; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; @@ -14,17 +16,14 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; -import com.google.common.base.Optional; - public abstract class RpcRoutingStrategy implements Identifiable { + private static final QName CONTEXT_REFERENCE = QName.cachedReference(QName.create("urn:opendaylight:yang:extension:yang-ext", + "2013-07-09", "context-reference")); private final QName identifier; - private static final QName CONTEXT_REFERENCE = QName.create("urn:opendaylight:yang:extension:yang-ext", - "2013-07-09", "context-reference"); private RpcRoutingStrategy(final QName identifier) { - super(); - this.identifier = identifier; + this.identifier = Preconditions.checkNotNull(identifier); } /** @@ -47,7 +46,7 @@ public abstract class RpcRoutingStrategy implements Identifiable { public abstract QName getContext(); @Override - public QName getIdentifier() { + public final QName getIdentifier() { return identifier; } @@ -64,14 +63,14 @@ public abstract class RpcRoutingStrategy implements Identifiable { for (DataSchemaNode schemaNode : input.getChildNodes()) { Optional context = getRoutingContext(schemaNode); if (context.isPresent()) { - return createRoutedStrategy(rpc, context.get(), schemaNode.getQName()); + return new RoutedRpcStrategy(rpc.getQName(), context.get(), schemaNode.getQName()); } } } - return createGlobalStrategy(rpc); + return new GlobalRpcStrategy(rpc.getQName()); } - public static Optional getRoutingContext(final DataSchemaNode schemaNode) { + public static Optional getRoutingContext(final DataSchemaNode schemaNode) { for (UnknownSchemaNode extension : schemaNode.getUnknownSchemaNodes()) { if (CONTEXT_REFERENCE.equals(extension.getNodeType())) { return Optional.fromNullable(extension.getQName()); @@ -80,26 +79,14 @@ public abstract class RpcRoutingStrategy implements Identifiable { return Optional.absent(); } - private static RpcRoutingStrategy createRoutedStrategy(final RpcDefinition rpc, final QName context, final QName leafNode) { - return new RoutedRpcStrategy(rpc.getQName(), context, leafNode); - } - - - - private static RpcRoutingStrategy createGlobalStrategy(final RpcDefinition rpc) { - GlobalRpcStrategy ret = new GlobalRpcStrategy(rpc.getQName()); - return ret; - } - - private static class RoutedRpcStrategy extends RpcRoutingStrategy { - - final QName context; + private static final class RoutedRpcStrategy extends RpcRoutingStrategy { + private final QName context; private final QName leaf; private RoutedRpcStrategy(final QName identifier, final QName ctx, final QName leaf) { super(identifier); - this.context = ctx; - this.leaf = leaf; + this.context = Preconditions.checkNotNull(ctx); + this.leaf = Preconditions.checkNotNull(leaf); } @Override @@ -118,7 +105,7 @@ public abstract class RpcRoutingStrategy implements Identifiable { } } - private static class GlobalRpcStrategy extends RpcRoutingStrategy { + private static final class GlobalRpcStrategy extends RpcRoutingStrategy { public GlobalRpcStrategy(final QName identifier) { super(identifier); @@ -131,12 +118,12 @@ public abstract class RpcRoutingStrategy implements Identifiable { @Override public QName getContext() { - throw new UnsupportedOperationException("Not routed strategy does not have context."); + throw new UnsupportedOperationException("Non-routed strategy does not have a context"); } @Override public QName getLeaf() { - throw new UnsupportedOperationException("Not routed strategy does not have context."); + throw new UnsupportedOperationException("Non-routed strategy does not have a context"); } } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-xsql-config/pom.xml b/opendaylight/md-sal/sal-dom-xsql-config/pom.xml index 077405fe6e..e8919d0ee1 100644 --- a/opendaylight/md-sal/sal-dom-xsql-config/pom.xml +++ b/opendaylight/md-sal/sal-dom-xsql-config/pom.xml @@ -12,7 +12,7 @@ sal-parent org.opendaylight.controller - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-dom-xsql-config org.opendaylight.controller diff --git a/opendaylight/md-sal/sal-dom-xsql/pom.xml b/opendaylight/md-sal/sal-dom-xsql/pom.xml index 2ab80daf3b..f5898a2bb9 100644 --- a/opendaylight/md-sal/sal-dom-xsql/pom.xml +++ b/opendaylight/md-sal/sal-dom-xsql/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-dom-xsql bundle diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCDriver.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/odl/xsql/JDBCDriver.java similarity index 84% rename from opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCDriver.java rename to opendaylight/md-sal/sal-dom-xsql/src/main/java/org/odl/xsql/JDBCDriver.java index e4b4e249df..cc92b48a15 100644 --- a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCDriver.java +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/odl/xsql/JDBCDriver.java @@ -1,4 +1,4 @@ -package org.opendaylight.controller.md.sal.dom.xsql.jdbc; +package org.odl.xsql; import java.sql.Connection; import java.sql.Driver; @@ -9,6 +9,8 @@ import java.sql.SQLFeatureNotSupportedException; import java.util.Properties; import java.util.logging.Logger; +import org.opendaylight.controller.md.sal.dom.xsql.jdbc.JDBCConnection; + public class JDBCDriver implements Driver { public static JDBCDriver drv = new JDBCDriver(); @@ -34,11 +36,12 @@ public class JDBCDriver implements Driver { if (url.equals("svr")) { return new JDBCConnection(true); } else { - return new JDBCConnection(url); + return new JDBCConnection(url).getProxy(); } } catch (Exception err) { err.printStackTrace(); } + System.err.println("Error JDBC Connection"); return null; } @@ -55,7 +58,7 @@ public class JDBCDriver implements Driver { @Override public DriverPropertyInfo[] getPropertyInfo(String arg0, Properties arg1) throws SQLException { - DriverPropertyInfo i = new DriverPropertyInfo("NQL", "NQL"); + DriverPropertyInfo i = new DriverPropertyInfo("OpenDayLight", "OpenDayLight"); return new DriverPropertyInfo[] {i}; } diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLAdapter.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLAdapter.java index d1f11ba9a3..ecea744d14 100644 --- a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLAdapter.java +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLAdapter.java @@ -30,6 +30,8 @@ public class XSQLAdapter extends Thread implements SchemaContextListener { private static final int SLEEP = 10000; private static XSQLAdapter a = new XSQLAdapter(); private static PrintStream l = null; + private static String tmpDir = null; + private static File xqlLog = null; public boolean stopped = false; private List elementHosts = new ArrayList(); private String username; @@ -63,10 +65,28 @@ public class XSQLAdapter extends Thread implements SchemaContextListener { } + public void loadBluePrint(){ + try{ + InputStream in = this.getClass().getClassLoader().getResourceAsStream("BluePrintCache.dat"); + if(in!=null){ + this.bluePrint = XSQLBluePrint.load(in); + } + in.close(); + }catch(Exception err){ + err.printStackTrace(); + } + } + public static XSQLAdapter getInstance() { return a; } + public static File getXQLLogfile() { + tmpDir = System.getProperty("java.io.tmpdir"); + xqlLog = new File(tmpDir + "/xql.log"); + return xqlLog; + } + public static void main(String args[]) { XSQLAdapter adapter = new XSQLAdapter(); adapter.start(); @@ -78,7 +98,7 @@ public class XSQLAdapter extends Thread implements SchemaContextListener { synchronized (XSQLAdapter.class) { if (l == null) { l = new PrintStream( - new FileOutputStream("/tmp/xql.log")); + new FileOutputStream(getXQLLogfile())); } } } @@ -96,7 +116,7 @@ public class XSQLAdapter extends Thread implements SchemaContextListener { synchronized (XSQLAdapter.class) { if (l == null) { l = new PrintStream( - new FileOutputStream("/tmp/xql.log")); + new FileOutputStream(getXQLLogfile())); } } } @@ -164,6 +184,10 @@ public class XSQLAdapter extends Thread implements SchemaContextListener { } public void execute(JDBCResultSet rs) { + if(this.domDataBroker==null){ + rs.setFinished(true); + return; + } List tables = rs.getTables(); List roots = collectModuleRoots(tables.get(0),LogicalDatastoreType.OPERATIONAL); roots.addAll(collectModuleRoots(tables.get(0),LogicalDatastoreType.CONFIGURATION)); @@ -282,6 +306,8 @@ public class XSQLAdapter extends Thread implements SchemaContextListener { sout.close(); } catch (Exception err) { } + } else if (input.equals("save")) { + XSQLBluePrint.save(this.bluePrint); } else if (input.equals("tocsv")) { toCsv = !toCsv; sout.println("to csv file is " + toCsv); diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLBluePrint.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLBluePrint.java index 1a31662020..7b51d03a97 100644 --- a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLBluePrint.java +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLBluePrint.java @@ -1,5 +1,12 @@ package org.opendaylight.controller.md.sal.dom.xsql; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; @@ -17,18 +24,20 @@ import java.util.List; import java.util.Map; import java.util.Set; -public class XSQLBluePrint implements DatabaseMetaData { +public class XSQLBluePrint implements DatabaseMetaData, Serializable { - public static final String CACHE_FILE_NAME = "BluePrintCache.dat"; + private static final long serialVersionUID = 1L; + + public static final String CACHE_FILE_NAME = "./BluePrintCache.dat"; private Map tableNameToBluePrint = new HashMap(); - private Map> odlNameToBluePrint = new HashMap>(); + private Map> odlNameToBluePrint = new HashMap>(); private boolean cacheLoadedSuccessfuly = false; private DatabaseMetaData myProxy = null; public static final String replaceAll(String source, String toReplace, - String withThis) { + String withThis) { int index = source.indexOf(toReplace); int index2 = 0; StringBuffer result = new StringBuffer(); @@ -47,9 +56,41 @@ public class XSQLBluePrint implements DatabaseMetaData { public XSQLBluePrint() { } + public static void save(XSQLBluePrint bp) { + ObjectOutputStream out = null; + try { + out = new ObjectOutputStream(new DataOutputStream( + new FileOutputStream(CACHE_FILE_NAME))); + out.writeObject(bp); + } catch (Exception err) { + err.printStackTrace(); + } finally { + try { + out.close(); + } catch (Exception err) { + } + } + } + + public static XSQLBluePrint load(InputStream ins) { + ObjectInputStream in = null; + try { + in = new ObjectInputStream(new DataInputStream(ins)); + return (XSQLBluePrint) in.readObject(); + } catch (Exception err) { + err.printStackTrace(); + } finally { + try { + in.close(); + } catch (Exception err) { + } + } + return null; + } + private class NQLBluePrintProxy implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable { + throws Throwable { System.out.println("Method " + method); return method.invoke(XSQLBluePrint.this, args); } @@ -58,9 +99,9 @@ public class XSQLBluePrint implements DatabaseMetaData { public DatabaseMetaData getProxy() { if (myProxy == null) { try { - myProxy = (DatabaseMetaData) Proxy - .newProxyInstance(getClass().getClassLoader(), - new Class[] {DatabaseMetaData.class}, + myProxy = (DatabaseMetaData) Proxy.newProxyInstance(getClass() + .getClassLoader(), + new Class[] { DatabaseMetaData.class }, new NQLBluePrintProxy()); } catch (Exception err) { err.printStackTrace(); @@ -69,22 +110,12 @@ public class XSQLBluePrint implements DatabaseMetaData { return myProxy; } - /* - public void loadBluePrintCache(String hostName) { - try { - ObjectInputStream in = new ObjectInputStream( - new FileInputStream(hostName + "-" + CACHE_FILE_NAME)); - cache = (Map) in.readObject(); - in.close(); - cacheLoadedSuccessfuly = true; - } catch (Exception err) { - //err.printStackTrace(); - } - }*/ - - public XSQLBluePrintNode[] getBluePrintNodeByODLTableName(String odlTableName) { - Map map = this.odlNameToBluePrint.get(odlTableName); - if(map==null) return null; + public XSQLBluePrintNode[] getBluePrintNodeByODLTableName( + String odlTableName) { + Map map = this.odlNameToBluePrint + .get(odlTableName); + if (map == null) + return null; return map.values().toArray(new XSQLBluePrintNode[map.size()]); } @@ -106,26 +137,28 @@ public class XSQLBluePrint implements DatabaseMetaData { } for (XSQLBluePrintNode n : tableNameToBluePrint.values()) { - if (n.getBluePrintNodeName().toLowerCase().endsWith(tableName.toLowerCase())) { + if (n.getBluePrintNodeName().toLowerCase() + .endsWith(tableName.toLowerCase())) { return n; } } for (XSQLBluePrintNode n : tableNameToBluePrint.values()) { - if (n.getBluePrintNodeName().toLowerCase().equals(tableName.toLowerCase())) { + if (n.getBluePrintNodeName().toLowerCase() + .equals(tableName.toLowerCase())) { return n; } } for (XSQLBluePrintNode n : tableNameToBluePrint.values()) { - if (n.getBluePrintNodeName().toLowerCase().indexOf(tableName.toLowerCase())!= -1) { + if (n.getBluePrintNodeName().toLowerCase() + .indexOf(tableName.toLowerCase()) != -1) { return n; } } return null; } - public boolean isCacheLoaded() { return cacheLoadedSuccessfuly; } @@ -133,7 +166,7 @@ public class XSQLBluePrint implements DatabaseMetaData { private static Map> superClassMap = new HashMap>(); public static Set getInheritance(Class myObjectClass, - Class returnType) { + Class returnType) { if (returnType != null && myObjectClass.equals(returnType)) { return new HashSet(); @@ -171,10 +204,11 @@ public class XSQLBluePrint implements DatabaseMetaData { public void addToBluePrintCache(XSQLBluePrintNode blNode) { this.tableNameToBluePrint.put(blNode.getBluePrintNodeName(), blNode); - Map map = this.odlNameToBluePrint.get(blNode.getODLTableName()); - if(map==null){ - map = new HashMap(); - this.odlNameToBluePrint.put(blNode.getODLTableName(),map); + Map map = this.odlNameToBluePrint.get(blNode + .getODLTableName()); + if (map == null) { + map = new HashMap(); + this.odlNameToBluePrint.put(blNode.getODLTableName(), map); } map.put(blNode.getBluePrintNodeName(), blNode); } @@ -265,15 +299,15 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public ResultSet getAttributes(String catalog, String schemaPattern, - String typeNamePattern, String attributeNamePattern) - throws SQLException { + String typeNamePattern, String attributeNamePattern) + throws SQLException { // TODO Auto-generated method stub return null; } @Override public ResultSet getBestRowIdentifier(String catalog, String schema, - String table, int scope, boolean nullable) throws SQLException { + String table, int scope, boolean nullable) throws SQLException { // TODO Auto-generated method stub return null; } @@ -304,15 +338,15 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public ResultSet getColumnPrivileges(String catalog, String schema, - String table, String columnNamePattern) throws SQLException { + String table, String columnNamePattern) throws SQLException { // TODO Auto-generated method stub return null; } @Override public ResultSet getColumns(String catalog, String schemaPattern, - String tableNamePattern, String columnNamePattern) - throws SQLException { + String tableNamePattern, String columnNamePattern) + throws SQLException { // TODO Auto-generated method stub return null; } @@ -325,8 +359,8 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public ResultSet getCrossReference(String parentCatalog, - String parentSchema, String parentTable, String foreignCatalog, - String foreignSchema, String foreignTable) throws SQLException { + String parentSchema, String parentTable, String foreignCatalog, + String foreignSchema, String foreignTable) throws SQLException { // TODO Auto-generated method stub return null; } @@ -344,7 +378,7 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public String getDatabaseProductName() throws SQLException { - return "VNE Query Language"; + return "OpenDayLight"; } @Override @@ -383,9 +417,8 @@ public class XSQLBluePrint implements DatabaseMetaData { } @Override - public ResultSet getExportedKeys(String catalog, String schema, - String table) - throws SQLException { + public ResultSet getExportedKeys(String catalog, String schema, String table) + throws SQLException { // TODO Auto-generated method stub return null; } @@ -398,15 +431,15 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public ResultSet getFunctionColumns(String catalog, String schemaPattern, - String functionNamePattern, String columnNamePattern) - throws SQLException { + String functionNamePattern, String columnNamePattern) + throws SQLException { // TODO Auto-generated method stub return null; } @Override public ResultSet getFunctions(String catalog, String schemaPattern, - String functionNamePattern) throws SQLException { + String functionNamePattern) throws SQLException { // TODO Auto-generated method stub return null; } @@ -418,16 +451,15 @@ public class XSQLBluePrint implements DatabaseMetaData { } @Override - public ResultSet getImportedKeys(String catalog, String schema, - String table) - throws SQLException { + public ResultSet getImportedKeys(String catalog, String schema, String table) + throws SQLException { // TODO Auto-generated method stub return null; } @Override public ResultSet getIndexInfo(String catalog, String schema, String table, - boolean unique, boolean approximate) throws SQLException { + boolean unique, boolean approximate) throws SQLException { // TODO Auto-generated method stub return null; } @@ -572,22 +604,22 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public ResultSet getPrimaryKeys(String catalog, String schema, String table) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return null; } @Override public ResultSet getProcedureColumns(String catalog, String schemaPattern, - String procedureNamePattern, String columnNamePattern) - throws SQLException { + String procedureNamePattern, String columnNamePattern) + throws SQLException { // TODO Auto-generated method stub return null; } @Override public ResultSet getProcedures(String catalog, String schemaPattern, - String procedureNamePattern) throws SQLException { + String procedureNamePattern) throws SQLException { // TODO Auto-generated method stub return null; } @@ -618,7 +650,7 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public ResultSet getSchemas(String catalog, String schemaPattern) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return null; } @@ -655,14 +687,14 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public ResultSet getSuperTables(String catalog, String schemaPattern, - String tableNamePattern) throws SQLException { + String tableNamePattern) throws SQLException { // TODO Auto-generated method stub return null; } @Override public ResultSet getSuperTypes(String catalog, String schemaPattern, - String typeNamePattern) throws SQLException { + String typeNamePattern) throws SQLException { // TODO Auto-generated method stub return null; } @@ -675,14 +707,14 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public ResultSet getTablePrivileges(String catalog, String schemaPattern, - String tableNamePattern) throws SQLException { + String tableNamePattern) throws SQLException { // TODO Auto-generated method stub return null; } @Override public ResultSet getTables(String catalog, String schemaPattern, - String tableNamePattern, String[] types) throws SQLException { + String tableNamePattern, String[] types) throws SQLException { return new TablesResultSet(this); } @@ -706,7 +738,7 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public ResultSet getUDTs(String catalog, String schemaPattern, - String typeNamePattern, int[] types) throws SQLException { + String typeNamePattern, int[] types) throws SQLException { // TODO Auto-generated method stub return null; } @@ -725,7 +757,7 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public ResultSet getVersionColumns(String catalog, String schema, - String table) throws SQLException { + String table) throws SQLException { // TODO Auto-generated method stub return null; } @@ -905,8 +937,7 @@ public class XSQLBluePrint implements DatabaseMetaData { } @Override - public boolean supportsCatalogsInPrivilegeDefinitions() - throws SQLException { + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { // TODO Auto-generated method stub return false; } @@ -937,7 +968,7 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public boolean supportsConvert(int fromType, int toType) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return false; } @@ -956,21 +987,20 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public boolean supportsDataDefinitionAndDataManipulationTransactions() - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return false; } @Override public boolean supportsDataManipulationTransactionsOnly() - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return false; } @Override - public boolean supportsDifferentTableCorrelationNames() - throws SQLException { + public boolean supportsDifferentTableCorrelationNames() throws SQLException { // TODO Auto-generated method stub return false; } @@ -1133,14 +1163,14 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public boolean supportsResultSetConcurrency(int type, int concurrency) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return false; } @Override public boolean supportsResultSetHoldability(int holdability) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return false; } @@ -1200,8 +1230,7 @@ public class XSQLBluePrint implements DatabaseMetaData { } @Override - public boolean supportsStoredFunctionsUsingCallSyntax() - throws SQLException { + public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { // TODO Auto-generated method stub return false; } @@ -1244,7 +1273,7 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public boolean supportsTransactionIsolationLevel(int level) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return false; } @@ -1299,8 +1328,8 @@ public class XSQLBluePrint implements DatabaseMetaData { @Override public ResultSet getPseudoColumns(String catalog, String schemaPattern, - String tableNamePattern, String columnNamePattern) - throws SQLException { + String tableNamePattern, String columnNamePattern) + throws SQLException { // TODO Auto-generated method stub return null; } diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLBluePrintNode.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLBluePrintNode.java index fbd818e632..8d905f2081 100644 --- a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLBluePrintNode.java +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLBluePrintNode.java @@ -3,7 +3,9 @@ package org.opendaylight.controller.md.sal.dom.xsql; import java.io.Serializable; import java.sql.SQLException; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; public class XSQLBluePrintNode implements Serializable { @@ -11,10 +13,8 @@ public class XSQLBluePrintNode implements Serializable { private static final long serialVersionUID = 1L; private Class myInterface = null; private String myInterfaceString = null; - private Set relations = - new HashSet(); - private Set inheritingNodes = - new HashSet(); + private Set relations = new HashSet(); + private Set inheritingNodes = new HashSet(); private Set children = new HashSet(); private XSQLBluePrintNode parent = null; @@ -22,11 +22,20 @@ public class XSQLBluePrintNode implements Serializable { private transient Set parentHierarchySet = null; private String myInterfaceName = null; private Set columns = new HashSet(); + private Map origNameToColumn = new HashMap(); private transient Object odlNode = null; private boolean module = false; private String bluePrintTableName = null; private String odlTableName = null; + private String origName = null; + + public XSQLBluePrintNode(String name, String _origName, int _level) { + this.level = _level; + this.odlTableName = name; + this.bluePrintTableName = name; + this.origName = _origName; + } public XSQLBluePrintNode(Class _myInterface, int _level) { this.myInterface = _myInterface; @@ -35,16 +44,21 @@ public class XSQLBluePrintNode implements Serializable { this.level = _level; } - public XSQLBluePrintNode(Object _odlNode, int _level,XSQLBluePrintNode _parent) { + public XSQLBluePrintNode(Object _odlNode, int _level, + XSQLBluePrintNode _parent) { this.odlNode = _odlNode; this.level = _level; this.module = XSQLODLUtils.isModule(_odlNode); this.parent = _parent; this.bluePrintTableName = XSQLODLUtils.getBluePrintName(_odlNode); + this.odlTableName = XSQLODLUtils.getODLNodeName(this.odlNode); + } + public String getOrigName() { + return this.origName; } - public String getBluePrintNodeName(){ + public String getBluePrintNodeName() { return this.bluePrintTableName; } @@ -82,10 +96,11 @@ public class XSQLBluePrintNode implements Serializable { } for (XSQLBluePrintRelation dtr : this.relations) { XSQLBluePrintNode parent = dtr.getParent(); - if (!parent.getInterface().equals(this.getInterface()) && !parent - .getInterface().isAssignableFrom(this.getInterface()) && - this.getInterface().isAssignableFrom(parent.getInterface()) - && parent.isModelChild(p)) { + if (!parent.getInterface().equals(this.getInterface()) + && !parent.getInterface().isAssignableFrom( + this.getInterface()) + && this.getInterface().isAssignableFrom( + parent.getInterface()) && parent.isModelChild(p)) { return true; } } @@ -109,8 +124,16 @@ public class XSQLBluePrintNode implements Serializable { } public void addColumn(Object node, String tableName) { - XSQLColumn c = new XSQLColumn(node,getBluePrintNodeName(), this); + XSQLColumn c = new XSQLColumn(node, getBluePrintNodeName(), this); + this.columns.add(c); + } + + public XSQLColumn addColumn(String name, String tableName, String origName, + String origTableName) { + XSQLColumn c = new XSQLColumn(name, tableName, origName, origTableName); this.columns.add(c); + this.origNameToColumn.put(origName, c); + return c; } public void addColumn(String methodName) { @@ -165,17 +188,16 @@ public class XSQLBluePrintNode implements Serializable { throw new SQLException("Unknown field name '" + name + "'"); } - public void addParent(XSQLBluePrintNode parent, String property) { try { if (property.equals("ContainingTPs")) { return; } - //Method m = parent.getInterface().getMethod("get"+property, null); - //if(!m.getDeclaringClass().equals(parent.getInterface())) - //return; - XSQLBluePrintRelation rel = - new XSQLBluePrintRelation(parent, property, myInterface); + // Method m = parent.getInterface().getMethod("get"+property, null); + // if(!m.getDeclaringClass().equals(parent.getInterface())) + // return; + XSQLBluePrintRelation rel = new XSQLBluePrintRelation(parent, + property, myInterface); relations.add(rel); } catch (Exception err) { err.printStackTrace(); @@ -187,8 +209,7 @@ public class XSQLBluePrintNode implements Serializable { } public Set getClonedParents() { - Set result = - new HashSet(); + Set result = new HashSet(); result.addAll(this.relations); return result; } @@ -200,6 +221,9 @@ public class XSQLBluePrintNode implements Serializable { if (odlNode != null) { return getBluePrintNodeName(); } + if (odlTableName != null) { + return odlTableName; + } return "Unknown"; } @@ -216,11 +240,12 @@ public class XSQLBluePrintNode implements Serializable { XSQLBluePrintNode other = (XSQLBluePrintNode) obj; if (odlNode != null) { return getBluePrintNodeName().equals(other.getBluePrintNodeName()); - } else if (this.odlTableName != null) { + } else if (this.odlTableName == null && other.odlTableName != null) + return false; + if (this.odlTableName != null && other.odlTableName == null) + return false; + else return this.odlTableName.equals(other.odlTableName); - } else { - return other.myInterface.equals(myInterface); - } } @Override diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLColumn.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLColumn.java index 55ac600f4a..4c6cca7fa6 100644 --- a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLColumn.java +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLColumn.java @@ -8,6 +8,8 @@ public class XSQLColumn implements Serializable, Comparable { private int charWidth = -1; private Class type = null; private transient Object bluePrintNode = null; + private String origName = null; + private String origTableName = null; public XSQLColumn(Object odlNode, String _tableName, Object _bluePrintNode) { this.name = XSQLODLUtils.getNodeNameFromDSN(odlNode); @@ -16,6 +18,13 @@ public class XSQLColumn implements Serializable, Comparable { this.type = XSQLODLUtils.getTypeForODLColumn(odlNode); } + public XSQLColumn(String _name, String _tableName,String _origName, String _origTableName){ + this.name = _name; + this.tableName = _tableName; + this.origName = _origName; + this.origTableName = _origTableName; + } + public String getName() { return name; } diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCCommand.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCCommand.java index 85ce0e5392..019711157c 100644 --- a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCCommand.java +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCCommand.java @@ -3,6 +3,8 @@ package org.opendaylight.controller.md.sal.dom.xsql.jdbc; import java.io.Serializable; import java.util.Map; +import org.opendaylight.controller.md.sal.dom.xsql.XSQLBluePrint; + public class JDBCCommand implements Serializable { public int type = 0; public static final int TYPE_EXECUTE_QUERY = 1; @@ -10,11 +12,22 @@ public class JDBCCommand implements Serializable { public static final int TYPE_QUERY_RECORD = 3; public static final int TYPE_QUERY_FINISH = 4; public static final int TYPE_QUERY_ERROR = 5; + public static final int TYPE_METADATA = 6; + public static final int TYPE_METADATA_REPLY = 7; private JDBCResultSet rs = null; private Map record = null; private int rsID = -1; private Exception err = null; + private XSQLBluePrint bluePrint = null; + + public JDBCCommand() { + + } + + public void setType(int t) { + this.type = t; + } public JDBCCommand(Exception _err, int _RSID) { this.type = TYPE_QUERY_ERROR; @@ -22,6 +35,11 @@ public class JDBCCommand implements Serializable { this.rsID = _RSID; } + public JDBCCommand(XSQLBluePrint bl) { + this.type = TYPE_METADATA_REPLY; + this.bluePrint = bl; + } + public JDBCCommand(JDBCResultSet _rs, int _type) { this.type = TYPE_EXECUTE_QUERY; this.rs = _rs; @@ -59,4 +77,8 @@ public class JDBCCommand implements Serializable { public Exception getERROR() { return this.err; } + + public XSQLBluePrint getBluePrint() { + return this.bluePrint; + } } diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCConnection.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCConnection.java index 3e72dc95ee..bf1244f2e3 100644 --- a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCConnection.java +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCConnection.java @@ -31,38 +31,59 @@ import java.util.Properties; import java.util.concurrent.Executor; import org.opendaylight.controller.md.sal.dom.xsql.XSQLAdapter; +import org.opendaylight.controller.md.sal.dom.xsql.XSQLBluePrint; -public class JDBCConnection extends Thread implements Connection { +public class JDBCConnection implements Connection, Runnable { private Socket socket = null; private DataInputStream in = null; private DataOutputStream out = null; private LinkedList queue = new LinkedList(); private XSQLAdapter adapter = null; + private XSQLBluePrint metaData = null; + private String addr = null; + private boolean wasClosed = false; public JDBCConnection(Socket s, XSQLAdapter _a) { this.socket = s; this.adapter = _a; try { in = new DataInputStream( - new BufferedInputStream(s.getInputStream())); - out = new DataOutputStream( - new BufferedOutputStream(s.getOutputStream())); + new BufferedInputStream(s.getInputStream())); + out = new DataOutputStream(new BufferedOutputStream( + s.getOutputStream())); new JDBCObjectReader(); - this.start(); + new Thread(this).start(); } catch (Exception err) { err.printStackTrace(); } } - public JDBCConnection(String addr) throws Exception { + public Connection getProxy() { + return this; + /* + return (Connection) Proxy.newProxyInstance(this.getClass() + .getClassLoader(), new Class[] { Connection.class }, + new JDBCProxy(this)); + */ + } + + public JDBCConnection(String _addr) throws Exception { + this.addr = _addr; + init(); + } + + private void init() throws Exception { + if (addr.startsWith("http://")) + addr = addr.substring(7); + System.err.print("Address is:" + addr); socket = new Socket(addr, 40004); try { - in = new DataInputStream( - new BufferedInputStream(socket.getInputStream())); - out = new DataOutputStream( - new BufferedOutputStream(socket.getOutputStream())); + in = new DataInputStream(new BufferedInputStream( + socket.getInputStream())); + out = new DataOutputStream(new BufferedOutputStream( + socket.getOutputStream())); new JDBCObjectReader(); - this.start(); + new Thread(this).start(); } catch (Exception err) { err.printStackTrace(); } @@ -73,12 +94,12 @@ public class JDBCConnection extends Thread implements Connection { ServerSocket s = new ServerSocket(50003); socket = s.accept(); try { - in = new DataInputStream( - new BufferedInputStream(socket.getInputStream())); - out = new DataOutputStream( - new BufferedOutputStream(socket.getOutputStream())); + in = new DataInputStream(new BufferedInputStream( + socket.getInputStream())); + out = new DataOutputStream(new BufferedOutputStream( + socket.getOutputStream())); new JDBCObjectReader(); - this.start(); + new Thread(this).start(); } catch (Exception err) { err.printStackTrace(); } @@ -87,7 +108,6 @@ public class JDBCConnection extends Thread implements Connection { } } - private boolean isStopped() { if (adapter != null && adapter.stopped) { return true; @@ -109,11 +129,21 @@ public class JDBCConnection extends Thread implements Connection { } catch (Exception err) { System.out.println("Connection Lost or Closed."); + try { + out.close(); + } catch (Exception er) { + } + out = null; + try { + in.close(); + } catch (Exception er) { + } + in = null; try { socket.close(); } catch (Exception err2) { } - //err.printStackTrace(); + socket = null; } } } @@ -167,38 +197,46 @@ public class JDBCConnection extends Thread implements Connection { public void processCommand(JDBCCommand cmd) { switch (cmd.getType()) { - case JDBCCommand.TYPE_EXECUTE_QUERY: - try { - JDBCServer.execute(cmd.getRS(), adapter); - send(new JDBCCommand(cmd.getRS(), - JDBCCommand.TYPE_QUERY_REPLY)); - QueryUpdater u = new QueryUpdater(cmd.getRS()); - new Thread(u).start(); - } catch (Exception err) { - send(new JDBCCommand(err, cmd.getRSID())); - } - break; - case JDBCCommand.TYPE_QUERY_REPLY: - JDBCResultSet rs1 = JDBCStatement.getQuery(cmd.getRS().getID()); - rs1.updateData(cmd.getRS()); - break; - case JDBCCommand.TYPE_QUERY_RECORD: - JDBCResultSet rs2 = JDBCStatement.getQuery(cmd.getRSID()); - rs2.addRecord(cmd.getRecord()); - break; - case JDBCCommand.TYPE_QUERY_FINISH: - JDBCResultSet rs3 = JDBCStatement.removeQuery(cmd.getRSID()); - rs3.setFinished(true); - break; - case JDBCCommand.TYPE_QUERY_ERROR: - System.err.println("ERROR Executing Query\n"); - cmd.getERROR().printStackTrace(); - JDBCResultSet rs4 = JDBCStatement.removeQuery(cmd.getRSID()); - rs4.setError(cmd.getERROR()); - rs4.setFinished(true); - synchronized (rs4) { - rs4.notifyAll(); - } + case JDBCCommand.TYPE_METADATA_REPLY: + this.metaData = cmd.getBluePrint(); + synchronized (this) { + this.notifyAll(); + } + break; + case JDBCCommand.TYPE_METADATA: + send(new JDBCCommand(this.adapter.getBluePrint())); + break; + case JDBCCommand.TYPE_EXECUTE_QUERY: + try { + JDBCServer.execute(cmd.getRS(), adapter); + send(new JDBCCommand(cmd.getRS(), JDBCCommand.TYPE_QUERY_REPLY)); + QueryUpdater u = new QueryUpdater(cmd.getRS()); + new Thread(u).start(); + } catch (Exception err) { + send(new JDBCCommand(err, cmd.getRSID())); + } + break; + case JDBCCommand.TYPE_QUERY_REPLY: + JDBCResultSet rs1 = JDBCStatement.getQuery(cmd.getRS().getID()); + rs1.updateData(cmd.getRS()); + break; + case JDBCCommand.TYPE_QUERY_RECORD: + JDBCResultSet rs2 = JDBCStatement.getQuery(cmd.getRSID()); + rs2.addRecord(cmd.getRecord()); + break; + case JDBCCommand.TYPE_QUERY_FINISH: + JDBCResultSet rs3 = JDBCStatement.removeQuery(cmd.getRSID()); + rs3.setFinished(true); + break; + case JDBCCommand.TYPE_QUERY_ERROR: + System.err.println("ERROR Executing Query\n"); + cmd.getERROR().printStackTrace(); + JDBCResultSet rs4 = JDBCStatement.removeQuery(cmd.getRSID()); + rs4.setError(cmd.getERROR()); + rs4.setFinished(true); + synchronized (rs4) { + rs4.notifyAll(); + } } } @@ -221,6 +259,15 @@ public class JDBCConnection extends Thread implements Connection { } public void send(Object o) { + + if (this.socket == null) { + try { + init(); + } catch (Exception err) { + err.printStackTrace(); + } + } + try { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oout = new ObjectOutputStream(bout); @@ -256,6 +303,7 @@ public class JDBCConnection extends Thread implements Connection { @Override public void close() throws SQLException { + wasClosed = true; try { socket.close(); } catch (Exception err) { @@ -271,7 +319,7 @@ public class JDBCConnection extends Thread implements Connection { @Override public Array createArrayOf(String typeName, Object[] elements) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return null; } @@ -302,28 +350,25 @@ public class JDBCConnection extends Thread implements Connection { @Override public Statement createStatement() throws SQLException { - return new JDBCStatement(this); + return new JDBCStatement(this).getProxy(); } @Override public Statement createStatement(int resultSetType, - int resultSetConcurrency, int resultSetHoldability) - throws SQLException { - // TODO Auto-generated method stub - return null; + int resultSetConcurrency, int resultSetHoldability) + throws SQLException { + return new JDBCStatement(this).getProxy(); } @Override - public Statement createStatement(int resultSetType, - int resultSetConcurrency) - throws SQLException { - // TODO Auto-generated method stub - return null; + public Statement createStatement(int resultSetType, int resultSetConcurrency) + throws SQLException { + return new JDBCStatement(this).getProxy(); } @Override public Struct createStruct(String typeName, Object[] attributes) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return null; } @@ -360,8 +405,19 @@ public class JDBCConnection extends Thread implements Connection { @Override public DatabaseMetaData getMetaData() throws SQLException { - // TODO Auto-generated method stub - return null; + if (this.metaData == null) { + JDBCCommand cmd = new JDBCCommand(); + cmd.setType(JDBCCommand.TYPE_METADATA); + synchronized (this) { + send(cmd); + try { + this.wait(); + } catch (Exception err) { + err.printStackTrace(); + } + } + } + return metaData; } @Override @@ -384,7 +440,6 @@ public class JDBCConnection extends Thread implements Connection { @Override public boolean isClosed() throws SQLException { - // TODO Auto-generated method stub return false; } @@ -408,15 +463,15 @@ public class JDBCConnection extends Thread implements Connection { @Override public CallableStatement prepareCall(String sql, int resultSetType, - int resultSetConcurrency, int resultSetHoldability) - throws SQLException { + int resultSetConcurrency, int resultSetHoldability) + throws SQLException { // TODO Auto-generated method stub return null; } @Override public CallableStatement prepareCall(String sql, int resultSetType, - int resultSetConcurrency) throws SQLException { + int resultSetConcurrency) throws SQLException { // TODO Auto-generated method stub return null; } @@ -429,44 +484,44 @@ public class JDBCConnection extends Thread implements Connection { @Override public PreparedStatement prepareStatement(String sql, int resultSetType, - int resultSetConcurrency, int resultSetHoldability) - throws SQLException { - // TODO Auto-generated method stub - return null; + int resultSetConcurrency, int resultSetHoldability) + throws SQLException { + System.err.println("SQL 1=" + sql); + return new JDBCStatement(this, sql).getProxy(); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, - int resultSetConcurrency) throws SQLException { - // TODO Auto-generated method stub - return null; + int resultSetConcurrency) throws SQLException { + System.err.println("SQL 2=" + sql); + return new JDBCStatement(this, sql).getProxy(); } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) - throws SQLException { - // TODO Auto-generated method stub - return null; + throws SQLException { + System.err.println("SQL 3=" + sql); + return new JDBCStatement(this, sql).getProxy(); } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) - throws SQLException { - // TODO Auto-generated method stub - return null; + throws SQLException { + System.err.println("SQL 4=" + sql); + return new JDBCStatement(this, sql).getProxy(); } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) - throws SQLException { - // TODO Auto-generated method stub - return null; + throws SQLException { + System.err.println("SQL 5=" + sql); + return new JDBCStatement(this, sql).getProxy(); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { - // TODO Auto-generated method stub - return null; + System.err.println("SQL 6=" + sql); + return new JDBCStatement(this, sql).getProxy(); } @Override @@ -501,14 +556,14 @@ public class JDBCConnection extends Thread implements Connection { @Override public void setClientInfo(Properties properties) - throws SQLClientInfoException { + throws SQLClientInfoException { // TODO Auto-generated method stub } @Override public void setClientInfo(String name, String value) - throws SQLClientInfoException { + throws SQLClientInfoException { // TODO Auto-generated method stub } @@ -569,7 +624,7 @@ public class JDBCConnection extends Thread implements Connection { @Override public void setNetworkTimeout(Executor executor, int milliseconds) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -579,5 +634,5 @@ public class JDBCConnection extends Thread implements Connection { // TODO Auto-generated method stub return 0; } -} +} diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCProxy.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCProxy.java new file mode 100644 index 0000000000..7e29947a01 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCProxy.java @@ -0,0 +1,24 @@ +package org.opendaylight.controller.md.sal.dom.xsql.jdbc; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +public class JDBCProxy implements InvocationHandler { + + private Object myObject = null; + private Class myObjectClass = null; + + public JDBCProxy(Object obj) { + this.myObject = obj; + this.myObjectClass = this.myObject.getClass(); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + System.err.println("Class " + this.myObjectClass.getSimpleName() + + " Method " + method.getName()); + return method.invoke(this.myObject, args); + } + +} diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCResultSet.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCResultSet.java index 7603a3e9ae..021f6ee19b 100644 --- a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCResultSet.java +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCResultSet.java @@ -4,6 +4,7 @@ import java.io.InputStream; import java.io.Reader; import java.io.Serializable; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.math.BigDecimal; import java.net.URL; import java.sql.Array; @@ -37,15 +38,13 @@ import org.opendaylight.controller.md.sal.dom.xsql.XSQLColumn; import org.opendaylight.controller.md.sal.dom.xsql.XSQLCriteria; import org.opendaylight.controller.md.sal.dom.xsql.XSQLODLUtils; -public class JDBCResultSet - implements Serializable, ResultSet, ResultSetMetaData { +public class JDBCResultSet implements Serializable, ResultSet, + ResultSetMetaData { private static final long serialVersionUID = -7450200738431047057L; private String sql = null; - private List tablesInQuery = - new ArrayList(); - private Map tablesInQueryMap = - new ConcurrentHashMap(); + private List tablesInQuery = new ArrayList(); + private Map tablesInQueryMap = new ConcurrentHashMap(); private List fieldsInQuery = new ArrayList(); private transient LinkedList records = new LinkedList(); private transient Map currentRecord = null; @@ -53,10 +52,32 @@ public class JDBCResultSet private int id = 0; private static Integer nextID = new Integer(0); public int numberOfTasks = 0; - private Map>> criteria = - new ConcurrentHashMap>>(); + private Map>> criteria = new ConcurrentHashMap>>(); private Exception err = null; private List EMPTY_RESULT = new LinkedList(); + private transient Map subQueries = new HashMap(); + + public ResultSet getProxy() { + return (ResultSet) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {ResultSet.class }, new JDBCProxy(this)); + } + + public void setSQL(String _sql) { + this.sql = _sql; + } + + public JDBCResultSet addSubQuery(String _sql,String logicalName) { + if(subQueries == null) + subQueries = new HashMap(); + JDBCResultSet rs = new JDBCResultSet(_sql); + this.subQueries.put(logicalName,rs); + return rs; + } + + public Map getSubQueries() { + if(this.subQueries==null) + this.subQueries = new HashMap<>(); + return this.subQueries; + } public JDBCResultSet(String _sql) { synchronized (JDBCResultSet.class) { @@ -88,12 +109,13 @@ public class JDBCResultSet } public int isObjectFitCriteria(Map objValues, String tableName) { - Map> tblCriteria = criteria.get(tableName); + Map> tblCriteria = criteria + .get(tableName); if (tblCriteria == null) { return 1; } for (Map.Entry> cc : tblCriteria - .entrySet()) { + .entrySet()) { for (XSQLCriteria c : cc.getValue()) { Object value = objValues.get(cc.getKey().toString()); int result = c.checkValue(value); @@ -106,16 +128,16 @@ public class JDBCResultSet } public int isObjectFitCriteria(Object element, Class cls) { - Map> tblCriteria = - criteria.get(cls.getName()); + Map> tblCriteria = criteria.get(cls + .getName()); if (tblCriteria == null) { return 1; } for (Map.Entry> cc : tblCriteria - .entrySet()) { + .entrySet()) { for (XSQLCriteria c : cc.getValue()) { - int result = - c.isObjectFitCriteria(element, cc.getKey().getName()); + int result = c.isObjectFitCriteria(element, cc.getKey() + .getName()); if (result == 0) { return 0; } @@ -185,16 +207,15 @@ public class JDBCResultSet } } - public void addRecord(ArrayList hierarchy) { Map rec = new HashMap(); for (int i = hierarchy.size() - 1; i >= 0; i--) { Object element = hierarchy.get(i); for (XSQLColumn c : fieldsInQuery) { - if (c.getTableName() - .equals(element.getClass().getSimpleName())) { + if (c.getTableName().equals(element.getClass().getSimpleName())) { try { - Method m = element.getClass().getMethod(c.getName(), null); + Method m = element.getClass().getMethod(c.getName(), + null); Object value = m.invoke(element, null); rec.put(c.getName(), value); } catch (Exception err) { @@ -276,18 +297,16 @@ public class JDBCResultSet Map subChildren = XSQLODLUtils.getChildren(node); Map result = new HashMap(); for (Object stc : subChildren.values()) { - if (stc.getClass().getName() - .endsWith("ImmutableAugmentationNode")) { + if (stc.getClass().getName().endsWith("ImmutableAugmentationNode")) { Map values = XSQLODLUtils.getChildren(stc); for (Object key : values.keySet()) { Object val = values.get(key); - if (val.getClass().getName() - .endsWith("ImmutableLeafNode")) { + if (val.getClass().getName().endsWith("ImmutableLeafNode")) { Object value = XSQLODLUtils.getValue(val); String k = XSQLODLUtils.getNodeName(val); if (value != null) { result.put(bpn.getBluePrintNodeName() + "." + k, - value.toString()); + value.toString()); } } } @@ -295,20 +314,27 @@ public class JDBCResultSet String k = XSQLODLUtils.getNodeName(stc); Object value = XSQLODLUtils.getValue(stc); if (value != null) { - result.put(bpn.getBluePrintNodeName() + "." + k, value.toString()); + result.put(bpn.getBluePrintNodeName() + "." + k, + value.toString()); } } } return result; } - private void addToData(Record rec, XSQLBluePrintNode bpn, XSQLBluePrint bluePrint, Map fullRecord) { - XSQLBluePrintNode eNodes[] = bluePrint.getBluePrintNodeByODLTableName(XSQLODLUtils.getNodeIdentiofier(rec.element)); + private void addToData(Record rec, XSQLBluePrintNode bpn, + XSQLBluePrint bluePrint, Map fullRecord) { + XSQLBluePrintNode eNodes[] = bluePrint + .getBluePrintNodeByODLTableName(XSQLODLUtils + .getNodeIdentiofier(rec.element)); if (bpn != null) { for (XSQLColumn c : fieldsInQuery) { - for(XSQLBluePrintNode eNode:eNodes){ - if (((XSQLBluePrintNode) c.getBluePrintNode()).getBluePrintNodeName().equals(eNode.getBluePrintNodeName())) { - //Object value = Criteria.getValue(rec.element, c.getName()); + for (XSQLBluePrintNode eNode : eNodes) { + if (((XSQLBluePrintNode) c.getBluePrintNode()) + .getBluePrintNodeName().equals( + eNode.getBluePrintNodeName())) { + // Object value = Criteria.getValue(rec.element, + // c.getName()); String columnName = c.toString(); Object value = fullRecord.get(columnName); if (value != null) { @@ -346,7 +372,8 @@ public class JDBCResultSet return false; } - public List getChildren(Object node, String tableName,XSQLBluePrint bluePrint) { + public List getChildren(Object node, String tableName, + XSQLBluePrint bluePrint) { List children = XSQLODLUtils.getMChildren(node); List result = new LinkedList(); @@ -354,28 +381,33 @@ public class JDBCResultSet for (Object child : children) { String odlNodeName = XSQLODLUtils.getNodeIdentiofier(child); - if(odlNodeName==null) continue; + if (odlNodeName == null) + continue; - XSQLBluePrintNode eNodes[] = bluePrint.getBluePrintNodeByODLTableName(odlNodeName); - if(eNodes==null) continue; + XSQLBluePrintNode eNodes[] = bluePrint + .getBluePrintNodeByODLTableName(odlNodeName); + if (eNodes == null) + continue; boolean match = false; - for(XSQLBluePrintNode enode:eNodes){ - if(tableName.startsWith(enode.toString())){ + for (XSQLBluePrintNode enode : eNodes) { + if (tableName.startsWith(enode.toString())) { match = true; break; } } - if(!match) continue; + if (!match) + continue; if (child.getClass().getName().endsWith("ImmutableContainerNode")) { result.add(child); - }else - if (child.getClass().getName().endsWith("ImmutableAugmentationNode")) { + } else if (child.getClass().getName() + .endsWith("ImmutableAugmentationNode")) { List _children = XSQLODLUtils.getMChildren(child); for (Object c : _children) { - if (c.getClass().getName().endsWith("ImmutableContainerNode")) { + if (c.getClass().getName() + .endsWith("ImmutableContainerNode")) { result.add(c); } } @@ -386,21 +418,26 @@ public class JDBCResultSet return result; } - public List addRecords(Object element, XSQLBluePrintNode node,boolean root, String tableName,XSQLBluePrint bluePrint) { + public List addRecords(Object element, XSQLBluePrintNode node, + boolean root, String tableName, XSQLBluePrint bluePrint) { List result = new LinkedList(); String nodeID = XSQLODLUtils.getNodeIdentiofier(element); if (node.getODLTableName().equals(nodeID)) { - XSQLBluePrintNode bluePrintNode = bluePrint.getBluePrintNodeByODLTableName(nodeID)[0]; + XSQLBluePrintNode bluePrintNode = bluePrint + .getBluePrintNodeByODLTableName(nodeID)[0]; Record rec = new Record(); rec.element = element; - XSQLBluePrintNode bpn = this.tablesInQueryMap.get(bluePrintNode.getBluePrintNodeName()); - if (this.criteria.containsKey(bluePrintNode.getBluePrintNodeName()) || bpn != null) { + XSQLBluePrintNode bpn = this.tablesInQueryMap.get(bluePrintNode + .getBluePrintNodeName()); + if (this.criteria.containsKey(bluePrintNode.getBluePrintNodeName()) + || bpn != null) { Map allKeyValues = collectColumnValues(element, bpn); - if (!(isObjectFitCriteria(allKeyValues, bpn.getBluePrintNodeName()) == 1)) { + if (!(isObjectFitCriteria(allKeyValues, + bpn.getBluePrintNodeName()) == 1)) { return EMPTY_RESULT; } - addToData(rec, bpn, bluePrint,allKeyValues); + addToData(rec, bpn, bluePrint, allKeyValues); } if (root) { addRecord(rec.data); @@ -411,9 +448,11 @@ public class JDBCResultSet } XSQLBluePrintNode parent = node.getParent(); - List subRecords = addRecords(element, parent, false, tableName,bluePrint); + List subRecords = addRecords(element, parent, false, tableName, + bluePrint); for (Record subRec : subRecords) { - List subO = getChildren(subRec.element, tableName,bluePrint); + List subO = getChildren(subRec.element, tableName, + bluePrint); if (subO != null) { for (Object subData : subO) { Record rec = new Record(); @@ -421,18 +460,21 @@ public class JDBCResultSet rec.data.putAll(subRec.data); String recID = XSQLODLUtils.getNodeIdentiofier(rec.element); - XSQLBluePrintNode eNodes[] = bluePrint.getBluePrintNodeByODLTableName(recID); + XSQLBluePrintNode eNodes[] = bluePrint + .getBluePrintNodeByODLTableName(recID); XSQLBluePrintNode bpn = null; - for(XSQLBluePrintNode eNode:eNodes){ - bpn = this.tablesInQueryMap.get(eNode.getBluePrintNodeName()); - if(bpn!=null) + for (XSQLBluePrintNode eNode : eNodes) { + bpn = this.tablesInQueryMap.get(eNode + .getBluePrintNodeName()); + if (bpn != null) break; } boolean isObjectInCriteria = true; if (bpn != null) { Map allKeyValues = collectColumnValues(rec.element, bpn); - if ((isObjectFitCriteria(allKeyValues, bpn.getBluePrintNodeName()) == 1)) { - addToData(rec, bpn,bluePrint,allKeyValues); + if ((isObjectFitCriteria(allKeyValues, + bpn.getBluePrintNodeName()) == 1)) { + addToData(rec, bpn, bluePrint, allKeyValues); } else { isObjectInCriteria = false; } @@ -440,7 +482,7 @@ public class JDBCResultSet if (isObjectInCriteria) { if (root) { - if(!rec.data.isEmpty()) + if (!rec.data.isEmpty()) addRecord(rec.data); } else { result.add(rec); @@ -545,7 +587,7 @@ public class JDBCResultSet @Override public BigDecimal getBigDecimal(int columnIndex, int scale) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return null; } @@ -558,7 +600,7 @@ public class JDBCResultSet @Override public BigDecimal getBigDecimal(String columnLabel, int scale) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return null; } @@ -798,22 +840,20 @@ public class JDBCResultSet @Override public Object getObject(int columnIndex, Map> map) - throws SQLException { - // TODO Auto-generated method stub - return null; + throws SQLException { + return getObject(columnIndex); } @Override public Object getObject(int columnIndex) throws SQLException { - return currentRecord - .get(this.fieldsInQuery.get(columnIndex - 1).toString()); + return currentRecord.get(this.fieldsInQuery.get(columnIndex - 1) + .toString()); } @Override public Object getObject(String columnLabel, Map> map) - throws SQLException { - // TODO Auto-generated method stub - return null; + throws SQLException { + return getObject(columnLabel); } @Override @@ -883,14 +923,12 @@ public class JDBCResultSet @Override public String getString(int columnIndex) throws SQLException { - // TODO Auto-generated method stub - return null; + return "Kuku"; } @Override public String getString(String columnLabel) throws SQLException { - // TODO Auto-generated method stub - return null; + return "Kuku"; } @Override @@ -919,7 +957,7 @@ public class JDBCResultSet @Override public Timestamp getTimestamp(int columnIndex, Calendar cal) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return null; } @@ -932,7 +970,7 @@ public class JDBCResultSet @Override public Timestamp getTimestamp(String columnLabel, Calendar cal) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return null; } @@ -945,8 +983,7 @@ public class JDBCResultSet @Override public int getType() throws SQLException { - // TODO Auto-generated method stub - return 0; + return ResultSet.TYPE_FORWARD_ONLY; } @Override @@ -968,8 +1005,7 @@ public class JDBCResultSet } @Override - public InputStream getUnicodeStream(String columnLabel) - throws SQLException { + public InputStream getUnicodeStream(String columnLabel) throws SQLException { // TODO Auto-generated method stub return null; } @@ -1096,100 +1132,98 @@ public class JDBCResultSet @Override public void updateAsciiStream(int columnIndex, InputStream x, int length) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateAsciiStream(int columnIndex, InputStream x, long length) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateAsciiStream(int columnIndex, InputStream x) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateAsciiStream(String columnLabel, InputStream x, int length) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override - public void updateAsciiStream(String columnLabel, InputStream x, - long length) - throws SQLException { + public void updateAsciiStream(String columnLabel, InputStream x, long length) + throws SQLException { // TODO Auto-generated method stub } @Override public void updateAsciiStream(String columnLabel, InputStream x) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateBigDecimal(int columnIndex, BigDecimal x) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateBigDecimal(String columnLabel, BigDecimal x) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateBinaryStream(int columnIndex, InputStream x, int length) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateBinaryStream(int columnIndex, InputStream x, long length) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateBinaryStream(int columnIndex, InputStream x) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override - public void updateBinaryStream(String columnLabel, InputStream x, - int length) - throws SQLException { + public void updateBinaryStream(String columnLabel, InputStream x, int length) + throws SQLException { // TODO Auto-generated method stub } @Override public void updateBinaryStream(String columnLabel, InputStream x, - long length) throws SQLException { + long length) throws SQLException { // TODO Auto-generated method stub } @Override public void updateBinaryStream(String columnLabel, InputStream x) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1201,16 +1235,15 @@ public class JDBCResultSet } @Override - public void updateBlob(int columnIndex, InputStream inputStream, - long length) - throws SQLException { + public void updateBlob(int columnIndex, InputStream inputStream, long length) + throws SQLException { // TODO Auto-generated method stub } @Override public void updateBlob(int columnIndex, InputStream inputStream) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1223,14 +1256,14 @@ public class JDBCResultSet @Override public void updateBlob(String columnLabel, InputStream inputStream, - long length) throws SQLException { + long length) throws SQLException { // TODO Auto-generated method stub } @Override public void updateBlob(String columnLabel, InputStream inputStream) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1243,7 +1276,7 @@ public class JDBCResultSet @Override public void updateBoolean(String columnLabel, boolean x) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1274,42 +1307,42 @@ public class JDBCResultSet @Override public void updateCharacterStream(int columnIndex, Reader x, int length) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateCharacterStream(int columnIndex, Reader x, long length) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateCharacterStream(int columnIndex, Reader x) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateCharacterStream(String columnLabel, Reader reader, - int length) throws SQLException { + int length) throws SQLException { // TODO Auto-generated method stub } @Override public void updateCharacterStream(String columnLabel, Reader reader, - long length) throws SQLException { + long length) throws SQLException { // TODO Auto-generated method stub } @Override public void updateCharacterStream(String columnLabel, Reader reader) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1322,7 +1355,7 @@ public class JDBCResultSet @Override public void updateClob(int columnIndex, Reader reader, long length) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1341,14 +1374,14 @@ public class JDBCResultSet @Override public void updateClob(String columnLabel, Reader reader, long length) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateClob(String columnLabel, Reader reader) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1415,28 +1448,28 @@ public class JDBCResultSet @Override public void updateNCharacterStream(int columnIndex, Reader x, long length) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateNCharacterStream(int columnIndex, Reader x) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateNCharacterStream(String columnLabel, Reader reader, - long length) throws SQLException { + long length) throws SQLException { // TODO Auto-generated method stub } @Override public void updateNCharacterStream(String columnLabel, Reader reader) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1449,49 +1482,48 @@ public class JDBCResultSet @Override public void updateNClob(int columnIndex, Reader reader, long length) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override - public void updateNClob(int columnIndex, Reader reader) - throws SQLException { + public void updateNClob(int columnIndex, Reader reader) throws SQLException { // TODO Auto-generated method stub } @Override public void updateNClob(String columnLabel, NClob nClob) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateNClob(String columnLabel, Reader reader, long length) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateNClob(String columnLabel, Reader reader) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateNString(int columnIndex, String nString) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateNString(String columnLabel, String nString) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1510,7 +1542,7 @@ public class JDBCResultSet @Override public void updateObject(int columnIndex, Object x, int scaleOrLength) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1523,7 +1555,7 @@ public class JDBCResultSet @Override public void updateObject(String columnLabel, Object x, int scaleOrLength) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1566,14 +1598,14 @@ public class JDBCResultSet @Override public void updateSQLXML(int columnIndex, SQLXML xmlObject) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateSQLXML(String columnLabel, SQLXML xmlObject) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1616,14 +1648,14 @@ public class JDBCResultSet @Override public void updateTimestamp(int columnIndex, Timestamp x) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @Override public void updateTimestamp(String columnLabel, Timestamp x) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub } @@ -1670,8 +1702,7 @@ public class JDBCResultSet @Override public int getColumnType(int column) throws SQLException { - // TODO Auto-generated method stub - return 0; + return 12; } @Override @@ -1766,15 +1797,11 @@ public class JDBCResultSet @Override public T getObject(String columnLabel, Class type) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return null; } - - - ////Metadata - - + // //Metadata } diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCServer.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCServer.java index 26b8c70b8b..5be701f82e 100644 --- a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCServer.java +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCServer.java @@ -1,20 +1,22 @@ package org.opendaylight.controller.md.sal.dom.xsql.jdbc; -import org.opendaylight.controller.md.sal.dom.xsql.XSQLAdapter; -import org.opendaylight.controller.md.sal.dom.xsql.XSQLBluePrint; -import org.opendaylight.controller.md.sal.dom.xsql.XSQLBluePrintNode; -import org.opendaylight.controller.md.sal.dom.xsql.XSQLColumn; -import org.opendaylight.controller.md.sal.dom.xsql.XSQLCriteria; - import java.net.ServerSocket; import java.net.Socket; import java.sql.SQLException; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.concurrent.ConcurrentHashMap; +import org.opendaylight.controller.md.sal.dom.xsql.XSQLAdapter; +import org.opendaylight.controller.md.sal.dom.xsql.XSQLBluePrint; +import org.opendaylight.controller.md.sal.dom.xsql.XSQLBluePrintNode; +import org.opendaylight.controller.md.sal.dom.xsql.XSQLColumn; +import org.opendaylight.controller.md.sal.dom.xsql.XSQLCriteria; + public class JDBCServer extends Thread { private ServerSocket socket = null; private XSQLAdapter adapter = null; @@ -47,19 +49,179 @@ public class JDBCServer extends Thread { } public static void execute(JDBCResultSet rs, XSQLAdapter adapter) - throws SQLException { - parseTables(rs, adapter.getBluePrint()); - parseFields(rs, adapter.getBluePrint()); - parseCriteria(rs, adapter.getBluePrint()); + throws SQLException { + if(rs.getSQL().toLowerCase().trim().equals("select 1")){ + rs.setFinished(true); + return; + } + checkAndBreakSubQueries(rs, adapter); + if (rs.getSubQueries().size() == 0) { + parseTables(rs, adapter.getBluePrint()); + parseFields(rs, adapter.getBluePrint()); + parseCriteria(rs, adapter.getBluePrint()); + try { + adapter.execute(rs); + } catch (Exception err) { + throw new SQLException("Error", err); + } + } else { + parseExternalQuery(rs); + } + } + + public static void parseExternalQuery(JDBCResultSet rs) throws SQLException { + String sql = rs.getSQL(); + for (Map.Entry entry : rs.getSubQueries() + .entrySet()) { + int index = sql.toLowerCase().indexOf(entry.getValue().getSQL()); + String extSql = sql.substring(0, index); + index = extSql.lastIndexOf("("); + extSql = extSql.substring(0, index); + System.out.println("External SQL=" + extSql); + parseLogicalFields(extSql, rs); + } + } + + public static void parseLogicalFields(String sql, JDBCResultSet rs) + throws SQLException { + if(sql.trim().toLowerCase().equals("select * from")){ + for (Map.Entry entry : rs.getSubQueries().entrySet()) { + for(XSQLBluePrintNode node:entry.getValue().getTables()){ + rs.addTableToQuery(node); + } + rs.getFields().addAll(entry.getValue().getFields()); + while (entry.getValue().next()) { + Map rec = entry.getValue().getCurrent(); + Map newRec = new HashMap(); + newRec.putAll(rec); + rs.addRecord(newRec); + } + } + rs.setFinished(true); + return; + } + + Map logicalNameToNode = new HashMap(); + Map origNameToName = new HashMap(); + List columnOrder = new ArrayList<>(); + int nextLogField = addNextLogicalField(sql, 0, + logicalNameToNode, origNameToName,columnOrder); + int next = sql.toLowerCase().indexOf(" as ", nextLogField); + while (next != -1) { + nextLogField = addNextLogicalField(sql, nextLogField + 1, + logicalNameToNode, origNameToName,columnOrder); + next = sql.toLowerCase().indexOf(" as ", nextLogField + 1); + } + + for (XSQLBluePrintNode node : logicalNameToNode.values()) { + rs.addTableToQuery(node); + } + rs.getFields().addAll(columnOrder); + for (Map.Entry entry : rs.getSubQueries().entrySet()) { + while (entry.getValue().next()) { + Map rec = entry.getValue().getCurrent(); + Map newRec = new HashMap(); + for (Iterator iter = rec.entrySet().iterator(); iter.hasNext();) { + Map.Entry e = (Map.Entry) iter.next(); + String key = (String) e.getKey(); + Object value = e.getValue(); + String logicalKey = origNameToName.get(key); + if (value != null && logicalKey != null) { + newRec.put(logicalKey, value); + } + } + rs.addRecord(newRec); + } + } + rs.setFinished(true); + } + + public static void main(String args[]) { + String sql = "SELECT DISTINCT" + + "\"LOGICAL_TABLE_1\".\"nodes/node.id\" AS \"COL0\"\n" + + ",\"LOGICAL_TABLE_1\".\"nodes/node.id\" AS \"COL1\"\n" + + ",\"LOGICAL_TABLE_1\".\"nodes/node.id\" AS \"COL2\"\n" + + "FROM\n" + + "(select * from nodes/node;) \"LOGICAL_TABLE_1\"\n"; + JDBCResultSet rs = new JDBCResultSet(sql); try { - adapter.execute(rs); + parseLogicalFields(sql, rs); } catch (Exception err) { - throw new SQLException("Error", err); + err.printStackTrace(); + } + } + + public static int addNextLogicalField(String sql, int startIndex, + Map logicalNameToNode, + Map origNameToName, List columnOrder) { + int index1 = sql.indexOf("\"", startIndex); + int index2 = sql.indexOf("\".\"", index1); + int index3 = sql.indexOf("\"", index2 + 3); + int index4 = sql.toLowerCase().indexOf(" as ", startIndex); + int index5 = sql.indexOf("\"", index4); + int index6 = sql.indexOf("\"", index5 + 1); + + String tblName = sql.substring(index1 + 1, index2); + String origFieldNameFull = sql.substring(index2 + 3, index3); + String origTableName = ""; + String origFieldName = ""; + if (origFieldNameFull.indexOf(".") != -1) { + origTableName = origFieldNameFull.substring(0,origFieldNameFull.indexOf(".")); + origFieldName = origFieldNameFull.substring(origFieldNameFull.indexOf(".") + 1); + } + String logicalFieldName = sql.substring(index5 + 1, index6); + XSQLBluePrintNode node = logicalNameToNode.get(tblName); + if (node == null) { + node = new XSQLBluePrintNode(tblName, origTableName, 0); + logicalNameToNode.put(tblName, node); + } + columnOrder.add(node.addColumn(logicalFieldName, tblName, origFieldName, origTableName)); + origNameToName.put(origFieldNameFull, tblName + "." + logicalFieldName); + return index6; + } + + public static void checkAndBreakSubQueries(JDBCResultSet rs,XSQLAdapter adapter) throws SQLException { + String sql = rs.getSQL().toLowerCase(); + int index = sql.indexOf("select"); + if (index == -1) + throw new SQLException("Select statement is missing..."); + int index2 = sql.indexOf("select", index + 6); + if (index2 != -1) { + int startSubQuery = index2; + for (int i = startSubQuery; i >= 0; i--) { + if (sql.charAt(i) == '(') { + startSubQuery = i; + break; + } + } + int braketCount = 0; + int endSubQuery = startSubQuery; + do { + if (sql.charAt(endSubQuery) == '(') + braketCount++; + else if (sql.charAt(endSubQuery) == ')') + braketCount--; + endSubQuery++; + } while (braketCount > 0 || endSubQuery == sql.length()); + String subQuerySQL = sql.substring(startSubQuery + 1,endSubQuery - 1); + if(rs.getSQL().toLowerCase().substring(0,startSubQuery).trim().equals("select * from")){ + rs.setSQL(subQuerySQL); + return; + } + index = sql.indexOf("\"", endSubQuery); + index2 = sql.indexOf("\"", index + 1); + if(index==-1){ + index = endSubQuery; + index2 = sql.length(); + } + String logicalName = rs.getSQL().substring(index + 1, index2).trim(); + JDBCResultSet subRS = rs.addSubQuery(subQuerySQL, logicalName); + JDBCServer.execute(subRS, adapter); } } public static void parseTables(JDBCResultSet rs, XSQLBluePrint bp) - throws SQLException { + throws SQLException { String lowSQL = rs.getSQL().toLowerCase(); int from = lowSQL.indexOf("from"); int where = lowSQL.indexOf("where"); @@ -90,20 +252,19 @@ public class JDBCServer extends Thread { String tableName = tokens.nextToken().trim(); XSQLBluePrintNode table = bp.getBluePrintNodeByTableName(tableName); if (table == null) { - throw new SQLException( - "Unknown table name \"" + tableName + "\""); + throw new SQLException("Unknown table name \"" + tableName + + "\""); } rs.addTableToQuery(table); } } public static void addCriteria(XSQLColumn col, XSQLCriteria c, - JDBCResultSet rs) { - Map> tblCriteria = - rs.getCriteria().get(col.getTableName()); + JDBCResultSet rs) { + Map> tblCriteria = rs.getCriteria().get( + col.getTableName()); if (tblCriteria == null) { - tblCriteria = - new ConcurrentHashMap>(); + tblCriteria = new ConcurrentHashMap>(); rs.getCriteria().put(col.getTableName(), tblCriteria); } List lstCriteria = tblCriteria.get(col); @@ -115,7 +276,7 @@ public class JDBCServer extends Thread { } public static void parseFields(JDBCResultSet rs, XSQLBluePrint bp) - throws SQLException { + throws SQLException { String lowSQL = rs.getSQL().toLowerCase(); if (!lowSQL.startsWith("select")) { throw new SQLException("Missing 'select' statement."); @@ -135,8 +296,8 @@ public class JDBCServer extends Thread { return; } if (token.indexOf(".") != -1) { - XSQLBluePrintNode tbl = bp.getBluePrintNodeByTableName( - token.substring(0, token.indexOf(".")).trim()); + XSQLBluePrintNode tbl = bp.getBluePrintNodeByTableName(token + .substring(0, token.indexOf(".")).trim()); String p = token.substring(token.indexOf(".") + 1); if (p.equals("*")) { for (XSQLColumn c : tbl.getColumns()) { @@ -158,8 +319,8 @@ public class JDBCServer extends Thread { } } if (col == null) { - throw new SQLException( - "Unknown field name '" + token + "'."); + throw new SQLException("Unknown field name '" + token + + "'."); } rs.getFields().add(col); @@ -171,28 +332,21 @@ public class JDBCServer extends Thread { String lowSQL = rs.getSQL().toLowerCase(); int where = lowSQL.indexOf("where"); int order = lowSQL.indexOf("order"); - int subQuery = lowSQL.indexOf("select", 2); int whereTo = lowSQL.indexOf(";"); if (where == -1) { return; } - if (where != -1 && subQuery != -1 && subQuery < where) { - return; - } - - if (order != -1 && subQuery != -1 && order < subQuery) { - whereTo = order; - } else if (order != -1 && subQuery != -1 && order > subQuery) { - whereTo = subQuery; - } else if (order != -1) { + if (order != -1) { whereTo = order; - } else if (subQuery != -1) { - whereTo = subQuery; } - String whereStatement = - rs.getSQL().substring(where + 5, whereTo).trim(); + + if(whereTo==-1) + whereTo=lowSQL.length(); + + String whereStatement = rs.getSQL().substring(where + 5, whereTo) + .trim(); XSQLCriteria cr = new XSQLCriteria(whereStatement, -1); for (XSQLBluePrintNode tbl : rs.getTables()) { for (XSQLColumn col : tbl.getColumns()) { diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCStatement.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCStatement.java index a9ce1dd9bf..b71b015351 100644 --- a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCStatement.java +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/jdbc/JDBCStatement.java @@ -1,28 +1,63 @@ package org.opendaylight.controller.md.sal.dom.xsql.jdbc; +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.Array; +import java.sql.Blob; +import java.sql.Clob; import java.sql.Connection; +import java.sql.Date; +import java.sql.NClob; +import java.sql.ParameterMetaData; +import java.sql.PreparedStatement; +import java.sql.Ref; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.RowId; import java.sql.SQLException; import java.sql.SQLWarning; -import java.sql.Statement; +import java.sql.SQLXML; +import java.sql.Time; +import java.sql.Timestamp; import java.util.ArrayList; +import java.util.Calendar; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -public class JDBCStatement implements Statement { +public class JDBCStatement implements PreparedStatement { private JDBCResultSet rs = null; private transient JDBCConnection connection = null; - private static Map queries = - new ConcurrentHashMap(); + private static Map queries = new ConcurrentHashMap(); + private String sql = null; + + public JDBCStatement(JDBCConnection con,String _sql) { + this.connection = con; + this.sql = _sql; + } public JDBCStatement(JDBCConnection con) { this.connection = con; } + public void setSQL(String _sql){ + this.sql = _sql; + } + public JDBCStatement() { } + public PreparedStatement getProxy() { + return this; + /* + return (PreparedStatement) Proxy.newProxyInstance(this.getClass() + .getClassLoader(), new Class[] { PreparedStatement.class }, + new JDBCProxy(this)); + */ + } + public static JDBCResultSet getQuery(int id) { return queries.get(id); } @@ -36,8 +71,8 @@ public class JDBCStatement implements Statement { rs = new JDBCResultSet(_sql); queries.put(rs.getID(), rs); synchronized (rs) { - this.connection - .send(new JDBCCommand(rs, JDBCCommand.TYPE_EXECUTE_QUERY)); + this.connection.send(new JDBCCommand(rs, + JDBCCommand.TYPE_EXECUTE_QUERY)); try { rs.wait(); } catch (Exception err) { @@ -46,7 +81,7 @@ public class JDBCStatement implements Statement { throw ((SQLException) rs.getError()); } } - return rs; + return rs.getProxy(); } @Override @@ -118,21 +153,20 @@ public class JDBCStatement implements Statement { @Override public boolean execute(String sql, int autoGeneratedKeys) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return false; } @Override - public boolean execute(String sql, int[] columnIndexes) - throws SQLException { + public boolean execute(String sql, int[] columnIndexes) throws SQLException { // TODO Auto-generated method stub return false; } @Override public boolean execute(String sql, String[] columnNames) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return false; } @@ -145,21 +179,21 @@ public class JDBCStatement implements Statement { @Override public int executeUpdate(String sql, int autoGeneratedKeys) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return 0; } @Override public int executeUpdate(String sql, int[] columnIndexes) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return 0; } @Override public int executeUpdate(String sql, String[] columnNames) - throws SQLException { + throws SQLException { // TODO Auto-generated method stub return 0; } @@ -202,8 +236,7 @@ public class JDBCStatement implements Statement { @Override public int getMaxRows() throws SQLException { - // TODO Auto-generated method stub - return 0; + return 200; } @Override @@ -326,5 +359,358 @@ public class JDBCStatement implements Statement { return false; } + @Override + public ResultSet executeQuery() throws SQLException { + return this.executeQuery(this.sql); + } + + @Override + public int executeUpdate() throws SQLException { + // TODO Auto-generated method stub + return 0; + } + + @Override + public void setNull(int parameterIndex, int sqlType) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setByte(int parameterIndex, byte x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setShort(int parameterIndex, short x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setInt(int parameterIndex, int x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setLong(int parameterIndex, long x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setFloat(int parameterIndex, float x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setDouble(int parameterIndex, double x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setBigDecimal(int parameterIndex, BigDecimal x) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setString(int parameterIndex, String x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setBytes(int parameterIndex, byte[] x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setDate(int parameterIndex, Date x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setTime(int parameterIndex, Time x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setTimestamp(int parameterIndex, Timestamp x) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setAsciiStream(int parameterIndex, InputStream x, int length) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setUnicodeStream(int parameterIndex, InputStream x, int length) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setBinaryStream(int parameterIndex, InputStream x, int length) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void clearParameters() throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setObject(int parameterIndex, Object x, int targetSqlType) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setObject(int parameterIndex, Object x) throws SQLException { + // TODO Auto-generated method stub + } + + @Override + public boolean execute() throws SQLException { + // TODO Auto-generated method stub + return false; + } + + @Override + public void addBatch() throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setCharacterStream(int parameterIndex, Reader reader, int length) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setRef(int parameterIndex, Ref x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setBlob(int parameterIndex, Blob x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setClob(int parameterIndex, Clob x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setArray(int parameterIndex, Array x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public ResultSetMetaData getMetaData() throws SQLException { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setDate(int parameterIndex, Date x, Calendar cal) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setTime(int parameterIndex, Time x, Calendar cal) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setNull(int parameterIndex, int sqlType, String typeName) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setURL(int parameterIndex, URL x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public ParameterMetaData getParameterMetaData() throws SQLException { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setRowId(int parameterIndex, RowId x) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setNString(int parameterIndex, String value) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setNCharacterStream(int parameterIndex, Reader value, + long length) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setNClob(int parameterIndex, NClob value) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setClob(int parameterIndex, Reader reader, long length) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setBlob(int parameterIndex, InputStream inputStream, long length) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setNClob(int parameterIndex, Reader reader, long length) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setSQLXML(int parameterIndex, SQLXML xmlObject) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setObject(int parameterIndex, Object x, int targetSqlType, + int scaleOrLength) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setAsciiStream(int parameterIndex, InputStream x, long length) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setBinaryStream(int parameterIndex, InputStream x, long length) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setCharacterStream(int parameterIndex, Reader reader, + long length) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setAsciiStream(int parameterIndex, InputStream x) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setBinaryStream(int parameterIndex, InputStream x) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setCharacterStream(int parameterIndex, Reader reader) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setNCharacterStream(int parameterIndex, Reader value) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setClob(int parameterIndex, Reader reader) throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setBlob(int parameterIndex, InputStream inputStream) + throws SQLException { + // TODO Auto-generated method stub + + } + + @Override + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + // TODO Auto-generated method stub + + } } diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/xsql/XSQLProvider.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/xsql/XSQLProvider.java index b421e56cf4..cde01573f2 100644 --- a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/xsql/XSQLProvider.java +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/xsql/XSQLProvider.java @@ -1,7 +1,5 @@ package org.opendaylight.xsql; -import java.util.concurrent.ExecutionException; - import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.xsql.rev140626.XSQL; @@ -25,16 +23,15 @@ public class XSQLProvider implements AutoCloseable { XSQLBuilder builder = new XSQLBuilder(); builder.setPort("34343"); XSQL xsql = builder.build(); - if (dps != null) { - final DataModificationTransaction t = dps.beginTransaction(); - t.removeOperationalData(ID); - t.putOperationalData(ID,xsql); - - try { + try { + if (dps != null) { + final DataModificationTransaction t = dps.beginTransaction(); + t.removeOperationalData(ID); + t.putOperationalData(ID,xsql); t.commit().get(); - } catch (InterruptedException | ExecutionException e) { - LOG.warn("Failed to update toaster status, operational otherwise", e); } + } catch (Exception e) { + LOG.warn("Failed to update XSQL port status, ", e); } return xsql; } diff --git a/opendaylight/md-sal/sal-dom-xsql/src/test/java/org/opendaylight/xsql/test/XSQLTest.java b/opendaylight/md-sal/sal-dom-xsql/src/test/java/org/opendaylight/xsql/test/XSQLTest.java new file mode 100644 index 0000000000..8a6b184f82 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-xsql/src/test/java/org/opendaylight/xsql/test/XSQLTest.java @@ -0,0 +1,170 @@ +package org.opendaylight.xsql.test; + +import java.io.InputStream; +import java.sql.SQLException; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.md.sal.dom.xsql.XSQLAdapter; +import org.opendaylight.controller.md.sal.dom.xsql.XSQLBluePrint; +import org.opendaylight.controller.md.sal.dom.xsql.jdbc.JDBCResultSet; +import org.opendaylight.controller.md.sal.dom.xsql.jdbc.JDBCServer; + +public class XSQLTest { + + XSQLBluePrint bluePrint = null; + + @Before + public void before() { + try{ + InputStream in = this.getClass().getClassLoader().getResourceAsStream("BluePrintCache.dat"); + if(in!=null){ + bluePrint = XSQLBluePrint.load(in); + log("Loaded Blue Print!"); + }else{ + log("Can't find Blue Print!"); + } + in.close(); + }catch(Exception err){ + err.printStackTrace(); + } + } + + @Test + public void testQueryParsingSimpleNoCriteria() { + String sql = "select * from nodes/node;"; + JDBCResultSet rs = new JDBCResultSet(sql); + parseTables(sql,bluePrint, rs); + parseFields(sql, bluePrint, rs); + JDBCServer.parseCriteria(rs, bluePrint); + if(rs.getCriteria().isEmpty()){ + log("Test Criteria parsing of \""+sql+"\" Passed!"); + Assert.assertEquals(true, true); + }else{ + log("Test Criteria parsing of \""+sql+"\" Failed!"); + Assert.assertEquals(false, true); + } + } + + @Test + public void testQueryParsingComplexNoCriteria() { + String sql = "select nodes/node.id,nodes/node/node-connector.id,nodes/node/node-connector.hardware-address from nodes/node,nodes/node/node-connector;"; + JDBCResultSet rs = new JDBCResultSet(sql); + parseTables(sql,bluePrint, rs); + parseFields(sql, bluePrint, rs); + JDBCServer.parseCriteria(rs, bluePrint); + if(rs.getCriteria().isEmpty()){ + log("Test Criteria parsing of \""+sql+"\" Passed!"); + Assert.assertEquals(true, true); + }else{ + log("Test Criteria parsing of \""+sql+"\" Failed!"); + Assert.assertEquals(false, true); + } + } + + @Test + public void testQueryParsingComplexWithCriteria() { + String sql = "select nodes/node.id,nodes/node/node-connector.id,nodes/node/node-connector.hardware-address from nodes/node,nodes/node/node-connector where hardware-address like 'AB';"; + JDBCResultSet rs = new JDBCResultSet(sql); + parseTables(sql,bluePrint, rs); + parseFields(sql, bluePrint, rs); + JDBCServer.parseCriteria(rs, bluePrint); + if(!rs.getCriteria().isEmpty()){ + log("Test Criteria parsing of \""+sql+"\" Passed!"); + Assert.assertEquals(true, true); + }else{ + log("Test Criteria parsing of \""+sql+"\" Failed!"); + Assert.assertEquals(false, true); + } + } + + @Test + public void testQueryParsingSimpleWithCriteria() { + String sql = "select * from nodes/node where nodes/node.id like 'something...';"; + JDBCResultSet rs = new JDBCResultSet(sql); + parseTables(sql,bluePrint, rs); + parseFields(sql, bluePrint, rs); + JDBCServer.parseCriteria(rs, bluePrint); + if(!rs.getCriteria().isEmpty()){ + log("Test Criteria parsing of \""+sql+"\" Passed!"); + Assert.assertEquals(true, true); + }else{ + log("Test Criteria parsing of \""+sql+"\" Failed!"); + Assert.assertEquals(false, true); + } + } + + private static void parseTables(String sql,XSQLBluePrint bp,JDBCResultSet rs){ + try{ + JDBCServer.parseTables(rs, bp); + log("Test Table parsing of \""+sql+"\" Passed!"); + Assert.assertEquals(true,true); + }catch(SQLException err){ + log("Test Table parsing of \""+sql+"\" Failed!"); + err.printStackTrace(); + Assert.assertEquals(false,true); + } + } + + @Test + public void testQueryParsingComplexWithCriteriaAndGrouping() { + + String sub_sql = "select nodes/node.id,nodes/node/node-connector.id,nodes/node/node-connector.hardware-address from nodes/node,nodes/node/node-connector where hardware-address like 'AB';"; + + String sql = "SELECT DISTINCT" + + "\"LOGICAL_TABLE_1\".\"nodes/node.id\" AS \"COL0\"\n" + + ",\"LOGICAL_TABLE_1\".\"nodes/node.address\" AS \"COL1\"\n" + + ",\"LOGICAL_TABLE_1\".\"nodes/node/node-connector.hardware-address\" AS \"COL2\"\n" + + "FROM\n" + + "("+sub_sql+") \"LOGICAL_TABLE_1\"\n"; + + + + JDBCResultSet rs = new JDBCResultSet(sql); + XSQLAdapter.getInstance().loadBluePrint(); + try{ + JDBCServer.checkAndBreakSubQueries(rs, XSQLAdapter.getInstance()); + if(rs.getSubQueries().isEmpty()){ + log("Logical table parsing for "+sql+" Failed!"); + }else{ + JDBCServer.parseExternalQuery(rs); + log("Fields="+rs.getFields().size()); + Assert.assertEquals(rs.getFields().size(), 3); + Assert.assertEquals(rs.getTables().size(), 1); + Assert.assertEquals(rs.getTables().get(0).getODLTableName(), "LOGICAL_TABLE_1"); + + JDBCResultSet subRS = rs.getSubQueries().values().iterator().next(); + parseTables(sql,bluePrint, subRS); + parseFields(sql, bluePrint, subRS); + JDBCServer.parseCriteria(subRS, bluePrint); + if(!subRS.getCriteria().isEmpty()){ + log("Test Criteria parsing of \""+sql+"\" Passed!"); + Assert.assertEquals(true, true); + }else{ + log("Test Criteria parsing of \""+sql+"\" Failed!"); + Assert.assertEquals(false, true); + } + } + }catch(SQLException err){ + err.printStackTrace(); + } + } + + private static void parseFields(String sql,XSQLBluePrint bp,JDBCResultSet rs){ + try{ + JDBCServer.parseFields(rs, bp); + log("Test Fields parsing of \""+sql+"\" Passed!"); + Assert.assertEquals(true,true); + }catch(SQLException err){ + log("Test Fields parsing of \""+sql+"\" Failed!"); + err.printStackTrace(); + Assert.assertEquals(false,true); + } + } + + private static void log(String str) { + System.out.print("*** XSQL Tests -"); + System.out.println(str); + } +} diff --git a/opendaylight/md-sal/sal-dom-xsql/src/test/resources/BluePrintCache.dat b/opendaylight/md-sal/sal-dom-xsql/src/test/resources/BluePrintCache.dat new file mode 100644 index 0000000000..b6b34acfcd Binary files /dev/null and b/opendaylight/md-sal/sal-dom-xsql/src/test/resources/BluePrintCache.dat differ diff --git a/opendaylight/md-sal/sal-inmemory-datastore/pom.xml b/opendaylight/md-sal/sal-inmemory-datastore/pom.xml index 725b24cd9e..473b065b59 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/pom.xml +++ b/opendaylight/md-sal/sal-inmemory-datastore/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-inmemory-datastore diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChainedTransactionCommitImpl.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChainedTransactionCommitImpl.java new file mode 100644 index 0000000000..5b0f739428 --- /dev/null +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChainedTransactionCommitImpl.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl; + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; + +final class ChainedTransactionCommitImpl implements DOMStoreThreePhaseCommitCohort { + private final SnapshotBackedWriteTransaction transaction; + private final DOMStoreThreePhaseCommitCohort delegate; + private final DOMStoreTransactionChainImpl txChain; + + protected ChainedTransactionCommitImpl(final SnapshotBackedWriteTransaction transaction, + final DOMStoreThreePhaseCommitCohort delegate, final DOMStoreTransactionChainImpl txChain) { + this.transaction = Preconditions.checkNotNull(transaction); + this.delegate = Preconditions.checkNotNull(delegate); + this.txChain = Preconditions.checkNotNull(txChain); + } + + @Override + public ListenableFuture canCommit() { + return delegate.canCommit(); + } + + @Override + public ListenableFuture preCommit() { + return delegate.preCommit(); + } + + @Override + public ListenableFuture abort() { + return delegate.abort(); + } + + @Override + public ListenableFuture commit() { + ListenableFuture commitFuture = delegate.commit(); + Futures.addCallback(commitFuture, new FutureCallback() { + @Override + public void onFailure(final Throwable t) { + txChain.onTransactionFailed(transaction, t); + } + + @Override + public void onSuccess(final Void result) { + txChain.onTransactionCommited(transaction); + } + }); + return commitFuture; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DOMStoreTransactionChainImpl.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DOMStoreTransactionChainImpl.java new file mode 100644 index 0000000000..3f731cf18b --- /dev/null +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DOMStoreTransactionChainImpl.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl; + +import com.google.common.base.Preconditions; +import java.util.AbstractMap.SimpleEntry; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class DOMStoreTransactionChainImpl extends TransactionReadyPrototype implements DOMStoreTransactionChain { + private static abstract class State { + /** + * Allocate a new snapshot. + * + * @return A new snapshot + */ + protected abstract DataTreeSnapshot getSnapshot(); + } + + private static final class Idle extends State { + private final InMemoryDOMDataStore store; + + Idle(final InMemoryDOMDataStore store) { + this.store = Preconditions.checkNotNull(store); + } + + @Override + protected DataTreeSnapshot getSnapshot() { + return store.takeSnapshot(); + } + } + + /** + * We have a transaction out there. + */ + private static final class Allocated extends State { + private static final AtomicReferenceFieldUpdater SNAPSHOT_UPDATER = + AtomicReferenceFieldUpdater.newUpdater(Allocated.class, DataTreeSnapshot.class, "snapshot"); + private final DOMStoreWriteTransaction transaction; + private volatile DataTreeSnapshot snapshot; + + Allocated(final DOMStoreWriteTransaction transaction) { + this.transaction = Preconditions.checkNotNull(transaction); + } + + public DOMStoreWriteTransaction getTransaction() { + return transaction; + } + + @Override + protected DataTreeSnapshot getSnapshot() { + final DataTreeSnapshot ret = snapshot; + Preconditions.checkState(ret != null, "Previous transaction %s is not ready yet", transaction.getIdentifier()); + return ret; + } + + void setSnapshot(final DataTreeSnapshot snapshot) { + final boolean success = SNAPSHOT_UPDATER.compareAndSet(this, null, snapshot); + Preconditions.checkState(success, "Transaction %s has already been marked as ready", transaction.getIdentifier()); + } + } + + /** + * Chain is logically shut down, no further allocation allowed. + */ + private static final class Shutdown extends State { + private final String message; + + Shutdown(final String message) { + this.message = Preconditions.checkNotNull(message); + } + + @Override + protected DataTreeSnapshot getSnapshot() { + throw new IllegalStateException(message); + } + } + + private static final AtomicReferenceFieldUpdater STATE_UPDATER = + AtomicReferenceFieldUpdater.newUpdater(DOMStoreTransactionChainImpl.class, State.class, "state"); + private static final Logger LOG = LoggerFactory.getLogger(DOMStoreTransactionChainImpl.class); + private static final Shutdown CLOSED = new Shutdown("Transaction chain is closed"); + private static final Shutdown FAILED = new Shutdown("Transaction chain has failed"); + private final InMemoryDOMDataStore store; + private final Idle idleState; + private volatile State state; + + DOMStoreTransactionChainImpl(final InMemoryDOMDataStore store) { + this.store = Preconditions.checkNotNull(store); + idleState = new Idle(store); + state = idleState; + } + + private Entry getSnapshot() { + final State localState = state; + return new SimpleEntry<>(localState, localState.getSnapshot()); + } + + private boolean recordTransaction(final State expected, final DOMStoreWriteTransaction transaction) { + final State state = new Allocated(transaction); + return STATE_UPDATER.compareAndSet(this, expected, state); + } + + @Override + public DOMStoreReadTransaction newReadOnlyTransaction() { + final Entry entry = getSnapshot(); + return new SnapshotBackedReadTransaction(store.nextIdentifier(), store.getDebugTransactions(), entry.getValue()); + } + + @Override + public DOMStoreReadWriteTransaction newReadWriteTransaction() { + Entry entry; + DOMStoreReadWriteTransaction ret; + + do { + entry = getSnapshot(); + ret = new SnapshotBackedReadWriteTransaction(store.nextIdentifier(), + store.getDebugTransactions(), entry.getValue(), this); + } while (!recordTransaction(entry.getKey(), ret)); + + return ret; + } + + @Override + public DOMStoreWriteTransaction newWriteOnlyTransaction() { + Entry entry; + DOMStoreWriteTransaction ret; + + do { + entry = getSnapshot(); + ret = new SnapshotBackedWriteTransaction(store.nextIdentifier(), + store.getDebugTransactions(), entry.getValue(), this); + } while (!recordTransaction(entry.getKey(), ret)); + + return ret; + } + + @Override + protected void transactionAborted(final SnapshotBackedWriteTransaction tx) { + final State localState = state; + if (localState instanceof Allocated) { + final Allocated allocated = (Allocated)localState; + if (allocated.getTransaction().equals(tx)) { + final boolean success = STATE_UPDATER.compareAndSet(this, localState, idleState); + if (!success) { + LOG.info("State already transitioned from {} to {}", localState, state); + } + } + } + } + + @Override + protected DOMStoreThreePhaseCommitCohort transactionReady(final SnapshotBackedWriteTransaction tx, final DataTreeModification tree) { + final State localState = state; + + if (localState instanceof Allocated) { + final Allocated allocated = (Allocated)localState; + final DOMStoreWriteTransaction transaction = allocated.getTransaction(); + Preconditions.checkState(tx.equals(transaction), "Mis-ordered ready transaction %s last allocated was %s", tx, transaction); + allocated.setSnapshot(tree); + } else { + LOG.debug("Ignoring transaction {} readiness due to state {}", tx, localState); + } + + return new ChainedTransactionCommitImpl(tx, store.transactionReady(tx, tree), this); + } + + @Override + public void close() { + final State localState = state; + + do { + Preconditions.checkState(!CLOSED.equals(localState), "Transaction chain {} has been closed", this); + + if (FAILED.equals(localState)) { + LOG.debug("Ignoring user close in failed state"); + return; + } + } while (!STATE_UPDATER.compareAndSet(this, localState, CLOSED)); + } + + void onTransactionFailed(final SnapshotBackedWriteTransaction transaction, final Throwable t) { + LOG.debug("Transaction chain {} failed on transaction {}", this, transaction, t); + state = FAILED; + } + + void onTransactionCommited(final SnapshotBackedWriteTransaction transaction) { + // If the committed transaction was the one we allocated last, + // we clear it and the ready snapshot, so the next transaction + // allocated refers to the data tree directly. + final State localState = state; + + if (!(localState instanceof Allocated)) { + LOG.debug("Ignoring successful transaction {} in state {}", transaction, localState); + return; + } + + final Allocated allocated = (Allocated)localState; + final DOMStoreWriteTransaction tx = allocated.getTransaction(); + if (!tx.equals(transaction)) { + LOG.debug("Ignoring non-latest successful transaction {} in state {}", transaction, allocated); + return; + } + + if (!STATE_UPDATER.compareAndSet(this, localState, idleState)) { + LOG.debug("Transaction chain {} has already transitioned from {} to {}, not making it idle", this, localState, state); + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java index 74fa73afb9..213f60e951 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java @@ -10,7 +10,6 @@ package org.opendaylight.controller.md.sal.dom.store.impl; import static com.google.common.base.Preconditions.checkState; import com.google.common.base.Optional; import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; @@ -18,7 +17,6 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; -import javax.annotation.concurrent.GuardedBy; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException; @@ -142,7 +140,7 @@ public class InMemoryDOMDataStore extends TransactionReadyPrototype implements D @Override public DOMStoreTransactionChain createTransactionChain() { - return new DOMStoreTransactionChainImpl(); + return new DOMStoreTransactionChainImpl(this); } @Override @@ -164,10 +162,14 @@ public class InMemoryDOMDataStore extends TransactionReadyPrototype implements D } } - boolean getDebugTransactions() { + public final boolean getDebugTransactions() { return debugTransactions; } + final DataTreeSnapshot takeSnapshot() { + return dataTree.takeSnapshot(); + } + @Override public >> ListenerRegistration registerChangeListener( final YangInstanceIdentifier path, final L listener, final DataChangeScope scope) { @@ -219,156 +221,11 @@ public class InMemoryDOMDataStore extends TransactionReadyPrototype implements D return new ThreePhaseCommitImpl(tx, tree); } - private Object nextIdentifier() { + Object nextIdentifier() { return name + "-" + txCounter.getAndIncrement(); } - private class DOMStoreTransactionChainImpl extends TransactionReadyPrototype implements DOMStoreTransactionChain { - @GuardedBy("this") - private SnapshotBackedWriteTransaction allocatedTransaction; - @GuardedBy("this") - private DataTreeSnapshot readySnapshot; - @GuardedBy("this") - private boolean chainFailed = false; - - @GuardedBy("this") - private void checkFailed() { - Preconditions.checkState(!chainFailed, "Transaction chain is failed."); - } - - @GuardedBy("this") - private DataTreeSnapshot getSnapshot() { - checkFailed(); - - if (allocatedTransaction != null) { - Preconditions.checkState(readySnapshot != null, "Previous transaction %s is not ready yet", allocatedTransaction.getIdentifier()); - return readySnapshot; - } else { - return dataTree.takeSnapshot(); - } - } - - @GuardedBy("this") - private T recordTransaction(final T transaction) { - allocatedTransaction = transaction; - readySnapshot = null; - return transaction; - } - - @Override - public synchronized DOMStoreReadTransaction newReadOnlyTransaction() { - final DataTreeSnapshot snapshot = getSnapshot(); - return new SnapshotBackedReadTransaction(nextIdentifier(), getDebugTransactions(), snapshot); - } - - @Override - public synchronized DOMStoreReadWriteTransaction newReadWriteTransaction() { - final DataTreeSnapshot snapshot = getSnapshot(); - return recordTransaction(new SnapshotBackedReadWriteTransaction(nextIdentifier(), - getDebugTransactions(), snapshot, this)); - } - - @Override - public synchronized DOMStoreWriteTransaction newWriteOnlyTransaction() { - final DataTreeSnapshot snapshot = getSnapshot(); - return recordTransaction(new SnapshotBackedWriteTransaction(nextIdentifier(), - getDebugTransactions(), snapshot, this)); - } - - @Override - protected synchronized void transactionAborted(final SnapshotBackedWriteTransaction tx) { - if (tx.equals(allocatedTransaction)) { - Preconditions.checkState(readySnapshot == null, "Unexpected abort of transaction %s with ready snapshot %s", tx, readySnapshot); - allocatedTransaction = null; - } - } - - @Override - protected synchronized DOMStoreThreePhaseCommitCohort transactionReady(final SnapshotBackedWriteTransaction tx, final DataTreeModification tree) { - Preconditions.checkState(tx.equals(allocatedTransaction), "Mis-ordered ready transaction %s last allocated was %s", tx, allocatedTransaction); - if (readySnapshot != null) { - // The snapshot should have been cleared - LOG.warn("Uncleared snapshot {} encountered, overwritten with transaction {} snapshot {}", readySnapshot, tx, tree); - } - - final DOMStoreThreePhaseCommitCohort cohort = InMemoryDOMDataStore.this.transactionReady(tx, tree); - readySnapshot = tree; - return new ChainedTransactionCommitImpl(tx, cohort, this); - } - - @Override - public void close() { - // FIXME: this call doesn't look right here - listeningExecutor is shared and owned - // by the outer class. - //listeningExecutor.shutdownNow(); - } - - protected synchronized void onTransactionFailed(final SnapshotBackedWriteTransaction transaction, - final Throwable t) { - chainFailed = true; - } - - public synchronized void onTransactionCommited(final SnapshotBackedWriteTransaction transaction) { - // If the committed transaction was the one we allocated last, - // we clear it and the ready snapshot, so the next transaction - // allocated refers to the data tree directly. - if (transaction.equals(allocatedTransaction)) { - if (readySnapshot == null) { - LOG.warn("Transaction {} committed while no ready snapshot present", transaction); - } - - allocatedTransaction = null; - readySnapshot = null; - } - } - } - - private static class ChainedTransactionCommitImpl implements DOMStoreThreePhaseCommitCohort { - private final SnapshotBackedWriteTransaction transaction; - private final DOMStoreThreePhaseCommitCohort delegate; - private final DOMStoreTransactionChainImpl txChain; - - protected ChainedTransactionCommitImpl(final SnapshotBackedWriteTransaction transaction, - final DOMStoreThreePhaseCommitCohort delegate, final DOMStoreTransactionChainImpl txChain) { - this.transaction = transaction; - this.delegate = delegate; - this.txChain = txChain; - } - - @Override - public ListenableFuture canCommit() { - return delegate.canCommit(); - } - - @Override - public ListenableFuture preCommit() { - return delegate.preCommit(); - } - - @Override - public ListenableFuture abort() { - return delegate.abort(); - } - - @Override - public ListenableFuture commit() { - ListenableFuture commitFuture = delegate.commit(); - Futures.addCallback(commitFuture, new FutureCallback() { - @Override - public void onFailure(final Throwable t) { - txChain.onTransactionFailed(transaction, t); - } - - @Override - public void onSuccess(final Void result) { - txChain.onTransactionCommited(transaction); - } - }); - return commitFuture; - } - } - - private class ThreePhaseCommitImpl implements DOMStoreThreePhaseCommitCohort { + private final class ThreePhaseCommitImpl implements DOMStoreThreePhaseCommitCohort { private final SnapshotBackedWriteTransaction transaction; private final DataTreeModification modification; diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java index 5fe9866b12..25ddbf5df2 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java @@ -11,10 +11,8 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; - import java.util.Collection; import java.util.Map.Entry; - import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.Builder; import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.SimpleEventFactory; @@ -120,7 +118,9 @@ final class ResolveDataChangeEventsTask { Preconditions.checkArgument(node.getDataAfter().isPresent(), "Modification at {} has type {} but no after-data", state.getPath(), node.getModificationType()); if (!node.getDataBefore().isPresent()) { - resolveCreateEvent(state, node.getDataAfter().get()); + @SuppressWarnings({ "unchecked", "rawtypes" }) + final NormalizedNode afterNode = (NormalizedNode)node.getDataAfter().get(); + resolveSameEventRecursivelly(state, afterNode, DOMImmutableDataChangeEvent.getCreateEventFactory()); return true; } @@ -128,7 +128,10 @@ final class ResolveDataChangeEventsTask { case DELETE: Preconditions.checkArgument(node.getDataBefore().isPresent(), "Modification at {} has type {} but no before-data", state.getPath(), node.getModificationType()); - resolveDeleteEvent(state, node.getDataBefore().get()); + + @SuppressWarnings({ "unchecked", "rawtypes" }) + final NormalizedNode beforeNode = (NormalizedNode)node.getDataBefore().get(); + resolveSameEventRecursivelly(state, beforeNode, DOMImmutableDataChangeEvent.getRemoveEventFactory()); return true; case UNMODIFIED: return false; @@ -223,26 +226,6 @@ final class ResolveDataChangeEventsTask { return true; } - /** - * Resolves create events deep down the interest listener tree. - * - * @param path - * @param listeners - * @param afterState - * @return - */ - private void resolveCreateEvent(final ResolveDataChangeState state, final NormalizedNode afterState) { - @SuppressWarnings({ "unchecked", "rawtypes" }) - final NormalizedNode node = (NormalizedNode) afterState; - resolveSameEventRecursivelly(state, node, DOMImmutableDataChangeEvent.getCreateEventFactory()); - } - - private void resolveDeleteEvent(final ResolveDataChangeState state, final NormalizedNode beforeState) { - @SuppressWarnings({ "unchecked", "rawtypes" }) - final NormalizedNode node = (NormalizedNode) beforeState; - resolveSameEventRecursivelly(state, node, DOMImmutableDataChangeEvent.getRemoveEventFactory()); - } - private void resolveSameEventRecursivelly(final ResolveDataChangeState state, final NormalizedNode node, final SimpleEventFactory eventFactory) { if (!state.needsProcessing()) { @@ -277,6 +260,11 @@ final class ResolveDataChangeEventsTask { Preconditions.checkArgument(modification.getDataBefore().isPresent(), "Subtree change with before-data not present at path %s", state.getPath()); Preconditions.checkArgument(modification.getDataAfter().isPresent(), "Subtree change with after-data not present at path %s", state.getPath()); + if (!state.needsProcessing()) { + LOG.trace("Not processing modified subtree {}", state.getPath()); + return true; + } + DataChangeScope scope = null; for (DataTreeCandidateNode childMod : modification.getChildNodes()) { final ResolveDataChangeState childState = state.child(childMod.getIdentifier()); diff --git a/opendaylight/md-sal/sal-karaf-xsql/pom.xml b/opendaylight/md-sal/sal-karaf-xsql/pom.xml index c32d960841..9ed3707d3d 100644 --- a/opendaylight/md-sal/sal-karaf-xsql/pom.xml +++ b/opendaylight/md-sal/sal-karaf-xsql/pom.xml @@ -1,21 +1,21 @@ - 4.0.0 @@ -23,13 +23,12 @@ sal-parent org.opendaylight.controller - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT - xsqlcommand - xsqlcommand + org.opendaylight.controller + sal-karaf-xsql bundle - 1.0.0-SNAPSHOT Apache Karaf :: Shell odl/xsql Commands Provides the OSGi odl commands @@ -64,8 +63,7 @@ org.opendaylight.controller sal-dom-xsql - bundle - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT diff --git a/opendaylight/md-sal/sal-karaf-xsql/src/main/java/org/opendaylight/controller/xsql/xsql.java b/opendaylight/md-sal/sal-karaf-xsql/src/main/java/org/opendaylight/controller/xsql/xsql.java index b7994dc1bf..9f0266c19d 100644 --- a/opendaylight/md-sal/sal-karaf-xsql/src/main/java/org/opendaylight/controller/xsql/xsql.java +++ b/opendaylight/md-sal/sal-karaf-xsql/src/main/java/org/opendaylight/controller/xsql/xsql.java @@ -16,6 +16,10 @@ public class xsql extends OsgiCommandSupport { private String argument; protected Object doExecute() throws Exception { + if(argument==null){ + System.out.println("Nothing to do..., please specify a command."); + return null; + } XSQLAdapter.getInstance().processCommand(new StringBuffer(argument), System.out); return null; diff --git a/opendaylight/md-sal/sal-karaf-xsql/src/main/resources/OSGI-INF/blueprint/shell-log.xml b/opendaylight/md-sal/sal-karaf-xsql/src/main/resources/OSGI-INF/blueprint/shell-log.xml new file mode 100644 index 0000000000..e9a4a233d3 --- /dev/null +++ b/opendaylight/md-sal/sal-karaf-xsql/src/main/resources/OSGI-INF/blueprint/shell-log.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/opendaylight/md-sal/sal-netconf-connector/pom.xml b/opendaylight/md-sal/sal-netconf-connector/pom.xml index 049f8c2e3c..c8836d1b88 100644 --- a/opendaylight/md-sal/sal-netconf-connector/pom.xml +++ b/opendaylight/md-sal/sal-netconf-connector/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-netconf-connector diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilities.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilities.java index 2642116927..09e178f5ce 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilities.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilities.java @@ -8,11 +8,10 @@ import com.google.common.base.Splitter; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; - +import java.net.URI; import java.util.Collection; import java.util.HashSet; import java.util.Set; - import org.opendaylight.controller.netconf.client.NetconfClientSession; import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil; import org.opendaylight.yangtools.yang.common.QName; @@ -119,10 +118,14 @@ public final class NetconfSessionCapabilities { return fromStrings(session.getServerCapabilities()); } - private static final QName cachedQName(String namespace, String revision, String moduleName) { + private static QName cachedQName(final String namespace, final String revision, final String moduleName) { return QName.cachedReference(QName.create(namespace, revision, moduleName)); } + private static QName cachedQName(final String namespace, final String moduleName) { + return QName.cachedReference(QName.create(URI.create(namespace), null, moduleName).withoutRevision()); + } + public static NetconfSessionCapabilities fromStrings(final Collection capabilities) { final Set moduleBasedCaps = new HashSet<>(); final Set nonModuleCaps = Sets.newHashSet(capabilities); @@ -142,8 +145,7 @@ public final class NetconfSessionCapabilities { String revision = REVISION_PARAM.from(queryParams); if (revision != null) { - moduleBasedCaps.add(cachedQName(namespace, revision, moduleName)); - nonModuleCaps.remove(capability); + addModuleQName(moduleBasedCaps, nonModuleCaps, capability, cachedQName(namespace, revision, moduleName)); continue; } @@ -151,21 +153,29 @@ public final class NetconfSessionCapabilities { * We have seen devices which mis-escape revision, but the revision may not * even be there. First check if there is a substring that matches revision. */ - if (!Iterables.any(queryParams, CONTAINS_REVISION)) { + if (Iterables.any(queryParams, CONTAINS_REVISION)) { + + LOG.debug("Netconf device was not reporting revision correctly, trying to get amp;revision="); + revision = BROKEN_REVISON_PARAM.from(queryParams); + if (revision == null) { + LOG.warn("Netconf device returned revision incorrectly escaped for {}, ignoring it", capability); + addModuleQName(moduleBasedCaps, nonModuleCaps, capability, cachedQName(namespace, moduleName)); + } else { + addModuleQName(moduleBasedCaps, nonModuleCaps, capability, cachedQName(namespace, revision, moduleName)); + } continue; } - LOG.debug("Netconf device was not reporting revision correctly, trying to get amp;revision="); - revision = BROKEN_REVISON_PARAM.from(queryParams); - if (revision == null) { - LOG.warn("Netconf device returned revision incorrectly escaped for {}, ignoring it", capability); - } - - // FIXME: do we really want to continue here? - moduleBasedCaps.add(cachedQName(namespace, revision, moduleName)); - nonModuleCaps.remove(capability); + // Fallback, no revision provided for module + addModuleQName(moduleBasedCaps, nonModuleCaps, capability, cachedQName(namespace, moduleName)); } return new NetconfSessionCapabilities(ImmutableSet.copyOf(nonModuleCaps), ImmutableSet.copyOf(moduleBasedCaps)); } + + + private static void addModuleQName(final Set moduleBasedCaps, final Set nonModuleCaps, final String capability, final QName qName) { + moduleBasedCaps.add(qName); + nonModuleCaps.remove(capability); + } } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilitiesTest.java b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilitiesTest.java index 87947b57fa..80bb08f5af 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilitiesTest.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilitiesTest.java @@ -43,6 +43,19 @@ public class NetconfSessionCapabilitiesTest { assertThat(merged.getNonModuleCaps(), JUnitMatchers.hasItem("urn:ietf:params:netconf:capability:rollback-on-error:1.0")); } + @Test + public void testCapabilityNoRevision() throws Exception { + final List caps1 = Lists.newArrayList( + "namespace:2?module=module2", + "namespace:2?module=module2&revision=2012-12-12", + "namespace:2?module=module1&RANDOMSTRING;revision=2013-12-12", + "namespace:2?module=module2&RANDOMSTRING;revision=2013-12-12" // This one should be ignored(same as first), since revision is in wrong format + ); + + final NetconfSessionCapabilities sessionCaps1 = NetconfSessionCapabilities.fromStrings(caps1); + assertCaps(sessionCaps1, 0, 3); + } + private void assertCaps(final NetconfSessionCapabilities sessionCaps1, final int nonModuleCaps, final int moduleCaps) { assertEquals(nonModuleCaps, sessionCaps1.getNonModuleCaps().size()); assertEquals(moduleCaps, sessionCaps1.getModuleBasedCaps().size()); diff --git a/opendaylight/md-sal/sal-remote/pom.xml b/opendaylight/md-sal/sal-remote/pom.xml index 31f1f02693..d47cf4ca07 100644 --- a/opendaylight/md-sal/sal-remote/pom.xml +++ b/opendaylight/md-sal/sal-remote/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-remote bundle diff --git a/opendaylight/md-sal/sal-remoterpc-connector/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/pom.xml index 0fb468be86..d16f67209f 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-remoterpc-connector bundle diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java index 2e355d4f51..c82a72eaa5 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java @@ -38,8 +38,9 @@ public class RemoteRpcProviderFactory { Thread.currentThread().getContextClassLoader()); Config actorSystemConfig = config.get(); - LOG.debug("Actor system configuration\n{}", actorSystemConfig.root().render()); - + if(LOG.isDebugEnabled()) { + LOG.debug("Actor system configuration\n{}", actorSystemConfig.root().render()); + } if (config.isMetricCaptureEnabled()) { LOG.info("Instrumentation is enabled in actor system {}. Metrics can be viewed in JMX console.", config.getActorSystemName()); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RoutedRpcListener.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RoutedRpcListener.java index 98cf6a329f..2aaac5a78e 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RoutedRpcListener.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RoutedRpcListener.java @@ -53,7 +53,9 @@ public class RoutedRpcListener implements RouteChangeListener> announcements) { - LOG.debug("Announcing [{}]", announcements); + if(LOG.isDebugEnabled()) { + LOG.debug("Announcing [{}]", announcements); + } RpcRegistry.Messages.AddOrUpdateRoutes addRpcMsg = new RpcRegistry.Messages.AddOrUpdateRoutes(new ArrayList<>(announcements)); rpcRegistry.tell(addRpcMsg, ActorRef.noSender()); } @@ -63,7 +65,9 @@ public class RoutedRpcListener implements RouteChangeListener> removals){ - LOG.debug("Removing [{}]", removals); + if(LOG.isDebugEnabled()) { + LOG.debug("Removing [{}]", removals); + } RpcRegistry.Messages.RemoveRoutes removeRpcMsg = new RpcRegistry.Messages.RemoveRoutes(new ArrayList<>(removals)); rpcRegistry.tell(removeRpcMsg, ActorRef.noSender()); } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcBroker.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcBroker.java index 6b02235dc7..2046e419d9 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcBroker.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcBroker.java @@ -79,8 +79,9 @@ public class RpcBroker extends AbstractUntypedActor { } private void invokeRemoteRpc(final InvokeRpc msg) { - LOG.debug("Looking up the remote actor for rpc {}", msg.getRpc()); - + if(LOG.isDebugEnabled()) { + LOG.debug("Looking up the remote actor for rpc {}", msg.getRpc()); + } RpcRouter.RouteIdentifier routeId = new RouteIdentifierImpl( null, msg.getRpc(), msg.getIdentifier()); RpcRegistry.Messages.FindRouters findMsg = new RpcRegistry.Messages.FindRouters(routeId); @@ -147,8 +148,9 @@ public class RpcBroker extends AbstractUntypedActor { } private void executeRpc(final ExecuteRpc msg) { - LOG.debug("Executing rpc {}", msg.getRpc()); - + if(LOG.isDebugEnabled()) { + LOG.debug("Executing rpc {}", msg.getRpc()); + } Future> future = brokerSession.rpc(msg.getRpc(), XmlUtils.inputXmlToCompositeNode(msg.getRpc(), msg.getInputCompositeNode(), schemaContext)); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcListener.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcListener.java index dee98521ae..22879dda2f 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcListener.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcListener.java @@ -31,7 +31,9 @@ public class RpcListener implements RpcRegistrationListener{ @Override public void onRpcImplementationAdded(QName rpc) { - LOG.debug("Adding registration for [{}]", rpc); + if(LOG.isDebugEnabled()) { + LOG.debug("Adding registration for [{}]", rpc); + } RpcRouter.RouteIdentifier routeId = new RouteIdentifierImpl(null, rpc, null); List> routeIds = new ArrayList<>(); routeIds.add(routeId); @@ -41,7 +43,9 @@ public class RpcListener implements RpcRegistrationListener{ @Override public void onRpcImplementationRemoved(QName rpc) { - LOG.debug("Removing registration for [{}]", rpc); + if(LOG.isDebugEnabled()) { + LOG.debug("Removing registration for [{}]", rpc); + } RpcRouter.RouteIdentifier routeId = new RouteIdentifierImpl(null, rpc, null); List> routeIds = new ArrayList<>(); routeIds.add(routeId); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/TerminationMonitor.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/TerminationMonitor.java index abe2008c29..48ccd824d4 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/TerminationMonitor.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/TerminationMonitor.java @@ -25,7 +25,9 @@ public class TerminationMonitor extends UntypedActor{ @Override public void onReceive(Object message) throws Exception { if(message instanceof Terminated){ Terminated terminated = (Terminated) message; - LOG.debug("Actor terminated : {}", terminated.actor()); + if(LOG.isDebugEnabled()) { + LOG.debug("Actor terminated : {}", terminated.actor()); + } }else if(message instanceof Monitor){ Monitor monitor = (Monitor) message; getContext().watch(monitor.getActorRef()); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStore.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStore.java index 3de3fc00d0..b50dfb1ba3 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStore.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStore.java @@ -111,7 +111,9 @@ public class BucketStore extends AbstractUntypedActorWithMetering { receiveUpdateRemoteBuckets( ((UpdateRemoteBuckets) message).getBuckets()); } else { - log.debug("Unhandled message [{}]", message); + if(log.isDebugEnabled()) { + log.debug("Unhandled message [{}]", message); + } unhandled(message); } } @@ -236,8 +238,9 @@ public class BucketStore extends AbstractUntypedActorWithMetering { versions.put(entry.getKey(), remoteVersion); } } - - log.debug("State after update - Local Bucket [{}], Remote Buckets [{}]", localBucket, remoteBuckets); + if(log.isDebugEnabled()) { + log.debug("State after update - Local Bucket [{}], Remote Buckets [{}]", localBucket, remoteBuckets); + } } /// diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Gossiper.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Gossiper.java index 85c6ebe26f..1bbcc69f5e 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Gossiper.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Gossiper.java @@ -170,7 +170,9 @@ public class Gossiper extends AbstractUntypedActorWithMetering { } clusterMembers.remove(member.address()); - log.debug("Removed member [{}], Active member list [{}]", member.address(), clusterMembers); + if(log.isDebugEnabled()) { + log.debug("Removed member [{}], Active member list [{}]", member.address(), clusterMembers); + } } /** @@ -184,8 +186,9 @@ public class Gossiper extends AbstractUntypedActorWithMetering { if (!clusterMembers.contains(member.address())) clusterMembers.add(member.address()); - - log.debug("Added member [{}], Active member list [{}]", member.address(), clusterMembers); + if(log.isDebugEnabled()) { + log.debug("Added member [{}], Active member list [{}]", member.address(), clusterMembers); + } } /** @@ -205,8 +208,9 @@ public class Gossiper extends AbstractUntypedActorWithMetering { Integer randomIndex = ThreadLocalRandom.current().nextInt(0, clusterMembers.size()); remoteMemberToGossipTo = clusterMembers.get(randomIndex); } - - log.debug("Gossiping to [{}]", remoteMemberToGossipTo); + if(log.isDebugEnabled()) { + log.debug("Gossiping to [{}]", remoteMemberToGossipTo); + } getLocalStatusAndSendTo(remoteMemberToGossipTo); } @@ -244,7 +248,9 @@ public class Gossiper extends AbstractUntypedActorWithMetering { void receiveGossip(GossipEnvelope envelope){ //TODO: Add more validations if (!selfAddress.equals(envelope.to())) { - log.debug("Ignoring message intended for someone else. From [{}] to [{}]", envelope.from(), envelope.to()); + if(log.isDebugEnabled()) { + log.debug("Ignoring message intended for someone else. From [{}] to [{}]", envelope.from(), envelope.to()); + } return; } @@ -291,7 +297,9 @@ public class Gossiper extends AbstractUntypedActorWithMetering { ActorSelection remoteRef = getContext().system().actorSelection( remoteActorSystemAddress.toString() + getSelf().path().toStringWithoutAddress()); - log.debug("Sending bucket versions to [{}]", remoteRef); + if(log.isDebugEnabled()) { + log.debug("Sending bucket versions to [{}]", remoteRef); + } futureReply.map(getMapperToSendLocalStatus(remoteRef), getContext().dispatcher()); @@ -416,7 +424,9 @@ public class Gossiper extends AbstractUntypedActorWithMetering { public Void apply(Object msg) { if (msg instanceof GetBucketsByMembersReply) { Map buckets = ((GetBucketsByMembersReply) msg).getBuckets(); - log.debug("Buckets to send from {}: {}", selfAddress, buckets); + if(log.isDebugEnabled()) { + log.debug("Buckets to send from {}: {}", selfAddress, buckets); + } GossipEnvelope envelope = new GossipEnvelope(selfAddress, sender.path().address(), buckets); sender.tell(envelope, getSelf()); } diff --git a/opendaylight/md-sal/sal-rest-connector-config/pom.xml b/opendaylight/md-sal/sal-rest-connector-config/pom.xml index fa91f0398d..dc3dd8e476 100644 --- a/opendaylight/md-sal/sal-rest-connector-config/pom.xml +++ b/opendaylight/md-sal/sal-rest-connector-config/pom.xml @@ -12,7 +12,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-rest-connector-config Configuration files for sal-rest-connector diff --git a/opendaylight/md-sal/sal-rest-connector/pom.xml b/opendaylight/md-sal/sal-rest-connector/pom.xml index fe5c9f39d8..4a96847175 100644 --- a/opendaylight/md-sal/sal-rest-connector/pom.xml +++ b/opendaylight/md-sal/sal-rest-connector/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-rest-connector bundle @@ -139,7 +139,7 @@ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.rest.connector.rev140724.*, *, - com.sun.jersey.spi.container.servlet + com.sun.jersey.spi.container.servlet, org.eclipse.jetty.servlets /restconf diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java index 4a46a3c267..7f8f0a1d0e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java @@ -60,31 +60,31 @@ public interface RestconfService { @GET @Path("/modules") - @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON, + @Produces({ Draft02.MediaTypes.API + JSON, Draft02.MediaTypes.API + XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public StructuredData getModules(@Context UriInfo uriInfo); @GET @Path("/modules/{identifier:.+}") - @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON, + @Produces({ Draft02.MediaTypes.API + JSON, Draft02.MediaTypes.API + XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public StructuredData getModules(@PathParam("identifier") String identifier, @Context UriInfo uriInfo); @GET @Path("/modules/module/{identifier:.+}") - @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON, + @Produces({ Draft02.MediaTypes.API + JSON, Draft02.MediaTypes.API + XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public StructuredData getModule(@PathParam("identifier") String identifier, @Context UriInfo uriInfo); @GET @Path("/operations") - @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON, + @Produces({ Draft02.MediaTypes.API + JSON, Draft02.MediaTypes.API + XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public StructuredData getOperations(@Context UriInfo uriInfo); @GET @Path("/operations/{identifier:.+}") - @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON, + @Produces({ Draft02.MediaTypes.API + JSON, Draft02.MediaTypes.API + XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public StructuredData getOperations(@PathParam("identifier") String identifier, @Context UriInfo uriInfo); @@ -149,7 +149,7 @@ public interface RestconfService { @GET @Path("/streams") - @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON, + @Produces({ Draft02.MediaTypes.API + JSON, Draft02.MediaTypes.API + XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public StructuredData getAvailableStreams(@Context UriInfo uriInfo); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeReader.java index 5fbb605558..552e2bbd19 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeReader.java @@ -29,7 +29,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; class JsonToCompositeNodeReader { - private static final Logger LOG = LoggerFactory.getLogger(JsonReader.class); + private static final Logger LOG = LoggerFactory.getLogger(JsonToCompositeNodeReader.class); private static final Splitter COLON_SPLITTER = Splitter.on(':'); private JsonToCompositeNodeReader() { @@ -113,14 +113,29 @@ class JsonToCompositeNodeReader { } } + /** + * Transform input value to URI instance. + * + * Input string has to be in format moduleName:localName. moduleName part is then transformed to URI instance. + * If moduleName part contains character like "<" or ">" then null value is returned because they + * aren't valid URI characters. + * + * @param jsonElementName + * value in format moduleName:localName + * @return + */ private static URI getNamespaceFor(final String jsonElementName) { final Iterator it = COLON_SPLITTER.split(jsonElementName).iterator(); - // The string needs to me in form "moduleName:localName" + // The string needs to be in form "moduleName:localName" if (it.hasNext()) { final String maybeURI = it.next(); if (Iterators.size(it) == 1) { - return URI.create(maybeURI); + try { + return URI.create(maybeURI); + } catch (IllegalArgumentException e) { + LOG.debug("Value {} couldn't be interpreted as URI.", maybeURI); + } } } @@ -144,7 +159,7 @@ class JsonToCompositeNodeReader { } } - // it could be identityref Built-In Type + // it could be identityref Built-In Type therefore it is necessary to look at value as module_name:local_name URI namespace = getNamespaceFor(value); if (namespace != null) { return new IdentityValuesDTO(namespace.toString(), getLocalNameFor(value), null, value); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeXmlBodyWriter.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeXmlBodyWriter.java index 3a6de300a0..bab26dfc01 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeXmlBodyWriter.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeXmlBodyWriter.java @@ -16,7 +16,6 @@ import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; import javax.xml.stream.FactoryConfigurationError; @@ -28,6 +27,8 @@ import org.opendaylight.controller.sal.rest.api.RestconfService; import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext; import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; @@ -72,7 +73,9 @@ public class NormalizedNodeXmlBodyWriter implements MessageBodyWriter accepts = headers.getAcceptableMediaTypes(); + accepts.remove(MediaType.WILDCARD_TYPE); LOG.debug("Accept headers: {}", accepts); + final MediaType mediaType; if (accepts != null && accepts.size() > 0) { mediaType = accepts.get(0); // just pick the first one + } else { + // Default to the content type if there's no Accept header + mediaType = MediaType.APPLICATION_JSON_TYPE; } LOG.debug("Using MediaType: {}", mediaType); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java index 569a81f603..95fb9a4826 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java @@ -230,7 +230,7 @@ public class BrokerFacade { private CheckedFuture deleteDataViaTransaction( final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore, YangInstanceIdentifier path) { - LOG.info("Delete " + datastore.name() + " via Restconf: {}", path); + LOG.trace("Delete " + datastore.name() + " via Restconf: {}", path); writeTransaction.delete(datastore, path); return writeTransaction.submit(); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/resources/WEB-INF/web.xml b/opendaylight/md-sal/sal-rest-connector/src/main/resources/WEB-INF/web.xml index 60c3378471..120a826b32 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/resources/WEB-INF/web.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/main/resources/WEB-INF/web.xml @@ -23,6 +23,27 @@ /* + + cross-origin-restconf + org.eclipse.jetty.servlets.CrossOriginFilter + + allowedOrigins + * + + + allowedMethods + GET,POST,OPTIONS,DELETE,PUT,HEAD + + + allowedHeaders + origin, content-type, accept, authorization + + + + cross-origin-restconf + /* + + NB api diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/yang/sal-remote-augment.yang b/opendaylight/md-sal/sal-rest-connector/src/main/yang/sal-remote-augment.yang index 83934568cc..cc1d26fb97 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/yang/sal-remote-augment.yang +++ b/opendaylight/md-sal/sal-rest-connector/src/main/yang/sal-remote-augment.yang @@ -9,7 +9,7 @@ module sal-remote-augment { description "Added input parameters to rpc create-data-change-event-subscription"; - revision "2014-7-8" { + revision "2014-07-08" { } augment "/salrmt:create-data-change-event-subscription/salrmt:input" { @@ -28,4 +28,4 @@ module sal-remote-augment { } } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java index 3699e4924f..d65cb1bdbf 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java @@ -422,4 +422,36 @@ public class JsonToCnSnTest { assertTrue(exceptionMessage.contains("Root element of Json has to be Object")); } + /** + * Tests case when JSON input data value is in format string1:string2 and first string contain characters "<" or ">" (invalid URI characters). + * + * During loading data it is also interpreting as data value in moduleName:localName (potential leafref value). + * ModuleName part is transformed to URI which causes exception which is caught and URI value is null which cause that potential value in simple node is + * simple string (value from JSON input) and not IdentityValueDTO instance which is used for leaf-ref candidates. + */ + @Test + public void invalidUriCharacterInValue() { + final Node rootNode = TestUtils.readInputToCnSn("/json-to-cnsn/invalid-uri-character-in-value.json", true, + JsonToCompositeNodeProvider.INSTANCE); + + assertTrue(rootNode instanceof CompositeNode); + Node lf1 = null; + Node lf2 = null; + for(Node child : ((CompositeNode)rootNode).getChildren()) { + if (child.getNodeType().getLocalName().equals("lf1")) { + lf1 = child; + } else if (child.getNodeType().getLocalName().equals("lf2")) { + lf2 = child; + } + } + + assertNotNull(lf1); + assertNotNull(lf2); + assertTrue(lf1 instanceof SimpleNode); + assertTrue(lf2 instanceof SimpleNode); + + assertEquals("module) lf1).getValue()); + assertEquals("module>Name:value lf2", ((SimpleNode) lf2).getValue()); + } + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/invalid-uri-character-in-value.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/invalid-uri-character-in-value.json new file mode 100644 index 0000000000..6a78e9fc87 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/invalid-uri-character-in-value.json @@ -0,0 +1,6 @@ +{ + "moduleName:cont":{ + "lf1":"moduleName:value lf2" + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-docgen/pom.xml b/opendaylight/md-sal/sal-rest-docgen/pom.xml index 1141e1d72e..5abb4f8910 100644 --- a/opendaylight/md-sal/sal-rest-docgen/pom.xml +++ b/opendaylight/md-sal/sal-rest-docgen/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-rest-docgen @@ -113,7 +113,7 @@ MD SAL Rest Api Doc Generator *, - com.sun.jersey.spi.container.servlet + com.sun.jersey.spi.container.servlet, org.eclipse.jetty.servlets org.opendaylight.controller.sal.rest.doc.DocProvider /apidoc diff --git a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/BaseYangSwaggerGenerator.java b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/BaseYangSwaggerGenerator.java index 5d0f3612e4..4d567bdef5 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/BaseYangSwaggerGenerator.java +++ b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/BaseYangSwaggerGenerator.java @@ -173,12 +173,12 @@ public class BaseYangSwaggerGenerator { resourcePath = getDataStorePath("/operational/", context); addApis(node, apis, resourcePath, pathParams, schemaContext, false); } + } - Set rpcs = m.getRpcs(); - for (RpcDefinition rpcDefinition : rpcs) { - String resourcePath = getDataStorePath("/operations/", context); - addRpcs(rpcDefinition, apis, resourcePath, schemaContext); - } + Set rpcs = m.getRpcs(); + for (RpcDefinition rpcDefinition : rpcs) { + String resourcePath = getDataStorePath("/operations/", context); + addRpcs(rpcDefinition, apis, resourcePath, schemaContext); } _logger.debug("Number of APIs found [{}]", apis.size()); diff --git a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java index f4274870c9..3b503ebba3 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java +++ b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java @@ -146,8 +146,10 @@ public class ModelGenerator { for (DataSchemaNode childNode : module.getChildNodes()) { // For every container and list in the module - processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, true, schemaContext); - processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, false, schemaContext); + if (childNode instanceof ContainerSchemaNode || childNode instanceof ListSchemaNode) { + processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, true, schemaContext); + processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, false, schemaContext); + } } } @@ -306,6 +308,9 @@ public class ModelGenerator { property.put(TYPE_KEY, childNode instanceof ListSchemaNode ? ARRAY_TYPE : OBJECT_TYPE); property.put(ITEMS_KEY, items); properties.put(childNode.getQName().getLocalName(), property); + } else if (childNode instanceof LeafSchemaNode){ + JSONObject property = processLeafNode((LeafSchemaNode)childNode); + properties.put(childNode.getQName().getLocalName(), property); } } return properties; diff --git a/opendaylight/md-sal/sal-rest-docgen/src/main/resources/WEB-INF/web.xml b/opendaylight/md-sal/sal-rest-docgen/src/main/resources/WEB-INF/web.xml index c470b3237e..d777942b53 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/main/resources/WEB-INF/web.xml +++ b/opendaylight/md-sal/sal-rest-docgen/src/main/resources/WEB-INF/web.xml @@ -20,39 +20,28 @@ /apis/* - + cross-origin-api-doc + /apis/* + + + free access diff --git a/opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGeneratorTest.java b/opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGeneratorTest.java new file mode 100644 index 0000000000..5918a0e839 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGeneratorTest.java @@ -0,0 +1,45 @@ +package org.opendaylight.controller.sal.rest.doc.impl; + +import com.google.common.base.Preconditions; +import org.json.JSONObject; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; + +import java.io.File; +import java.util.HashSet; +import java.util.Map; + + +public class ModelGeneratorTest { + + private DocGenTestHelper helper; + private SchemaContext schemaContext; + + @Before + public void setUp() throws Exception { + helper = new DocGenTestHelper(); + helper.setUp(); + schemaContext = new YangParserImpl().resolveSchemaContext(new HashSet(helper.getModules().values())); + } + + @Test + public void testConvertToJsonSchema() throws Exception { + + Preconditions.checkArgument(helper.getModules() != null, "No modules found"); + + ModelGenerator generator = new ModelGenerator(); + + for (Map.Entry m : helper.getModules().entrySet()) { + if (m.getKey().getAbsolutePath().endsWith("opflex.yang")) { + + JSONObject jsonObject = generator.convertToJsonSchema(m.getValue(), schemaContext); + Assert.assertNotNull(jsonObject); + } + } + + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/opflex.yang b/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/opflex.yang new file mode 100644 index 0000000000..8e598ddaab --- /dev/null +++ b/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/opflex.yang @@ -0,0 +1,50 @@ +module opflex { + yang-version 1; + + namespace "urn:opendaylight:groupbasedpolicy:opflex"; + prefix "opflex"; + + + + + + description + "This module defines the group-based policy OpFlex renderer model."; + + revision "2014-05-28" { + description + "Initial revision."; + } + + typedef serialization { + description + "The serialization to use for OpFlex messages."; + + type enumeration { + enum json { + description + "JSON 1.0 serialization."; + } + enum xml { + description + "XML serialization."; + } + enum binary { + description + "OpFlex binary serialization."; + } + } + } + + // ****************** + // Configuration Data + // ****************** + leaf domain { + description + "The OpFlex administrative domain."; + + config true; + + type string; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster.yang b/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster.yang index 20bbd78622..ffddc8c3da 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster.yang +++ b/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster.yang @@ -20,11 +20,19 @@ module toaster { "Toaster module in progress."; } + leaf domain { + description + "Toaster domain."; + + config true; + + type string; + } identity toast-type { description "Base for all bread types supported by the toaster. - New bread types not listed here nay be added in the + New bread types not listed here nay be added in the future."; } @@ -72,7 +80,7 @@ module toaster { "Indicates the toaster service is available"; description "Top-level container for all toaster database objects."; - + leaf testToasterBits { type bits { bit testbit1 { @@ -84,21 +92,21 @@ module toaster { } default "testbit2"; } - + leaf testUnion { type union { type int32; type string; } - - } - + + } + leaf-list allow-user { type string; description "A list of user name patterns to allow"; - + } - + choice how { default interval; case interval { @@ -123,14 +131,14 @@ module toaster { type string; } } - } - + } + leaf toasterManufacturer { type DisplayString; config false; mandatory true; description - "The name of the toaster's manufacturer. For instance, + "The name of the toaster's manufacturer. For instance, Microsoft Toaster."; } @@ -161,7 +169,7 @@ module toaster { config false; mandatory true; description - "This variable indicates the current state of + "This variable indicates the current state of the toaster."; } } @@ -169,11 +177,11 @@ module toaster { rpc make-toast { description "Make some toast. - The toastDone notification will be sent when + The toastDone notification will be sent when the toast is finished. An 'in-use' error will be returned if toast is already being made. - A 'resource-denied' error will be returned + A 'resource-denied' error will be returned if the toaster service is disabled."; input { leaf toasterDoneness { @@ -182,10 +190,10 @@ module toaster { } default '5'; description - "This variable controls how well-done is the + "This variable controls how well-done is the ensuing toast. It should be on a scale of 1 to 10. - Toast made at 10 generally is considered unfit - for human consumption; toast made at 1 is warmed + Toast made at 10 generally is considered unfit + for human consumption; toast made at 1 is warmed lightly."; } @@ -195,23 +203,23 @@ module toaster { } default 'wheat-bread'; description - "This variable informs the toaster of the type of - material that is being toasted. The toaster - uses this information, combined with - toasterDoneness, to compute for how - long the material must be toasted to achieve + "This variable informs the toaster of the type of + material that is being toasted. The toaster + uses this information, combined with + toasterDoneness, to compute for how + long the material must be toasted to achieve the required doneness."; } } - } + } rpc cancel-toast { description "Stop making toast, if any is being made. - A 'resource-denied' error will be returned + A 'resource-denied' error will be returned if the toaster service is disabled."; - } - + } + notification toastDone { description "Indicates that the toast in progress has completed."; @@ -236,5 +244,5 @@ module toaster { description "Indicates the final toast status"; } - } - } + } + } diff --git a/opendaylight/md-sal/sal-restconf-broker/pom.xml b/opendaylight/md-sal/sal-restconf-broker/pom.xml index 9e64c3aed6..db2b06e714 100644 --- a/opendaylight/md-sal/sal-restconf-broker/pom.xml +++ b/opendaylight/md-sal/sal-restconf-broker/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sal-restconf-broker bundle diff --git a/opendaylight/md-sal/sal-test-model/pom.xml b/opendaylight/md-sal/sal-test-model/pom.xml index 11a0ef211a..2a8a80da09 100644 --- a/opendaylight/md-sal/sal-test-model/pom.xml +++ b/opendaylight/md-sal/sal-test-model/pom.xml @@ -5,7 +5,7 @@ sal-parent org.opendaylight.controller - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT 4.0.0 diff --git a/opendaylight/md-sal/samples/clustering-test-app/configuration/pom.xml b/opendaylight/md-sal/samples/clustering-test-app/configuration/pom.xml index 8d4bbbd64c..33a8a92f9f 100644 --- a/opendaylight/md-sal/samples/clustering-test-app/configuration/pom.xml +++ b/opendaylight/md-sal/samples/clustering-test-app/configuration/pom.xml @@ -12,7 +12,7 @@ clustering-it org.opendaylight.controller.samples - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT clustering-it-config jar diff --git a/opendaylight/md-sal/samples/clustering-test-app/model/pom.xml b/opendaylight/md-sal/samples/clustering-test-app/model/pom.xml index a23e32df2b..60eeba64c7 100644 --- a/opendaylight/md-sal/samples/clustering-test-app/model/pom.xml +++ b/opendaylight/md-sal/samples/clustering-test-app/model/pom.xml @@ -4,7 +4,7 @@ clustering-it org.opendaylight.controller.samples - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT clustering-it-model bundle diff --git a/opendaylight/md-sal/samples/clustering-test-app/pom.xml b/opendaylight/md-sal/samples/clustering-test-app/pom.xml index 863bbecdf9..5824621331 100644 --- a/opendaylight/md-sal/samples/clustering-test-app/pom.xml +++ b/opendaylight/md-sal/samples/clustering-test-app/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller.samples sal-samples - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT clustering-it pom diff --git a/opendaylight/md-sal/samples/clustering-test-app/provider/pom.xml b/opendaylight/md-sal/samples/clustering-test-app/provider/pom.xml index 093b681125..d4d55b04c0 100644 --- a/opendaylight/md-sal/samples/clustering-test-app/provider/pom.xml +++ b/opendaylight/md-sal/samples/clustering-test-app/provider/pom.xml @@ -4,7 +4,7 @@ clustering-it org.opendaylight.controller.samples - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT clustering-it-provider bundle diff --git a/opendaylight/md-sal/samples/l2switch/implementation/pom.xml b/opendaylight/md-sal/samples/l2switch/implementation/pom.xml index 8824284785..a0e119b49c 100644 --- a/opendaylight/md-sal/samples/l2switch/implementation/pom.xml +++ b/opendaylight/md-sal/samples/l2switch/implementation/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller.samples sal-samples - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT ../.. org.opendaylight.controller.samples.l2switch.md diff --git a/opendaylight/md-sal/samples/l2switch/model/pom.xml b/opendaylight/md-sal/samples/l2switch/model/pom.xml index 0ccc74d952..fa35c1f6cd 100644 --- a/opendaylight/md-sal/samples/l2switch/model/pom.xml +++ b/opendaylight/md-sal/samples/l2switch/model/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller.samples sal-samples - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT ../.. org.opendaylight.controller.samples.l2switch.md diff --git a/opendaylight/md-sal/samples/l2switch/pom.xml b/opendaylight/md-sal/samples/l2switch/pom.xml index 2e2100b287..6a715c74ab 100644 --- a/opendaylight/md-sal/samples/l2switch/pom.xml +++ b/opendaylight/md-sal/samples/l2switch/pom.xml @@ -4,10 +4,15 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 + + org.opendaylight.controller.samples + sal-samples + 1.2.0-SNAPSHOT + l2switch.aggregator org.opendaylight.controller.samples.l2switch - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT pom diff --git a/opendaylight/md-sal/samples/pom.xml b/opendaylight/md-sal/samples/pom.xml index d13200e4e8..6070c72472 100644 --- a/opendaylight/md-sal/samples/pom.xml +++ b/opendaylight/md-sal/samples/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT org.opendaylight.controller.samples diff --git a/opendaylight/md-sal/samples/toaster-config/pom.xml b/opendaylight/md-sal/samples/toaster-config/pom.xml index b30c4ba12f..b0592b654d 100644 --- a/opendaylight/md-sal/samples/toaster-config/pom.xml +++ b/opendaylight/md-sal/samples/toaster-config/pom.xml @@ -12,7 +12,7 @@ org.opendaylight.controller.samples sal-samples - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT toaster-config Configuration files for toaster diff --git a/opendaylight/md-sal/samples/toaster-consumer/pom.xml b/opendaylight/md-sal/samples/toaster-consumer/pom.xml index 6e720299d8..fb6828a250 100644 --- a/opendaylight/md-sal/samples/toaster-consumer/pom.xml +++ b/opendaylight/md-sal/samples/toaster-consumer/pom.xml @@ -4,13 +4,13 @@ org.opendaylight.controller.samples sal-samples - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sample-toaster-consumer bundle - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT diff --git a/opendaylight/md-sal/samples/toaster-it/pom.xml b/opendaylight/md-sal/samples/toaster-it/pom.xml index 56ed9a07a6..804da597ac 100644 --- a/opendaylight/md-sal/samples/toaster-it/pom.xml +++ b/opendaylight/md-sal/samples/toaster-it/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller.samples sal-samples - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sample-toaster-it diff --git a/opendaylight/md-sal/samples/toaster-provider/pom.xml b/opendaylight/md-sal/samples/toaster-provider/pom.xml index 89dcab2c3d..08f0988b5c 100644 --- a/opendaylight/md-sal/samples/toaster-provider/pom.xml +++ b/opendaylight/md-sal/samples/toaster-provider/pom.xml @@ -4,13 +4,13 @@ org.opendaylight.controller.samples sal-samples - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sample-toaster-provider bundle - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT diff --git a/opendaylight/md-sal/samples/toaster/pom.xml b/opendaylight/md-sal/samples/toaster/pom.xml index 5c8b20a4e3..ab761fd6bf 100644 --- a/opendaylight/md-sal/samples/toaster/pom.xml +++ b/opendaylight/md-sal/samples/toaster/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller.samples sal-samples - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT sample-toaster bundle diff --git a/opendaylight/md-sal/statistics-manager/pom.xml b/opendaylight/md-sal/statistics-manager/pom.xml index 399d53b67f..1a443177c6 100644 --- a/opendaylight/md-sal/statistics-manager/pom.xml +++ b/opendaylight/md-sal/statistics-manager/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT org.opendaylight.controller.md statistics-manager @@ -21,8 +21,9 @@ junit - org.eclipse.xtend - org.eclipse.xtend.lib + org.opendaylight.controller + sal-binding-broker-impl + test org.opendaylight.controller @@ -57,7 +58,6 @@ org.opendaylight.controller.md.statistics.manager.StatisticsManagerActivator - org.opendaylight.controller.md.statistics.manager diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java deleted file mode 100644 index 167fb21ffd..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.statistics.manager; - -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; - -abstract class AbstractListeningStatsTracker extends AbstractStatsTracker implements AutoCloseable, DataChangeListener { - private static final Logger logger = LoggerFactory.getLogger(AbstractListeningStatsTracker.class); - private ListenerRegistration reg; - - protected AbstractListeningStatsTracker(FlowCapableContext context) { - super(context); - } - - protected abstract InstanceIdentifier listenPath(); - protected abstract String statName(); - - public void start(final DataBrokerService dbs) { - Preconditions.checkState(reg == null); - - reg = dbs.registerDataChangeListener(listenPath(), this); - logger.debug("{} Statistics tracker for node {} started", statName(), getNodeIdentifier()); - } - - @Override - public final void close() { - if (reg != null) { - try { - reg.close(); - } catch (Exception e) { - logger.warn("Failed to stop {} Statistics tracker for node {}", statName(), getNodeIdentifier(), e); - } - reg = null; - } - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java deleted file mode 100644 index 838aeb7dc3..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java +++ /dev/null @@ -1,127 +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.md.statistics.manager; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.Future; - -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.JdkFutureAdapters; - -abstract class AbstractStatsTracker { - private static final Logger logger = LoggerFactory.getLogger(AbstractStatsTracker.class); - - private static final int WAIT_FOR_REQUEST_CYCLE = 2; - - private final FutureCallback> callback = - new FutureCallback>() { - @Override - public void onSuccess(RpcResult result) { - if (result.isSuccessful()) { - final TransactionId id = result.getResult().getTransactionId(); - if (id == null) { - final Throwable t = new UnsupportedOperationException("No protocol support"); - t.fillInStackTrace(); - onFailure(t); - } else { - context.registerTransaction(id); - } - } else { - logger.debug("Statistics request failed: {}", result.getErrors()); - - final Throwable t = new RPCFailedException("Failed to send statistics request", result.getErrors()); - t.fillInStackTrace(); - onFailure(t); - } - } - - @Override - public void onFailure(Throwable t) { - logger.debug("Failed to send statistics request", t); - } - }; - - private final Map trackedItems = new HashMap<>(); - private final FlowCapableContext context; - private long requestCounter; - - protected AbstractStatsTracker(final FlowCapableContext context) { - this.context = Preconditions.checkNotNull(context); - this.requestCounter = 0; - } - - protected final InstanceIdentifierBuilder getNodeIdentifierBuilder() { - return getNodeIdentifier().builder(); - } - - protected final NodeRef getNodeRef() { - return context.getNodeRef(); - } - - protected final InstanceIdentifier getNodeIdentifier() { - return context.getNodeIdentifier(); - } - - protected final void requestHelper(Future> future) { - Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), callback); - } - - protected final DataModificationTransaction startTransaction() { - return context.startDataModification(); - } - - public final synchronized void increaseRequestCounter(){ - this.requestCounter++; - } - protected abstract void cleanupSingleStat(DataModificationTransaction trans, K item); - protected abstract K updateSingleStat(DataModificationTransaction trans, I item); - protected abstract K createInvariantKey(K item); - public abstract void request(); - - public final synchronized void updateStats(List list) { - - final DataModificationTransaction trans = startTransaction(); - for (final I item : list) { - K key = updateSingleStat(trans, item); - trackedItems.put(createInvariantKey(key), requestCounter); - } - - trans.commit(); - } - - /** - * Statistics will be cleaned up if not update in last two request cycles. - * @param trans - */ - public final synchronized void cleanup(final DataModificationTransaction trans) { - for (Iterator> it = trackedItems.entrySet().iterator();it.hasNext();){ - Entry e = it.next(); - if (requestCounter >= e.getValue()+WAIT_FOR_REQUEST_CYCLE) { - cleanupSingleStat(trans, e.getKey()); - it.remove(); - } - } - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java deleted file mode 100644 index 520b344199..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.statistics.manager; - -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Interface exposed to AbstractStatsTracker by its parent NodeStatisticsHandler. - * While we could simply exist without this interface, its purpose is to document - * the contract between the two classes. - */ -interface FlowCapableContext { - InstanceIdentifier getNodeIdentifier(); - NodeRef getNodeRef(); - DataModificationTransaction startDataModification(); - void registerTransaction(TransactionId id); - void registerTableTransaction(TransactionId id, Short tableId); -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java deleted file mode 100644 index bb1544c57a..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java +++ /dev/null @@ -1,111 +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.md.statistics.manager; - -import java.util.Collection; - -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Function; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.Collections2; -import com.google.common.collect.Sets; - -/** - * There is a single instance of this class and that instance is responsible for - * monitoring the operational data store for nodes being created/deleted and - * notifying StatisticsProvider. These events then control the lifecycle of - * NodeStatisticsHandler for a particular switch. - */ -final class FlowCapableTracker implements DataChangeListener { - private static final Logger logger = LoggerFactory.getLogger(FlowCapableTracker.class); - - private final InstanceIdentifier root; - private final StatisticsProvider stats; - - private final Predicate> filterIdentifiers = new Predicate>() { - @Override - public boolean apply(final InstanceIdentifier input) { - /* - * This notification has been triggered either by the ancestor, - * descendant or directly for the FlowCapableNode itself. We - * are not interested descendants, so let's prune them based - * on the depth of their identifier. - */ - if (root.getPath().size() < input.getPath().size()) { - logger.debug("Ignoring notification for descendant {}", input); - return false; - } - - logger.debug("Including notification for {}", input); - return true; - } - }; - - public FlowCapableTracker(final StatisticsProvider stats, InstanceIdentifier root) { - this.stats = Preconditions.checkNotNull(stats); - this.root = Preconditions.checkNotNull(root); - } - - /* - * This method is synchronized because we want to make sure to serialize input - * from the datastore. Competing add/remove could be problematic otherwise. - */ - @Override - public synchronized void onDataChanged(final DataChangeEvent, DataObject> change) { - logger.debug("Tracker at root {} processing notification", root); - - /* - * First process all the identifiers which were removed, trying to figure out - * whether they constitute removal of FlowCapableNode. - */ - final Collection removedNodes = - Collections2.filter(Collections2.transform( - Sets.filter(change.getRemovedOperationalData(), filterIdentifiers), - new Function, NodeKey>() { - @Override - public NodeKey apply(final InstanceIdentifier input) { - final NodeKey key = input.firstKeyOf(Node.class, NodeKey.class); - if (key == null) { - // FIXME: do we have a backup plan? - logger.info("Failed to extract node key from {}", input); - } - return key; - } - }), Predicates.notNull()); - stats.stopNodeHandlers(removedNodes); - - final Collection addedNodes = - Collections2.filter(Collections2.transform( - Sets.filter(change.getCreatedOperationalData().keySet(), filterIdentifiers), - new Function, NodeKey>() { - @Override - public NodeKey apply(final InstanceIdentifier input) { - final NodeKey key = input.firstKeyOf(Node.class, NodeKey.class); - if (key == null) { - // FIXME: do we have a backup plan? - logger.info("Failed to extract node key from {}", input); - } - return key; - } - }), Predicates.notNull()); - stats.startNodeHandlers(addedNodes); - - logger.debug("Tracker at root {} finished processing notification", root); - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java deleted file mode 100644 index c43c1ebaca..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java +++ /dev/null @@ -1,64 +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.md.statistics.manager; - -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; - -final class FlowStatsEntry { - private final Short tableId; - private final Flow flow; - - public FlowStatsEntry(Short tableId, Flow flow){ - this.tableId = tableId; - this.flow = flow; - } - - public Short getTableId() { - return tableId; - } - - public Flow getFlow() { - return flow; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((flow == null) ? 0 : flow.hashCode()); - result = prime * result + ((tableId == null) ? 0 : tableId.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; - FlowStatsEntry other = (FlowStatsEntry) obj; - if (flow == null) { - if (other.flow != null) - return false; - } else if (!flow.equals(other.flow)) - return false; - if (tableId == null) { - if (other.tableId != null) - return false; - } else if (!tableId.equals(other.tableId)) - return false; - return true; - } - - @Override - public String toString() { - return "FlowStatsEntry [tableId=" + tableId + ", flow=" + flow + "]"; - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java deleted file mode 100644 index d540f115c3..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java +++ /dev/null @@ -1,313 +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.md.statistics.manager; - -import java.math.BigInteger; -import java.util.Collection; -import java.util.Collections; -import java.util.Map.Entry; - -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCookieMapping; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMapBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMapKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Optional; - -final class FlowStatsTracker extends AbstractListeningStatsTracker { - private static final Logger LOG = LoggerFactory.getLogger(FlowStatsTracker.class); - private static final String ALIEN_SYSTEM_FLOW_ID = "#UF$TABLE*"; - private final OpendaylightFlowStatisticsService flowStatsService; - private FlowTableStatsTracker flowTableStats; - private int unaccountedFlowsCounter = 1; - - - FlowStatsTracker(final OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context) { - super(context); - this.flowStatsService = flowStatsService; - } - FlowStatsTracker(final OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context, final FlowTableStatsTracker flowTableStats) { - this(flowStatsService, context); - this.flowTableStats = flowTableStats; - } - - @Override - protected void cleanupSingleStat(final DataModificationTransaction trans, final FlowStatsEntry item) { - KeyedInstanceIdentifier flowRef = getNodeIdentifier() - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(item.getTableId())) - .child(Flow.class, item.getFlow().getKey()); - trans.removeOperationalData(flowRef); - } - - @Override - protected FlowStatsEntry updateSingleStat(final DataModificationTransaction trans, final FlowAndStatisticsMapList map) { - short tableId = map.getTableId(); - - FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder(); - - FlowBuilder flowBuilder = new FlowBuilder(map); - if (map.getFlowId() != null) { - flowBuilder.setId(new FlowId(map.getFlowId().getValue())); - } - if (map.getFlowId() != null) { - flowBuilder.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue()))); - } - - Flow flowRule = flowBuilder.build(); - - FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder(); - stats.setByteCount(map.getByteCount()); - stats.setPacketCount(map.getPacketCount()); - stats.setDuration(map.getDuration()); - - GenericStatistics flowStats = stats.build(); - - //Augment the data to the flow node - - FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder(); - flowStatistics.setByteCount(flowStats.getByteCount()); - flowStatistics.setPacketCount(flowStats.getPacketCount()); - flowStatistics.setDuration(flowStats.getDuration()); - - flowStatisticsData.setFlowStatistics(flowStatistics.build()); - - LOG.debug("Flow : {}",flowRule.toString()); - LOG.debug("Statistics to augment : {}",flowStatistics.build().toString()); - - InstanceIdentifier
  • tableRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)).toInstance(); - - final FlowCookie flowCookie = flowRule.getCookie() != null - ? flowRule.getCookie() : new FlowCookie(BigInteger.ZERO); - final InstanceIdentifier flowCookieRef = tableRef - .augmentation(FlowCookieMapping.class) - .child(FlowCookieMap.class, new FlowCookieMapKey(flowCookie)); - - FlowCookieMap cookieMap = (FlowCookieMap) trans.readOperationalData(flowCookieRef); - - /* find flowKey in FlowCookieMap from DataStore/OPERATIONAL */ - Optional flowKey = this.getExistFlowKey(flowRule, tableRef, trans, cookieMap); - if ( ! flowKey.isPresent()) { - /* DataStore/CONFIG For every first statistic needs to be created */ - flowKey = this.getFlowKeyFromExistFlow(flowRule, tableRef, trans); - if ( ! flowKey.isPresent()) { - /* Alien flow */ - flowKey = this.makeAlienFlowKey(flowRule); - } - cookieMap = applyNewFlowKey(cookieMap, flowKey, flowCookie); - trans.putOperationalData(flowCookieRef, cookieMap); - } - - InstanceIdentifier flowRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class, flowKey.get()).toInstance(); - flowBuilder.setKey(flowKey.get()); - flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - - // Update entry with timestamp of latest response - flowBuilder.setKey(flowKey.get()); - FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId, flowBuilder.build()); - trans.putOperationalData(flowRef, flowBuilder.build()); - return flowStatsEntry; - } - - @Override - protected InstanceIdentifier listenPath() { - return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Table.class).child(Flow.class).build(); - } - - @Override - protected String statName() { - return "Flow"; - } - - @Override - public void request() { - // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest() - // comes back -- we do not have any tables anyway. - final Collection tables = flowTableStats.getTables(); - LOG.debug("Node {} supports {} table(s)", this.getNodeRef(), tables.size()); - for (final TableKey key : tables) { - LOG.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), this.getNodeRef()); - this.requestAggregateFlows(key); - } - - this.requestAllFlowsAllTables(); - - } - public void requestAllFlowsAllTables() { - if (flowStatsService != null) { - final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input = new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder(); - input.setNode(getNodeRef()); - - requestHelper(flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build())); - } - } - - public void requestAggregateFlows(final TableKey key) { - if (flowStatsService != null) { - GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = - new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder(); - - input.setNode(getNodeRef()); - input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(key.getId())); - requestHelper(flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build())); - } - } - - public void requestFlow(final Flow flow) { - if (flowStatsService != null) { - final GetFlowStatisticsFromFlowTableInputBuilder input = - new GetFlowStatisticsFromFlowTableInputBuilder(flow); - input.setNode(getNodeRef()); - - requestHelper(flowStatsService.getFlowStatisticsFromFlowTable(input.build())); - } - } - - @Override - public void onDataChanged(final DataChangeEvent, DataObject> change) { - for (Entry, DataObject> e : change.getCreatedConfigurationData().entrySet()) { - if (Flow.class.equals(e.getKey().getTargetType())) { - final Flow flow = (Flow) e.getValue(); - LOG.debug("Key {} triggered request for flow {}", e.getKey(), flow); - requestFlow(flow); - } else { - LOG.debug("Ignoring key {}", e.getKey()); - } - } - - final DataModificationTransaction trans = startTransaction(); - for (InstanceIdentifier key : change.getRemovedConfigurationData()) { - if (Flow.class.equals(key.getTargetType())) { - @SuppressWarnings("unchecked") - final InstanceIdentifier flow = (InstanceIdentifier)key; - LOG.debug("Key {} triggered remove of Flow from operational space.", key); - trans.removeOperationalData(flow); - } - } - trans.commit(); - } - - @Override - public void start(final DataBrokerService dbs) { - if (flowStatsService == null) { - LOG.debug("No Flow Statistics service, not subscribing to flows on node {}", getNodeIdentifier()); - return; - } - - super.start(dbs); - } - - /* Returns Exist FlowKey from exist FlowCookieMap identified by cookie - * and by switch flow identification (priority and match)*/ - private Optional getExistFlowKey(final Flow flowRule, final InstanceIdentifier
    tableRef, - final DataModificationTransaction trans, final FlowCookieMap cookieMap) { - - if (cookieMap != null) { - for (FlowId flowId : cookieMap.getFlowIds()) { - InstanceIdentifier flowIdent = tableRef.child(Flow.class, new FlowKey(flowId)); - if (flowId.getValue().startsWith(ALIEN_SYSTEM_FLOW_ID)) { - LOG.debug("Search for flow in the operational datastore by flowID: {} ", flowIdent); - Flow readedFlow = (Flow) trans.readOperationalData(flowIdent); - if (FlowComparator.flowEquals(flowRule, readedFlow)) { - return Optional. of(new FlowKey(flowId)); - } - } else { - LOG.debug("Search for flow in the configuration datastore by flowID: {} ", flowIdent); - Flow readedFlow = (Flow) trans.readConfigurationData(flowIdent); - if (FlowComparator.flowEquals(flowRule, readedFlow)) { - return Optional. of(new FlowKey(flowId)); - } - } - } - LOG.debug("Flow was not found in the datastore. Flow {} ", flowRule); - } - return Optional.absent(); - } - - /* Returns FlowKey from existing Flow in DataStore/CONFIGURATIONAL which is identified by cookie - * and by switch flow identification (priority and match) */ - private Optional getFlowKeyFromExistFlow(final Flow flowRule, final InstanceIdentifier
    tableRef, - final DataModificationTransaction trans) { - - /* Try to find it in DataSotre/CONFIG */ - Table table= (Table)trans.readConfigurationData(tableRef); - if(table != null) { - for(Flow existingFlow : table.getFlow()) { - LOG.debug("Existing flow in data store : {}",existingFlow.toString()); - if(FlowComparator.flowEquals(flowRule,existingFlow)){ - return Optional. of(new FlowKey(existingFlow.getId())); - } - } - } - return Optional.absent(); - } - - /* Returns FlowKey which doesn't exist in any DataStore for now */ - private Optional makeAlienFlowKey(final Flow flowRule) { - - StringBuilder sBuilder = new StringBuilder(ALIEN_SYSTEM_FLOW_ID) - .append(flowRule.getTableId()).append("-").append(this.unaccountedFlowsCounter); - this.unaccountedFlowsCounter++; - final FlowId flowId = new FlowId(sBuilder.toString()); - return Optional. of(new FlowKey(flowId)); - } - - /* Build new whole FlowCookieMap or add new flowKey */ - private FlowCookieMap applyNewFlowKey(FlowCookieMap flowCookieMap, final Optional flowKey, - final FlowCookie flowCookie) { - if (flowCookieMap != null) { - flowCookieMap.getFlowIds().add(flowKey.get().getId()); - } else { - final FlowCookieMapBuilder flowCookieMapBuilder = new FlowCookieMapBuilder(); - flowCookieMapBuilder.setCookie(flowCookie); - flowCookieMapBuilder.setFlowIds(Collections.singletonList(flowKey.get().getId())); - flowCookieMap = flowCookieMapBuilder.build(); - } - return flowCookieMap; - } - - @Override - protected FlowStatsEntry createInvariantKey(final FlowStatsEntry item) { - FlowBuilder newFlow = new FlowBuilder(); - newFlow.setId(item.getFlow().getId()); - newFlow.setKey(item.getFlow().getKey()); - newFlow.fieldsFrom(item.getFlow()); - return new FlowStatsEntry(item.getTableId(),newFlow.build()); - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java deleted file mode 100644 index 2e85058041..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java +++ /dev/null @@ -1,82 +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.md.statistics.manager; - -import java.util.Collections; -import java.util.Set; -import java.util.concurrent.ConcurrentSkipListSet; - -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMapBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -final class FlowTableStatsTracker extends AbstractStatsTracker { - private final Set privateTables = new ConcurrentSkipListSet<>(); - private final Set tables = Collections.unmodifiableSet(privateTables); - private final OpendaylightFlowTableStatisticsService flowTableStatsService; - - FlowTableStatsTracker(OpendaylightFlowTableStatisticsService flowTableStatsService, final FlowCapableContext context) { - super(context); - this.flowTableStatsService = flowTableStatsService; - } - - Set getTables() { - return tables; - } - - @Override - protected void cleanupSingleStat(DataModificationTransaction trans, FlowTableAndStatisticsMap item) { - // TODO: do we want to do this? - } - - @Override - protected FlowTableAndStatisticsMap updateSingleStat(DataModificationTransaction trans, FlowTableAndStatisticsMap item) { - - InstanceIdentifier
    tableRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(item.getTableId().getValue())).build(); - - FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder(); - final FlowTableStatistics stats = new FlowTableStatisticsBuilder(item).build(); - statisticsDataBuilder.setFlowTableStatistics(stats); - - TableBuilder tableBuilder = new TableBuilder(); - tableBuilder.setKey(new TableKey(item.getTableId().getValue())); - tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build()); - trans.putOperationalData(tableRef, tableBuilder.build()); - return item; - } - - @Override - public void request() { - if (flowTableStatsService != null) { - final GetFlowTablesStatisticsInputBuilder input = new GetFlowTablesStatisticsInputBuilder(); - input.setNode(getNodeRef()); - - requestHelper(flowTableStatsService.getFlowTablesStatistics(input.build())); - } - } - - @Override - protected FlowTableAndStatisticsMap createInvariantKey(FlowTableAndStatisticsMap item) { - FlowTableAndStatisticsMapBuilder flowTableAndStatisticsMapBuilder = new FlowTableAndStatisticsMapBuilder(); - flowTableAndStatisticsMapBuilder.setTableId(item.getTableId()); - flowTableAndStatisticsMapBuilder.setKey(item.getKey()); - return flowTableAndStatisticsMapBuilder.build(); - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java deleted file mode 100644 index 11c6d4c22d..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java +++ /dev/null @@ -1,123 +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.md.statistics.manager; - -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class GroupDescStatsTracker extends AbstractListeningStatsTracker { - private static final Logger logger = LoggerFactory.getLogger(GroupDescStatsTracker.class); - private final OpendaylightGroupStatisticsService groupStatsService; - - public GroupDescStatsTracker(OpendaylightGroupStatisticsService groupStatsService, final FlowCapableContext context) { - super(context); - this.groupStatsService = groupStatsService; - } - - @Override - protected GroupDescStats updateSingleStat(DataModificationTransaction trans, GroupDescStats item) { - GroupBuilder groupBuilder = new GroupBuilder(); - GroupKey groupKey = new GroupKey(item.getGroupId()); - groupBuilder.setKey(groupKey); - - InstanceIdentifier groupRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class).child(Group.class,groupKey).build(); - - NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder(); - groupDesc.setGroupDesc(new GroupDescBuilder(item).build()); - - //Update augmented data - groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build()); - - trans.putOperationalData(groupRef, groupBuilder.build()); - return item; - } - - @Override - protected void cleanupSingleStat(DataModificationTransaction trans, GroupDescStats item) { - InstanceIdentifier groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class) - .child(Group.class, new GroupKey(item.getGroupId())).augmentation(NodeGroupDescStats.class).build(); - trans.removeOperationalData(groupRef); - } - - @Override - protected InstanceIdentifier listenPath() { - return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Group.class).build(); - } - - @Override - protected String statName() { - return "Group Descriptor"; - } - - @Override - public void request() { - if (groupStatsService != null) { - final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder(); - input.setNode(getNodeRef()); - - requestHelper(groupStatsService.getGroupDescription(input.build())); - } - } - - @Override - public void onDataChanged(DataChangeEvent, DataObject> change) { - for (InstanceIdentifier key : change.getCreatedConfigurationData().keySet()) { - if (Group.class.equals(key.getTargetType())) { - logger.debug("Key {} triggered request", key); - request(); - } else { - logger.debug("Ignoring key {}", key); - } - } - - final DataModificationTransaction trans = startTransaction(); - for (InstanceIdentifier key : change.getRemovedConfigurationData()) { - if (Group.class.equals(key.getTargetType())) { - @SuppressWarnings("unchecked") - InstanceIdentifier group = (InstanceIdentifier)key; - InstanceIdentifier del = group.augmentation(NodeGroupDescStats.class); - logger.debug("Key {} triggered remove of augmentation {}", key, del); - - trans.removeOperationalData(del); - } - } - trans.commit(); - } - - @Override - public void start(final DataBrokerService dbs) { - if (groupStatsService == null) { - logger.debug("No Group Statistics service, not subscribing to groups on node {}", getNodeIdentifier()); - return; - } - - super.start(dbs); - } - - @Override - protected GroupDescStats createInvariantKey(GroupDescStats item) { - // No invariant data exist in the group description stats. - return item; - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java deleted file mode 100644 index f3ba45643c..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java +++ /dev/null @@ -1,117 +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.md.statistics.manager; - -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStatsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; - -final class GroupStatsTracker extends AbstractListeningStatsTracker { - private static final Logger logger = LoggerFactory.getLogger(GroupStatsTracker.class); - private final OpendaylightGroupStatisticsService groupStatsService; - - GroupStatsTracker(OpendaylightGroupStatisticsService groupStatsService, FlowCapableContext context) { - super(context); - this.groupStatsService = Preconditions.checkNotNull(groupStatsService); - } - - @Override - protected void cleanupSingleStat(DataModificationTransaction trans, GroupStats item) { - InstanceIdentifier groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class) - .child(Group.class, new GroupKey(item.getGroupId())).augmentation(NodeGroupStatistics.class).build(); - trans.removeOperationalData(groupRef); - } - - @Override - protected GroupStats updateSingleStat(DataModificationTransaction trans, - GroupStats item) { - GroupBuilder groupBuilder = new GroupBuilder(); - GroupKey groupKey = new GroupKey(item.getGroupId()); - groupBuilder.setKey(groupKey); - - InstanceIdentifier groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class) - .child(Group.class,groupKey).build(); - - NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder(); - groupStatisticsBuilder.setGroupStatistics(new GroupStatisticsBuilder(item).build()); - - //Update augmented data - groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build()); - trans.putOperationalData(groupRef, groupBuilder.build()); - return item; - } - - @Override - protected InstanceIdentifier listenPath() { - return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Group.class).build(); - } - - @Override - protected String statName() { - return "Group"; - } - - @Override - public void request() { - final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder(); - input.setNode(getNodeRef()); - - requestHelper(groupStatsService.getAllGroupStatistics(input.build())); - } - - @Override - public void onDataChanged(DataChangeEvent, DataObject> change) { - final DataModificationTransaction trans = startTransaction(); - for (InstanceIdentifier key : change.getRemovedConfigurationData()) { - if (Group.class.equals(key.getTargetType())) { - @SuppressWarnings("unchecked") - InstanceIdentifier group = (InstanceIdentifier)key; - InstanceIdentifier del = group.augmentation(NodeGroupStatistics.class); - logger.debug("Key {} triggered remove of augmentation {}", key, del); - - trans.removeOperationalData(del); - } - } - trans.commit(); - } - - @Override - public void start(final DataBrokerService dbs) { - if (groupStatsService == null) { - logger.debug("No Group Statistics service, not subscribing to groups on node {}", getNodeIdentifier()); - return; - } - - super.start(dbs); - } - - @Override - protected GroupStats createInvariantKey(GroupStats item) { - GroupStatsBuilder groupStatsBuilder = new GroupStatsBuilder(); - groupStatsBuilder.setKey(item.getKey()); - groupStatsBuilder.setGroupId(item.getGroupId()); - return groupStatsBuilder.build(); - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java deleted file mode 100644 index 88139fc606..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java +++ /dev/null @@ -1,118 +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.md.statistics.manager; - -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class MeterConfigStatsTracker extends AbstractListeningStatsTracker { - private static final Logger logger = LoggerFactory.getLogger(MeterConfigStatsTracker.class); - private final OpendaylightMeterStatisticsService meterStatsService; - - protected MeterConfigStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context) { - super(context); - this.meterStatsService = meterStatsService; - } - - @Override - protected void cleanupSingleStat(DataModificationTransaction trans, MeterConfigStats item) { - InstanceIdentifier meterRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class) - .child(Meter.class, new MeterKey(item.getMeterId())) - .augmentation(NodeMeterConfigStats.class).build(); - trans.removeOperationalData(meterRef); - } - - @Override - protected MeterConfigStats updateSingleStat(DataModificationTransaction trans, MeterConfigStats item) { - MeterBuilder meterBuilder = new MeterBuilder(); - MeterKey meterKey = new MeterKey(item.getMeterId()); - meterBuilder.setKey(meterKey); - - InstanceIdentifier meterRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class) - .child(Meter.class,meterKey).toInstance(); - - NodeMeterConfigStatsBuilder meterConfig = new NodeMeterConfigStatsBuilder(); - meterConfig.setMeterConfigStats(new MeterConfigStatsBuilder(item).build()); - - //Update augmented data - meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build()); - - trans.putOperationalData(meterRef, meterBuilder.build()); - return item; - } - - @Override - public void request() { - if (meterStatsService != null) { - GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder(); - input.setNode(getNodeRef()); - - requestHelper(meterStatsService.getAllMeterConfigStatistics(input.build())); - } - } - - @Override - public void onDataChanged(DataChangeEvent, DataObject> change) { - final DataModificationTransaction trans = startTransaction(); - - for (InstanceIdentifier key : change.getRemovedConfigurationData()) { - if (Meter.class.equals(key.getTargetType())) { - @SuppressWarnings("unchecked") - InstanceIdentifier meter = (InstanceIdentifier)key; - - InstanceIdentifier nodeMeterStatisticsAugmentation = - meter.augmentation(NodeMeterConfigStats.class); - trans.removeOperationalData(nodeMeterStatisticsAugmentation); - } - } - - trans.commit(); - } - - @Override - protected InstanceIdentifier listenPath() { - return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Meter.class).build(); - } - - @Override - protected String statName() { - return "Meter Config"; - } - - @Override - public void start(final DataBrokerService dbs) { - if (meterStatsService == null) { - logger.debug("No Meter Statistics service, not subscribing to meter on node {}", getNodeIdentifier()); - return; - } - - super.start(dbs); - } - - @Override - protected MeterConfigStats createInvariantKey(MeterConfigStats item) { - // No invariant data exist in the meter config stats. - return item; - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java deleted file mode 100644 index f43ec693cd..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java +++ /dev/null @@ -1,124 +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.md.statistics.manager; - -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStatsBuilder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class MeterStatsTracker extends AbstractListeningStatsTracker { - private static final Logger logger = LoggerFactory.getLogger(MeterStatsTracker.class); - private final OpendaylightMeterStatisticsService meterStatsService; - - MeterStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context) { - super(context); - this.meterStatsService = meterStatsService; - } - - @Override - protected void cleanupSingleStat(DataModificationTransaction trans, MeterStats item) { - InstanceIdentifier meterRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class) - .child(Meter.class,new MeterKey(item.getMeterId())) - .augmentation(NodeMeterStatistics.class).build(); - trans.removeOperationalData(meterRef); - } - - @Override - protected MeterStats updateSingleStat(DataModificationTransaction trans, MeterStats item) { - MeterBuilder meterBuilder = new MeterBuilder(); - MeterKey meterKey = new MeterKey(item.getMeterId()); - meterBuilder.setKey(meterKey); - - InstanceIdentifier meterRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class).child(Meter.class,meterKey).build(); - - NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder(); - meterStatsBuilder.setMeterStatistics(new MeterStatisticsBuilder(item).build()); - - //Update augmented data - meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build()); - trans.putOperationalData(meterRef, meterBuilder.build()); - return item; - } - - @Override - public void request() { - if (meterStatsService != null) { - GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder(); - input.setNode(getNodeRef()); - - requestHelper(meterStatsService.getAllMeterStatistics(input.build())); - } - } - - @Override - public void onDataChanged(DataChangeEvent, DataObject> change) { - for (InstanceIdentifier key : change.getCreatedConfigurationData().keySet()) { - if (Meter.class.equals(key.getTargetType())) { - request(); - } - } - - final DataModificationTransaction trans = startTransaction(); - for (InstanceIdentifier key : change.getRemovedConfigurationData()) { - if (Meter.class.equals(key.getTargetType())) { - @SuppressWarnings("unchecked") - InstanceIdentifier meter = (InstanceIdentifier)key; - - InstanceIdentifier nodeMeterStatisticsAugmentation = - meter.augmentation(NodeMeterStatistics.class); - trans.removeOperationalData(nodeMeterStatisticsAugmentation); - } - } - trans.commit(); - } - - @Override - protected InstanceIdentifier listenPath() { - return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Meter.class).build(); - } - - @Override - protected String statName() { - return "Meter"; - } - - @Override - public void start(final DataBrokerService dbs) { - if (meterStatsService == null) { - logger.debug("No Meter Statistics service, not subscribing to meters on node {}", getNodeIdentifier()); - return; - } - - super.start(dbs); - } - - @Override - protected MeterStats createInvariantKey(MeterStats item) { - MeterStatsBuilder meterStatsBuilder = new MeterStatsBuilder(); - meterStatsBuilder.setKey(item.getKey()); - meterStatsBuilder.setMeterId(item.getMeterId()); - return meterStatsBuilder.build(); - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java deleted file mode 100644 index 425a44946e..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java +++ /dev/null @@ -1,153 +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.md.statistics.manager; - -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.MultipartTransactionAware; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; - -import com.google.common.base.Preconditions; - -/** - * Main responsibility of the class is to manage multipart response - * for multipart request. It also handles the flow aggregate request - * and response mapping. - * @author avishnoi@in.ibm.com - * - */ -class MultipartMessageManager { - /* - * Map for tx id and type of request, to keep track of all the request sent - * by Statistics Manager. Statistics Manager won't entertain any multipart - * response for which it didn't send the request. - */ - private final Map txIdToRequestTypeMap = new ConcurrentHashMap<>(); - /* - * Map to keep track of the request tx id for flow table statistics request. - * Because flow table statistics multi part response do not contains the table id. - */ - private final Map txIdTotableIdMap = new ConcurrentHashMap<>(); - private final long lifetimeNanos; - - public MultipartMessageManager(long lifetimeNanos) { - this.lifetimeNanos = lifetimeNanos; - } - - private static final class TxIdEntry { - private final TransactionId txId; - - public TxIdEntry(TransactionId txId) { - this.txId = txId; - } - public TransactionId getTxId() { - return txId; - } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((txId == null) ? 0 : txId.hashCode()); - return result; - } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof TxIdEntry)) { - return false; - } - TxIdEntry other = (TxIdEntry) obj; - - if (txId == null) { - if (other.txId != null) { - return false; - } - } else if (!txId.equals(other.txId)) { - return false; - } - return true; - } - - @Override - public String toString() { - return "TxIdEntry [txId=" + txId + ']'; - } - } - - public void recordExpectedTableTransaction(TransactionId id, Short tableId) { - recordExpectedTransaction(id); - txIdTotableIdMap.put(new TxIdEntry(id), Preconditions.checkNotNull(tableId)); - } - - public Short isExpectedTableTransaction(TransactionAware transaction) { - Boolean more = null; - if (transaction instanceof MultipartTransactionAware) { - more = ((MultipartTransactionAware)transaction).isMoreReplies(); - } - - if (!isExpectedTransaction(transaction, more)) { - return null; - } - - final TxIdEntry key = new TxIdEntry(transaction.getTransactionId()); - if (more != null && more.booleanValue()) { - return txIdTotableIdMap.get(key); - } else { - return txIdTotableIdMap.remove(key); - } - } - - public void recordExpectedTransaction(TransactionId id) { - TxIdEntry entry = new TxIdEntry(Preconditions.checkNotNull(id)); - txIdToRequestTypeMap.put(entry, getExpiryTime()); - } - - private boolean isExpectedTransaction(TransactionAware transaction, Boolean more) { - final TxIdEntry entry = new TxIdEntry(transaction.getTransactionId()); - if (more != null && more.booleanValue()) { - return txIdToRequestTypeMap.containsKey(entry); - } else { - return txIdToRequestTypeMap.remove(entry) != null; - } - } - - public boolean isExpectedTransaction(TransactionAware transaction) { - Boolean more = null; - if (transaction instanceof MultipartTransactionAware) { - more = ((MultipartTransactionAware)transaction).isMoreReplies(); - } - - return isExpectedTransaction(transaction, more); - } - - private Long getExpiryTime() { - return System.nanoTime() + lifetimeNanos; - } - - public void cleanStaleTransactionIds() { - final long now = System.nanoTime(); - - for (Iterator it = txIdToRequestTypeMap.keySet().iterator();it.hasNext();){ - TxIdEntry txIdEntry = it.next(); - - Long expiryTime = txIdToRequestTypeMap.get(txIdEntry); - if(now > expiryTime){ - it.remove(); - txIdTotableIdMap.remove(txIdEntry); - } - } - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java deleted file mode 100644 index 2e2bf1cd51..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java +++ /dev/null @@ -1,95 +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.md.statistics.manager; - -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMapBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class NodeConnectorStatsTracker extends AbstractStatsTracker { - private static final Logger logger = LoggerFactory.getLogger(NodeConnectorStatsTracker.class); - private final OpendaylightPortStatisticsService portStatsService; - - NodeConnectorStatsTracker(final OpendaylightPortStatisticsService portStatsService, final FlowCapableContext context) { - super(context); - this.portStatsService = portStatsService; - } - - @Override - protected void cleanupSingleStat(final DataModificationTransaction trans, final NodeConnectorStatisticsAndPortNumberMap item) { - // TODO Auto-generated method stub - } - - @Override - protected NodeConnectorStatisticsAndPortNumberMap updateSingleStat(final DataModificationTransaction trans, final NodeConnectorStatisticsAndPortNumberMap item) { - FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder - = new FlowCapableNodeConnectorStatisticsBuilder(); - statisticsBuilder.setBytes(item.getBytes()); - statisticsBuilder.setCollisionCount(item.getCollisionCount()); - statisticsBuilder.setDuration(item.getDuration()); - statisticsBuilder.setPackets(item.getPackets()); - statisticsBuilder.setReceiveCrcError(item.getReceiveCrcError()); - statisticsBuilder.setReceiveDrops(item.getReceiveDrops()); - statisticsBuilder.setReceiveErrors(item.getReceiveErrors()); - statisticsBuilder.setReceiveFrameError(item.getReceiveFrameError()); - statisticsBuilder.setReceiveOverRunError(item.getReceiveOverRunError()); - statisticsBuilder.setTransmitDrops(item.getTransmitDrops()); - statisticsBuilder.setTransmitErrors(item.getTransmitErrors()); - - //Augment data to the node-connector - FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder = - new FlowCapableNodeConnectorStatisticsDataBuilder(); - - statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build()); - - final NodeConnectorKey key = new NodeConnectorKey(item.getNodeConnectorId()); - final InstanceIdentifier nodeConnectorRef = getNodeIdentifier().child(NodeConnector.class, key); - - // FIXME: can we bypass this read? - NodeConnector nodeConnector = (NodeConnector)trans.readOperationalData(nodeConnectorRef); - if(nodeConnector != null){ - final FlowCapableNodeConnectorStatisticsData stats = statisticsDataBuilder.build(); - logger.debug("Augmenting port statistics {} to port {}",stats,nodeConnectorRef.toString()); - NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder() - .setKey(key).setId(item.getNodeConnectorId()) - .addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats); - trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build()); - } - - return item; - } - - @Override - public void request() { - if (portStatsService != null) { - final GetAllNodeConnectorsStatisticsInputBuilder input = new GetAllNodeConnectorsStatisticsInputBuilder(); - input.setNode(getNodeRef()); - - requestHelper(portStatsService.getAllNodeConnectorsStatistics(input.build())); - } - } - - @Override - protected NodeConnectorStatisticsAndPortNumberMap createInvariantKey(NodeConnectorStatisticsAndPortNumberMap item) { - NodeConnectorStatisticsAndPortNumberMapBuilder ncStatsBuilder = new NodeConnectorStatisticsAndPortNumberMapBuilder(); - ncStatsBuilder.setNodeConnectorId(item.getNodeConnectorId()); - ncStatsBuilder.setKey(item.getKey()); - return ncStatsBuilder.build(); - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java deleted file mode 100644 index db216237d0..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java +++ /dev/null @@ -1,333 +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.md.statistics.manager; - -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.TimeUnit; - -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; - -/** - * This class handles the lifecycle of per-node statistics. It receives data - * from StatisticsListener, stores it in the data store and keeps track of - * when the data should be removed. - * - * @author avishnoi@in.ibm.com - */ -public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableContext { - private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsHandler.class); - - private static final long STATS_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(15); - private static final long FIRST_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(5); - private static final int NUMBER_OF_WAIT_CYCLES = 2; - - private final MultipartMessageManager msgManager; - private final StatisticsRequestScheduler srScheduler; - private final InstanceIdentifier targetNodeIdentifier; - private final FlowStatsTracker flowStats; - private final FlowTableStatsTracker flowTableStats; - private final GroupDescStatsTracker groupDescStats; - private final GroupStatsTracker groupStats; - private final MeterConfigStatsTracker meterConfigStats; - private final MeterStatsTracker meterStats; - private final NodeConnectorStatsTracker nodeConnectorStats; - private final QueueStatsTracker queueStats; - private final DataProviderService dps; - private final NodeRef targetNodeRef; - private final NodeKey targetNodeKey; - private final TimerTask task = new TimerTask() { - @Override - public void run() { - try{ - requestPeriodicStatistics(); - cleanStaleStatistics(); - }catch(Exception e){ - logger.warn("Exception occured while sending statistics request : {}",e); - } - } - }; - - public NodeStatisticsHandler(final DataProviderService dps, final NodeKey nodeKey, - final OpendaylightFlowStatisticsService flowStatsService, - final OpendaylightFlowTableStatisticsService flowTableStatsService, - final OpendaylightGroupStatisticsService groupStatsService, - final OpendaylightMeterStatisticsService meterStatsService, - final OpendaylightPortStatisticsService portStatsService, - final OpendaylightQueueStatisticsService queueStatsService, - final StatisticsRequestScheduler srScheduler) { - this.dps = Preconditions.checkNotNull(dps); - this.targetNodeKey = Preconditions.checkNotNull(nodeKey); - this.srScheduler = Preconditions.checkNotNull(srScheduler); - this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build(); - this.targetNodeRef = new NodeRef(targetNodeIdentifier); - - final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES); - - msgManager = new MultipartMessageManager(lifetimeNanos); - flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this); - flowStats = new FlowStatsTracker(flowStatsService, this, flowTableStats); - groupDescStats = new GroupDescStatsTracker(groupStatsService, this); - groupStats = new GroupStatsTracker(groupStatsService, this); - meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this); - meterStats = new MeterStatsTracker(meterStatsService, this); - nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this); - queueStats = new QueueStatsTracker(queueStatsService, this); - } - - public NodeKey getTargetNodeKey() { - return targetNodeKey; - } - - @Override - public InstanceIdentifier getNodeIdentifier() { - return targetNodeIdentifier; - } - - @Override - public NodeRef getNodeRef() { - return targetNodeRef; - } - - @Override - public DataModificationTransaction startDataModification() { - DataModificationTransaction dmt = dps.beginTransaction(); - dmt.registerListener(this.srScheduler); - return dmt; - } - - public synchronized void updateGroupDescStats(TransactionAware transaction, List list) { - if (msgManager.isExpectedTransaction(transaction)) { - groupDescStats.updateStats(list); - } - } - - public synchronized void updateGroupStats(TransactionAware transaction, List list) { - if (msgManager.isExpectedTransaction(transaction)) { - groupStats.updateStats(list); - } - } - - public synchronized void updateMeterConfigStats(TransactionAware transaction, List list) { - if (msgManager.isExpectedTransaction(transaction)) { - meterConfigStats.updateStats(list); - } - } - - public synchronized void updateMeterStats(TransactionAware transaction, List list) { - if (msgManager.isExpectedTransaction(transaction)) { - meterStats.updateStats(list); - } - } - - public synchronized void updateQueueStats(TransactionAware transaction, List list) { - if (msgManager.isExpectedTransaction(transaction)) { - queueStats.updateStats(list); - } - } - - public synchronized void updateFlowTableStats(TransactionAware transaction, List list) { - if (msgManager.isExpectedTransaction(transaction)) { - flowTableStats.updateStats(list); - } - } - - public synchronized void updateNodeConnectorStats(TransactionAware transaction, List list) { - if (msgManager.isExpectedTransaction(transaction)) { - nodeConnectorStats.updateStats(list); - } - } - - public synchronized void updateAggregateFlowStats(TransactionAware transaction, AggregateFlowStatistics flowStats) { - final Short tableId = msgManager.isExpectedTableTransaction(transaction); - if (tableId != null) { - final DataModificationTransaction trans = this.startDataModification(); - InstanceIdentifier
    tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) - .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); - - AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder(); - AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats); - - aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build()); - - logger.debug("Augment aggregate statistics: {} for table {} on Node {}", - aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey); - - TableBuilder tableBuilder = new TableBuilder(); - tableBuilder.setKey(new TableKey(tableId)); - tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build()); - trans.putOperationalData(tableRef, tableBuilder.build()); - - trans.commit(); - } - } - - public synchronized void updateFlowStats(TransactionAware transaction, List list) { - if (msgManager.isExpectedTransaction(transaction)) { - flowStats.updateStats(list); - } - } - - public synchronized void updateGroupFeatures(GroupFeatures notification) { - final DataModificationTransaction trans = this.startDataModification(); - - final NodeBuilder nodeData = new NodeBuilder(); - nodeData.setKey(targetNodeKey); - - NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder(); - GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification); - nodeGroupFeatures.setGroupFeatures(groupFeatures.build()); - - //Update augmented data - nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build()); - trans.putOperationalData(targetNodeIdentifier, nodeData.build()); - - // FIXME: should we be tracking this data? - trans.commit(); - } - - public synchronized void updateMeterFeatures(MeterFeatures features) { - final DataModificationTransaction trans = this.startDataModification(); - - final NodeBuilder nodeData = new NodeBuilder(); - nodeData.setKey(targetNodeKey); - - NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder(); - MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features); - nodeMeterFeatures.setMeterFeatures(meterFeature.build()); - - //Update augmented data - nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build()); - trans.putOperationalData(targetNodeIdentifier, nodeData.build()); - - // FIXME: should we be tracking this data? - trans.commit(); - } - - public synchronized void cleanStaleStatistics() { - final DataModificationTransaction trans = this.startDataModification(); - - flowStats.cleanup(trans); - groupDescStats.cleanup(trans); - groupStats.cleanup(trans); - meterConfigStats.cleanup(trans); - meterStats.cleanup(trans); - nodeConnectorStats.cleanup(trans); - queueStats.cleanup(trans); - msgManager.cleanStaleTransactionIds(); - - trans.commit(); - } - - public synchronized void requestPeriodicStatistics() { - logger.debug("Send requests for statistics collection to node : {}", targetNodeKey); - - this.srScheduler.addRequestToSchedulerQueue(flowTableStats); - - this.srScheduler.addRequestToSchedulerQueue(flowStats); - - this.srScheduler.addRequestToSchedulerQueue(nodeConnectorStats); - - this.srScheduler.addRequestToSchedulerQueue(groupStats); - - this.srScheduler.addRequestToSchedulerQueue(groupDescStats); - - this.srScheduler.addRequestToSchedulerQueue(meterStats); - - this.srScheduler.addRequestToSchedulerQueue(meterConfigStats); - - this.srScheduler.addRequestToSchedulerQueue(queueStats); - } - - public synchronized void start(final Timer timer) { - flowStats.start(dps); - groupDescStats.start(dps); - groupStats.start(dps); - meterConfigStats.start(dps); - meterStats.start(dps); - queueStats.start(dps); - - timer.schedule(task, (long) (Math.random() * FIRST_COLLECTION_MILLIS), STATS_COLLECTION_MILLIS); - - logger.debug("Statistics handler for node started with base interval {}ms", STATS_COLLECTION_MILLIS); - - requestPeriodicStatistics(); - } - - @Override - public synchronized void close() { - task.cancel(); - flowStats.close(); - groupDescStats.close(); - groupStats.close(); - meterConfigStats.close(); - meterStats.close(); - queueStats.close(); - - //Clean up queued statistics request from scheduler queue - srScheduler.removeRequestsFromSchedulerQueue(this.getNodeRef()); - - logger.debug("Statistics handler for {} shut down", targetNodeKey.getId()); - } - - @Override - public void registerTransaction(TransactionId id) { - msgManager.recordExpectedTransaction(id); - logger.debug("Transaction {} for node {} sent successfully", id, targetNodeKey); - } - - @Override - public void registerTableTransaction(final TransactionId id, final Short table) { - msgManager.recordExpectedTableTransaction(id, table); - logger.debug("Transaction {} for node {} table {} sent successfully", id, targetNodeKey, table); - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java deleted file mode 100644 index d1f2529de8..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java +++ /dev/null @@ -1,62 +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.md.statistics.manager; - -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; - -final class QueueStatsEntry { - private final NodeConnectorId nodeConnectorId; - private final QueueId queueId; - public QueueStatsEntry(NodeConnectorId ncId, QueueId queueId){ - this.nodeConnectorId = ncId; - this.queueId = queueId; - } - public NodeConnectorId getNodeConnectorId() { - return nodeConnectorId; - } - public QueueId getQueueId() { - return queueId; - } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode()); - result = prime * result + ((queueId == null) ? 0 : queueId.hashCode()); - return result; - } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof QueueStatsEntry)) { - return false; - } - QueueStatsEntry other = (QueueStatsEntry) obj; - if (nodeConnectorId == null) { - if (other.nodeConnectorId != null) { - return false; - } - } else if (!nodeConnectorId.equals(other.nodeConnectorId)) { - return false; - } - if (queueId == null) { - if (other.queueId != null) { - return false; - } - } else if (!queueId.equals(other.queueId)) { - return false; - } - return true; - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java deleted file mode 100644 index 4a589703be..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java +++ /dev/null @@ -1,161 +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.md.statistics.manager; - -import java.util.Map.Entry; - -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class QueueStatsTracker extends AbstractListeningStatsTracker { - private static final Logger logger = LoggerFactory.getLogger(QueueStatsTracker.class); - private final OpendaylightQueueStatisticsService queueStatsService; - - QueueStatsTracker(OpendaylightQueueStatisticsService queueStatsService, final FlowCapableContext context) { - super(context); - this.queueStatsService = queueStatsService; - } - - @Override - protected void cleanupSingleStat(DataModificationTransaction trans, QueueStatsEntry item) { - InstanceIdentifier queueRef - = getNodeIdentifierBuilder().child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId())) - .augmentation(FlowCapableNodeConnector.class) - .child(Queue.class, new QueueKey(item.getQueueId())) - .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).build(); - trans.removeOperationalData(queueRef); - } - - @Override - protected QueueStatsEntry updateSingleStat(DataModificationTransaction trans, QueueIdAndStatisticsMap item) { - - QueueStatsEntry queueEntry = new QueueStatsEntry(item.getNodeConnectorId(), item.getQueueId()); - - FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder(); - - FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder(); - - queueStatisticsBuilder.fieldsFrom(item); - - queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build()); - - InstanceIdentifier queueRef = getNodeIdentifierBuilder().child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId())) - .augmentation(FlowCapableNodeConnector.class) - .child(Queue.class, new QueueKey(item.getQueueId())).toInstance(); - - QueueBuilder queueBuilder = new QueueBuilder(); - FlowCapableNodeConnectorQueueStatisticsData qsd = queueStatisticsDataBuilder.build(); - queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, qsd); - queueBuilder.setKey(new QueueKey(item.getQueueId())); - - logger.debug("Augmenting queue statistics {} of queue {} to port {}", - qsd, - item.getQueueId(), - item.getNodeConnectorId()); - - trans.putOperationalData(queueRef, queueBuilder.build()); - return queueEntry; - } - - @Override - public void request() { - if (queueStatsService != null) { - GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder(); - input.setNode(getNodeRef()); - - requestHelper(queueStatsService.getAllQueuesStatisticsFromAllPorts(input.build())); - } - } - - public void request(NodeConnectorId nodeConnectorId, QueueId queueId) { - if (queueStatsService != null) { - GetQueueStatisticsFromGivenPortInputBuilder input = new GetQueueStatisticsFromGivenPortInputBuilder(); - - input.setNode(getNodeRef()); - input.setNodeConnectorId(nodeConnectorId); - input.setQueueId(queueId); - - requestHelper(queueStatsService.getQueueStatisticsFromGivenPort(input.build())); - } - } - - @Override - public void onDataChanged(DataChangeEvent, DataObject> change) { - for (Entry, DataObject> e : change.getCreatedConfigurationData().entrySet()) { - if (Queue.class.equals(e.getKey().getTargetType())) { - final Queue queue = (Queue) e.getValue(); - final NodeConnectorKey key = e.getKey().firstKeyOf(NodeConnector.class, NodeConnectorKey.class); - logger.debug("Key {} triggered request for connector {} queue {}", key.getId(), queue.getQueueId()); - request(key.getId(), queue.getQueueId()); - } else { - logger.debug("Ignoring key {}", e.getKey()); - } - } - - final DataModificationTransaction trans = startTransaction(); - for (InstanceIdentifier key : change.getRemovedConfigurationData()) { - if (Queue.class.equals(key.getTargetType())) { - @SuppressWarnings("unchecked") - final InstanceIdentifier queue = (InstanceIdentifier)key; - final InstanceIdentifier del = queue - .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class); - logger.debug("Key {} triggered remove of augmentation {}", key, del); - - trans.removeOperationalData(del); - } - } - trans.commit(); - } - - @Override - protected InstanceIdentifier listenPath() { - return getNodeIdentifierBuilder().child(NodeConnector.class) - .augmentation(FlowCapableNodeConnector.class).child(Queue.class).build(); - } - - @Override - protected String statName() { - return "Queue"; - } - - @Override - public void start(final DataBrokerService dbs) { - if (queueStatsService == null) { - logger.debug("No Queue Statistics service, not subscribing to queues on node {}", getNodeIdentifier()); - return; - } - - super.start(dbs); - } - - @Override - protected QueueStatsEntry createInvariantKey(QueueStatsEntry item) { - // No invariant data exist in the group description stats. - return item; - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatListeningCommiter.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatListeningCommiter.java new file mode 100644 index 0000000000..be3d40246b --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatListeningCommiter.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager; + +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.NotificationListener; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager + * + * StatListeningCommiter + * Definition Interface for {@link DataChangeListener} implementer class rule. + * Interface represent a contract between Config/DataStore changes and + * Operational/DataStore commits. All Operational/DataStore commit have + * to by represent as RPC Device response Notification processing. So + * Operational/DS could contains only real mirror of OF Device + * + * @author Vaclav Demcak + * + * Created: Aug 27, 2014 + */ +public interface StatListeningCommiter extends DataChangeListener, StatNotifyCommiter { + + + /** + * All StatListeningCommiter implementer has to clean its actual state + * for all cached data related to disconnected node. + * Method prevents unwanted dataStore changes. + * + * @param nodeIdent + */ + void cleanForDisconnect(InstanceIdentifier nodeIdent); +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatNodeRegistration.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatNodeRegistration.java new file mode 100644 index 0000000000..80a15a3230 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatNodeRegistration.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SwitchFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager.impl + * + * StatNodeRegistration + * Class represents {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode} + * {@link org.opendaylight.controller.md.sal.binding.api.DataChangeListener} in Operational/DataStore for ADD / REMOVE + * actions which are represented connect / disconnect OF actions. Connect functionality are expecting + * + * @author Vaclav Demcak + * + * Created: Sep 5, 2014 + */ +public interface StatNodeRegistration extends OpendaylightInventoryListener, AutoCloseable { + + /** + * Method contains {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode} registration to {@link StatisticsManager} + * for permanently collecting statistics by {@link StatPermCollector} and + * as a prevention to use a validation check to the Operational/DS for identify + * connected {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode}. + * + * @param InstanceIdentifier keyIdent + * @param FlowCapableNode data + * @param InstanceIdentifier nodeIdent + */ + void connectFlowCapableNode(InstanceIdentifier keyIdent, + SwitchFeatures data, InstanceIdentifier nodeIdent); + + /** + * Method cut {@link Node} registration for {@link StatPermCollector} + * + * @param InstanceIdentifier keyIdent + */ + void disconnectFlowCapableNode(InstanceIdentifier keyIdent); +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatNotifyCommiter.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatNotifyCommiter.java new file mode 100644 index 0000000000..0392e47817 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatNotifyCommiter.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager; + +import org.opendaylight.yangtools.yang.binding.NotificationListener; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager + * + * StatNotifyCommiter + * Definition Interface for notification implementer class rule + * Interface represent a contract between RPC Device Notification + * and Operational/DataStore commits. + * + * + * @author Vaclav Demcak + * + * Created: Aug 28, 2014 + */ +public interface StatNotifyCommiter extends AutoCloseable, NotificationListener { + + +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatPermCollector.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatPermCollector.java new file mode 100644 index 0000000000..9116e66737 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatPermCollector.java @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager; + +import java.util.List; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager + * + * StatPermCollector + * Class implement {@link Runnable} and inside is running statistic collecting + * process DataObject statistics by DataObject statistics for every {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode}. + * Every statistics wait to finish previous statistics. Only if all statistics finish, + * next {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode} + * Statistics should be collecting. We are able to set minimal time for start next round cross all Network, + * but all depends on network possibility. + * + * @author Vaclav Demcak + * + * Created: Aug 28, 2014 + */ +public interface StatPermCollector extends Runnable, AutoCloseable { + + /** + * StatCapType + * Enum class refers ofp_statistics capabilities fields from OF Switch + * capabilities specification which have to come as a post HandShake + * information from OF Switch and Inventory Manager adds all to the + * Operational/DS. + * If the capabilities are not add (for any reason) NodeRegistrator + * adds all StatCapTypes for the {@link Node}. + */ + public enum StatCapabTypes { + /** + * OFPC_FLOW_STATS + */ + FLOW_STATS, + /** + * OFPC_TABLE_STATS + */ + TABLE_STATS, + /** + * OFPC_PORT_STATS + */ + PORT_STATS, + /** + * OFPC_GROUP_STATS + */ + GROUP_STATS, + /** + * OFPC_QUEUE_STATS + */ + QUEUE_STATS, + /** + * Meter statistics has no support from OF Switch capabilities + * so we have to try get statistics for it and wait for response + * Error or response package with results. + */ + METER_STATS + } + + /** + * Add new connected node for permanent statistics collecting process + * + * @param flowNode + * @param statTypes + * @param nrOfSwitchTables + * @return true/false if the {@link Node} added successful + */ + boolean connectedNodeRegistration(InstanceIdentifier nodeIdent, + List statTypes, Short nrOfSwitchTables); + + /** + * All disconnected Nodes need be removed from stat list Nodes + * @param flowNode + * @return true/false if the {@link Node} removed successful + */ + boolean disconnectedNodeUnregistration(InstanceIdentifier nodeIdent); + + /** + * Method return true only and only if {@link StatPermCollector} contain + * valid node registration in its internal {@link Node} map. + * Otherwise return false. + * + * @param InstanceIdentifier flowNode + * @return + */ + boolean isProvidedFlowNodeActive(InstanceIdentifier nodeIdent); + + /** + * Object notification for continue statistics collecting process. + * It is call from collecting allStatistics methods as a future result for + * Operational/DS statistic store call (does not matter in the outcome). + */ + void collectNextStatistics(); + + /** + * Method returns true if collector has registered some active nodes + * otherwise return false. + * + * @return + */ + boolean hasActiveNodes(); +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatRpcMsgManager.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatRpcMsgManager.java new file mode 100644 index 0000000000..0576c2a645 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatRpcMsgManager.java @@ -0,0 +1,191 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager; + +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.common.RpcResult; + +import com.google.common.base.Optional; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager + * + * StatRpcMsgManager + * It represent access point for Device statistics RPC services which are + * filtered for needed methods only and they are wrapped in simply way. + * Many statistics responses are Multipart messages, so StatRpcMsgManager + * provide a functionality to add all multipart msg and provides back whole + * stack to listener when listener catch the last Multipart msg. + * + * @author Vaclav Demcak + * + * Created: Aug 29, 2014 + */ +public interface StatRpcMsgManager extends Runnable, AutoCloseable { + + interface RpcJobsQueue extends Callable {} + + /** + * Transaction container is definition for Multipart transaction + * join container for all Multipart msg with same TransactionId + * Input {@link DataObject} is a possible light-weight DataObject + * which is used for identification (e.g. Flow-> Priority,Match,Cookie,FlowId) + * + * @param extends TransactionAware - + */ + interface TransactionCacheContainer { + + void addNotif(T notification); + + TransactionId getId(); + + NodeId getNodeId(); + + Optional getConfInput(); + + List getNotifications(); + } + + /** + * Method is used for check a transaction registration + * for multipart cache holder + * + * @param TransactionId id + * @return true if the transaction has been correctly registered + */ + Future isExpectedStatistics(TransactionId id, NodeId nodeId); + + /** + * Method converts {@link java.util.concurrent.Future} object to listenenable future which + * is registered for Multipart Notification Statistics Collecting processing. + * + * @param future - result every Device RPC call + */ + void registrationRpcFutureCallBack(Future> future, D inputObj, NodeRef ref); + + /** + * Method adds Notification which is marked as Multipart to the transaction cash + * to wait for the last one. + * + * @param notification + */ + void addNotification(T notification, NodeId nodeId); + + /** + * The last Multipart should inform code about possibility to take all previous + * messages for next processing. The method take all msg and possible input object + * and build all to TransactionCacheContainer Object to return. This process clean + * all instances in Cache. + * + * @param TransactionId id + * @return TransactionCacheContainer + */ + Future>> getTransactionCacheContainer(TransactionId id, NodeId nodeId); + + /** + * Method wraps OpendaylightGroupStatisticsService.getAllGroupStatistics + * and registers to Transaction Cache + * + * @param NodeRef nodeRef + */ + void getAllGroupsStat(NodeRef nodeRef); + + /** + * Method wraps OpendaylightGroupStatisticsService.getGroupDescription + * and registers to Transaction Cache + * + * @param NodeRef nodeRef + */ + void getAllGroupsConfStats(NodeRef nodeRef); + + /** + * Method wraps OpendaylightMeterStatisticsService.getGroupFeatures + * and registers to Transaction Cache + * + * @param NodeRef nodeRef + */ + void getGroupFeaturesStat(NodeRef nodeRef); + + /** + * Method wraps OpendaylightMeterStatisticsService.getAllMeterStatistics + * and registers to Transaction Cache + * + * @param NodeRef nodeRef + */ + void getAllMetersStat(NodeRef nodeRef); + + /** + * Method wraps OpendaylightMeterStatisticsService.getAllMeterConfigStatistics + * and registers to Transaction Cache + * + * @param NodeRef nodeRef + */ + void getAllMeterConfigStat(NodeRef nodeRef); + + /** + * Method wraps OpendaylightMeterStatisticsService.getMeterFeatures + * and registers to Transaction Cache + * + * @param NodeRef nodeRef + */ + void getMeterFeaturesStat(NodeRef nodeRef); + + /** + * Method wraps OpendaylightFlowStatisticsService.getAllFlowsStatisticsFromAllFlowTables + * and registers to Transaction Cache + * + * @param NodeRef nodeRef + */ + void getAllFlowsStat(NodeRef nodeRef); + + /** + * Method wraps OpendaylightFlowStatisticsService.getAggregateFlowStatisticsFromFlowTableForAllFlows + * and registers to Transaction Cache + * + * @param NodeRef nodeRef + * @param TableId tableId + */ + void getAggregateFlowStat(NodeRef nodeRef, TableId tableId); + + /** + * Method wraps OpendaylightPortStatisticsService.getAllNodeConnectorsStatistics + * and registers to Transaction Cache + * + * @param NodeRef nodeRef + */ + void getAllPortsStat(NodeRef nodeRef); + + /** + * Method wraps OpendaylightFlowTableStatisticsService.getFlowTablesStatistics + * and registers to Transaction Cache + * + * @param NodeRef nodeRef + */ + void getAllTablesStat(NodeRef nodeRef); + + /** + * Method wraps OpendaylightQueueStatisticsService.getAllQueuesStatisticsFromAllPorts + * and registers to Transaction Cache + * + * @param NodeRef nodeRef + */ + void getAllQueueStat(NodeRef nodeRef); + +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java deleted file mode 100644 index a06f7efdbb..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java +++ /dev/null @@ -1,144 +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.md.statistics.manager; - -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterConfigStatsUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class is responsible for listening for statistics update notifications and - * routing them to the appropriate NodeStatisticsHandler. - - * TODO: Need to add error message listener and clean-up the associated tx id - * if it exists in the tx-id cache. - * @author vishnoianil - */ -public class StatisticsListener implements OpendaylightGroupStatisticsListener, - OpendaylightMeterStatisticsListener, - OpendaylightFlowStatisticsListener, - OpendaylightPortStatisticsListener, - OpendaylightFlowTableStatisticsListener, - OpendaylightQueueStatisticsListener{ - - private final static Logger sucLogger = LoggerFactory.getLogger(StatisticsListener.class); - private final StatisticsProvider statisticsManager; - - /** - * default ctor - * @param manager - */ - public StatisticsListener(final StatisticsProvider manager){ - this.statisticsManager = manager; - } - - @Override - public void onMeterConfigStatsUpdated(final MeterConfigStatsUpdated notification) { - final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); - if (handler != null) { - handler.updateMeterConfigStats(notification, notification.getMeterConfigStats()); - } - } - - @Override - public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) { - final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); - if (handler != null) { - handler.updateMeterStats(notification, notification.getMeterStats()); - } - } - - @Override - public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) { - final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId()); - if (handler != null) { - handler.updateGroupDescStats(notification, notification.getGroupDescStats()); - } - } - - @Override - public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) { - final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId()); - if (handler != null) { - handler.updateGroupStats(notification, notification.getGroupStats()); - } - } - - @Override - public void onMeterFeaturesUpdated(MeterFeaturesUpdated notification) { - final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId()); - if (sna != null) { - sna.updateMeterFeatures(notification); - } - } - - @Override - public void onGroupFeaturesUpdated(GroupFeaturesUpdated notification) { - final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId()); - if (sna != null) { - sna.updateGroupFeatures(notification); - } - } - - @Override - public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) { - sucLogger.debug("Received flow stats update : {}",notification.toString()); - final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId()); - if (sna != null) { - sna.updateFlowStats(notification, notification.getFlowAndStatisticsMapList()); - } - } - - @Override - public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) { - final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); - if (handler != null) { - handler.updateAggregateFlowStats(notification, notification); - } - } - - @Override - public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) { - final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); - if (handler != null) { - handler.updateNodeConnectorStats(notification, notification.getNodeConnectorStatisticsAndPortNumberMap()); - } - } - - @Override - public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) { - final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); - if (handler != null) { - handler.updateFlowTableStats(notification, notification.getFlowTableAndStatisticsMap()); - } - } - - @Override - public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) { - final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); - if (handler != null) { - handler.updateQueueStats(notification, notification.getQueueIdAndStatisticsMap()); - } - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManager.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManager.java new file mode 100644 index 0000000000..b53c54e360 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManager.java @@ -0,0 +1,179 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager; + +import java.util.List; + +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.statistics.manager.StatPermCollector.StatCapabTypes; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager + * + * StatisticsManager + * It represent a central point for whole module. Implementation + * StatisticsManager registers all Operation/DS {@link StatNotifyCommiter} and + * Config/DS {@StatListeningCommiter}, as well as {@link StatPermCollector} + * for statistic collecting and {@link StatRpcMsgManager} as Device RPCs provider. + * In next, StatisticsManager provides all DS contact Transaction services. + * + * @author Vaclav Demcak + * + * Created: Aug 27, 2014 + */ +public interface StatisticsManager extends AutoCloseable, TransactionChainListener { + + /** + * StatDataStoreOperation + * Interface represent functionality to submit changes to DataStore. + * Internal {@link TransactionChainListener} joining all DS commits + * to Set of chained changes for prevent often DataStore touches. + */ + public interface StatDataStoreOperation { + + /** + * Apply all read / write (put|merge) operation + * for DataStore + * @param {@link ReadWriteTransaction} tx + */ + void applyOperation(ReadWriteTransaction tx); + + } + + /** + * Method starts whole StatisticManager functionality + * + * @param {@link NotificationProviderService} notifService + * @param {@link RpcConsumerRegistry} rpcRegistry + * @param minReqNetMonitInt + */ + void start(final NotificationProviderService notifService, + final RpcConsumerRegistry rpcRegistry, final long minReqNetMonitInt); + + /** + * Method provides read/write DataStore functionality cross applyOperation + * defined in {@link StatDataStoreOperation} + * + * @param inventoryOper - operation for DataStore + */ + void enqueue(final StatDataStoreOperation inventoryOper); + + /** + * Method wraps {@link StatisticCollector}.isProvidedFlowNodeActive method + * to provide parallel statCollection process for Set of Nodes. So it has to + * identify correct Node Set by NodeIdentifier + * + * @param nodeIdent + */ + boolean isProvidedFlowNodeActive(InstanceIdentifier nodeIdent); + + /** + * Method wraps {@link StatPermCollector}.collectNextStatistics to provide + * parallel statCollection process for Set of Nodes. So it has to + * identify correct Node Set by NodeIdentifier. + * + * @param nodeIdent + */ + void collectNextStatistics(InstanceIdentifier nodeIdent); + + /** + * Method wraps {@link StatPermCollector}.connectedNodeRegistration to provide + * parallel statCollection process for Set of Nodes. So it has to + * connect node to new or not full Node statCollector Set. + * + * @param nodeIdent + * @param statTypes + * @param nrOfSwitchTables + */ + void connectedNodeRegistration(InstanceIdentifier nodeIdent, + List statTypes, Short nrOfSwitchTables); + + /** + * Method wraps {@link StatPermCollector}.disconnectedNodeUnregistration to provide + * parallel statCollection process for Set of Nodes. So it has to identify + * correct collector for disconnect node. + * + * @param nodeIdent + */ + void disconnectedNodeUnregistration(InstanceIdentifier nodeIdent); + + /** + * Method provides access to Device RPC methods by wrapped + * internal method. In next {@link StatRpcMsgManager} is registered all + * Multipart device msg response and joining all to be able run all + * collected statistics in one time (easy identification Data for delete) + * + * @return {@link StatRpcMsgManager} + */ + StatRpcMsgManager getRpcMsgManager(); + + /** + * Define Method : {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode} + * Operational/DS data change listener -> impl. target -> register FlowCapableNode to Statistic Collecting process + * @return {@link StatNodeRegistration} + */ + StatNodeRegistration getNodeRegistrator(); + + /** + * Define Method : Flow Config/DS data change listener -> impl. target -> + * -> make pair between Config/DS FlowId and Device Flow response Hash + * @return + */ + StatListeningCommiter getFlowListenComit(); + + /** + * Define Method : Meter Config/DS data change listener and Operation/DS notify commit + * functionality + * @return + */ + StatListeningCommiter getMeterListenCommit(); + + /** + * Define Method : Group Config/DS data change listener and Operation/DS notify commit + * functionality + * @return + */ + StatListeningCommiter getGroupListenCommit(); + + /** + * Define Method : Queue Config/DS change listener and Operation/DS notify commit functionality + * @return + */ + StatListeningCommiter getQueueNotifyCommit(); + + /** + * Define Method : Table Operation/DS notify commit functionality + * @return + */ + StatNotifyCommiter getTableNotifCommit(); + + /** + * Define Method : Port Operation/DS notify commit functionality + * @return + */ + StatNotifyCommiter getPortNotifyCommit(); + +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java index 5bcbef119a..c505af49e6 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java @@ -8,29 +8,66 @@ package org.opendaylight.controller.md.statistics.manager; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.statistics.manager.impl.StatisticsManagerImpl; import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.osgi.framework.BundleContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.common.annotations.VisibleForTesting; + +/** + * Statistics Manager Activator + * + * OSGi bundle activator + * + */ public class StatisticsManagerActivator extends AbstractBindingAwareProvider { - private StatisticsProvider statsProvider; + + private final static Logger LOG = LoggerFactory.getLogger(StatisticsManagerActivator.class); + + /* TODO move it to ConfigSubsystem */ + private static final long DEFAULT_MIN_REQUEST_NET_MONITOR_INTERVAL = 3000L; + private static final int MAX_NODES_FOR_COLLECTOR = 16; + + private StatisticsManager statsProvider; @Override - public void onSessionInitiated(ProviderContext session) { - final DataProviderService dps = session.getSALService(DataProviderService.class); - final NotificationProviderService nps = session.getSALService(NotificationProviderService.class); + public void onSessionInitiated(final ProviderContext session) { + LOG.info("StatisticsManagerActivator initialization."); + try { + final DataBroker dataBroker = session.getSALService(DataBroker.class); + final NotificationProviderService notifService = + session.getSALService(NotificationProviderService.class); + statsProvider = new StatisticsManagerImpl(dataBroker, MAX_NODES_FOR_COLLECTOR); + statsProvider.start(notifService, session, DEFAULT_MIN_REQUEST_NET_MONITOR_INTERVAL); + LOG.info("StatisticsManagerActivator started successfully."); + } + catch (final Exception e) { + LOG.error("Unexpected error by initialization of StatisticsManagerActivator", e); + stopImpl(null); + } + } - statsProvider = new StatisticsProvider(dps); - statsProvider.start(nps, session); + @VisibleForTesting + StatisticsManager getStatisticManager() { + return statsProvider; } @Override - protected void stopImpl(BundleContext context) { + protected void stopImpl(final BundleContext context) { if (statsProvider != null) { - statsProvider.close(); + try { + statsProvider.close(); + } + catch (final Exception e) { + LOG.error("Unexpected error by stopping StatisticsManagerActivator", e); + } statsProvider = null; } + LOG.info("StatisticsManagerActivator stoped."); } } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java deleted file mode 100644 index 8c9b60e43f..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java +++ /dev/null @@ -1,172 +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.md.statistics.manager; - -import java.util.Collection; -import java.util.Timer; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.NotificationListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; - -/** - * Following are main responsibilities of the class: - * 1) Invoke statistics request thread to send periodic statistics request to all the - * flow capable switch connected to the controller. It sends statistics request for - * Group,Meter,Table,Flow,Queue,Aggregate stats. - * - * 2) Invoke statistics ager thread, to clean up all the stale statistics data from - * operational data store. - * - * @author avishnoi@in.ibm.com - * - */ -public class StatisticsProvider implements AutoCloseable { - private static final Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class); - - private final ConcurrentMap handlers = new ConcurrentHashMap<>(); - private final Timer timer = new Timer("statistics-manager", true); - private final DataProviderService dps; - - private OpendaylightGroupStatisticsService groupStatsService; - - private OpendaylightMeterStatisticsService meterStatsService; - - private OpendaylightFlowStatisticsService flowStatsService; - - private OpendaylightPortStatisticsService portStatsService; - - private OpendaylightFlowTableStatisticsService flowTableStatsService; - - private OpendaylightQueueStatisticsService queueStatsService; - - private final StatisticsRequestScheduler srScheduler; - - public StatisticsProvider(final DataProviderService dataService) { - this.dps = Preconditions.checkNotNull(dataService); - this.srScheduler = new StatisticsRequestScheduler(); - } - - private final StatisticsListener updateCommiter = new StatisticsListener(StatisticsProvider.this); - - private ListenerRegistration listenerRegistration; - - private ListenerRegistration flowCapableTrackerRegistration; - - public void start(final NotificationProviderService nps, final RpcConsumerRegistry rpcRegistry) { - - // Get Group/Meter statistics service instances - groupStatsService = rpcRegistry.getRpcService(OpendaylightGroupStatisticsService.class); - meterStatsService = rpcRegistry.getRpcService(OpendaylightMeterStatisticsService.class); - flowStatsService = rpcRegistry.getRpcService(OpendaylightFlowStatisticsService.class); - portStatsService = rpcRegistry.getRpcService(OpendaylightPortStatisticsService.class); - flowTableStatsService = rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class); - queueStatsService = rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class); - this.srScheduler.start(); - - // Start receiving notifications - this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter); - - // Register for switch connect/disconnect notifications - final InstanceIdentifier fcnId = InstanceIdentifier.builder(Nodes.class) - .child(Node.class).augmentation(FlowCapableNode.class).build(); - spLogger.debug("Registering FlowCapable tracker to {}", fcnId); - this.flowCapableTrackerRegistration = dps.registerDataChangeListener(fcnId, - new FlowCapableTracker(this, fcnId)); - - spLogger.info("Statistics Provider started."); - } - - /** - * Get the handler for a particular node. - * - * @param nodeId source node - * @return Node statistics handler for that node. Null if the statistics should - * not handled. - */ - public final NodeStatisticsHandler getStatisticsHandler(final NodeId nodeId) { - Preconditions.checkNotNull(nodeId); - NodeStatisticsHandler handler = handlers.get(nodeId); - if (handler == null) { - spLogger.info("Attempted to get non-existing handler for {}", nodeId); - } - return handler; - } - - @Override - public void close() { - try { - if (this.listenerRegistration != null) { - this.listenerRegistration.close(); - this.listenerRegistration = null; - } - if (this.flowCapableTrackerRegistration != null) { - this.flowCapableTrackerRegistration.close(); - this.flowCapableTrackerRegistration = null; - } - timer.cancel(); - } catch (Exception e) { - spLogger.warn("Failed to stop Statistics Provider completely", e); - } finally { - spLogger.info("Statistics Provider stopped."); - } - } - - void startNodeHandlers(final Collection addedNodes) { - for (NodeKey key : addedNodes) { - if (handlers.containsKey(key.getId())) { - spLogger.warn("Attempted to start already-existing handler for {}, very strange", key.getId()); - continue; - } - - final NodeStatisticsHandler h = new NodeStatisticsHandler(dps, key, - flowStatsService, flowTableStatsService, groupStatsService, - meterStatsService, portStatsService, queueStatsService,srScheduler); - final NodeStatisticsHandler old = handlers.putIfAbsent(key.getId(), h); - if (old == null) { - spLogger.debug("Started node handler for {}", key.getId()); - h.start(timer); - } else { - spLogger.debug("Prevented race on handler for {}", key.getId()); - } - } - } - - void stopNodeHandlers(final Collection removedNodes) { - for (NodeKey key : removedNodes) { - final NodeStatisticsHandler s = handlers.remove(key.getId()); - if (s != null) { - spLogger.debug("Stopping node handler for {}", key.getId()); - s.close(); - } else { - spLogger.warn("Attempted to remove non-existing handler for {}, very strange", key.getId()); - } - } - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java deleted file mode 100644 index 29a27e2bb2..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java +++ /dev/null @@ -1,140 +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.md.statistics.manager; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.TimeUnit; - -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction.DataTransactionListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Main responsibility of the class is to check the MD-SAL data store read/write - * transaction accumulation level and send statistics request if number of pending - * read/write transactions are zero. - * @author avishnoi@in.ibm.com - * - */ -@SuppressWarnings("rawtypes") -public class StatisticsRequestScheduler implements DataTransactionListener { - - private static final Logger srsLogger = LoggerFactory.getLogger(StatisticsRequestScheduler.class); - private final Timer timer = new Timer("request-monitor", true); - - // We need ordered retrieval, and O(1) contains operation - private final Map requestQueue = - Collections.synchronizedMap(new LinkedHashMap()); - - private Long PendingTransactions; - - private long lastRequestTime = System.nanoTime(); - - private static final long REQUEST_MONITOR_INTERVAL = 1000; - - private final TimerTask task = new TimerTask() { - @Override - public void run() { - try{ - long now = System.nanoTime(); - if(now > lastRequestTime+TimeUnit.MILLISECONDS.toNanos(REQUEST_MONITOR_INTERVAL)){ - requestStatistics(); - } - }catch (IllegalArgumentException | IllegalStateException | NullPointerException e){ - srsLogger.warn("Exception occured while sending statistics request : {}",e); - } - } - }; - - public StatisticsRequestScheduler(){ - PendingTransactions = (long) 0; - } - - public void addRequestToSchedulerQueue(AbstractStatsTracker statsRequest){ - requestQueue.put(statsRequest, null); - } - - public void removeRequestsFromSchedulerQueue(NodeRef node){ - AbstractStatsTracker stats = null; - synchronized(requestQueue){ - Iterator> nodesItr = requestQueue.entrySet().iterator(); - while(nodesItr.hasNext()){ - stats = nodesItr.next().getKey(); - if(stats.getNodeRef().equals(node)){ - nodesItr.remove(); - } - } - } - - } - public AbstractStatsTracker getNextRequestFromSchedulerQueue(){ - //Remove first element - AbstractStatsTracker stats = null; - synchronized(requestQueue){ - Iterator> nodesItr = requestQueue.entrySet().iterator(); - if(nodesItr.hasNext()){ - stats = nodesItr.next().getKey(); - srsLogger.debug("{} chosen up for execution",stats.getNodeRef()); - nodesItr.remove(); - return stats; - } - } - return stats; - } - - private void requestStatistics(){ - AbstractStatsTracker stats = this.getNextRequestFromSchedulerQueue(); - sendStatsRequest(stats); - } - @Override - public void onStatusUpdated(DataModificationTransaction transaction, TransactionStatus status) { - - AbstractStatsTracker stats = null; - synchronized(PendingTransactions){ - switch(status){ - case SUBMITED: - this.PendingTransactions++; - break; - case COMMITED: - case FAILED: - this.PendingTransactions--; - if(PendingTransactions == 0){ - lastRequestTime = System.nanoTime(); - stats = this.getNextRequestFromSchedulerQueue(); - } - srsLogger.debug("Pending MD-SAL transactions : {} & Scheduler queue size : {}",this.PendingTransactions,this.requestQueue.size()); - break; - default: - break; - } - } - sendStatsRequest(stats); - } - - private void sendStatsRequest(AbstractStatsTracker stats){ - if(stats != null){ - try{ - stats.request(); - stats.increaseRequestCounter(); - }catch(Exception e){ - srsLogger.warn("Statistics request was not sent successfully. Reason : {}",e.getMessage()); - } - } - } - public void start(){ - timer.schedule(task, 0, REQUEST_MONITOR_INTERVAL); - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatAbstractListenCommit.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatAbstractListenCommit.java new file mode 100644 index 0000000000..6db73d5ddc --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatAbstractListenCommit.java @@ -0,0 +1,139 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager.impl; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatListeningCommiter; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.NotificationListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager.impl + * + * StatAbstractListeneningCommiter + * Class is abstract implementation for all Configuration/DataStore DataChange + * listenable DataObjects like flows, groups, meters. It is a holder for common + * functionality needed by construction/destruction class and for DataChange + * event processing. + * + */ +public abstract class StatAbstractListenCommit + extends StatAbstractNotifyCommit implements StatListeningCommiter { + + private static final Logger LOG = LoggerFactory.getLogger(StatAbstractListenCommit.class); + + private ListenerRegistration listenerRegistration; + + protected final Map, Map, Integer>> mapNodesForDelete = new ConcurrentHashMap<>(); + + private final Class clazz; + + private final DataBroker dataBroker; + + private volatile ReadOnlyTransaction currentReadTx; + + /* Constructor has to make a registration */ + public StatAbstractListenCommit(final StatisticsManager manager, final DataBroker db, + final NotificationProviderService nps, final Class clazz) { + super(manager,nps); + this.clazz = Preconditions.checkNotNull(clazz, "Referenced Class can not be null"); + Preconditions.checkArgument(db != null, "DataBroker can not be null!"); + listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + getWildCardedRegistrationPath(), this, DataChangeScope.BASE); + this.dataBroker = db; + } + + /** + * Method returns WildCarded Path which is used for registration as a listening path changes in + * {@link org.opendaylight.controller.md.sal.binding.api.DataChangeListener} + * @return + */ + protected abstract InstanceIdentifier getWildCardedRegistrationPath(); + + @Override + public void onDataChanged(final AsyncDataChangeEvent, DataObject> changeEvent) { + Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!"); + /* + * If we have opened read transaction for configuraiton data store, + * we will close and null it. + * + * Latest read transaction will be allocated on another read using readLatestConfiguration + */ + if(currentReadTx != null) { + final ReadOnlyTransaction previous = currentReadTx; + currentReadTx = null; + previous.close(); + } + } + + @SuppressWarnings("unchecked") + protected void removeData(final InstanceIdentifier key, final Integer value) { + if (clazz.equals(key.getTargetType())) { + final InstanceIdentifier nodeIdent = key.firstIdentifierOf(Node.class); + Map, Integer> map = null; + if (mapNodesForDelete.containsKey(nodeIdent)) { + map = mapNodesForDelete.get(nodeIdent); + } + if (map == null) { + map = new ConcurrentHashMap<>(); + mapNodesForDelete.put(nodeIdent, map); + } + map.put((InstanceIdentifier) key, value); + } + } + + @Override + public void cleanForDisconnect(final InstanceIdentifier nodeIdent) { + mapNodesForDelete.remove(nodeIdent); + } + + @Override + public void close() { + if (listenerRegistration != null) { + try { + listenerRegistration.close(); + } catch (final Exception e) { + LOG.error("Error by stop {} DataChange StatListeningCommiter.", clazz.getSimpleName(), e); + } + listenerRegistration = null; + } + } + + protected final Optional readLatestConfiguration(final InstanceIdentifier path) { + if(currentReadTx == null) { + currentReadTx = dataBroker.newReadOnlyTransaction(); + } + try { + return currentReadTx.read(LogicalDatastoreType.CONFIGURATION, path).checkedGet(); + } catch (final ReadFailedException e) { + return Optional.absent(); + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatAbstractNotifyCommit.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatAbstractNotifyCommit.java new file mode 100644 index 0000000000..08871e9980 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatAbstractNotifyCommit.java @@ -0,0 +1,134 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager.impl; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.opendaylight.controller.md.statistics.manager.StatNotifyCommiter; +import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.NotificationListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager.impl + * + * StatAbstratNotifiCommiter + * Class is abstract implementation for all no Configuration/DataStore DataObjects + * and represent common functionality for all DataObject Statistics Commiters. + * Class defines contract between DataObject and relevant Statistics NotificationListener. + * + */ +public abstract class StatAbstractNotifyCommit implements StatNotifyCommiter { + + private static final Logger LOG = LoggerFactory.getLogger(StatAbstractNotifyCommit.class); + + protected final StatisticsManager manager; + private ListenerRegistration notifyListenerRegistration; + + public StatAbstractNotifyCommit(final StatisticsManager manager, + final NotificationProviderService nps) { + Preconditions.checkArgument(nps != null, "NotificationProviderService can not be null!"); + this.manager = Preconditions.checkNotNull(manager, "StatisticManager can not be null!"); + notifyListenerRegistration = nps.registerNotificationListener(getStatNotificationListener()); + } + + @Override + public void close() { + if (notifyListenerRegistration != null) { + try { + notifyListenerRegistration.close(); + } + catch (final Exception e) { + LOG.error("Error by stop {} StatNotificationListener.", this.getClass().getSimpleName()); + } + notifyListenerRegistration = null; + } + } + + /** + * Method returns Statistics Notification Listener for relevant DataObject implementation, + * which is declared for {@link StatNotifyCommiter} interface. + * + * @return + */ + protected abstract N getStatNotificationListener(); + + /** + * PreConfigurationCheck - Node identified by input InstanceIdentifier + * has to be registered in {@link org.opendaylight.controller.md.statistics.manager.StatPermCollector} + * + * @param InstanceIdentifier nodeIdent + */ + protected boolean preConfigurationCheck(final InstanceIdentifier nodeIdent) { + Preconditions.checkNotNull(nodeIdent, "FlowCapableNode ident can not be null!"); + return manager.isProvidedFlowNodeActive(nodeIdent); + } + + protected void notifyToCollectNextStatistics(final InstanceIdentifier nodeIdent) { + Preconditions.checkNotNull(nodeIdent, "FlowCapableNode ident can not be null!"); + manager.collectNextStatistics(nodeIdent); + } + + /** + * Wrapping Future object call for {@link org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager} + * getTransactionCacheContainer with 10sec TimeOut. + * Method has returned {@link Optional} which could contains a {@link TransactionCacheContainer} + * + * @param TransactionId transId + * @param NodeId nodeId + * @return + */ + protected Optional> getTransactionCacheContainer(final TransactionId transId, final NodeId nodeId) { + Optional> txContainer; + try { + txContainer = manager.getRpcMsgManager().getTransactionCacheContainer(transId, nodeId).get(10, TimeUnit.SECONDS); + } + catch (InterruptedException | ExecutionException | TimeoutException e) { + LOG.warn("Get TransactionCacheContainer fail!", e); + txContainer = Optional.absent(); + } + return txContainer; + } + + /** + * Wrapping Future object call to {@link org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager} + * isExpectedStatistics with 10sec TimeOut. + * Method has checked registration for provided {@link TransactionId} and {@link NodeId} + * + * @param TransactionId transId - Transaction identification + * @param NodeId nodeId - Node identification + * @return boolean + */ + protected boolean isExpectedStatistics(final TransactionId transId, final NodeId nodeId) { + Boolean isExpectedStat = Boolean.FALSE; + try { + isExpectedStat = manager.getRpcMsgManager().isExpectedStatistics(transId, nodeId).get(10, TimeUnit.SECONDS); + } + catch (InterruptedException | ExecutionException | TimeoutException e) { + LOG.warn("Check Transaction registraion {} fail!", transId, e); + return false; + } + return isExpectedStat.booleanValue(); + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitFlow.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitFlow.java new file mode 100644 index 0000000000..230425999e --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitFlow.java @@ -0,0 +1,471 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicInteger; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation; +import org.opendaylight.controller.md.statistics.manager.impl.helper.FlowComparator; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowHashIdMapping; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowHashIdMappingBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowHashIdMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowHashIdMapBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowHashIdMapKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager.impl + * + * StatListenCommitFlow + * Class is a NotifyListener for FlowStatistics and DataChangeListener for Config/DataStore for Flow node. + * All expected (registered) FlowStatistics will be builded and commit to Operational/DataStore. + * DataChangeEven should call create/delete Flow in Operational/DS create process needs to pair + * Device Flow HashCode and FlowId from Config/DS + * + * @author Vaclav Demcak + * + */ +public class StatListenCommitFlow extends StatAbstractListenCommit + implements OpendaylightFlowStatisticsListener { + + protected static final Logger LOG = LoggerFactory.getLogger(StatListenCommitFlow.class); + + private static final String ALIEN_SYSTEM_FLOW_ID = "#UF$TABLE*"; + + private static final Integer REMOVE_AFTER_MISSING_COLLECTION = 1; + + private final AtomicInteger unaccountedFlowsCounter = new AtomicInteger(0); + + public StatListenCommitFlow (final StatisticsManager manager, final DataBroker db, + final NotificationProviderService nps){ + super(manager, db, nps, Flow.class); + } + + @Override + protected OpendaylightFlowStatisticsListener getStatNotificationListener() { + return this; + } + + @Override + protected InstanceIdentifier getWildCardedRegistrationPath() { + return InstanceIdentifier.create(Nodes.class).child(Node.class) + .augmentation(FlowCapableNode.class).child(Table.class).child(Flow.class); + } + + @Override + public void onAggregateFlowStatisticsUpdate(final AggregateFlowStatisticsUpdate notification) { + final TransactionId transId = notification.getTransactionId(); + final NodeId nodeId = notification.getId(); + if ( ! isExpectedStatistics(transId, nodeId)) { + LOG.debug("STAT-MANAGER - AggregateFlowStatisticsUpdate: unregistred notification detect TransactionId {}", transId); + return; + } + manager.getRpcMsgManager().addNotification(notification, nodeId); + if (notification.isMoreReplies()) { + return; + } + /* check flow Capable Node and write statistics */ + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction tx) { + + final Optional> txContainer = getTransactionCacheContainer(transId, nodeId); + if (( ! txContainer.isPresent()) || txContainer.get().getNotifications() == null) { + return; + } + final Optional inputObj = txContainer.get().getConfInput(); + if (( ! inputObj.isPresent()) || ( ! (inputObj.get() instanceof Table))) { + return; + } + final Table table = (Table) inputObj.get(); + final List cacheNotifs = txContainer.get().getNotifications(); + for (final TransactionAware notif : cacheNotifs) { + if (notif instanceof AggregateFlowStatisticsUpdate) { + final AggregateFlowStatisticsData stats = new AggregateFlowStatisticsDataBuilder() + .setAggregateFlowStatistics(new AggregateFlowStatisticsBuilder(notification).build()).build(); + final InstanceIdentifier fNodeIdent = InstanceIdentifier.create(Nodes.class) + .child(Node.class, new NodeKey(nodeId)).augmentation(FlowCapableNode.class); + final InstanceIdentifier
    tableRef = fNodeIdent.child(Table.class, table.getKey()); + final InstanceIdentifier tableStatRef = tableRef + .augmentation(AggregateFlowStatisticsData.class); + Optional fNode = Optional.absent(); + try { + fNode = tx.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet(); + } catch (final ReadFailedException e) { + LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e); + return; + } + if (fNode.isPresent()) { + ensureTable(tx, table.getId(), tableRef); + tx.put(LogicalDatastoreType.OPERATIONAL, tableStatRef, stats); + } + } + } + } + }); + } + + public void ensureTable(final ReadWriteTransaction tx, final Short tableId, final InstanceIdentifier
    tableRef) { + final Table tableNew = new TableBuilder().setId(tableId).build(); + tx.merge(LogicalDatastoreType.OPERATIONAL, tableRef, tableNew); + } + + @Override + public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) { + final TransactionId transId = notification.getTransactionId(); + final NodeId nodeId = notification.getId(); + if ( ! isExpectedStatistics(transId, nodeId)) { + LOG.debug("STAT-MANAGER - FlowsStatisticsUpdate: unregistred notification detect TransactionId {}", transId); + return; + } + manager.getRpcMsgManager().addNotification(notification, nodeId); + if (notification.isMoreReplies()) { + LOG.trace("Next notification for join txId {}", transId); + return; + } + /* add flow's statistics */ + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction tx) { + final Optional> txContainer = getTransactionCacheContainer(transId, nodeId); + if (( ! txContainer.isPresent()) || txContainer.get().getNotifications() == null) { + return; + } + final List flowStats = new ArrayList(10); + final InstanceIdentifier nodeIdent = InstanceIdentifier.create(Nodes.class) + .child(Node.class, new NodeKey(nodeId)); + final List cacheNotifs = txContainer.get().getNotifications(); + for (final TransactionAware notif : cacheNotifs) { + if (notif instanceof FlowsStatisticsUpdate) { + final List notifList = + ((FlowsStatisticsUpdate) notif).getFlowAndStatisticsMapList(); + if (notifList != null) { + flowStats.addAll(notifList); + } + } + } + + statsFlowCommitAll(flowStats, nodeIdent, tx); + /* cleaning all not cached hash collisions */ + final Map, Integer> listAliens = mapNodesForDelete.get(nodeIdent); + if (listAliens != null) { + for (final Entry, Integer> nodeForDelete : listAliens.entrySet()) { + final Integer lifeIndex = nodeForDelete.getValue(); + if (nodeForDelete.getValue() > 0) { + nodeForDelete.setValue(Integer.valueOf(lifeIndex.intValue() - 1)); + } else { + final InstanceIdentifier flowNodeIdent = nodeForDelete.getKey(); + mapNodesForDelete.get(nodeIdent).remove(flowNodeIdent); + tx.delete(LogicalDatastoreType.OPERATIONAL, flowNodeIdent); + } + } + } + /* Notification for continue collecting statistics */ + notifyToCollectNextStatistics(nodeIdent); + } + }); + } + + private void statsFlowCommitAll(final List list, + final InstanceIdentifier nodeIdent, final ReadWriteTransaction tx) { + + final InstanceIdentifier fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class); + + final Optional fNode; + try { + fNode = tx.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet(); + } + catch (final ReadFailedException e) { + LOG.debug("Read FlowCapableNode {} in Operational/DS fail! Statistic scan not be updated.", nodeIdent, e); + return; + } + if ( ! fNode.isPresent()) { + LOG.trace("FlowCapableNode {} is not presented in Operational/DS. Statisticscan not be updated.", nodeIdent); + return; + } + + final NodeUpdateState nodeState = new NodeUpdateState(fNodeIdent,fNode.get()); + + for (final FlowAndStatisticsMapList flowStat : list) { + final TableKey tableKey = new TableKey(flowStat.getTableId()); + final TableFlowUpdateState tableState = nodeState.getTable(tableKey, tx); + tableState.reportFlow(flowStat,tx); + } + + for (final TableFlowUpdateState table : nodeState.getTables()) { + table.removeUnreportedFlows(tx); + } + } + + /** + * Method adds statistics to Flow + * + * @param flowBuilder + * @param deviceFlow + */ + private void addStatistics(final FlowBuilder flowBuilder, final FlowAndStatisticsMapList deviceFlow) { + final FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder(deviceFlow); + final FlowStatisticsBuilder flowStatisticsBuilder = new FlowStatisticsBuilder(stats.build()); + final FlowStatisticsDataBuilder flowStatisticsData =new FlowStatisticsDataBuilder(); + flowStatisticsData.setFlowStatistics(flowStatisticsBuilder.build()); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); + } + + /** + * build pseudoUnique hashCode for flow in table + * for future easy identification + * + * FIXME: we expect same version for YANG models for all clusters and that has to be fix + * FIXME: CREATE BETTER KEY - for flow (MATCH is the problem) + */ + static String buildFlowIdOperKey(final FlowAndStatisticsMapList deviceFlow) { + return new StringBuffer().append(deviceFlow.getMatch()) + .append(deviceFlow.getPriority()).append(deviceFlow.getCookie().getValue()).toString(); + } + + private class NodeUpdateState { + private final InstanceIdentifier nodeIdentifier; + private final Map tables = new HashMap<>(); + + public NodeUpdateState(final InstanceIdentifier fNodeIdent, final FlowCapableNode flowCapableNode) { + nodeIdentifier = fNodeIdent; + final List
    tableList = flowCapableNode.getTable(); + if(tableList != null) { + for (final Table table : tableList) { + final TableKey tableKey = table.getKey(); + tables.put(tableKey, new TableFlowUpdateState(nodeIdentifier.child(Table.class,tableKey),table)); + } + } + } + + public Iterable getTables() { + return tables.values(); + } + + TableFlowUpdateState getTable(final TableKey key,final ReadWriteTransaction tx) { + TableFlowUpdateState table = tables.get(key); + if(table == null) { + table = new TableFlowUpdateState(nodeIdentifier.child(Table.class, key), null); + tables.put(key, table); + } + return table; + } + } + + private class TableFlowUpdateState { + + private boolean tableEnsured = false; + final KeyedInstanceIdentifier tableRef; + final TableKey tableKey; + final BiMap flowIdByHash; + List configFlows; + + public TableFlowUpdateState(final KeyedInstanceIdentifier tablePath, final Table table) { + tableRef = tablePath; + tableKey = tablePath.getKey(); + flowIdByHash = HashBiMap.create(); + if(table != null) { + final FlowHashIdMapping flowHashMapping = table.getAugmentation(FlowHashIdMapping.class); + if (flowHashMapping != null) { + final List flowHashMap = flowHashMapping.getFlowHashIdMap() != null + ? flowHashMapping.getFlowHashIdMap() : Collections. emptyList(); + for (final FlowHashIdMap flowHashId : flowHashMap) { + try { + flowIdByHash.put(flowHashId.getKey(), flowHashId.getFlowId()); + } catch (final Exception e) { + LOG.warn("flow hashing hit a duplicate for {} -> {}", flowHashId.getKey(), flowHashId.getFlowId()); + } + } + } + } + } + + private void ensureTableFowHashIdMapping(final ReadWriteTransaction tx) { + if( ! tableEnsured) { + ensureTable(tx, tableKey.getId(), tableRef); + final FlowHashIdMapping emptyMapping = new FlowHashIdMappingBuilder() + .setFlowHashIdMap(Collections. emptyList()).build(); + tx.merge(LogicalDatastoreType.OPERATIONAL, tableRef.augmentation(FlowHashIdMapping.class), emptyMapping); + tableEnsured = true; + } + } + + private FlowKey searchInConfiguration(final FlowAndStatisticsMapList flowStat, final ReadWriteTransaction trans) { + initConfigFlows(trans); + final Iterator it = configFlows.iterator(); + while(it.hasNext()) { + final Flow cfgFlow = it.next(); + final FlowKey cfgKey = cfgFlow.getKey(); + if(flowIdByHash.inverse().containsKey(cfgKey)) { + it.remove(); + } else if(FlowComparator.flowEquals(flowStat, cfgFlow)) { + it.remove(); + return cfgKey; + } + } + return null; + } + + private void initConfigFlows(final ReadWriteTransaction trans) { + final Optional
    table = readLatestConfiguration(tableRef); + List localList = null; + if(table.isPresent()) { + localList = table.get().getFlow(); + } + if(localList == null) { + configFlows = Collections.emptyList(); + } else { + configFlows = new LinkedList<>(localList); + } + } + + private FlowKey getFlowKeyAndRemoveHash(final FlowHashIdMapKey key) { + final FlowId ret = flowIdByHash.get(key); + if(ret != null) { + flowIdByHash.remove(key); + return new FlowKey(ret); + } + return null; + } + + /* Returns FlowKey which doesn't exist in any DataStore for now */ + private FlowKey makeAlienFlowKey() { + final StringBuilder sBuilder = new StringBuilder(ALIEN_SYSTEM_FLOW_ID) + .append(tableKey.getId()).append("-").append(unaccountedFlowsCounter.incrementAndGet()); + final FlowId flowId = new FlowId(sBuilder.toString()); + return new FlowKey(flowId); + } + + private Map getRemovalList() { + return flowIdByHash; + } + + void reportFlow(final FlowAndStatisticsMapList flowStat, final ReadWriteTransaction trans) { + ensureTableFowHashIdMapping(trans); + final FlowHashIdMapKey hashingKey = new FlowHashIdMapKey(buildFlowIdOperKey(flowStat)); + FlowKey flowKey = getFlowKeyAndRemoveHash(hashingKey); + if (flowKey == null) { + flowKey = searchInConfiguration(flowStat, trans); + if ( flowKey == null) { + flowKey = makeAlienFlowKey(); + } + updateHashCache(trans,flowKey,hashingKey); + } + final FlowBuilder flowBuilder = new FlowBuilder(flowStat); + flowBuilder.setKey(flowKey); + addStatistics(flowBuilder, flowStat); + final InstanceIdentifier flowIdent = tableRef.child(Flow.class, flowKey); + trans.put(LogicalDatastoreType.OPERATIONAL, flowIdent, flowBuilder.build()); + /* check life for Alien flows */ + if (flowKey.getId().getValue().startsWith(ALIEN_SYSTEM_FLOW_ID)) { + removeData(flowIdent, REMOVE_AFTER_MISSING_COLLECTION); + } + } + + /* Build and deploy new FlowHashId map */ + private void updateHashCache(final ReadWriteTransaction trans, final FlowKey flowKey, final FlowHashIdMapKey hashingKey) { + final FlowHashIdMapBuilder flHashIdMap = new FlowHashIdMapBuilder(); + flHashIdMap.setFlowId(flowKey.getId()); + flHashIdMap.setKey(hashingKey); + final KeyedInstanceIdentifier flHashIdent = tableRef + .augmentation(FlowHashIdMapping.class).child(FlowHashIdMap.class, hashingKey); + /* Add new FlowHashIdMap */ + trans.put(LogicalDatastoreType.OPERATIONAL, flHashIdent, flHashIdMap.build()); + } + + void removeUnreportedFlows(final ReadWriteTransaction tx) { + final InstanceIdentifier nodeIdent = tableRef.firstIdentifierOf(Node.class); + final List> listMissingConfigFlows = notStatReportedConfigFlows(); + final Map, Integer> nodeDeleteMap = mapNodesForDelete.get(nodeIdent); + final Map listForRemove = getRemovalList(); + for (final Entry entryForRemove : listForRemove.entrySet()) { + final FlowKey flowKey = new FlowKey(entryForRemove.getValue()); + final InstanceIdentifier flowRef = tableRef.child(Flow.class, flowKey); + if (nodeDeleteMap != null && flowKey.getId().getValue().startsWith(ALIEN_SYSTEM_FLOW_ID)) { + final Integer lifeIndex = nodeDeleteMap.get(flowRef); + if (lifeIndex > 0) { + break; + } else { + nodeDeleteMap.remove(flowRef); + } + } else { + if (listMissingConfigFlows.remove(flowRef)) { + break; // we probably lost some multipart msg + } + } + final InstanceIdentifier flHashIdent = + tableRef.augmentation(FlowHashIdMapping.class).child(FlowHashIdMap.class, entryForRemove.getKey()); + tx.delete(LogicalDatastoreType.OPERATIONAL, flowRef); + tx.delete(LogicalDatastoreType.OPERATIONAL, flHashIdent); + } + } + + List> notStatReportedConfigFlows() { + if (configFlows != null) { + final List> returnList = new ArrayList<>(configFlows.size()); + for (final Flow confFlow : configFlows) { + final InstanceIdentifier confFlowIdent = tableRef.child(Flow.class, confFlow.getKey()); + returnList.add(confFlowIdent); + } + return returnList; + } + return Collections.emptyList(); + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitGroup.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitGroup.java new file mode 100644 index 0000000000..f351132f7f --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitGroup.java @@ -0,0 +1,296 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager.impl + * + * StatListenCommitGroup + * Class is a NotifyListener for GroupStatistics and DataChangeListener for Config/DataStore for Group node. + * All expected (registered) GroupStatistics will be builded and commit to Operational/DataStore. + * DataChangeEven should call create/delete Group in Operational/DS + * + * @author Vaclav Demcak + * + */ +public class StatListenCommitGroup extends StatAbstractListenCommit + implements OpendaylightGroupStatisticsListener { + + private static final Logger LOG = LoggerFactory.getLogger(StatListenCommitMeter.class); + + public StatListenCommitGroup(final StatisticsManager manager, final DataBroker db, + final NotificationProviderService nps) { + super(manager, db, nps, Group.class); + } + + @Override + protected OpendaylightGroupStatisticsListener getStatNotificationListener() { + return this; + } + + @Override + protected InstanceIdentifier getWildCardedRegistrationPath() { + return InstanceIdentifier.create(Nodes.class).child(Node.class) + .augmentation(FlowCapableNode.class).child(Group.class); + } + + @Override + public void onGroupDescStatsUpdated(final GroupDescStatsUpdated notification) { + final TransactionId transId = notification.getTransactionId(); + final NodeId nodeId = notification.getId(); + if ( ! isExpectedStatistics(transId, nodeId)) { + LOG.debug("STAT-MANAGER - GroupDescStatsUpdated: unregistred notification detect TransactionId {}", transId); + return; + } + if (notification.isMoreReplies()) { + manager.getRpcMsgManager().addNotification(notification, nodeId); + return; + } + final List groupStats = notification.getGroupDescStats() != null + ? new ArrayList<>(notification.getGroupDescStats()) : new ArrayList(10); + final Optional> txContainer = getTransactionCacheContainer(transId, nodeId); + if (txContainer.isPresent()) { + final List cacheNotifs = + txContainer.get().getNotifications(); + for (final TransactionAware notif : cacheNotifs) { + if (notif instanceof GroupDescStatsUpdated) { + groupStats.addAll(((GroupDescStatsUpdated) notif).getGroupDescStats()); + } + } + } + final InstanceIdentifier nodeIdent = InstanceIdentifier + .create(Nodes.class).child(Node.class, new NodeKey(nodeId)); + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction tx) { + statGroupDescCommit(groupStats, nodeIdent, tx); + /* Notification for continue collecting statistics */ + notifyToCollectNextStatistics(nodeIdent); + } + }); + } + + @Override + public void onGroupFeaturesUpdated(final GroupFeaturesUpdated notification) { + final TransactionId transId = notification.getTransactionId(); + final NodeId nodeId = notification.getId(); + if ( ! isExpectedStatistics(transId, nodeId)) { + LOG.debug("STAT-MANAGER - MeterFeaturesUpdated: unregistred notification detect TransactionId {}", transId); + return; + } + if (notification.isMoreReplies()) { + manager.getRpcMsgManager().addNotification(notification, nodeId); + return; + } + final Optional> txContainer = getTransactionCacheContainer(transId, nodeId); + if ( ! txContainer.isPresent()) { + return; + } + final InstanceIdentifier nodeIdent = InstanceIdentifier + .create(Nodes.class).child(Node.class, new NodeKey(nodeId)); + + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction tx) { + notifyToCollectNextStatistics(nodeIdent); + final GroupFeatures stats = new GroupFeaturesBuilder(notification).build(); + final InstanceIdentifier groupFeatureIdent = nodeIdent + .augmentation(NodeGroupFeatures.class).child(GroupFeatures.class); + Optional node = Optional.absent(); + try { + node = tx.read(LogicalDatastoreType.OPERATIONAL, nodeIdent).checkedGet(); + } + catch (final ReadFailedException e) { + LOG.debug("Read Operational/DS for Node fail! {}", nodeIdent, e); + } + if (node.isPresent()) { + tx.put(LogicalDatastoreType.OPERATIONAL, groupFeatureIdent, stats); + } + } + }); + } + + @Override + public void onGroupStatisticsUpdated(final GroupStatisticsUpdated notification) { + final TransactionId transId = notification.getTransactionId(); + final NodeId nodeId = notification.getId(); + if ( ! isExpectedStatistics(transId, nodeId)) { + LOG.debug("STAT-MANAGER - GroupStatisticsUpdated: unregistred notification detect TransactionId {}", transId); + return; + } + if (notification.isMoreReplies()) { + manager.getRpcMsgManager().addNotification(notification, nodeId); + return; + } + final List groupStats = notification.getGroupStats() != null + ? new ArrayList<>(notification.getGroupStats()) : new ArrayList(10); + Optional notifGroup = Optional.absent(); + final Optional> txContainer = getTransactionCacheContainer(transId, nodeId); + if (txContainer.isPresent()) { + final Optional inputObj = txContainer.get().getConfInput(); + if (inputObj.isPresent() && inputObj.get() instanceof Group) { + notifGroup = Optional. of((Group)inputObj.get()); + } + final List cacheNotifs = + txContainer.get().getNotifications(); + for (final TransactionAware notif : cacheNotifs) { + if (notif instanceof GroupStatisticsUpdated) { + groupStats.addAll(((GroupStatisticsUpdated) notif).getGroupStats()); + } + } + } + final Optional group = notifGroup; + final InstanceIdentifier nodeIdent = InstanceIdentifier + .create(Nodes.class).child(Node.class, new NodeKey(nodeId)); + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction tx) { + /* Notification for continue collecting statistics */ + if ( ! group.isPresent()) { + notifyToCollectNextStatistics(nodeIdent); + } + statGroupCommit(groupStats, nodeIdent, group, tx); + } + }); + } + + private void statGroupCommit(final List groupStats, final InstanceIdentifier nodeIdent, + final Optional group, final ReadWriteTransaction trans) { + final InstanceIdentifier fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class); + + for (final GroupStats groupStat : groupStats) { + final GroupStatistics stats = new GroupStatisticsBuilder(groupStat).build(); + + final GroupKey groupKey = new GroupKey(groupStat.getGroupId()); + final InstanceIdentifier gsIdent = fNodeIdent + .child(Group.class,groupKey).augmentation(NodeGroupStatistics.class) + .child(GroupStatistics.class); + /* Statistics Writing */ + Optional fNode = Optional.absent(); + try { + fNode = trans.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet(); + } + catch (final ReadFailedException e) { + LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e); + } + if (fNode.isPresent()) { + trans.put(LogicalDatastoreType.OPERATIONAL, gsIdent, stats); + } + } + } + + private void statGroupDescCommit(final List groupStats, final InstanceIdentifier nodeIdent, + final ReadWriteTransaction trans) { + final InstanceIdentifier fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class); + + final List deviceGroupKeys = new ArrayList<>(); + + for (final GroupDescStats group : groupStats) { + if (group.getGroupId() != null) { + final GroupBuilder groupBuilder = new GroupBuilder(group); + final GroupKey groupKey = new GroupKey(group.getGroupId()); + final InstanceIdentifier groupRef = fNodeIdent.child(Group.class,groupKey); + + final NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder(); + groupDesc.setGroupDesc(new GroupDescBuilder(group).build()); + //Update augmented data + groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build()); + deviceGroupKeys.add(groupKey); + Optional hashIdUpd = Optional.absent(); + try { + hashIdUpd = trans.read(LogicalDatastoreType.OPERATIONAL,fNodeIdent).checkedGet(); + } + catch (final ReadFailedException e) { + LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e); + } + if (hashIdUpd.isPresent()) { + trans.put(LogicalDatastoreType.OPERATIONAL, groupRef, groupBuilder.build()); + } + } + } + /* Delete all not presented Group Nodes */ + deleteAllNotPresentNode(fNodeIdent, trans, deviceGroupKeys); + } + + private void deleteAllNotPresentNode(final InstanceIdentifier fNodeIdent, + final ReadWriteTransaction trans, final List deviceGroupKeys) { + + final Optional fNode = readLatestConfiguration(fNodeIdent); + if ( ! fNode.isPresent()) { + LOG.trace("Read Operational/DS for FlowCapableNode fail! Node {} doesn't exist.", fNodeIdent); + return; + } + final List existGroups = fNode.get().getGroup() != null + ? fNode.get().getGroup() : Collections. emptyList(); + /* Add all existed groups paths - no updated paths has to be removed */ + for (final Group group : existGroups) { + if (deviceGroupKeys.remove(group.getKey())) { + break; // group still exist on device + } + LOG.trace("Group {} has to removed.", group); + final InstanceIdentifier delGroupIdent = fNodeIdent.child(Group.class, group.getKey()); + Optional delGroup = Optional.absent(); + try { + delGroup = trans.read(LogicalDatastoreType.OPERATIONAL, delGroupIdent).checkedGet(); + } + catch (final ReadFailedException e) { + // NOOP - probably another transaction delete that node + } + if (delGroup.isPresent()) { + trans.delete(LogicalDatastoreType.OPERATIONAL, delGroupIdent); + } + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitMeter.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitMeter.java new file mode 100644 index 0000000000..9c9de59a6a --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitMeter.java @@ -0,0 +1,283 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterConfigStatsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager.impl + * + * StatListenCommitMeter + * Class is a NotifyListener for MeterStatistics and DataChangeListener for Config/DataStore for Meter node. + * All expected (registered) MeterStatistics will be builded and commit to Operational/DataStore. + * DataChangeEven should call create/delete Meter in Operational/DS + * + */ +public class StatListenCommitMeter extends StatAbstractListenCommit + implements OpendaylightMeterStatisticsListener { + + private static final Logger LOG = LoggerFactory.getLogger(StatListenCommitMeter.class); + + public StatListenCommitMeter(final StatisticsManager manager, final DataBroker db, + final NotificationProviderService nps) { + super(manager, db, nps, Meter.class); + } + + @Override + protected InstanceIdentifier getWildCardedRegistrationPath() { + return InstanceIdentifier.create(Nodes.class).child(Node.class) + .augmentation(FlowCapableNode.class).child(Meter.class); + } + + @Override + protected OpendaylightMeterStatisticsListener getStatNotificationListener() { + return this; + } + + @Override + public void onMeterConfigStatsUpdated(final MeterConfigStatsUpdated notification) { + final TransactionId transId = notification.getTransactionId(); + final NodeId nodeId = notification.getId(); + if ( ! isExpectedStatistics(transId, nodeId)) { + LOG.debug("STAT-MANAGER - MeterConfigStatsUpdated: unregistred notification detect TransactionId {}", transId); + return; + } + if (notification.isMoreReplies()) { + manager.getRpcMsgManager().addNotification(notification, nodeId); + return; + } + final List meterConfStat = notification.getMeterConfigStats() != null + ? new ArrayList<>(notification.getMeterConfigStats()) : new ArrayList(10); + final Optional> txContainer = getTransactionCacheContainer(transId, nodeId); + if (txContainer.isPresent()) { + final List cacheNotifs = txContainer.get().getNotifications(); + for (final TransactionAware notif : cacheNotifs) { + if (notif instanceof MeterConfigStatsUpdated) { + meterConfStat.addAll(((MeterConfigStatsUpdated) notif).getMeterConfigStats()); + } + } + } + final InstanceIdentifier nodeIdent = InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(nodeId)); + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction tx) { + /* Notification for continue collecting statistics */ + notifyToCollectNextStatistics(nodeIdent); + comitConfMeterStats(meterConfStat, nodeIdent, tx); + } + }); + } + + @Override + public void onMeterFeaturesUpdated(final MeterFeaturesUpdated notification) { + final TransactionId transId = notification.getTransactionId(); + final NodeId nodeId = notification.getId(); + if ( ! isExpectedStatistics(transId, nodeId)) { + LOG.debug("STAT-MANAGER - MeterFeaturesUpdated: unregistred notification detect TransactionId {}", transId); + return; + } + if (notification.isMoreReplies()) { + manager.getRpcMsgManager().addNotification(notification, nodeId); + return; + } + final Optional> txContainer = getTransactionCacheContainer(transId, nodeId); + if ( ! txContainer.isPresent()) { + return; + } + final MeterFeatures stats = new MeterFeaturesBuilder(notification).build(); + final InstanceIdentifier nodeIdent = InstanceIdentifier + .create(Nodes.class).child(Node.class, new NodeKey(nodeId)); + final InstanceIdentifier meterFeatureIdent = nodeIdent + .augmentation(NodeMeterFeatures.class).child(MeterFeatures.class); + + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction tx) { + /* Notification for continue collecting statistics */ + notifyToCollectNextStatistics(nodeIdent); + Optional node = Optional.absent(); + try { + node = tx.read(LogicalDatastoreType.OPERATIONAL, nodeIdent).checkedGet(); + } + catch (final ReadFailedException e) { + LOG.debug("Read Operational/DS for Node fail! {}", nodeIdent, e); + } + if (node.isPresent()) { + tx.put(LogicalDatastoreType.OPERATIONAL, meterFeatureIdent, stats); + } + } + }); + } + + @Override + public void onMeterStatisticsUpdated(final MeterStatisticsUpdated notification) { + final TransactionId transId = notification.getTransactionId(); + final NodeId nodeId = notification.getId(); + if ( ! isExpectedStatistics(transId, nodeId)) { + LOG.debug("STAT-MANAGER - MeterStatisticsUpdated: unregistred notification detect TransactionId {}", transId); + return; + } + if (notification.isMoreReplies()) { + manager.getRpcMsgManager().addNotification(notification, nodeId); + return; + } + final List meterStat = notification.getMeterStats() != null + ? new ArrayList<>(notification.getMeterStats()) : new ArrayList(10); + final Optional> txContainer = getTransactionCacheContainer(transId, nodeId); + if (txContainer.isPresent()) { + final List cacheNotifs = txContainer.get().getNotifications(); + for (final TransactionAware notif : cacheNotifs) { + if (notif instanceof MeterConfigStatsUpdated) { + meterStat.addAll(((MeterStatisticsUpdated) notif).getMeterStats()); + } + } + } + final InstanceIdentifier nodeIdent = InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(nodeId)); + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction tx) { + statMeterCommit(meterStat, nodeIdent, tx); + /* Notification for continue collecting statistics */ + notifyToCollectNextStatistics(nodeIdent); + } + }); + } + + private void statMeterCommit(final List meterStats, + final InstanceIdentifier nodeIdent, final ReadWriteTransaction trans) { + + final InstanceIdentifier fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class); + for (final MeterStats mStat : meterStats) { + final MeterStatistics stats = new MeterStatisticsBuilder(mStat).build(); + + final MeterKey mKey = new MeterKey(mStat.getMeterId()); + final InstanceIdentifier msIdent = fNodeIdent + .child(Meter.class, mKey).augmentation(NodeMeterStatistics.class) + .child(MeterStatistics.class); + /* Meter Statistics commit */ + Optional fNode = Optional.absent(); + try { + fNode = trans.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet(); + } + catch (final ReadFailedException e) { + LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e); + } + if (fNode.isPresent()) { + trans.put(LogicalDatastoreType.OPERATIONAL, msIdent, stats); + } + } + } + + private void comitConfMeterStats(final List meterConfStat, + final InstanceIdentifier nodeIdent, final ReadWriteTransaction trans) { + + final InstanceIdentifier fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class); + final List deviceMeterKeys = new ArrayList<>(); + + for (final MeterConfigStats meterConf : meterConfStat) { + final MeterBuilder meterBuilder = new MeterBuilder(meterConf); + if (meterConf.getMeterId() != null) { + final MeterKey meterKey = new MeterKey(meterConf.getMeterId()); + meterBuilder.setKey(meterKey); + final InstanceIdentifier meterRef = nodeIdent + .augmentation(FlowCapableNode.class).child(Meter.class,meterKey); + final NodeMeterConfigStatsBuilder meterConfig = new NodeMeterConfigStatsBuilder(); + meterConfig.setMeterConfigStats(new MeterConfigStatsBuilder(meterConf).build()); + //Update augmented data + meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build()); + deviceMeterKeys.add(meterKey); + Optional fNode = Optional.absent(); + try { + fNode = trans.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet(); + } + catch (final ReadFailedException e) { + LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e); + } + if (fNode.isPresent()) { + trans.put(LogicalDatastoreType.OPERATIONAL, meterRef, meterBuilder.build()); + } + } + } + /* Delete all not presented Meter Nodes */ + deleteAllNotPresentedNodes(fNodeIdent, trans, deviceMeterKeys); + } + + private void deleteAllNotPresentedNodes(final InstanceIdentifier fNodeIdent, + final ReadWriteTransaction trans, final List deviceMeterKeys) { + /* Delete all not presented meters */ + final Optional fNode = readLatestConfiguration(fNodeIdent); + + if ( ! fNode.isPresent()) { + LOG.trace("Read Operational/DS for FlowCapableNode fail! Node {} doesn't exist.", fNodeIdent); + return; + } + final List existMeters = fNode.get().getMeter() != null + ? fNode.get().getMeter() : Collections. emptyList(); + /* Add all existed groups paths - no updated paths has to be removed */ + for (final Meter meter : existMeters) { + if (deviceMeterKeys.remove(meter.getKey())) { + break; // Meter still exist on device + } + final InstanceIdentifier delMeterIdent = fNodeIdent.child(Meter.class, meter.getKey()); + Optional delMeter = Optional.absent(); + try { + delMeter = trans.read(LogicalDatastoreType.OPERATIONAL, delMeterIdent).checkedGet(); + } + catch (final ReadFailedException e) { + // NOOP - probably another transaction delete that node + } + if (delMeter.isPresent()) { + trans.delete(LogicalDatastoreType.OPERATIONAL, delMeterIdent); + } + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitQueue.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitQueue.java new file mode 100644 index 0000000000..e336f01874 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitQueue.java @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager.impl + * + * StatNotifyCommitQueue + * Class is a NotifyListner for Queues Statistics + * All expected (registered) queueStatistics will be builded and + * commit to Operational/DataStore + * + * @author Vaclav Demcak + * + */ +public class StatListenCommitQueue extends StatAbstractListenCommit + implements OpendaylightQueueStatisticsListener { + + private final static Logger LOG = LoggerFactory.getLogger(StatListenCommitQueue.class); + + public StatListenCommitQueue(final StatisticsManager manager, final DataBroker db, + final NotificationProviderService nps) { + super(manager, db, nps, Queue.class); + } + + @Override + protected OpendaylightQueueStatisticsListener getStatNotificationListener() { + return this; + } + + @Override + protected InstanceIdentifier getWildCardedRegistrationPath() { + return InstanceIdentifier.create(Nodes.class).child(Node.class).child(NodeConnector.class) + .augmentation(FlowCapableNodeConnector.class).child(Queue.class); + } + + @Override + public void onQueueStatisticsUpdate(final QueueStatisticsUpdate notification) { + final TransactionId transId = notification.getTransactionId(); + final NodeId nodeId = notification.getId(); + if ( ! isExpectedStatistics(transId, nodeId)) { + LOG.debug("STAT-MANAGER - QueueStatisticsUpdate: unregistred notification detect TransactionId {}", transId); + return; + } + if (notification.isMoreReplies()) { + manager.getRpcMsgManager().addNotification(notification, nodeId); + return; + } + final List queueStats = notification.getQueueIdAndStatisticsMap() != null + ? new ArrayList<>(notification.getQueueIdAndStatisticsMap()) : new ArrayList(10); + final Optional> txContainer = getTransactionCacheContainer(transId, nodeId); + if (txContainer.isPresent()) { + final List cachedNotifs = + txContainer.get().getNotifications(); + for (final TransactionAware notif : cachedNotifs) { + if (notif instanceof QueueStatisticsUpdate) { + queueStats.addAll(((QueueStatisticsUpdate) notif).getQueueIdAndStatisticsMap()); + } + } + } + final InstanceIdentifier nodeIdent = InstanceIdentifier.create(Nodes.class) + .child(Node.class, new NodeKey(nodeId)); + /* Queue statistics are small size and we are not able to change for OF cross controller + * - don't need to make are atomic */ + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction trans) { + /* Notification for continue */ + notifyToCollectNextStatistics(nodeIdent); + statQueueCommit(queueStats, nodeIdent, trans); + } + }); + } + + private void statQueueCommit(final List queueStats, + final InstanceIdentifier nodeIdent, final ReadWriteTransaction trans) { + + /* check exist FlowCapableNode and write statistics */ + Optional fNode = Optional.absent(); + try { + fNode = trans.read(LogicalDatastoreType.OPERATIONAL, nodeIdent).checkedGet(); + } + catch (final ReadFailedException e) { + LOG.debug("Read Operational/DS for Node fail! {}", nodeIdent, e); + return; + } + if ( ! fNode.isPresent()) { + LOG.trace("Read Operational/DS for Node fail! Node {} doesn't exist.", nodeIdent); + return; + } + + for (final QueueIdAndStatisticsMap queueEntry : queueStats) { + final FlowCapableNodeConnectorQueueStatistics statChild = + new FlowCapableNodeConnectorQueueStatisticsBuilder(queueEntry).build(); + final FlowCapableNodeConnectorQueueStatisticsDataBuilder statBuild = + new FlowCapableNodeConnectorQueueStatisticsDataBuilder(); + statBuild.setFlowCapableNodeConnectorQueueStatistics(statChild); + final QueueKey qKey = new QueueKey(queueEntry.getQueueId()); + final InstanceIdentifier queueStatIdent = nodeIdent + .child(NodeConnector.class, new NodeConnectorKey(queueEntry.getNodeConnectorId())) + .augmentation(FlowCapableNodeConnector.class) + .child(Queue.class, qKey).augmentation(FlowCapableNodeConnectorQueueStatisticsData.class); + trans.put(LogicalDatastoreType.OPERATIONAL, queueStatIdent, statBuild.build()); + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNodeRegistrationImpl.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNodeRegistrationImpl.java new file mode 100644 index 0000000000..adb5870986 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNodeRegistrationImpl.java @@ -0,0 +1,207 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatNodeRegistration; +import org.opendaylight.controller.md.statistics.manager.StatPermCollector.StatCapabTypes; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FeatureCapability; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityFlowStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityGroupStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityPortStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityQueueStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityTableStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SwitchFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager.impl + * + * StatNodeRegistrationImpl + * {@link FlowCapableNode} Registration Implementation contains two method for registration/unregistration + * {@link FeatureCapability} for every connect/disconnect {@link FlowCapableNode}. Process of connection/disconnection + * is substituted by listening Operation/DS for add/delete {@link FeatureCapability}. + * All statistic capabilities are reading from new Node directly without contacting device or DS. + * + * @author Vaclav Demcak + * + * Created: Aug 28, 2014 + */ +public class StatNodeRegistrationImpl implements StatNodeRegistration { + + private static final Logger LOG = LoggerFactory.getLogger(StatNodeRegistrationImpl.class); + + private final StatisticsManager manager; + private ListenerRegistration listenerRegistration; + private ListenerRegistration notifListenerRegistration; + + public StatNodeRegistrationImpl(final StatisticsManager manager, final DataBroker db, + final NotificationProviderService notificationService) { + this.manager = Preconditions.checkNotNull(manager, "StatisticManager can not be null!"); + Preconditions.checkArgument(db != null, "DataBroker can not be null!"); + Preconditions.checkArgument(notificationService != null, "NotificationProviderService can not be null!"); + notifListenerRegistration = notificationService.registerNotificationListener(this); + } + + @Override + public void close() throws Exception { + + if (notifListenerRegistration != null) { + try { + notifListenerRegistration.close(); + } + catch (final Exception e) { + LOG.warn("Error by stop FlowCapableNode Notification StatNodeRegistration."); + } + notifListenerRegistration = null; + } + + if (listenerRegistration != null) { + try { + listenerRegistration.close(); + } catch (final Exception e) { + LOG.warn("Error by stop FlowCapableNode DataChange StatListeningCommiter.", e); + } + listenerRegistration = null; + } + } + + @Override + public void connectFlowCapableNode(final InstanceIdentifier keyIdent, + final SwitchFeatures data, final InstanceIdentifier nodeIdent) { + Preconditions.checkNotNull(keyIdent, "InstanceIdentifier can not be null!"); + Preconditions.checkNotNull(data, "SwitchFeatures data for {} can not be null!", keyIdent); + Preconditions.checkArgument(( ! keyIdent.isWildcarded()), "InstanceIdentifier is WildCarded!"); + + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction tx) { + + final List statCapabTypes = new ArrayList<>(); + Short maxCapTables = Short.valueOf("1"); + + final List> capabilities = data.getCapabilities() != null + ? data.getCapabilities() : Collections.> emptyList(); + for (final Class capability : capabilities) { + if (capability == FlowFeatureCapabilityTableStats.class) { + statCapabTypes.add(StatCapabTypes.TABLE_STATS); + } else if (capability == FlowFeatureCapabilityFlowStats.class) { + statCapabTypes.add(StatCapabTypes.FLOW_STATS); + } else if (capability == FlowFeatureCapabilityGroupStats.class) { + statCapabTypes.add(StatCapabTypes.GROUP_STATS); + } else if (capability == FlowFeatureCapabilityPortStats.class) { + statCapabTypes.add(StatCapabTypes.PORT_STATS); + } else if (capability == FlowFeatureCapabilityQueueStats.class) { + statCapabTypes.add(StatCapabTypes.QUEUE_STATS); + } + } + maxCapTables = data.getMaxTables(); + + final Optional maxTables = Optional. of(maxCapTables); + + /* Meters management */ + final InstanceIdentifier meterFeaturesIdent = nodeIdent.augmentation(NodeMeterFeatures.class); + + + Optional meterFeatures = Optional.absent(); + try { + meterFeatures = tx.read(LogicalDatastoreType.OPERATIONAL, meterFeaturesIdent).checkedGet(); + } + catch (final ReadFailedException e) { + LOG.warn("Read NodeMeterFeatures {} fail!", meterFeaturesIdent, e); + } + if (meterFeatures.isPresent()) { + statCapabTypes.add(StatCapabTypes.METER_STATS); + } + manager.connectedNodeRegistration(nodeIdent, + Collections.unmodifiableList(statCapabTypes), maxTables.get()); + } + }); + } + + @Override + public void disconnectFlowCapableNode(final InstanceIdentifier nodeIdent) { + Preconditions.checkArgument(nodeIdent != null, "InstanceIdentifier can not be NULL!"); + Preconditions.checkArgument(( ! nodeIdent.isWildcarded()), + "InstanceIdentifier {} is WildCarded!", nodeIdent); + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction tx) { + manager.disconnectedNodeUnregistration(nodeIdent); + } + }); + } + + + @Override + public void onNodeConnectorRemoved(final NodeConnectorRemoved notification) { + // NOOP + } + + @Override + public void onNodeConnectorUpdated(final NodeConnectorUpdated notification) { + // NOOP + } + + @Override + public void onNodeRemoved(final NodeRemoved notification) { + final NodeRef nodeRef = notification.getNodeRef(); + final InstanceIdentifier nodeRefIdent = nodeRef.getValue(); + final InstanceIdentifier nodeIdent = + nodeRefIdent.firstIdentifierOf(Node.class); + if (nodeIdent != null) { + disconnectFlowCapableNode(nodeIdent); + } + } + + @Override + public void onNodeUpdated(final NodeUpdated notification) { + final FlowCapableNodeUpdated newFlowNode = + notification.getAugmentation(FlowCapableNodeUpdated.class); + if (newFlowNode != null && newFlowNode.getSwitchFeatures() != null) { + final NodeRef nodeRef = notification.getNodeRef(); + final InstanceIdentifier nodeRefIdent = nodeRef.getValue(); + final InstanceIdentifier nodeIdent = + nodeRefIdent.firstIdentifierOf(Node.class); + + final InstanceIdentifier swichFeaturesIdent = + nodeIdent.augmentation(FlowCapableNode.class).child(SwitchFeatures.class); + final SwitchFeatures switchFeatures = newFlowNode.getSwitchFeatures(); + connectFlowCapableNode(swichFeaturesIdent, switchFeatures, nodeIdent); + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNotifyCommitPort.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNotifyCommitPort.java new file mode 100644 index 0000000000..fb124376b6 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNotifyCommitPort.java @@ -0,0 +1,153 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager.impl + * + * StatNotifyCommitPort + * Class is a NotifyListener for PortStatistics + * All expected (registered) portStatistics will be builded and + * commit to Operational/DataStore + * + * @author Vaclav Demcak + * + */ +public class StatNotifyCommitPort extends StatAbstractNotifyCommit + implements OpendaylightPortStatisticsListener { + + private static final Logger LOG = LoggerFactory.getLogger(StatNotifyCommitPort.class); + + public StatNotifyCommitPort(final StatisticsManager manager, + final NotificationProviderService nps) { + super(manager, nps); + } + + @Override + protected OpendaylightPortStatisticsListener getStatNotificationListener() { + return this; + } + + @Override + public void onNodeConnectorStatisticsUpdate(final NodeConnectorStatisticsUpdate notification) { + final TransactionId transId = notification.getTransactionId(); + final NodeId nodeId = notification.getId(); + if ( ! isExpectedStatistics(transId, nodeId)) { + LOG.debug("STAT-MANAGER - NodeConnectorStatisticsUpdate: unregistred notification detect TransactionId {}", transId); + return; + } + manager.getRpcMsgManager().addNotification(notification, nodeId); + if (notification.isMoreReplies()) { + return; + } + final InstanceIdentifier nodeIdent = InstanceIdentifier.create(Nodes.class) + .child(Node.class, new NodeKey(nodeId)); + /* Don't block RPC Notification thread */ + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction trans) { + final Optional> txContainer = getTransactionCacheContainer(transId, nodeId); + if (( ! txContainer.isPresent()) || txContainer.get().getNotifications() == null) { + return; + } + final List portStats = + new ArrayList(10); + final List cachedNotifs = txContainer.get().getNotifications(); + for (final TransactionAware notif : cachedNotifs) { + if (notif instanceof NodeConnectorStatisticsUpdate) { + final List notifStat = + ((NodeConnectorStatisticsUpdate) notif).getNodeConnectorStatisticsAndPortNumberMap(); + if (notifStat != null) { + portStats.addAll(notifStat); + } + } + } + /* write stat to trans */ + statPortCommit(portStats, nodeIdent, trans); + /* Notification for continue collecting statistics - Port statistics are still same size + * and they are small - don't need to wait for whole apply operation*/ + notifyToCollectNextStatistics(nodeIdent); + } + }); + } + + private void statPortCommit(final List portStats, + final InstanceIdentifier nodeIdent, final ReadWriteTransaction tx) { + + /* check exist FlowCapableNode and write statistics probable with parent */ + Optional fNode = Optional.absent(); + try { + fNode = tx.read(LogicalDatastoreType.OPERATIONAL, nodeIdent).checkedGet(); + } + catch (final ReadFailedException e) { + LOG.debug("Read Operational/DS for Node fail! {}", nodeIdent, e); + return; + } + if ( ! fNode.isPresent()) { + LOG.trace("Read Operational/DS for Node fail! Node {} doesn't exist.", nodeIdent); + return; + } + for (final NodeConnectorStatisticsAndPortNumberMap nConnectPort : portStats) { + final FlowCapableNodeConnectorStatistics stats = new FlowCapableNodeConnectorStatisticsBuilder(nConnectPort).build(); + final NodeConnectorKey key = new NodeConnectorKey(nConnectPort.getNodeConnectorId()); + final InstanceIdentifier nodeConnectorIdent = nodeIdent.child(NodeConnector.class, key); + final InstanceIdentifier nodeConnStatIdent = nodeConnectorIdent + .augmentation(FlowCapableNodeConnectorStatisticsData.class); + final InstanceIdentifier flowCapNodeConnStatIdent = + nodeConnStatIdent.child(FlowCapableNodeConnectorStatistics.class); + Optional fNodeConector; + try { + fNodeConector = tx.read(LogicalDatastoreType.OPERATIONAL, nodeConnectorIdent).checkedGet(); + } + catch (final ReadFailedException e) { + LOG.debug("Read NodeConnector {} in Operational/DS fail!", nodeConnectorIdent, e); + fNodeConector = Optional.absent(); + } + if (fNodeConector.isPresent()) { + tx.merge(LogicalDatastoreType.OPERATIONAL, nodeConnectorIdent, new NodeConnectorBuilder().setId(key.getId()).build()); + tx.merge(LogicalDatastoreType.OPERATIONAL, nodeConnStatIdent, new FlowCapableNodeConnectorStatisticsDataBuilder().build()); + tx.put(LogicalDatastoreType.OPERATIONAL, flowCapNodeConnStatIdent, stats); + } + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNotifyCommitTable.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNotifyCommitTable.java new file mode 100644 index 0000000000..b41bd4973c --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNotifyCommitTable.java @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager.impl + * + * StatNotifyCommitTable + * Class is a NotifyListener for TableStatistics + * All expected (registered) tableStatistics will be builded and + * commit to Operational/DataStore + * + * @author Vaclav Demcak + * + */ +public class StatNotifyCommitTable extends StatAbstractNotifyCommit + implements OpendaylightFlowTableStatisticsListener { + + private final static Logger LOG = LoggerFactory.getLogger(StatNotifyCommitTable.class); + + public StatNotifyCommitTable(final StatisticsManager manager, + final NotificationProviderService nps) { + super(manager, nps); + } + + @Override + protected OpendaylightFlowTableStatisticsListener getStatNotificationListener() { + return this; + } + + @Override + public void onFlowTableStatisticsUpdate(final FlowTableStatisticsUpdate notification) { + final TransactionId transId = notification.getTransactionId(); + final NodeId nodeId = notification.getId(); + if ( ! isExpectedStatistics(transId, nodeId)) { + LOG.debug("STAT-MANAGER - FlowTableStatisticsUpdate: unregistred notification detect TransactionId {}", transId); + return; + } + manager.getRpcMsgManager().addNotification(notification, nodeId); + if (notification.isMoreReplies()) { + return; + } + /* Don't block RPC Notification thread */ + manager.enqueue(new StatDataStoreOperation() { + @Override + public void applyOperation(final ReadWriteTransaction trans) { + final List tableStats = new ArrayList(10); + final Optional> txContainer = getTransactionCacheContainer(transId, nodeId); + final InstanceIdentifier nodeIdent = InstanceIdentifier.create(Nodes.class) + .child(Node.class, new NodeKey(nodeId)); + if (( ! txContainer.isPresent()) || txContainer.get().getNodeId() == null) { + return; + } + final List cachedNotifs = txContainer.get().getNotifications(); + for (final TransactionAware notif : cachedNotifs) { + if (notif instanceof FlowTableStatisticsUpdate) { + final List statNotif = + ((FlowTableStatisticsUpdate) notif).getFlowTableAndStatisticsMap(); + if (statNotif != null) { + tableStats.addAll(statNotif); + } + } + } + /* write stat to trans */ + statTableCommit(tableStats, nodeIdent, trans); + /* Notification for continue collecting statistics - Tables statistics are still same size + * and they are small - don't need to wait to whole apply operation */ + notifyToCollectNextStatistics(nodeIdent); + } + }); + } + + private void statTableCommit(final List tableStats, final InstanceIdentifier nodeIdent, + final ReadWriteTransaction trans) { + final InstanceIdentifier fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class); + /* check flow Capable Node and write statistics */ + Optional fNode = Optional.absent(); + try { + fNode = trans.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet(); + } + catch (final ReadFailedException e) { + LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e); + return; + } + if ( ! fNode.isPresent()) { + LOG.trace("Read Operational/DS for FlowCapableNode fail! Node {} doesn't exist.", fNodeIdent); + return; + } + for (final FlowTableAndStatisticsMap tableStat : tableStats) { + final InstanceIdentifier
    tableIdent = fNodeIdent + .child(Table.class, new TableKey(tableStat.getTableId().getValue())); + final Table table = new TableBuilder().setId(tableStat.getTableId().getValue()).build(); + trans.merge(LogicalDatastoreType.OPERATIONAL, tableIdent, table); + final InstanceIdentifier tableStatIdent = tableIdent + .augmentation(FlowTableStatisticsData.class); + trans.merge(LogicalDatastoreType.OPERATIONAL, tableStatIdent, new FlowTableStatisticsDataBuilder().build()); + + final FlowTableStatistics stats = new FlowTableStatisticsBuilder(tableStat).build(); + final InstanceIdentifier tStatIdent = tableStatIdent.child(FlowTableStatistics.class); + trans.put(LogicalDatastoreType.OPERATIONAL, tStatIdent, stats); + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatPermCollectorImpl.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatPermCollectorImpl.java new file mode 100644 index 0000000000..d008042e8d --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatPermCollectorImpl.java @@ -0,0 +1,305 @@ +package org.opendaylight.controller.md.statistics.manager.impl; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +import org.opendaylight.controller.md.statistics.manager.StatPermCollector; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager.impl + * + * StatPermCollectorImpl + * Thread base statistic collector. Class holds internal map for all registered + * (means connected) nodes with List of Switch capabilities; + * Statistics collecting process get cross whole Network Device by device + * and statistic by statistic (follow Switch capabilities to prevent unnecessary + * ask) Next statistic start collecting by notification or by timeout. + * + * @author @author avishnoi@in.ibm.com Vaclav Demcak + * + */ +public class StatPermCollectorImpl implements StatPermCollector { + + private final static Logger LOG = LoggerFactory.getLogger(StatPermCollectorImpl.class); + + private final static long STAT_COLLECT_TIME_OUT = 30000L; + + private final ExecutorService statNetCollectorServ; + private final StatisticsManager manager; + + private final int maxNodeForCollector; + private final long minReqNetInterval; + private final String name; + + private final Object statCollectorLock = new Object(); + private final Object statNodeHolderLock = new Object(); + + private Map, StatNodeInfoHolder> statNodeHolder = + Collections., StatNodeInfoHolder> emptyMap(); + + private volatile boolean wakeMe = false; + private volatile boolean finishing = false; + + public StatPermCollectorImpl(final StatisticsManager manager, final long minReqNetInterv, final int nr, + final int maxNodeForCollectors) { + this.manager = Preconditions.checkNotNull(manager, "StatisticsManager can not be null!"); + name = "odl-stat-collector-" + nr; + minReqNetInterval = minReqNetInterv; + final ThreadFactory threadFact = new ThreadFactoryBuilder() + .setNameFormat(name + "-thread-%d").build(); + statNetCollectorServ = Executors.newSingleThreadExecutor(threadFact); + maxNodeForCollector = maxNodeForCollectors; + LOG.trace("StatCollector {} start successfull!", name); + } + + /** + * finish collecting statistics + */ + @Override + public void close() { + statNodeHolder = Collections., StatNodeInfoHolder> emptyMap(); + finishing = true; + collectNextStatistics(); + statNetCollectorServ.shutdown(); + } + + @Override + public boolean isProvidedFlowNodeActive( + final InstanceIdentifier flowNode) { + return statNodeHolder.containsKey(flowNode); + } + + @Override + public boolean connectedNodeRegistration(final InstanceIdentifier ident, + final List statTypes, final Short nrOfSwitchTables) { + if (ident.isWildcarded()) { + LOG.warn("FlowCapableNode IstanceIdentifier {} registration can not be wildcarded!", ident); + } else { + if ( ! statNodeHolder.containsKey(ident)) { + synchronized (statNodeHolderLock) { + final boolean startStatCollecting = statNodeHolder.size() == 0; + if ( ! statNodeHolder.containsKey(ident)) { + if (statNodeHolder.size() >= maxNodeForCollector) { + return false; + } + final Map, StatNodeInfoHolder> statNode = + new HashMap<>(statNodeHolder); + final NodeRef nodeRef = new NodeRef(ident); + final StatNodeInfoHolder nodeInfoHolder = new StatNodeInfoHolder(nodeRef, + statTypes, nrOfSwitchTables); + statNode.put(ident, nodeInfoHolder); + statNodeHolder = Collections.unmodifiableMap(statNode); + } + if (startStatCollecting) { + finishing = false; + statNetCollectorServ.execute(this); + } + } + } + } + return true; + } + + @Override + public boolean disconnectedNodeUnregistration(final InstanceIdentifier ident) { + if (ident.isWildcarded()) { + LOG.warn("FlowCapableNode IstanceIdentifier {} unregistration can not be wildcarded!", ident); + } else { + if (statNodeHolder.containsKey(ident)) { + synchronized (statNodeHolderLock) { + if (statNodeHolder.containsKey(ident)) { + final Map, StatNodeInfoHolder> statNode = + new HashMap<>(statNodeHolder); + statNode.remove(ident); + statNodeHolder = Collections.unmodifiableMap(statNode); + } + if (statNodeHolder.isEmpty()) { + finishing = true; + collectNextStatistics(); + statNetCollectorServ.shutdown(); + } + return true; + } + } + } + return false; + } + + @Override + public void collectNextStatistics() { + if (wakeMe) { + synchronized (statCollectorLock) { + if (wakeMe) { + LOG.trace("STAT-COLLECTOR is notified to conntinue"); + statCollectorLock.notify(); + } + } + } + } + + @Override + public void run() { + try { + Thread.sleep(5000); + } + catch (final InterruptedException e1) { + // NOOP + } + LOG.debug("StatCollector {} Start collecting!", name); + /* Neverending cyle - wait for finishing */ + while ( ! finishing) { + boolean collecting = false; + final long startTime = System.currentTimeMillis(); + + if ( ! statNodeHolder.isEmpty()) { + collecting = true; + collectStatCrossNetwork(); + collecting = false; + } + + if ( ! collecting) { + final long statFinalTime = System.currentTimeMillis() - startTime; + LOG.debug("STAT-MANAGER {}: last all NET statistics collection cost {} ms", name, statFinalTime); + if (statFinalTime < minReqNetInterval) { + LOG.trace("statCollector is about to make a collecting sleep"); + synchronized (statCollectorLock) { + wakeMe = true; + try { + final long waitTime = minReqNetInterval - statFinalTime; + statCollectorLock.wait(waitTime); + LOG.trace("STAT-MANAGER : statCollector {} is waking up from a collecting sleep for {} ms", name, waitTime); + } catch (final InterruptedException e) { + LOG.warn("statCollector has been interrupted during collecting sleep", e); + } finally { + wakeMe = false; + } + } + } + } + } + } + + private void waitingForNotification() { + synchronized (statCollectorLock) { + wakeMe = true; + try { + statCollectorLock.wait(STAT_COLLECT_TIME_OUT); + LOG.trace("statCollector is waking up from a wait stat Response sleep"); + } catch (final InterruptedException e) { + LOG.warn("statCollector has been interrupted waiting stat Response sleep", e); + } finally { + wakeMe = false; + } + } + } + + + private void collectStatCrossNetwork() { + for (final Entry, StatNodeInfoHolder> nodeEntity : statNodeHolder.entrySet()) { + final List listNeededStat = nodeEntity.getValue().getStatMarkers(); + final NodeRef actualNodeRef = nodeEntity.getValue().getNodeRef(); + final Short maxTables = nodeEntity.getValue().getMaxTables(); + for (final StatCapabTypes statMarker : listNeededStat) { + if ( ! isProvidedFlowNodeActive(nodeEntity.getKey())) { + break; + } + switch (statMarker) { + case PORT_STATS: + LOG.trace("STAT-MANAGER-collecting PORT-STATS for NodeRef {}", actualNodeRef); + manager.getRpcMsgManager().getAllPortsStat(actualNodeRef); + waitingForNotification(); + break; + case QUEUE_STATS: + LOG.trace("STAT-MANAGER-collecting QUEUE-STATS for NodeRef {}", actualNodeRef); + manager.getRpcMsgManager().getAllQueueStat(actualNodeRef); + waitingForNotification(); + break; + case TABLE_STATS: + LOG.trace("STAT-MANAGER-collecting TABLE-STATS for NodeRef {}", actualNodeRef); + manager.getRpcMsgManager().getAllTablesStat(actualNodeRef); + waitingForNotification(); + break; + case GROUP_STATS: + LOG.trace("STAT-MANAGER-collecting GROUP-STATS for NodeRef {}", actualNodeRef); + manager.getRpcMsgManager().getGroupFeaturesStat(actualNodeRef); + waitingForNotification(); + manager.getRpcMsgManager().getAllGroupsConfStats(actualNodeRef); + waitingForNotification(); + manager.getRpcMsgManager().getAllGroupsStat(actualNodeRef); + waitingForNotification(); + break; + case METER_STATS: + LOG.trace("STAT-MANAGER-collecting METER-STATS for NodeRef {}", actualNodeRef); + manager.getRpcMsgManager().getMeterFeaturesStat(actualNodeRef); + waitingForNotification(); + manager.getRpcMsgManager().getAllMeterConfigStat(actualNodeRef); + waitingForNotification(); + manager.getRpcMsgManager().getAllMetersStat(actualNodeRef); + waitingForNotification(); + break; + case FLOW_STATS: + LOG.trace("STAT-MANAGER-collecting FLOW-STATS-ALL_FLOWS for NodeRef {}", actualNodeRef); + manager.getRpcMsgManager().getAllFlowsStat(actualNodeRef); + waitingForNotification(); + LOG.trace("STAT-MANAGER-collecting FLOW-AGGREGATE-STATS for NodeRef {}", actualNodeRef); + for (short i = 0; i < maxTables; i++) { + final TableId tableId = new TableId(i); + manager.getRpcMsgManager().getAggregateFlowStat(actualNodeRef, tableId); + } + break; + default: + /* Exception for programmers in implementation cycle */ + throw new IllegalStateException("Not implemented ASK for " + statMarker); + } + } + } + } + + private class StatNodeInfoHolder { + private final NodeRef nodeRef; + private final List statMarkers; + private final Short maxTables; + + public StatNodeInfoHolder(final NodeRef nodeRef, + final List statMarkers, final Short maxTables) { + this.nodeRef = nodeRef; + this.maxTables = maxTables; + this.statMarkers = statMarkers; + } + + public final NodeRef getNodeRef() { + return nodeRef; + } + + public final List getStatMarkers() { + return statMarkers; + } + + public final Short getMaxTables() { + return maxTables; + } + } + + @Override + public boolean hasActiveNodes() { + return ( ! statNodeHolder.isEmpty()); + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatRPCFailedException.java similarity index 75% rename from opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java rename to opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatRPCFailedException.java index 308c6ddebe..5ff4913cc0 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatRPCFailedException.java @@ -5,17 +5,17 @@ * 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.md.statistics.manager; - -import java.util.Collection; +package org.opendaylight.controller.md.statistics.manager.impl; import org.opendaylight.yangtools.yang.common.RpcError; -final class RPCFailedException extends RuntimeException { +import java.util.Collection; + +public final class StatRPCFailedException extends RuntimeException { private static final long serialVersionUID = 1L; private final Collection errors; - public RPCFailedException(final String message, final Collection errors) { + public StatRPCFailedException(final String message, final Collection errors) { super(message); this.errors = errors; } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatRpcMsgManagerImpl.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatRpcMsgManagerImpl.java new file mode 100644 index 0000000000..e53f494129 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatRpcMsgManagerImpl.java @@ -0,0 +1,510 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager.impl; + +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupFeaturesInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetMeterFeaturesInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.JdkFutureAdapters; +import com.google.common.util.concurrent.SettableFuture; + + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager.impl + * + * StatRpcMsgManagerImpl + * Class register and provide all RPC Statistics Device Services and implement pre-defined + * wrapped methods for prepare easy access to RPC Statistics Device Services like getAllStatisticsFor... + * + * In next Class implement process for joining multipart messages. + * Class internally use two WeakHashMap and GuavaCache for holding values for joining multipart msg. + * One Weak map is used for holding all Multipart Messages and second is used for possible input + * Config/DS light-weight DataObject (DataObject contains only necessary identification fields as + * TableId, GroupId, MeterId or for flow Match, Priority, FlowCookie, TableId and FlowId ... + * + * @author avishnoi@in.ibm.com Vaclav Demcak + * + */ +public class StatRpcMsgManagerImpl implements StatRpcMsgManager { + + private final static Logger LOG = LoggerFactory.getLogger(StatRpcMsgManagerImpl.class); + + private final Cache> txCache; + + private final long maxLifeForRequest = 50; /* 50 second */ + private final int queueCapacity = 5000; + + private final OpendaylightGroupStatisticsService groupStatsService; + private final OpendaylightMeterStatisticsService meterStatsService; + private final OpendaylightFlowStatisticsService flowStatsService; + private final OpendaylightPortStatisticsService portStatsService; + private final OpendaylightFlowTableStatisticsService flowTableStatsService; + private final OpendaylightQueueStatisticsService queueStatsService; + + private BlockingQueue statsRpcJobQueue; + + private volatile boolean finishing = false; + + public StatRpcMsgManagerImpl (final StatisticsManager manager, + final RpcConsumerRegistry rpcRegistry, final long minReqNetMonitInt) { + Preconditions.checkArgument(manager != null, "StatisticManager can not be null!"); + Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !"); + groupStatsService = Preconditions.checkNotNull( + rpcRegistry.getRpcService(OpendaylightGroupStatisticsService.class), + "OpendaylightGroupStatisticsService can not be null!"); + meterStatsService = Preconditions.checkNotNull( + rpcRegistry.getRpcService(OpendaylightMeterStatisticsService.class), + "OpendaylightMeterStatisticsService can not be null!"); + flowStatsService = Preconditions.checkNotNull( + rpcRegistry.getRpcService(OpendaylightFlowStatisticsService.class), + "OpendaylightFlowStatisticsService can not be null!"); + portStatsService = Preconditions.checkNotNull( + rpcRegistry.getRpcService(OpendaylightPortStatisticsService.class), + "OpendaylightPortStatisticsService can not be null!"); + flowTableStatsService = Preconditions.checkNotNull( + rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class), + "OpendaylightFlowTableStatisticsService can not be null!"); + queueStatsService = Preconditions.checkNotNull( + rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class), + "OpendaylightQueueStatisticsService can not be null!"); + + statsRpcJobQueue = new LinkedBlockingQueue<>(queueCapacity); + txCache = CacheBuilder.newBuilder().expireAfterWrite(maxLifeForRequest, TimeUnit.SECONDS) + .maximumSize(10000).build(); + } + + @Override + public void close() { + finishing = true; + statsRpcJobQueue = null; + } + + @Override + public void run() { + /* Neverending cyle - wait for finishing */ + while ( ! finishing) { + try { + statsRpcJobQueue.take().call(); + } + catch (final Exception e) { + LOG.warn("Stat Element RPC executor fail!", e); + } + } + // Drain all rpcCall, making sure any blocked threads are unblocked + while ( ! statsRpcJobQueue.isEmpty()) { + statsRpcJobQueue.poll(); + } + } + + private void addGetAllStatJob(final RpcJobsQueue getAllStatJob) { + final boolean success = statsRpcJobQueue.offer(getAllStatJob); + if ( ! success) { + LOG.warn("Put RPC request getAllStat fail! Queue is full."); + } + } + + private void addStatJob(final RpcJobsQueue getStatJob) { + final boolean success = statsRpcJobQueue.offer(getStatJob); + if ( ! success) { + LOG.debug("Put RPC request for getStat fail! Queue is full."); + } + } + + @Override + public void registrationRpcFutureCallBack( + final Future> future, final D inputObj, final NodeRef nodeRef) { + + Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), + new FutureCallback>() { + + @Override + public void onSuccess(final RpcResult result) { + final TransactionId id = result.getResult().getTransactionId(); + if (id == null) { + LOG.warn("No protocol support"); + } else { + final NodeKey nodeKey = nodeRef.getValue().firstKeyOf(Node.class, NodeKey.class); + final String cacheKey = buildCacheKey(id, nodeKey.getId()); + final TransactionCacheContainer container = + new TransactionCacheContainerImpl<>(id, inputObj, nodeKey.getId()); + txCache.put(cacheKey, container); + } + } + + @Override + public void onFailure(final Throwable t) { + LOG.warn("Response Registration for Statistics RPC call fail!", t); + } + + }); + } + + private String buildCacheKey(final TransactionId id, final NodeId nodeId) { + return String.valueOf(id.getValue()) + "-" + nodeId.getValue(); + } + + @Override + public Future>> getTransactionCacheContainer( + final TransactionId id, final NodeId nodeId) { + Preconditions.checkArgument(id != null, "TransactionId can not be null!"); + Preconditions.checkArgument(nodeId != null, "NodeId can not be null!"); + + final String key = buildCacheKey(id, nodeId); + final SettableFuture>> result = SettableFuture.create(); + + final RpcJobsQueue getTransactionCacheContainer = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + final Optional> resultContainer = + Optional.> fromNullable(txCache.getIfPresent(key)); + if (resultContainer.isPresent()) { + txCache.invalidate(key); + } + result.set(resultContainer); + return null; + } + }; + addStatJob(getTransactionCacheContainer); + return result; + } + + @Override + public Future isExpectedStatistics(final TransactionId id, final NodeId nodeId) { + Preconditions.checkArgument(id != null, "TransactionId can not be null!"); + Preconditions.checkArgument(nodeId != null, "NodeId can not be null!"); + + final String key = buildCacheKey(id, nodeId); + final SettableFuture checkStatId = SettableFuture.create(); + + final RpcJobsQueue isExpecedStatistics = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + final Optional> result = + Optional.> fromNullable(txCache.getIfPresent(key)); + checkStatId.set(Boolean.valueOf(result.isPresent())); + return null; + } + }; + addStatJob(isExpecedStatistics); + return checkStatId; + } + + @Override + public void addNotification(final TransactionAware notification, final NodeId nodeId) { + Preconditions.checkArgument(notification != null, "TransactionAware can not be null!"); + Preconditions.checkArgument(nodeId != null, "NodeId can not be null!"); + + final RpcJobsQueue addNotification = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + final TransactionId txId = notification.getTransactionId(); + final String key = buildCacheKey(txId, nodeId); + final TransactionCacheContainer container = (txCache.getIfPresent(key)); + if (container != null) { + container.addNotif(notification); + } + return null; + } + }; + addStatJob(addNotification); + } + + @Override + public void getAllGroupsStat(final NodeRef nodeRef) { + Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!"); + final RpcJobsQueue getAllGroupStat = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + final GetAllGroupStatisticsInputBuilder builder = + new GetAllGroupStatisticsInputBuilder(); + builder.setNode(nodeRef); + registrationRpcFutureCallBack(groupStatsService + .getAllGroupStatistics(builder.build()), null, nodeRef); + return null; + } + }; + addGetAllStatJob(getAllGroupStat); + } + + @Override + public void getAllMetersStat(final NodeRef nodeRef) { + Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!"); + final RpcJobsQueue getAllMeterStat = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + final GetAllMeterStatisticsInputBuilder builder = + new GetAllMeterStatisticsInputBuilder(); + builder.setNode(nodeRef); + registrationRpcFutureCallBack(meterStatsService + .getAllMeterStatistics(builder.build()), null, nodeRef); + return null; + } + }; + addGetAllStatJob(getAllMeterStat); + } + + @Override + public void getAllFlowsStat(final NodeRef nodeRef) { + Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!"); + final RpcJobsQueue getAllFlowStat = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder builder = + new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder(); + builder.setNode(nodeRef); + registrationRpcFutureCallBack(flowStatsService + .getAllFlowsStatisticsFromAllFlowTables(builder.build()), null, nodeRef); + return null; + } + }; + addGetAllStatJob(getAllFlowStat); + } + + @Override + public void getAggregateFlowStat(final NodeRef nodeRef, final TableId tableId) { + Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!"); + Preconditions.checkArgument(tableId != null, "TableId can not be null!"); + final RpcJobsQueue getAggregateFlowStat = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + final GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder builder = + new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder(); + builder.setNode(nodeRef); + builder.setTableId(tableId); + + final TableBuilder tbuilder = new TableBuilder(); + tbuilder.setId(tableId.getValue()); + tbuilder.setKey(new TableKey(tableId.getValue())); + registrationRpcFutureCallBack(flowStatsService + .getAggregateFlowStatisticsFromFlowTableForAllFlows(builder.build()), tbuilder.build(), nodeRef); + return null; + } + }; + addGetAllStatJob(getAggregateFlowStat); + } + + @Override + public void getAllPortsStat(final NodeRef nodeRef) { + Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!"); + final RpcJobsQueue getAllPortsStat = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + final GetAllNodeConnectorsStatisticsInputBuilder builder = + new GetAllNodeConnectorsStatisticsInputBuilder(); + builder.setNode(nodeRef); + registrationRpcFutureCallBack(portStatsService + .getAllNodeConnectorsStatistics(builder.build()), null, nodeRef); + return null; + } + }; + addGetAllStatJob(getAllPortsStat); + } + + @Override + public void getAllTablesStat(final NodeRef nodeRef) { + Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!"); + final RpcJobsQueue getAllTableStat = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + final GetFlowTablesStatisticsInputBuilder builder = + new GetFlowTablesStatisticsInputBuilder(); + builder.setNode(nodeRef); + registrationRpcFutureCallBack(flowTableStatsService + .getFlowTablesStatistics(builder.build()), null, nodeRef); + return null; + } + }; + addGetAllStatJob(getAllTableStat); + } + + @Override + public void getAllQueueStat(final NodeRef nodeRef) { + Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!"); + final RpcJobsQueue getAllQueueStat = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + final GetAllQueuesStatisticsFromAllPortsInputBuilder builder = + new GetAllQueuesStatisticsFromAllPortsInputBuilder(); + builder.setNode(nodeRef); + registrationRpcFutureCallBack(queueStatsService + .getAllQueuesStatisticsFromAllPorts(builder.build()), null, nodeRef); + return null; + } + }; + addGetAllStatJob(getAllQueueStat); + } + + @Override + public void getAllMeterConfigStat(final NodeRef nodeRef) { + Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!"); + final RpcJobsQueue qetAllMeterConfStat = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + final GetAllMeterConfigStatisticsInputBuilder builder = + new GetAllMeterConfigStatisticsInputBuilder(); + builder.setNode(nodeRef); + registrationRpcFutureCallBack(meterStatsService + .getAllMeterConfigStatistics(builder.build()), null, nodeRef); + return null; + } + }; + addGetAllStatJob(qetAllMeterConfStat); + } + + @Override + public void getGroupFeaturesStat(final NodeRef nodeRef) { + Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!"); + final RpcJobsQueue getGroupFeaturesStat = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + /* RPC input */ + final GetGroupFeaturesInputBuilder input = new GetGroupFeaturesInputBuilder(); + input.setNode(nodeRef); + registrationRpcFutureCallBack(groupStatsService.getGroupFeatures(input.build()), null, nodeRef); + return null; + } + }; + addStatJob(getGroupFeaturesStat); + } + + @Override + public void getMeterFeaturesStat(final NodeRef nodeRef) { + Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!"); + final RpcJobsQueue getMeterFeaturesStat = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + /* RPC input */ + final GetMeterFeaturesInputBuilder input = new GetMeterFeaturesInputBuilder(); + input.setNode(nodeRef); + registrationRpcFutureCallBack(meterStatsService.getMeterFeatures(input.build()), null, nodeRef); + return null; + } + }; + addStatJob(getMeterFeaturesStat); + } + + @Override + public void getAllGroupsConfStats(final NodeRef nodeRef) { + Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!"); + final RpcJobsQueue getAllGropConfStat = new RpcJobsQueue() { + + @Override + public Void call() throws Exception { + Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!"); + final GetGroupDescriptionInputBuilder builder = + new GetGroupDescriptionInputBuilder(); + builder.setNode(nodeRef); + registrationRpcFutureCallBack(groupStatsService + .getGroupDescription(builder.build()), null, nodeRef); + + return null; + } + }; + addGetAllStatJob(getAllGropConfStat); + } + + public class TransactionCacheContainerImpl implements TransactionCacheContainer { + + private final TransactionId id; + private final NodeId nId; + private final List notifications; + private final Optional confInput; + + public TransactionCacheContainerImpl (final TransactionId id, final D input, final NodeId nodeId) { + this.id = Preconditions.checkNotNull(id, "TransactionId can not be null!"); + notifications = new CopyOnWriteArrayList(); + confInput = Optional.fromNullable(input); + nId = nodeId; + } + + @Override + public void addNotif(final T notif) { + notifications.add(notif); + } + + @Override + public TransactionId getId() { + return id; + } + + @Override + public NodeId getNodeId() { + return nId; + } + + @Override + public List getNotifications() { + return notifications; + } + + @Override + public Optional getConfInput() { + return confInput; + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatisticsManagerImpl.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatisticsManagerImpl.java new file mode 100644 index 0000000000..0f8030f620 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatisticsManagerImpl.java @@ -0,0 +1,347 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ThreadFactory; + +import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChain; +import org.opendaylight.controller.md.statistics.manager.StatListeningCommiter; +import org.opendaylight.controller.md.statistics.manager.StatNodeRegistration; +import org.opendaylight.controller.md.statistics.manager.StatNotifyCommiter; +import org.opendaylight.controller.md.statistics.manager.StatPermCollector; +import org.opendaylight.controller.md.statistics.manager.StatPermCollector.StatCapabTypes; +import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager; +import org.opendaylight.controller.md.statistics.manager.StatisticsManager; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +/** +* statistics-manager +* org.opendaylight.controller.md.statistics.manager.impl +* +* StatisticsManagerImpl +* It represent a central point for whole module. Implementation +* {@link StatisticsManager} registers all Operation/DS {@link StatNotifyCommiter} and +* Config/DS {@StatListeningCommiter}, as well as {@link StatPermCollector} +* for statistic collecting and {@link StatRpcMsgManager} as Device RPCs provider. +* In next, StatisticsManager provides all DS contact Transaction services. +* +* @author avishnoi@in.ibm.com Vaclav Demcak +* +*/ +public class StatisticsManagerImpl implements StatisticsManager, Runnable { + + private final static Logger LOG = LoggerFactory.getLogger(StatisticsManagerImpl.class); + + private static final int QUEUE_DEPTH = 5000; + private static final int MAX_BATCH = 100; + + private final BlockingQueue dataStoreOperQueue = new LinkedBlockingDeque<>(QUEUE_DEPTH); + + private final DataBroker dataBroker; + private final int maxNodesForCollectors; + private long minReqNetMonitInt; + private final ExecutorService statRpcMsgManagerExecutor; + private final ExecutorService statDataStoreOperationServ; + private StatRpcMsgManager rpcMsgManager; + private List statCollectors; + private final Object statCollectorLock = new Object(); + private BindingTransactionChain txChain; + private volatile boolean finishing = false; + + private StatNodeRegistration nodeRegistrator; + private StatListeningCommiter flowListeningCommiter; + private StatListeningCommiter meterListeningCommiter; + private StatListeningCommiter groupListeningCommiter; + private StatListeningCommiter queueNotifyCommiter; + private StatNotifyCommiter tableNotifCommiter; + private StatNotifyCommiter portNotifyCommiter; + + public StatisticsManagerImpl (final DataBroker dataBroker, final int maxNodesForCollector) { + this.dataBroker = Preconditions.checkNotNull(dataBroker, "DataBroker can not be null!"); + ThreadFactory threadFact; + threadFact = new ThreadFactoryBuilder().setNameFormat("odl-stat-rpc-oper-thread-%d").build(); + statRpcMsgManagerExecutor = Executors.newSingleThreadExecutor(threadFact); + threadFact = new ThreadFactoryBuilder().setNameFormat("odl-stat-ds-oper-thread-%d").build(); + statDataStoreOperationServ = Executors.newSingleThreadExecutor(threadFact); + maxNodesForCollectors = maxNodesForCollector; + txChain = dataBroker.createTransactionChain(this); + } + + @Override + public void start(final NotificationProviderService notifService, + final RpcConsumerRegistry rpcRegistry, final long minReqNetMonitInt) { + Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !"); + this.minReqNetMonitInt = minReqNetMonitInt; + rpcMsgManager = new StatRpcMsgManagerImpl(this, rpcRegistry, minReqNetMonitInt); + statCollectors = Collections.emptyList(); + nodeRegistrator = new StatNodeRegistrationImpl(this, dataBroker, notifService); + flowListeningCommiter = new StatListenCommitFlow(this, dataBroker, notifService); + meterListeningCommiter = new StatListenCommitMeter(this, dataBroker, notifService); + groupListeningCommiter = new StatListenCommitGroup(this, dataBroker, notifService); + tableNotifCommiter = new StatNotifyCommitTable(this, notifService); + portNotifyCommiter = new StatNotifyCommitPort(this, notifService); + queueNotifyCommiter = new StatListenCommitQueue(this, dataBroker, notifService); + + statRpcMsgManagerExecutor.execute(rpcMsgManager); + statDataStoreOperationServ.execute(this); + LOG.info("Statistics Manager started successfully!"); + } + + @Override + public void close() throws Exception { + finishing = true; + if (nodeRegistrator != null) { + nodeRegistrator.close(); + nodeRegistrator = null; + } + if (flowListeningCommiter != null) { + flowListeningCommiter.close(); + flowListeningCommiter = null; + } + if (meterListeningCommiter != null) { + meterListeningCommiter.close(); + meterListeningCommiter = null; + } + if (groupListeningCommiter != null) { + groupListeningCommiter.close(); + groupListeningCommiter = null; + } + if (tableNotifCommiter != null) { + tableNotifCommiter.close(); + tableNotifCommiter = null; + } + if (portNotifyCommiter != null) { + portNotifyCommiter.close(); + portNotifyCommiter = null; + } + if (queueNotifyCommiter != null) { + queueNotifyCommiter.close(); + queueNotifyCommiter = null; + } + if (statCollectors != null) { + for (StatPermCollector collector : statCollectors) { + collector.close(); + collector = null; + } + statCollectors = null; + } + if (rpcMsgManager != null) { + rpcMsgManager.close(); + rpcMsgManager = null; + } + statRpcMsgManagerExecutor.shutdown(); + statDataStoreOperationServ.shutdown(); + if (txChain != null) { + txChain.close(); + txChain = null; + } + } + + @Override + public void enqueue(final StatDataStoreOperation op) { + // we don't need to block anything - next statistics come soon + final boolean success = dataStoreOperQueue.offer(op); + if ( ! success) { + LOG.debug("Stat DS/Operational submiter Queue is full!"); + } + } + + @Override + public void run() { + /* Neverending cyle - wait for finishing */ + while ( ! finishing) { + try { + StatDataStoreOperation op = dataStoreOperQueue.take(); + final ReadWriteTransaction tx = txChain.newReadWriteTransaction(); + LOG.trace("New operations available, starting transaction {}", tx.getIdentifier()); + + int ops = 0; + do { + op.applyOperation(tx); + + ops++; + if (ops < MAX_BATCH) { + op = dataStoreOperQueue.poll(); + } else { + op = null; + } + } while (op != null); + + LOG.trace("Processed {} operations, submitting transaction {}", ops, tx.getIdentifier()); + + tx.submit().checkedGet(); + } catch (final InterruptedException e) { + LOG.warn("Stat Manager DS Operation thread interupted!", e); + finishing = true; + } catch (final Exception e) { + LOG.warn("Unhandled exception during processing statistics. Restarting transaction chain.", e); + txChain.close(); + txChain = dataBroker.createTransactionChain(StatisticsManagerImpl.this); + cleanDataStoreOperQueue(); + } + } + // Drain all events, making sure any blocked threads are unblocked + cleanDataStoreOperQueue(); + } + + private synchronized void cleanDataStoreOperQueue() { + // Drain all events, making sure any blocked threads are unblocked + while (! dataStoreOperQueue.isEmpty()) { + dataStoreOperQueue.poll(); + } + } + + @Override + public void onTransactionChainFailed(final TransactionChain chain, final AsyncTransaction transaction, + final Throwable cause) { + LOG.warn("Failed to export Flow Capable Statistics, Transaction {} failed.",transaction.getIdentifier(),cause); + } + + @Override + public void onTransactionChainSuccessful(final TransactionChain chain) { + // NOOP + } + + @Override + public boolean isProvidedFlowNodeActive(final InstanceIdentifier nodeIdent) { + for (final StatPermCollector collector : statCollectors) { + if (collector.isProvidedFlowNodeActive(nodeIdent)) { + return true; + } + } + return false; + } + + @Override + public void collectNextStatistics(final InstanceIdentifier nodeIdent) { + for (final StatPermCollector collector : statCollectors) { + if (collector.isProvidedFlowNodeActive(nodeIdent)) { + collector.collectNextStatistics(); + } + } + } + + @Override + public void connectedNodeRegistration(final InstanceIdentifier nodeIdent, + final List statTypes, final Short nrOfSwitchTables) { + for (final StatPermCollector collector : statCollectors) { + if (collector.connectedNodeRegistration(nodeIdent, statTypes, nrOfSwitchTables)) { + return; + } + } + synchronized (statCollectorLock) { + for (final StatPermCollector collector : statCollectors) { + if (collector.connectedNodeRegistration(nodeIdent, statTypes, nrOfSwitchTables)) { + return; + } + } + final StatPermCollectorImpl newCollector = new StatPermCollectorImpl(this, + minReqNetMonitInt, statCollectors.size() + 1, maxNodesForCollectors); + final List statCollectorsNew = new ArrayList<>(statCollectors); + newCollector.connectedNodeRegistration(nodeIdent, statTypes, nrOfSwitchTables); + statCollectorsNew.add(newCollector); + statCollectors = Collections.unmodifiableList(statCollectorsNew); + } + } + + @Override + public void disconnectedNodeUnregistration(final InstanceIdentifier nodeIdent) { + flowListeningCommiter.cleanForDisconnect(nodeIdent); + + for (final StatPermCollector collector : statCollectors) { + if (collector.disconnectedNodeUnregistration(nodeIdent)) { + if ( ! collector.hasActiveNodes()) { + synchronized (statCollectorLock) { + if (collector.hasActiveNodes()) { + return; + } + final List newStatColl = + new ArrayList<>(statCollectors); + newStatColl.remove(collector); + statCollectors = Collections.unmodifiableList(newStatColl); + } + } + return; + } + } + LOG.debug("Node {} has not removed.", nodeIdent); + } + + /* Getter internal Statistic Manager Job Classes */ + @Override + public StatRpcMsgManager getRpcMsgManager() { + return rpcMsgManager; + } + + @Override + public StatNodeRegistration getNodeRegistrator() { + return nodeRegistrator; + } + + @Override + public StatListeningCommiter getFlowListenComit() { + return flowListeningCommiter; + } + + @Override + public StatListeningCommiter getMeterListenCommit() { + return meterListeningCommiter; + } + + @Override + public StatListeningCommiter getGroupListenCommit() { + return groupListeningCommiter; + } + + @Override + public StatListeningCommiter getQueueNotifyCommit() { + return queueNotifyCommiter; + } + + + @Override + public StatNotifyCommiter getTableNotifCommit() { + return tableNotifCommiter; + } + + @Override + public StatNotifyCommiter getPortNotifyCommit() { + return portNotifyCommiter; + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/helper/FlowComparator.java similarity index 80% rename from opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java rename to opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/helper/FlowComparator.java index f3dac826e8..c6205cb13c 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/helper/FlowComparator.java @@ -5,15 +5,14 @@ * 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.md.statistics.manager; +package org.opendaylight.controller.md.statistics.manager.impl.helper; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.net.InetAddresses; import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.UnknownHostException; - 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.yang.types.rev100924.MacAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.MacAddressFilter; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch; @@ -22,19 +21,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026 import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.annotations.VisibleForTesting; - /** * Utility class for comparing flows. */ -final class FlowComparator { - private final static Logger logger = LoggerFactory.getLogger(FlowComparator.class); +public final class FlowComparator { + private final static Logger LOG = LoggerFactory.getLogger(FlowComparator.class); private FlowComparator() { - + throw new UnsupportedOperationException("Utilities class should not be instantiated"); } - public static boolean flowEquals(Flow statsFlow, Flow storedFlow) { + public static boolean flowEquals(final Flow statsFlow, final Flow storedFlow) { if (statsFlow == null || storedFlow == null) { return false; } @@ -93,7 +90,7 @@ final class FlowComparator { * @param storedFlow * @return */ - public static boolean matchEquals(Match statsFlow, Match storedFlow) { + public static boolean matchEquals(final Match statsFlow, final Match storedFlow) { if (statsFlow == storedFlow) { return true; } @@ -194,9 +191,9 @@ final class FlowComparator { * statistic data, openflow driver library returns AA:BB:CC:DD:EE:FF and default eqauls fails here. */ @VisibleForTesting - static boolean ethernetMatchEquals(EthernetMatch statsEthernetMatch, EthernetMatch storedEthernetMatch){ + static boolean ethernetMatchEquals(final EthernetMatch statsEthernetMatch, final EthernetMatch storedEthernetMatch){ boolean verdict = true; - Boolean checkNullValues = checkNullValues(statsEthernetMatch, storedEthernetMatch); + final Boolean checkNullValues = checkNullValues(statsEthernetMatch, storedEthernetMatch); if (checkNullValues != null) { verdict = checkNullValues; } else { @@ -219,10 +216,10 @@ final class FlowComparator { return verdict; } - private static boolean ethernetMatchFieldsEquals(MacAddressFilter statsEthernetMatchFields, - MacAddressFilter storedEthernetMatchFields){ + private static boolean ethernetMatchFieldsEquals(final MacAddressFilter statsEthernetMatchFields, + final MacAddressFilter storedEthernetMatchFields){ boolean verdict = true; - Boolean checkNullValues = checkNullValues(statsEthernetMatchFields, storedEthernetMatchFields); + final Boolean checkNullValues = checkNullValues(statsEthernetMatchFields, storedEthernetMatchFields); if (checkNullValues != null) { verdict = checkNullValues; } else { @@ -236,9 +233,9 @@ final class FlowComparator { return verdict; } - private static boolean macAddressEquals(MacAddress statsMacAddress, MacAddress storedMacAddress){ + private static boolean macAddressEquals(final MacAddress statsMacAddress, final MacAddress storedMacAddress){ boolean verdict = true; - Boolean checkNullValues = checkNullValues(statsMacAddress, storedMacAddress); + final Boolean checkNullValues = checkNullValues(statsMacAddress, storedMacAddress); if (checkNullValues != null) { verdict = checkNullValues; } else { @@ -248,11 +245,11 @@ final class FlowComparator { } @VisibleForTesting - static boolean layer3MatchEquals(Layer3Match statsLayer3Match, Layer3Match storedLayer3Match){ + static boolean layer3MatchEquals(final Layer3Match statsLayer3Match, final Layer3Match storedLayer3Match){ boolean verdict = true; if(statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match){ - Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match; - Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match; + final Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match; + final Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match; if (verdict) { verdict = compareNullSafe( @@ -263,7 +260,7 @@ final class FlowComparator { statsIpv4Match.getIpv4Source(), storedIpv4Match.getIpv4Source()); } } else { - Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match); + final Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match); if (nullCheckOut != null) { verdict = nullCheckOut; } else { @@ -274,9 +271,9 @@ final class FlowComparator { return verdict; } - private static boolean compareNullSafe(Ipv4Prefix statsIpv4, Ipv4Prefix storedIpv4) { + private static boolean compareNullSafe(final Ipv4Prefix statsIpv4, final Ipv4Prefix storedIpv4) { boolean verdict = true; - Boolean checkDestNullValuesOut = checkNullValues(storedIpv4, statsIpv4); + final Boolean checkDestNullValuesOut = checkNullValues(storedIpv4, statsIpv4); if (checkDestNullValuesOut != null) { verdict = checkDestNullValuesOut; } else if(!IpAddressEquals(statsIpv4, storedIpv4)){ @@ -286,7 +283,7 @@ final class FlowComparator { return verdict; } - private static Boolean checkNullValues(Object v1, Object v2) { + private static Boolean checkNullValues(final Object v1, final Object v2) { Boolean verdict = null; if (v1 == null && v2 != null) { verdict = Boolean.FALSE; @@ -306,9 +303,9 @@ final class FlowComparator { * @param storedIpAddress * @return true if IPv4prefixes equals */ - private static boolean IpAddressEquals(Ipv4Prefix statsIpAddress, Ipv4Prefix storedIpAddress) { - IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue()); - IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue()); + private static boolean IpAddressEquals(final Ipv4Prefix statsIpAddress, final Ipv4Prefix storedIpAddress) { + final IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue()); + final IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue()); if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){ return true; @@ -319,11 +316,11 @@ final class FlowComparator { return false; } - private static boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){ + private static boolean IpAndMaskBasedMatch(final IntegerIpAddress statsIpAddressInt,final IntegerIpAddress storedIpAddressInt){ return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) == (storedIpAddressInt.getIp() & storedIpAddressInt.getMask())); } - private static boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){ + private static boolean IpBasedMatch(final IntegerIpAddress statsIpAddressInt,final IntegerIpAddress storedIpAddressInt){ return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp()); } @@ -331,10 +328,10 @@ final class FlowComparator { * Method return integer version of ip address. Converted int will be mask if * mask specified */ - private static IntegerIpAddress StrIpToIntIp(String ipAddresss){ + private static IntegerIpAddress StrIpToIntIp(final String ipAddresss){ - String[] parts = ipAddresss.split("/"); - String ip = parts[0]; + final String[] parts = ipAddresss.split("/"); + final String ip = parts[0]; int prefix; if (parts.length < 2) { @@ -344,20 +341,19 @@ final class FlowComparator { } IntegerIpAddress integerIpAddress = null; - try { - Inet4Address addr = (Inet4Address) InetAddress.getByName(ip); - byte[] addrBytes = addr.getAddress(); - int ipInt = ((addrBytes[0] & 0xFF) << 24) | + + final Inet4Address addr = ((Inet4Address) InetAddresses.forString(ip)); + final byte[] addrBytes = addr.getAddress(); + final int ipInt = ((addrBytes[0] & 0xFF) << 24) | ((addrBytes[1] & 0xFF) << 16) | ((addrBytes[2] & 0xFF) << 8) | ((addrBytes[3] & 0xFF) << 0); - int mask = 0xffffffff << 32 - prefix; + // FIXME: Is this valid? + final int mask = 0xffffffff << 32 - prefix; integerIpAddress = new IntegerIpAddress(ipInt, mask); - } catch (UnknownHostException e){ - logger.error("Failed to determine host IP address by name: {}", e.getMessage(), e); - } + return integerIpAddress; } @@ -365,7 +361,7 @@ final class FlowComparator { private static class IntegerIpAddress{ int ip; int mask; - public IntegerIpAddress(int ip, int mask) { + public IntegerIpAddress(final int ip, final int mask) { this.ip = ip; this.mask = mask; } diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerProvider.java b/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerProvider.java new file mode 100644 index 0000000000..6a01cd2c26 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerProvider.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.statistics.manager; + +/** + * statistics-manager + * org.opendaylight.controller.md.statistics.manager + * + * + * + * @author Vaclav Demcak + * + * Created: Sep 6, 2014 + */ +public class StatisticsManagerProvider { + + private final StatisticsManagerActivator activator; + + public StatisticsManagerProvider(final StatisticsManagerActivator activator) { + this.activator = activator; + } + + /** + * Method provides Initialized {@link StatisticsManager} + * from {@link StatisticsManagerActivator} for all tests + * suites; + * + * @return + */ + public StatisticsManager getStatisticsManager() { + return activator.getStatisticManager(); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/impl/helper/StatisticsUpdateCommiterTest.java similarity index 81% rename from opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java rename to opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/impl/helper/StatisticsUpdateCommiterTest.java index a687b1f280..9361e281e9 100644 --- a/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java +++ b/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/impl/helper/StatisticsUpdateCommiterTest.java @@ -6,7 +6,7 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.controller.md.statistics.manager; +package org.opendaylight.controller.md.statistics.manager.impl.helper; import org.junit.Assert; import org.junit.Test; @@ -35,7 +35,7 @@ public class StatisticsUpdateCommiterTest { */ @Test public void testLayer3MatchEquals() { - String[][][] matchSeeds = new String[][][] { + final String[][][] matchSeeds = new String[][][] { {{"10.1.2.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}}, {{"10.1.2.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.1.0/24"}}, {{"10.1.1.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}}, @@ -55,7 +55,7 @@ public class StatisticsUpdateCommiterTest { {{null, null}, {null, null}}, }; - boolean[] matches = new boolean[] { + final boolean[] matches = new boolean[] { true, false, false, @@ -91,23 +91,23 @@ public class StatisticsUpdateCommiterTest { * @param matches expected match output * */ - private static void checkComparisonOfL3Match(String m1Source, String m1Destination, - String m2Source, String msDestination, boolean matches) { - Ipv4Match m1Layer3 = prepareIPv4Match(m1Source, m1Destination); - Ipv4Match m2Layer3 = prepareIPv4Match(m2Source, msDestination); + private static void checkComparisonOfL3Match(final String m1Source, final String m1Destination, + final String m2Source, final String msDestination, final boolean matches) { + final Ipv4Match m1Layer3 = prepareIPv4Match(m1Source, m1Destination); + final Ipv4Match m2Layer3 = prepareIPv4Match(m2Source, msDestination); boolean comparisonResult; try { comparisonResult = FlowComparator.layer3MatchEquals(m1Layer3, m2Layer3); Assert.assertEquals("failed to compare: "+m1Layer3+" vs. "+m2Layer3, matches, comparisonResult); - } catch (Exception e) { + } catch (final Exception e) { LOG.error("failed to compare: {} vs. {}", m1Layer3, m2Layer3, e); Assert.fail(e.getMessage()); } } - private static Ipv4Match prepareIPv4Match(String source, String destination) { - Ipv4MatchBuilder ipv4MatchBuilder = new Ipv4MatchBuilder(); + private static Ipv4Match prepareIPv4Match(final String source, final String destination) { + final Ipv4MatchBuilder ipv4MatchBuilder = new Ipv4MatchBuilder(); if (source != null) { ipv4MatchBuilder.setIpv4Source(new Ipv4Prefix(source)); } @@ -118,11 +118,11 @@ public class StatisticsUpdateCommiterTest { return ipv4MatchBuilder.build(); } /** - * Test method for {@link org.opendaylight.controller.md.statistics.manager.FlowComparator#ethernetMatchEquals(EthernetMatch, EthernetMatch) + * Test method for {@link org.opendaylight.controller.md.statistics.manager.impl.helper.FlowComparator#ethernetMatchEquals(EthernetMatch, EthernetMatch) */ @Test public void testEthernetMatchEquals() { - String[][][] ethernetMatchSeeds = new String[][][] { + final String[][][] ethernetMatchSeeds = new String[][][] { {{"aa:bb:cc:dd:ee:ff", "ff:ff:ff:ff:ff:ff","0800"}, {"aa:bb:cc:dd:ee:ff", "ff:ff:ff:ff:ff:ff","0800"}}, {{"aa:bb:cc:dd:ee:ff", "ff:ff:ff:ff:ff:ff","0800"}, {"aa:bb:bc:cd:ee:ff", "ff:ff:ff:ff:ff:ff","0800"}}, {{"aa:bb:cc:dd:ee:ff", "ff:ff:ff:ff:ff:ff","0800"}, {"AA:BB:CC:DD:EE:FF", "ff:ff:ff:ff:ff:ff","0800"}}, @@ -143,7 +143,7 @@ public class StatisticsUpdateCommiterTest { {{null, null,null}, {null, null,null}}, }; - boolean[] matches = new boolean[] { + final boolean[] matches = new boolean[] { true, false, true, @@ -176,24 +176,24 @@ public class StatisticsUpdateCommiterTest { * @param ethernetMatch1 * @param ethernetMatch2 */ - private static void checkComparisonOfEthernetMatch(String macAddress1, String macAddressMask1,String etherType1, - String macAddress2, String macAddressMask2,String etherType2, boolean expectedResult) { - EthernetMatch ethernetMatch1 = prepareEthernetMatch(macAddress1, macAddressMask1,etherType1); - EthernetMatch ethernetMatch2 = prepareEthernetMatch(macAddress2, macAddressMask2,etherType2); + private static void checkComparisonOfEthernetMatch(final String macAddress1, final String macAddressMask1,final String etherType1, + final String macAddress2, final String macAddressMask2,final String etherType2, final boolean expectedResult) { + final EthernetMatch ethernetMatch1 = prepareEthernetMatch(macAddress1, macAddressMask1,etherType1); + final EthernetMatch ethernetMatch2 = prepareEthernetMatch(macAddress2, macAddressMask2,etherType2); boolean comparisonResult; try { comparisonResult = FlowComparator.ethernetMatchEquals(ethernetMatch1, ethernetMatch2); Assert.assertEquals("failed to compare: "+ethernetMatch1+" vs. "+ethernetMatch2, expectedResult, comparisonResult); - } catch (Exception e) { + } catch (final Exception e) { LOG.error("failed to compare: {} vs. {}", ethernetMatch1, ethernetMatch2, e); Assert.fail(e.getMessage()); } } - private static EthernetMatch prepareEthernetMatch(String macAddress, String macAddressMask, String etherType) { - EthernetMatchBuilder ethernetMatchBuilder = new EthernetMatchBuilder(); - EthernetSourceBuilder ethernetSourceBuilder = new EthernetSourceBuilder(); + private static EthernetMatch prepareEthernetMatch(final String macAddress, final String macAddressMask, final String etherType) { + final EthernetMatchBuilder ethernetMatchBuilder = new EthernetMatchBuilder(); + final EthernetSourceBuilder ethernetSourceBuilder = new EthernetSourceBuilder(); if (macAddress != null) { ethernetSourceBuilder.setAddress(new MacAddress(macAddress)); } @@ -201,7 +201,7 @@ public class StatisticsUpdateCommiterTest { ethernetSourceBuilder.setMask(new MacAddress(macAddressMask)); } if(etherType != null){ - EthernetTypeBuilder ethernetType = new EthernetTypeBuilder(); + final EthernetTypeBuilder ethernetType = new EthernetTypeBuilder(); ethernetType.setType(new EtherType(Long.parseLong(etherType,16))); ethernetMatchBuilder.setEthernetType(ethernetType.build()); } diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/FlowStatisticsTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/FlowStatisticsTest.java new file mode 100644 index 0000000000..7fc171c49b --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/FlowStatisticsTest.java @@ -0,0 +1,159 @@ +package test.mock; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Collections; +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatisticsManagerActivator; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityFlowStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import test.mock.util.StatisticsManagerTest; + +import com.google.common.base.Optional; + +public class FlowStatisticsTest extends StatisticsManagerTest { + private final Object waitObject = new Object(); + +// @Test(timeout = 5000) + public void addedFlowOnDemandStatsTest() throws ExecutionException, InterruptedException, ReadFailedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNode(s1Key); + + final Flow flow = getFlow(); + + final InstanceIdentifier flowII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(flow.getTableId())) + .child(Flow.class, flow.getKey()); + final InstanceIdentifier
    tableII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(flow.getTableId())); + final Table table = new TableBuilder().setKey(new TableKey(flow.getTableId())).setFlow(Collections.emptyList()).build(); + + final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, tableII, table); + writeTx.put(LogicalDatastoreType.CONFIGURATION, flowII, flow); + writeTx.put(LogicalDatastoreType.OPERATIONAL, tableII, table); + writeTx.put(LogicalDatastoreType.OPERATIONAL, flowII, flow); + assertCommit(writeTx.submit()); + + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + flowII.augmentation(FlowStatisticsData.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + final ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + final Optional flowStatDataOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, flowII.augmentation(FlowStatisticsData.class)) + .checkedGet(); + assertTrue(flowStatDataOptional.isPresent()); + assertEquals(COUNTER_64_TEST_VALUE, flowStatDataOptional.get().getFlowStatistics().getByteCount()); + + } + +// @Test(timeout = 5000) + public void deletedFlowStatsRemovalTest() throws ExecutionException, InterruptedException, ReadFailedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNode(s1Key); + + final Flow flow = getFlow(); + + final InstanceIdentifier flowII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(flow.getTableId())) + .child(Flow.class, flow.getKey()); + final InstanceIdentifier
    tableII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(flow.getTableId())); + final Table table = new TableBuilder().setKey(new TableKey(flow.getTableId())).setFlow(Collections.emptyList()).build(); + + WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, tableII, table); + writeTx.put(LogicalDatastoreType.CONFIGURATION, flowII, flow); + writeTx.put(LogicalDatastoreType.OPERATIONAL, tableII, table); + writeTx.put(LogicalDatastoreType.OPERATIONAL, flowII, flow); + + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + flowII.augmentation(FlowStatisticsData.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + assertCommit(writeTx.submit()); + + synchronized (waitObject) { + waitObject.wait(); + } + + ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + Optional flowStatDataOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, flowII).checkedGet(); + assertTrue(flowStatDataOptional.isPresent()); +// assertEquals(COUNTER_64_TEST_VALUE, flowStatDataOptional.get().getFlowStatistics().getByteCount()); + + writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.delete(LogicalDatastoreType.CONFIGURATION, flowII); + assertCommit(writeTx.submit()); + + readTx = getDataBroker().newReadOnlyTransaction(); + flowStatDataOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, flowII).checkedGet(); + assertFalse(flowStatDataOptional.isPresent()); + } + +// @Test(timeout = 23000) + public void getAllStatsWhenNodeIsConnectedTest() throws ExecutionException, InterruptedException, ReadFailedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNodeWithFeatures(s1Key, false, FlowFeatureCapabilityFlowStats.class); + + final Flow flow = getFlow(); + + final InstanceIdentifier
    tableII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(flow.getTableId())); + + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + tableII.child(Flow.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + final ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + final Optional
    tableOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class) + .child(Node.class, s1Key).augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(flow.getTableId()))).checkedGet(); + assertTrue(tableOptional.isPresent()); + final FlowStatisticsData flowStats = tableOptional.get().getFlow().get(0).getAugmentation(FlowStatisticsData.class); + assertTrue(flowStats != null); + assertEquals(COUNTER_64_TEST_VALUE, flowStats.getFlowStatistics().getByteCount()); + } + + public class ChangeListener implements DataChangeListener { + + @Override + public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { + synchronized (waitObject) { + waitObject.notify(); + } + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/GroupStatisticsTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/GroupStatisticsTest.java new file mode 100644 index 0000000000..7a61bf280f --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/GroupStatisticsTest.java @@ -0,0 +1,151 @@ +package test.mock; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatisticsManagerActivator; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityGroupStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import test.mock.util.StatisticsManagerTest; + +import com.google.common.base.Optional; + +public class GroupStatisticsTest extends StatisticsManagerTest { + private final Object waitObject = new Object(); + +// @Test(timeout = 5000) + public void addedGroupOnDemandStatsTest() throws ExecutionException, InterruptedException, ReadFailedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNode(s1Key); + + final Group group = getGroup(); + + final InstanceIdentifier groupII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .augmentation(FlowCapableNode.class).child(Group.class, group.getKey()); + + final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, groupII, group); + writeTx.put(LogicalDatastoreType.OPERATIONAL, groupII, group); + assertCommit(writeTx.submit()); + + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + groupII.augmentation(NodeGroupStatistics.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + final ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + final Optional groupOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, groupII.augmentation(NodeGroupStatistics.class)).checkedGet(); + assertTrue(groupOptional.isPresent()); + assertEquals(COUNTER_64_TEST_VALUE, groupOptional.get().getGroupStatistics().getByteCount()); + } + +// @Test(timeout = 5000) + public void deletedGroupStasRemovalTest() throws ExecutionException, InterruptedException, ReadFailedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNode(s1Key); + + final Group group = getGroup(); + final InstanceIdentifier groupII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .augmentation(FlowCapableNode.class).child(Group.class, group.getKey()); + + WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, groupII, group); + writeTx.put(LogicalDatastoreType.OPERATIONAL, groupII, group); + assertCommit(writeTx.submit()); + + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + groupII.augmentation(NodeGroupStatistics.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + Optional groupOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, + groupII.augmentation(NodeGroupStatistics.class)).checkedGet(); + assertTrue(groupOptional.isPresent()); + assertEquals(COUNTER_64_TEST_VALUE, groupOptional.get().getGroupStatistics().getByteCount()); + + writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.delete(LogicalDatastoreType.CONFIGURATION, groupII); + assertCommit(writeTx.submit()); + + readTx = getDataBroker().newReadOnlyTransaction(); + groupOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, + groupII.augmentation(NodeGroupStatistics.class)).checkedGet(); + assertFalse(groupOptional.isPresent()); + + } + +// @Test(timeout = 23000) + public void getAllStatsFromConnectedNodeTest() throws ExecutionException, InterruptedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNodeWithFeatures(s1Key, false, FlowFeatureCapabilityGroupStats.class); + + final InstanceIdentifier groupII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .augmentation(FlowCapableNode.class).child(Group.class, getGroup().getKey()); + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + groupII.augmentation(NodeGroupStatistics.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + final Optional optionalGroup = readTx.read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class) + .child(Node.class, s1Key).augmentation(FlowCapableNode.class) + .child(Group.class, getGroup().getKey())).get(); + + assertTrue(optionalGroup.isPresent()); + assertTrue(optionalGroup.get().getAugmentation(NodeGroupDescStats.class) != null); + final NodeGroupStatistics groupStats = optionalGroup.get().getAugmentation(NodeGroupStatistics.class); + assertTrue(groupStats != null); + assertEquals(COUNTER_64_TEST_VALUE, groupStats.getGroupStatistics().getByteCount()); + + readTx = getDataBroker().newReadOnlyTransaction(); + final Optional optionalGroupFeatures = readTx.read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class) + .child(Node.class, s1Key).augmentation(NodeGroupFeatures.class).child(GroupFeatures.class)).get(); + assertTrue(optionalGroupFeatures.isPresent()); + assertEquals(1, optionalGroupFeatures.get().getMaxGroups().size()); + assertEquals(MAX_GROUPS_TEST_VALUE, optionalGroupFeatures.get().getMaxGroups().get(0)); + } + + private class ChangeListener implements DataChangeListener { + + @Override + public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { + synchronized (waitObject) { + waitObject.notify(); + } + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/MeterStatisticsTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/MeterStatisticsTest.java new file mode 100644 index 0000000000..a0f360c475 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/MeterStatisticsTest.java @@ -0,0 +1,150 @@ +package test.mock; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatisticsManagerActivator; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeatures; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import test.mock.util.StatisticsManagerTest; + +import com.google.common.base.Optional; + +public class MeterStatisticsTest extends StatisticsManagerTest { + private final Object waitObject = new Object(); + +// @Test(timeout = 5000) + public void addedMeterOnDemandStatsTest() throws ExecutionException, InterruptedException, ReadFailedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNode(s1Key); + + final Meter meter = getMeter(); + final InstanceIdentifier meterII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .augmentation(FlowCapableNode.class).child(Meter.class, meter.getKey()); + + final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, meterII, meter); + writeTx.put(LogicalDatastoreType.OPERATIONAL, meterII, meter); + assertCommit(writeTx.submit()); + + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + meterII.augmentation(NodeMeterStatistics.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + final ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + final Optional meterStatsOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, + meterII.augmentation(NodeMeterStatistics.class)).checkedGet(); + assertTrue(meterStatsOptional.isPresent()); + assertEquals(COUNTER_64_TEST_VALUE, meterStatsOptional.get().getMeterStatistics().getByteInCount()); + assertEquals(COUNTER_64_TEST_VALUE, meterStatsOptional.get().getMeterStatistics().getPacketInCount()); + } + +// @Test(timeout = 5000) + public void deletedMeterStatsRemovalTest() throws ExecutionException, InterruptedException, ReadFailedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNode(s1Key); + + final Meter meter = getMeter(); + final InstanceIdentifier meterII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .augmentation(FlowCapableNode.class).child(Meter.class, meter.getKey()); + + WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, meterII, meter); + writeTx.put(LogicalDatastoreType.OPERATIONAL, meterII, meter); + assertCommit(writeTx.submit()); + + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + meterII.augmentation(NodeMeterStatistics.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + final Optional meterStatsOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, + meterII.augmentation(NodeMeterStatistics.class)).checkedGet(); + assertTrue(meterStatsOptional.isPresent()); + assertEquals(COUNTER_64_TEST_VALUE, meterStatsOptional.get().getMeterStatistics().getByteInCount()); + assertEquals(COUNTER_64_TEST_VALUE, meterStatsOptional.get().getMeterStatistics().getPacketInCount()); + + writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.delete(LogicalDatastoreType.CONFIGURATION, meterII); + assertCommit(writeTx.submit()); + + readTx = getDataBroker().newReadOnlyTransaction(); + final Optional meterOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, meterII).checkedGet(); + assertFalse(meterOptional.isPresent()); + } + +// @Test(timeout = 23000) + public void getAllStatsFromConnectedNodeTest() throws ExecutionException, InterruptedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNodeWithFeatures(s1Key, true); + + final InstanceIdentifier meterII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .augmentation(FlowCapableNode.class).child(Meter.class, getMeter().getKey()); + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + meterII.augmentation(NodeMeterStatistics.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + final Optional optionalMeter = readTx.read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class) + .child(Node.class, s1Key).augmentation(FlowCapableNode.class) + .child(Meter.class, getMeter().getKey())).get(); + + assertTrue(optionalMeter.isPresent()); + assertTrue(optionalMeter.get().getAugmentation(NodeMeterConfigStats.class) != null); + final NodeMeterStatistics meterStats = optionalMeter.get().getAugmentation(NodeMeterStatistics.class); + assertTrue(meterStats != null); + assertEquals(COUNTER_64_TEST_VALUE, meterStats.getMeterStatistics().getByteInCount()); + assertEquals(COUNTER_64_TEST_VALUE, meterStats.getMeterStatistics().getPacketInCount()); + + readTx = getDataBroker().newReadOnlyTransaction(); + final Optional optionalMeterFeautures = readTx.read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class) + .child(Node.class, s1Key).augmentation(NodeMeterFeatures.class).child(MeterFeatures.class)).get(); + assertTrue(optionalMeterFeautures.isPresent()); + assertEquals(COUNTER_32_TEST_VALUE, optionalMeterFeautures.get().getMaxMeter()); + } + + private class ChangeListener implements DataChangeListener { + + @Override + public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { + synchronized (waitObject) { + waitObject.notify(); + } + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/NodeRegistrationTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/NodeRegistrationTest.java new file mode 100644 index 0000000000..18bd2d42ef --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/NodeRegistrationTest.java @@ -0,0 +1,48 @@ +package test.mock; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.md.statistics.manager.StatisticsManagerActivator; +import org.opendaylight.controller.md.statistics.manager.StatisticsManagerProvider; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import test.mock.util.StatisticsManagerTest; + +public class NodeRegistrationTest extends StatisticsManagerTest { + +// @Test + public void nodeRegistrationTest() throws ExecutionException, InterruptedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + final StatisticsManagerProvider statisticsManagerProvider = new StatisticsManagerProvider(activator); + activator.onSessionInitiated(providerContext); + + addFlowCapableNode(s1Key); + Thread.sleep(1000); + final InstanceIdentifier nodeII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key); + + assertTrue(statisticsManagerProvider.getStatisticsManager().isProvidedFlowNodeActive(nodeII)); + } + +// @Test + public void nodeUnregistrationTest() throws ExecutionException, InterruptedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + final StatisticsManagerProvider statisticsManagerProvider = new StatisticsManagerProvider(activator); + activator.onSessionInitiated(providerContext); + + addFlowCapableNode(s1Key); + Thread.sleep(1000); + final InstanceIdentifier nodeII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key); + + assertTrue(statisticsManagerProvider.getStatisticsManager().isProvidedFlowNodeActive(nodeII)); + + removeNode(s1Key); + Thread.sleep(1000); + assertFalse(statisticsManagerProvider.getStatisticsManager().isProvidedFlowNodeActive(nodeII)); + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/PortStatisticsTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/PortStatisticsTest.java new file mode 100644 index 0000000000..9f193b03d7 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/PortStatisticsTest.java @@ -0,0 +1,73 @@ +package test.mock; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatisticsManagerActivator; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityPortStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import test.mock.util.StatisticsManagerTest; + +import com.google.common.base.Optional; + +public class PortStatisticsTest extends StatisticsManagerTest { + private final Object waitObject = new Object(); + +// @Test(timeout = 23000) + public void getPortStatisticsTest() throws ExecutionException, InterruptedException, ReadFailedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNodeWithFeatures(s1Key, false, FlowFeatureCapabilityPortStats.class); + + final InstanceIdentifier nodeConnectorII = InstanceIdentifier.create(Nodes.class) + .child(Node.class, s1Key).child(NodeConnector.class, new NodeConnectorKey(getNodeConnectorId())); + + + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + nodeConnectorII.augmentation(FlowCapableNodeConnectorStatisticsData.class), + new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + final ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + final Optional flowCapableNodeConnectorStatisticsDataOptional = + readTx.read(LogicalDatastoreType.OPERATIONAL, + nodeConnectorII.augmentation(FlowCapableNodeConnectorStatisticsData.class)).checkedGet(); + assertTrue(flowCapableNodeConnectorStatisticsDataOptional.isPresent()); + assertEquals(BIG_INTEGER_TEST_VALUE, + flowCapableNodeConnectorStatisticsDataOptional.get().getFlowCapableNodeConnectorStatistics() + .getReceiveDrops()); + assertEquals(BIG_INTEGER_TEST_VALUE, + flowCapableNodeConnectorStatisticsDataOptional.get().getFlowCapableNodeConnectorStatistics() + .getCollisionCount()); + } + + private class ChangeListener implements DataChangeListener { + + @Override + public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { + synchronized (waitObject) { + waitObject.notify(); + } + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/QueueStatisticsTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/QueueStatisticsTest.java new file mode 100644 index 0000000000..bb9bd21134 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/QueueStatisticsTest.java @@ -0,0 +1,197 @@ +package test.mock; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Collections; +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatisticsManagerActivator; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityQueueStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.port.mod.port.Port; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import test.mock.util.StatisticsManagerTest; + +import com.google.common.base.Optional; + + +public class QueueStatisticsTest extends StatisticsManagerTest { + private final Object waitObject = new Object(); + +// @Test(timeout = 5000) + public void addedQueueOnDemandStatsTest() throws ExecutionException, InterruptedException, ReadFailedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNode(s1Key); + + final Port port = getPort(); + + final NodeConnectorBuilder ncBuilder = new NodeConnectorBuilder(); + final FlowCapableNodeConnectorBuilder fcncBuilder = new FlowCapableNodeConnectorBuilder(); + fcncBuilder.setConfiguration(port.getConfiguration()); + fcncBuilder.setPortNumber(port.getPortNumber()); + fcncBuilder.setQueue(Collections.emptyList()); + ncBuilder.setKey(new NodeConnectorKey(new NodeConnectorId("connector.1"))); + ncBuilder.addAugmentation(FlowCapableNodeConnector.class, fcncBuilder.build()); + + + final Queue queue = getQueue(); + final InstanceIdentifier queueII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .child(NodeConnector.class, ncBuilder.getKey()).augmentation(FlowCapableNodeConnector.class) + .child(Queue.class, queue.getKey()); + final InstanceIdentifier nodeConnectorII = InstanceIdentifier.create(Nodes.class) + .child(Node.class, s1Key).child(NodeConnector.class, ncBuilder.getKey()); + + final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, nodeConnectorII, ncBuilder.build()); + writeTx.put(LogicalDatastoreType.CONFIGURATION, queueII, queue); + writeTx.put(LogicalDatastoreType.OPERATIONAL, nodeConnectorII, ncBuilder.build()); + writeTx.put(LogicalDatastoreType.OPERATIONAL, queueII, queue); + assertCommit(writeTx.submit()); + + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + queueII.augmentation(FlowCapableNodeConnectorQueueStatisticsData.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + final ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + final Optional queueStatsOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, + queueII.augmentation(FlowCapableNodeConnectorQueueStatisticsData.class)).checkedGet(); + assertTrue(queueStatsOptional.isPresent()); + assertEquals(COUNTER_64_TEST_VALUE, + queueStatsOptional.get().getFlowCapableNodeConnectorQueueStatistics().getTransmittedBytes()); + } + +// @Test(timeout = 5000) + public void deletedQueueStatsRemovalTest() throws ExecutionException, InterruptedException, ReadFailedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNode(s1Key); + + final Port port = getPort(); + + final NodeConnectorBuilder ncBuilder = new NodeConnectorBuilder(); + final FlowCapableNodeConnectorBuilder fcncBuilder = new FlowCapableNodeConnectorBuilder(); + fcncBuilder.setConfiguration(port.getConfiguration()); + fcncBuilder.setPortNumber(port.getPortNumber()); + fcncBuilder.setQueue(Collections.emptyList()); + ncBuilder.setKey(new NodeConnectorKey(new NodeConnectorId("connector.1"))); + ncBuilder.addAugmentation(FlowCapableNodeConnector.class, fcncBuilder.build()); + + + final Queue queue = getQueue(); + final InstanceIdentifier queueII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .child(NodeConnector.class, ncBuilder.getKey()).augmentation(FlowCapableNodeConnector.class) + .child(Queue.class, queue.getKey()); + final InstanceIdentifier nodeConnectorII = InstanceIdentifier.create(Nodes.class) + .child(Node.class, s1Key).child(NodeConnector.class, ncBuilder.getKey()); + + WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, nodeConnectorII, ncBuilder.build()); + writeTx.put(LogicalDatastoreType.CONFIGURATION, queueII, queue); + writeTx.put(LogicalDatastoreType.OPERATIONAL, nodeConnectorII, ncBuilder.build()); + writeTx.put(LogicalDatastoreType.OPERATIONAL, queueII, queue); + assertCommit(writeTx.submit()); + + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + queueII.augmentation(FlowCapableNodeConnectorQueueStatisticsData.class), + new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + Optional queueStatsOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, + queueII.augmentation(FlowCapableNodeConnectorQueueStatisticsData.class)).checkedGet(); + assertTrue(queueStatsOptional.isPresent()); + assertEquals(COUNTER_64_TEST_VALUE, + queueStatsOptional.get().getFlowCapableNodeConnectorQueueStatistics().getTransmittedBytes()); + + writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.delete(LogicalDatastoreType.CONFIGURATION, queueII); + assertCommit(writeTx.submit()); + + readTx = getDataBroker().newReadOnlyTransaction(); + queueStatsOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, + queueII.augmentation(FlowCapableNodeConnectorQueueStatisticsData.class)).checkedGet(); + assertFalse(queueStatsOptional.isPresent()); + } + +// @Test(timeout = 23000) + public void getAllStatsFromConnectedNodeTest() throws ExecutionException, InterruptedException, ReadFailedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNodeWithFeatures(s1Key, false, FlowFeatureCapabilityQueueStats.class); + + final NodeConnectorBuilder ncBuilder = new NodeConnectorBuilder(); + final FlowCapableNodeConnectorBuilder fcncBuilder = new FlowCapableNodeConnectorBuilder(); + ncBuilder.setKey(new NodeConnectorKey(getNodeConnectorId())); + ncBuilder.addAugmentation(FlowCapableNodeConnector.class, fcncBuilder.build()); + + final InstanceIdentifier nodeConnectorII = InstanceIdentifier.create(Nodes.class) + .child(Node.class, s1Key) + .child(NodeConnector.class, ncBuilder.getKey()); + + final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.OPERATIONAL, nodeConnectorII, ncBuilder.build()); + final InstanceIdentifier queueII = nodeConnectorII.augmentation(FlowCapableNodeConnector.class) + .child(Queue.class, getQueue().getKey()); + final QueueBuilder qBuilder = new QueueBuilder(getQueue()); + writeTx.put(LogicalDatastoreType.OPERATIONAL, queueII, qBuilder.build()); + assertCommit(writeTx.submit()); + + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + queueII.augmentation(FlowCapableNodeConnectorQueueStatisticsData.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + final ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + final Optional queueOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, queueII).checkedGet(); + assertTrue(queueOptional.isPresent()); + final FlowCapableNodeConnectorQueueStatisticsData queueStats = + queueOptional.get().getAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class); + assertTrue(queueStats != null); + assertEquals(COUNTER_64_TEST_VALUE, + queueStats.getFlowCapableNodeConnectorQueueStatistics().getTransmittedBytes()); + } + + private class ChangeListener implements DataChangeListener { + + @Override + public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { + synchronized (waitObject) { + waitObject.notify(); + } + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/TableStatisticsTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/TableStatisticsTest.java new file mode 100644 index 0000000000..f0c0fedb70 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/TableStatisticsTest.java @@ -0,0 +1,71 @@ +package test.mock; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.statistics.manager.StatisticsManagerActivator; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityTableStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import test.mock.util.StatisticsManagerTest; + +import com.google.common.base.Optional; + +public class TableStatisticsTest extends StatisticsManagerTest { + private final Object waitObject = new Object(); + +// @Test(timeout = 23000) + public void getTableStatisticsTest() throws ExecutionException, InterruptedException, ReadFailedException { + final StatisticsManagerActivator activator = new StatisticsManagerActivator(); + activator.onSessionInitiated(providerContext); + + addFlowCapableNodeWithFeatures(s1Key, false, FlowFeatureCapabilityTableStats.class); + + final TableId tableId = getTableId(); + final InstanceIdentifier
    tableII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId.getValue())); + + getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + tableII.augmentation(FlowTableStatisticsData.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE); + + synchronized (waitObject) { + waitObject.wait(); + } + + final ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + final Optional flowTableStatisticsDataOptional = readTx.read( + LogicalDatastoreType.OPERATIONAL, tableII.augmentation(FlowTableStatisticsData.class)).checkedGet(); + assertTrue(flowTableStatisticsDataOptional.isPresent()); + assertEquals(COUNTER_32_TEST_VALUE, + flowTableStatisticsDataOptional.get().getFlowTableStatistics().getActiveFlows()); + assertEquals(COUNTER_64_TEST_VALUE, + flowTableStatisticsDataOptional.get().getFlowTableStatistics().getPacketsLookedUp()); + } + + private class ChangeListener implements DataChangeListener { + + @Override + public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { + synchronized (waitObject) { + waitObject.notify(); + } + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/AbstractDataBrokerTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/AbstractDataBrokerTest.java new file mode 100644 index 0000000000..f9efa51d41 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/AbstractDataBrokerTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package test.mock.util; + +import com.google.common.util.concurrent.ListenableFuture; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class AbstractDataBrokerTest extends AbstractSchemaAwareTest { + + private DataBrokerTestCustomizer testCustomizer; + private DataBroker dataBroker; + private DOMDataBroker domBroker; + + + @Override + protected void setupWithSchema(final SchemaContext context) { + testCustomizer = createDataBrokerTestCustomizer(); + dataBroker = testCustomizer.createDataBroker(); + domBroker = testCustomizer.createDOMDataBroker(); + testCustomizer.updateSchema(context); + setupWithDataBroker(dataBroker); + } + + protected void setupWithDataBroker(final DataBroker dataBroker) { + // Intentionally left No-op, subclasses may customize it + } + + protected DataBrokerTestCustomizer createDataBrokerTestCustomizer() { + return new DataBrokerTestCustomizer(); + } + + public DataBroker getDataBroker() { + return dataBroker; + } + + public DOMDataBroker getDomBroker() { + return domBroker; + } + + protected static final void assertCommit(final ListenableFuture commit) { + try { + commit.get(500, TimeUnit.MILLISECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + throw new IllegalStateException(e); + } + } + + +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/AbstractSchemaAwareTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/AbstractSchemaAwareTest.java new file mode 100644 index 0000000000..d520d59cdd --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/AbstractSchemaAwareTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package test.mock.util; + +import org.junit.Before; +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; +import org.opendaylight.yangtools.yang.binding.YangModuleInfo; +import org.opendaylight.yangtools.yang.binding.util.BindingReflections; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +public abstract class AbstractSchemaAwareTest { + + private Iterable moduleInfos; + private SchemaContext schemaContext; + + + protected Iterable getModuleInfos() { + return BindingReflections.loadModuleInfos(); + } + + + @Before + public final void setup() { + moduleInfos = getModuleInfos(); + ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create(); + moduleContext.addModuleInfos(moduleInfos); + schemaContext = moduleContext.tryToCreateSchemaContext().get(); + setupWithSchema(schemaContext); + } + + /** + * Setups test with Schema context. + * This method is called before {@link #setupWithSchemaService(SchemaService)} + * + * @param context + */ + protected abstract void setupWithSchema(SchemaContext context); + +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/BundleContextMock.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/BundleContextMock.java new file mode 100644 index 0000000000..37cea44ab0 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/BundleContextMock.java @@ -0,0 +1,149 @@ +package test.mock.util; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.BundleListener; +import org.osgi.framework.Filter; +import org.osgi.framework.FrameworkListener; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceListener; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; + +import java.io.File; +import java.io.InputStream; +import java.util.Collection; +import java.util.Dictionary; + +public class BundleContextMock implements BundleContext { + @Override + public String getProperty(String s) { + return null; + } + + @Override + public Bundle getBundle() { + return null; + } + + @Override + public Bundle installBundle(String s, InputStream inputStream) throws BundleException { + return null; + } + + @Override + public Bundle installBundle(String s) throws BundleException { + return null; + } + + @Override + public Bundle getBundle(long l) { + return null; + } + + @Override + public Bundle[] getBundles() { + return new Bundle[0]; + } + + @Override + public void addServiceListener(ServiceListener serviceListener, String s) throws InvalidSyntaxException { + + } + + @Override + public void addServiceListener(ServiceListener serviceListener) { + + } + + @Override + public void removeServiceListener(ServiceListener serviceListener) { + + } + + @Override + public void addBundleListener(BundleListener bundleListener) { + + } + + @Override + public void removeBundleListener(BundleListener bundleListener) { + + } + + @Override + public void addFrameworkListener(FrameworkListener frameworkListener) { + + } + + @Override + public void removeFrameworkListener(FrameworkListener frameworkListener) { + + } + + @Override + public ServiceRegistration registerService(String[] strings, Object o, Dictionary stringDictionary) { + return null; + } + + @Override + public ServiceRegistration registerService(String s, Object o, Dictionary stringDictionary) { + return null; + } + + @Override + public ServiceRegistration registerService(Class sClass, S s, Dictionary stringDictionary) { + return null; + } + + @Override + public ServiceReference[] getServiceReferences(String s, String s2) throws InvalidSyntaxException { + return new ServiceReference[0]; + } + + @Override + public ServiceReference[] getAllServiceReferences(String s, String s2) throws InvalidSyntaxException { + return new ServiceReference[0]; + } + + @Override + public ServiceReference getServiceReference(String s) { + return null; + } + + @Override + public ServiceReference getServiceReference(Class sClass) { + return null; + } + + @Override + public Collection> getServiceReferences(Class sClass, String s) throws InvalidSyntaxException { + return null; + } + + @Override + public S getService(ServiceReference sServiceReference) { + return null; + } + + @Override + public boolean ungetService(ServiceReference serviceReference) { + return false; + } + + @Override + public File getDataFile(String s) { + return null; + } + + @Override + public Filter createFilter(String s) throws InvalidSyntaxException { + return null; + } + + @Override + public Bundle getBundle(String s) { + return null; + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/DataBrokerTestCustomizer.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/DataBrokerTestCustomizer.java new file mode 100644 index 0000000000..36ab41fa68 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/DataBrokerTestCustomizer.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package test.mock.util; + +import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import javassist.ClassPool; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; +import org.opendaylight.controller.md.sal.binding.impl.ForwardedBackwardsCompatibleDataBroker; +import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl; +import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.controller.sal.core.spi.data.DOMStore; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; +import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy; +import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl; +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +public class DataBrokerTestCustomizer { + + private DOMDataBroker domDataBroker; + private final RuntimeGeneratedMappingServiceImpl mappingService; + private final MockSchemaService schemaService; + private ImmutableMap datastores; + private final BindingToNormalizedNodeCodec bindingToNormalized ; + + public ImmutableMap createDatastores() { + return ImmutableMap.builder() + .put(LogicalDatastoreType.OPERATIONAL, createOperationalDatastore()) + .put(LogicalDatastoreType.CONFIGURATION,createConfigurationDatastore()) + .build(); + } + + public DataBrokerTestCustomizer() { + schemaService = new MockSchemaService(); + ClassPool pool = ClassPool.getDefault(); + mappingService = new RuntimeGeneratedMappingServiceImpl(pool); + DataObjectSerializerGenerator generator = StreamWriterGenerator.create(JavassistUtils.forClassPool(pool)); + BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(generator); + GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(); + bindingToNormalized = new BindingToNormalizedNodeCodec(loading, mappingService, codecRegistry); + schemaService.registerSchemaContextListener(bindingToNormalized); + } + + public DOMStore createConfigurationDatastore() { + InMemoryDOMDataStore store = new InMemoryDOMDataStore("CFG", + MoreExecutors.sameThreadExecutor(), MoreExecutors.sameThreadExecutor()); + schemaService.registerSchemaContextListener(store); + return store; + } + + public DOMStore createOperationalDatastore() { + InMemoryDOMDataStore store = new InMemoryDOMDataStore("OPER", + MoreExecutors.sameThreadExecutor(), MoreExecutors.sameThreadExecutor()); + schemaService.registerSchemaContextListener(store); + return store; + } + + public DOMDataBroker createDOMDataBroker() { + return new DOMDataBrokerImpl(getDatastores(), getCommitCoordinatorExecutor()); + } + + public ListeningExecutorService getCommitCoordinatorExecutor() { + return MoreExecutors.sameThreadExecutor(); + } + + public DataBroker createDataBroker() { + return new ForwardedBindingDataBroker(getDOMDataBroker(), bindingToNormalized, schemaService ); + } + + public ForwardedBackwardsCompatibleDataBroker createBackwardsCompatibleDataBroker() { + return new ForwardedBackwardsCompatibleDataBroker(getDOMDataBroker(), bindingToNormalized, getSchemaService(), MoreExecutors.sameThreadExecutor()); + } + + private SchemaService getSchemaService() { + return schemaService; + } + + private DOMDataBroker getDOMDataBroker() { + if(domDataBroker == null) { + domDataBroker = createDOMDataBroker(); + } + return domDataBroker; + } + + private synchronized ImmutableMap getDatastores() { + if (datastores == null) { + datastores = createDatastores(); + } + return datastores; + } + + public void updateSchema(final SchemaContext ctx) { + schemaService.changeSchema(ctx); + mappingService.onGlobalContextUpdated(ctx); + } + +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/FlowMockGenerator.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/FlowMockGenerator.java new file mode 100644 index 0000000000..fb5351b43a --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/FlowMockGenerator.java @@ -0,0 +1,30 @@ +package test.mock.util; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; + +import java.math.BigInteger; +import java.util.Random; + +public class FlowMockGenerator { + private static final Random rnd = new Random(); + private static final FlowBuilder flowBuilder = new FlowBuilder(); + + public static Flow getRandomFlow() { + flowBuilder.setKey(new FlowKey(new FlowId("flow." + rnd.nextInt(1000)))); + flowBuilder.setOutGroup(TestUtils.nextLong(0, 4294967296L)); + flowBuilder.setTableId((short) rnd.nextInt(256)); + flowBuilder.setOutPort(BigInteger.valueOf(TestUtils.nextLong(0, Long.MAX_VALUE))); + flowBuilder.setStrict(rnd.nextBoolean()); + flowBuilder.setContainerName("container." + rnd.nextInt(1000)); + flowBuilder.setBarrier(rnd.nextBoolean()); + flowBuilder.setMatch(MatchMockGenerator.getRandomMatch()); + flowBuilder.setPriority(rnd.nextInt(65535)); + flowBuilder.setCookie(new FlowCookie(BigInteger.valueOf(TestUtils.nextLong(0, Long.MAX_VALUE)))); + flowBuilder.setCookieMask(flowBuilder.getCookie()); + return flowBuilder.build(); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/GroupMockGenerator.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/GroupMockGenerator.java new file mode 100644 index 0000000000..183524d4c0 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/GroupMockGenerator.java @@ -0,0 +1,23 @@ +package test.mock.util; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; + +import java.util.Random; + +public class GroupMockGenerator { + private static final Random rnd = new Random(); + private static final GroupBuilder groupBuilder = new GroupBuilder(); + + public static Group getRandomGroup() { + groupBuilder.setKey(new GroupKey(new GroupId(TestUtils.nextLong(0, 4294967295L)))); + groupBuilder.setContainerName("container." + rnd.nextInt(1000)); + groupBuilder.setBarrier(rnd.nextBoolean()); + groupBuilder.setGroupName("group." + rnd.nextInt(1000)); + groupBuilder.setGroupType(GroupTypes.forValue(rnd.nextInt(4))); + return groupBuilder.build(); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/MatchMockGenerator.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/MatchMockGenerator.java new file mode 100644 index 0000000000..8b603c26a5 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/MatchMockGenerator.java @@ -0,0 +1,30 @@ +package test.mock.util; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Dscp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.MetadataBuilder; + +import java.math.BigInteger; +import java.util.Random; + +public class MatchMockGenerator { + private static final Random rnd = new Random(); + private static final MatchBuilder matchBuilder = new MatchBuilder(); + private static final IpMatchBuilder ipMatchBuilder = new IpMatchBuilder(); + private static final MetadataBuilder metadataBuilder = new MetadataBuilder(); + + public static Match getRandomMatch() { + matchBuilder.setInPort(new NodeConnectorId("port." + rnd.nextInt(500))); + ipMatchBuilder.setIpDscp(new Dscp((short) rnd.nextInt(64))).build(); + ipMatchBuilder.setIpEcn((short) rnd.nextInt(256)); + ipMatchBuilder.setIpProtocol((short) rnd.nextInt(256)); + matchBuilder.setIpMatch(ipMatchBuilder.build()); + metadataBuilder.setMetadata(BigInteger.valueOf(TestUtils.nextLong(0, Long.MAX_VALUE))); + metadataBuilder.setMetadataMask(BigInteger.valueOf(TestUtils.nextLong(0, Long.MAX_VALUE))); + matchBuilder.setMetadata(metadataBuilder.build()); + return matchBuilder.build(); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/MeterMockGenerator.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/MeterMockGenerator.java new file mode 100644 index 0000000000..63ebcb0ea2 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/MeterMockGenerator.java @@ -0,0 +1,35 @@ +package test.mock.util; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.BandId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.MeterBandHeadersBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.meter.band.headers.MeterBandHeader; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.meter.band.headers.MeterBandHeaderBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.meter.band.headers.MeterBandHeaderKey; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class MeterMockGenerator { + private static final Random rnd = new Random(); + private static final MeterBuilder meterBuilder = new MeterBuilder(); + private static final MeterBandHeaderBuilder meterBandHeaderBuilder = new MeterBandHeaderBuilder(); + private static final MeterBandHeadersBuilder meterBandHeadersBuilder = new MeterBandHeadersBuilder(); + + public static Meter getRandomMeter() { + meterBandHeaderBuilder.setKey(new MeterBandHeaderKey(new BandId(TestUtils.nextLong(0, 4294967295L)))); + meterBandHeaderBuilder.setBandBurstSize(TestUtils.nextLong(0, 4294967295L)); + meterBandHeaderBuilder.setBandRate(TestUtils.nextLong(0, 4294967295L)); + List meterBandHeaders = new ArrayList<>(); + meterBuilder.setKey(new MeterKey(new MeterId(TestUtils.nextLong(0, 4294967295L)))); + meterBuilder.setBarrier(rnd.nextBoolean()); + meterBuilder.setContainerName("container." + rnd.nextInt(1000)); + meterBuilder.setMeterName("meter." + rnd.nextInt(1000)); + meterBuilder.setMeterBandHeaders(meterBandHeadersBuilder.setMeterBandHeader(meterBandHeaders).build()); + return meterBuilder.build(); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/MockSchemaService.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/MockSchemaService.java new file mode 100644 index 0000000000..b4876a3ee0 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/MockSchemaService.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package test.mock.util; + +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.util.ListenerRegistry; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; + +@SuppressWarnings("deprecation") +public final class MockSchemaService implements SchemaService, SchemaContextProvider { + + private SchemaContext schemaContext; + + ListenerRegistry listeners = ListenerRegistry.create(); + + @Override + public void addModule(final Module module) { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized SchemaContext getGlobalContext() { + return schemaContext; + } + + @Override + public synchronized SchemaContext getSessionContext() { + return schemaContext; + } + + @Override + public ListenerRegistration registerSchemaContextListener( + final SchemaContextListener listener) { + return listeners.register(listener); + } + + @Override + public void removeModule(final Module module) { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized SchemaContext getSchemaContext() { + return schemaContext; + } + + public synchronized void changeSchema(final SchemaContext newContext) { + schemaContext = newContext; + for (ListenerRegistration listener : listeners) { + listener.getInstance().onGlobalContextUpdated(schemaContext); + } + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/NotificationProviderServiceHelper.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/NotificationProviderServiceHelper.java new file mode 100644 index 0000000000..2d85f62ab5 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/NotificationProviderServiceHelper.java @@ -0,0 +1,29 @@ +package test.mock.util; + +import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; +import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl; +import org.opendaylight.yangtools.yang.binding.Notification; + +import java.util.Timer; +import java.util.TimerTask; + +public class NotificationProviderServiceHelper { + private NotificationBrokerImpl notifBroker = new NotificationBrokerImpl(SingletonHolder.getDefaultNotificationExecutor()); + + public NotificationBrokerImpl getNotifBroker() { + return notifBroker; + } + + public void pushDelayedNotification(final Notification notification, int delay) { + new Timer().schedule(new TimerTask() { + @Override + public void run() { + notifBroker.publish(notification); + } + }, delay); + } + + public void pushNotification(final Notification notification) { + notifBroker.publish(notification); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightFlowStatisticsServiceMock.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightFlowStatisticsServiceMock.java new file mode 100644 index 0000000000..2628bb9f41 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightFlowStatisticsServiceMock.java @@ -0,0 +1,116 @@ +package test.mock.util; + +import com.google.common.util.concurrent.Futures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForGivenMatchOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForGivenMatchOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsFromFlowTableInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsFromFlowTableOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsFromFlowTableOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; + +public class OpendaylightFlowStatisticsServiceMock implements OpendaylightFlowStatisticsService { + NotificationProviderServiceHelper notifService; + AtomicLong transNum = new AtomicLong(); + + public OpendaylightFlowStatisticsServiceMock(NotificationProviderServiceHelper notifService) { + this.notifService = notifService; + } + + @Override + public Future> getAggregateFlowStatisticsFromFlowTableForAllFlows(GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput input) { + GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutputBuilder builder = new GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getAggregateFlowStatisticsFromFlowTableForGivenMatch(GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput input) { + GetAggregateFlowStatisticsFromFlowTableForGivenMatchOutputBuilder builder = new GetAggregateFlowStatisticsFromFlowTableForGivenMatchOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + AggregateFlowStatisticsUpdateBuilder afsuBuilder = new AggregateFlowStatisticsUpdateBuilder(); + afsuBuilder.setMoreReplies(false); + afsuBuilder.setTransactionId(transId); + afsuBuilder.setByteCount(StatisticsManagerTest.COUNTER_64_TEST_VALUE); + afsuBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + notifService.pushDelayedNotification(afsuBuilder.build(), 100); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getAllFlowStatisticsFromFlowTable(GetAllFlowStatisticsFromFlowTableInput input) { + GetAllFlowStatisticsFromFlowTableOutputBuilder builder = new GetAllFlowStatisticsFromFlowTableOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getAllFlowsStatisticsFromAllFlowTables(GetAllFlowsStatisticsFromAllFlowTablesInput input) { + GetAllFlowsStatisticsFromAllFlowTablesOutputBuilder builder = new GetAllFlowsStatisticsFromAllFlowTablesOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + List flowAndStatisticsMapLists = new ArrayList<>(); + FlowsStatisticsUpdateBuilder flowsStatisticsUpdateBuilder = new FlowsStatisticsUpdateBuilder(); + flowsStatisticsUpdateBuilder.setTransactionId(transId); + flowsStatisticsUpdateBuilder.setMoreReplies(false); + flowsStatisticsUpdateBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + FlowAndStatisticsMapListBuilder flowAndStatisticsMapListBuilder = new FlowAndStatisticsMapListBuilder(StatisticsManagerTest.getFlow()); + flowAndStatisticsMapListBuilder.setTableId(StatisticsManagerTest.getFlow().getTableId()); + flowAndStatisticsMapListBuilder.setContainerName(StatisticsManagerTest.getFlow().getContainerName()); + flowAndStatisticsMapListBuilder.setBarrier(StatisticsManagerTest.getFlow().isBarrier()); + flowAndStatisticsMapListBuilder.setByteCount(StatisticsManagerTest.COUNTER_64_TEST_VALUE); + flowAndStatisticsMapLists.add(flowAndStatisticsMapListBuilder.build()); + flowsStatisticsUpdateBuilder.setFlowAndStatisticsMapList(flowAndStatisticsMapLists); + notifService.pushDelayedNotification(flowsStatisticsUpdateBuilder.build(), 100); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getFlowStatisticsFromFlowTable(GetFlowStatisticsFromFlowTableInput input) { + GetFlowStatisticsFromFlowTableOutputBuilder builder = new GetFlowStatisticsFromFlowTableOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + List flowAndStatisticsMapLists = new ArrayList<>(); + FlowsStatisticsUpdateBuilder flowsStatisticsUpdateBuilder = new FlowsStatisticsUpdateBuilder(); + flowsStatisticsUpdateBuilder.setTransactionId(transId); + flowsStatisticsUpdateBuilder.setMoreReplies(false); + flowsStatisticsUpdateBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + FlowAndStatisticsMapListBuilder flowAndStatisticsMapListBuilder = new FlowAndStatisticsMapListBuilder(input); + flowAndStatisticsMapListBuilder.setTableId(input.getTableId()); + flowAndStatisticsMapListBuilder.setContainerName(input.getContainerName()); + flowAndStatisticsMapListBuilder.setBarrier(input.isBarrier()); + flowAndStatisticsMapListBuilder.setByteCount(StatisticsManagerTest.COUNTER_64_TEST_VALUE); + flowAndStatisticsMapLists.add(flowAndStatisticsMapListBuilder.build()); + flowsStatisticsUpdateBuilder.setFlowAndStatisticsMapList(flowAndStatisticsMapLists); + notifService.pushDelayedNotification(flowsStatisticsUpdateBuilder.build(), 100); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightFlowTableStatisticsServiceMock.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightFlowTableStatisticsServiceMock.java new file mode 100644 index 0000000000..42be70892c --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightFlowTableStatisticsServiceMock.java @@ -0,0 +1,57 @@ +package test.mock.util; + +import com.google.common.util.concurrent.Futures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMapBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMapKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; + +public class OpendaylightFlowTableStatisticsServiceMock implements OpendaylightFlowTableStatisticsService { + NotificationProviderServiceHelper notifService; + AtomicLong transNum = new AtomicLong(); + + public OpendaylightFlowTableStatisticsServiceMock(NotificationProviderServiceHelper notifService) { + this.notifService = notifService; + } + + @Override + public Future> getFlowTablesStatistics(GetFlowTablesStatisticsInput input) { + GetFlowTablesStatisticsOutputBuilder builder = new GetFlowTablesStatisticsOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + FlowTableStatisticsUpdateBuilder ftsBuilder = new FlowTableStatisticsUpdateBuilder(); + FlowTableAndStatisticsMapBuilder ftasmBuilder = new FlowTableAndStatisticsMapBuilder(); + List tableAndStatisticsMaps = new ArrayList<>(); + ftasmBuilder.setKey(new FlowTableAndStatisticsMapKey(StatisticsManagerTest.getTableId())); + ftasmBuilder.setActiveFlows(StatisticsManagerTest.COUNTER_32_TEST_VALUE); + tableAndStatisticsMaps.add(ftasmBuilder.build()); + ftsBuilder.setTransactionId(transId); + ftsBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + ftsBuilder.setFlowTableAndStatisticsMap(tableAndStatisticsMaps); + ftsBuilder.setMoreReplies(true); + notifService.pushDelayedNotification(ftsBuilder.build(), 0); // 1st notification + ftsBuilder.setMoreReplies(false); + ftasmBuilder.setPacketsLookedUp(StatisticsManagerTest.COUNTER_64_TEST_VALUE); + tableAndStatisticsMaps.clear(); + tableAndStatisticsMaps.add(ftasmBuilder.build()); + ftsBuilder.setFlowTableAndStatisticsMap(tableAndStatisticsMaps); + notifService.pushDelayedNotification(ftsBuilder.build(), 0); // 2nd notification + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightGroupStatisticsServiceMock.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightGroupStatisticsServiceMock.java new file mode 100644 index 0000000000..7e7342f609 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightGroupStatisticsServiceMock.java @@ -0,0 +1,123 @@ +package test.mock.util; + +import com.google.common.util.concurrent.Futures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupFeaturesInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupFeaturesOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupFeaturesOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupStatisticsInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupStatisticsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupStatisticsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStatsKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStatsKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; + +public class OpendaylightGroupStatisticsServiceMock implements OpendaylightGroupStatisticsService { + NotificationProviderServiceHelper notifService; + AtomicLong transNum = new AtomicLong(); + + public OpendaylightGroupStatisticsServiceMock(NotificationProviderServiceHelper notifService) { + this.notifService = notifService; + } + + @Override + public Future> getAllGroupStatistics(GetAllGroupStatisticsInput input) { + GetAllGroupStatisticsOutputBuilder builder = new GetAllGroupStatisticsOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + List groupStats = new ArrayList<>(); + GroupStatsBuilder gsBuilder = new GroupStatsBuilder(); + GroupStatisticsUpdatedBuilder gsuBuilder = new GroupStatisticsUpdatedBuilder(); + gsBuilder.setKey(new GroupStatsKey(StatisticsManagerTest.getGroup().getGroupId())); + gsBuilder.setByteCount(StatisticsManagerTest.COUNTER_64_TEST_VALUE); + groupStats.add(gsBuilder.build()); + builder.setGroupStats(groupStats); + gsuBuilder.setTransactionId(transId); + gsuBuilder.setMoreReplies(false); + gsuBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + gsuBuilder.setGroupStats(groupStats); + notifService.pushDelayedNotification(gsuBuilder.build(), 500); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getGroupDescription(GetGroupDescriptionInput input) { + GetGroupDescriptionOutputBuilder builder = new GetGroupDescriptionOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + List groupDescStats = new ArrayList<>(); + GroupDescStatsUpdatedBuilder gdsuBuilder = new GroupDescStatsUpdatedBuilder(); + GroupDescStatsBuilder gdsBuilder = new GroupDescStatsBuilder(); + gdsBuilder.setKey(new GroupDescStatsKey(StatisticsManagerTest.getGroup().getGroupId())); + gdsBuilder.setBuckets(StatisticsManagerTest.getGroup().getBuckets()); + gdsBuilder.setContainerName(StatisticsManagerTest.getGroup().getContainerName()); + gdsBuilder.setGroupName(StatisticsManagerTest.getGroup().getGroupName()); + gdsBuilder.setGroupType(StatisticsManagerTest.getGroup().getGroupType()); + groupDescStats.add(gdsBuilder.build()); + builder.setGroupDescStats(groupDescStats); + gdsuBuilder.setTransactionId(transId); + gdsuBuilder.setMoreReplies(false); + gdsuBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + gdsuBuilder.setGroupDescStats(groupDescStats); + notifService.pushDelayedNotification(gdsuBuilder.build(), 100); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getGroupFeatures(GetGroupFeaturesInput input) { + GetGroupFeaturesOutputBuilder builder = new GetGroupFeaturesOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + GroupFeaturesUpdatedBuilder gfuBuilder = new GroupFeaturesUpdatedBuilder(); + gfuBuilder.setTransactionId(transId); + gfuBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + gfuBuilder.setMoreReplies(false); + List maxGroups = new ArrayList<>(); + maxGroups.add(StatisticsManagerTest.MAX_GROUPS_TEST_VALUE); + gfuBuilder.setMaxGroups(maxGroups); + notifService.pushDelayedNotification(gfuBuilder.build(), 100); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getGroupStatistics(GetGroupStatisticsInput input) { + GetGroupStatisticsOutputBuilder builder = new GetGroupStatisticsOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + GroupStatsBuilder gsBuilder = new GroupStatsBuilder(); + List groupStats = new ArrayList<>(); + gsBuilder.setKey(new GroupStatsKey(input.getGroupId())); + gsBuilder.setByteCount(StatisticsManagerTest.COUNTER_64_TEST_VALUE); + groupStats.add(gsBuilder.build()); + GroupStatisticsUpdatedBuilder gsuBuilder = new GroupStatisticsUpdatedBuilder(); + gsuBuilder.setTransactionId(transId); + gsuBuilder.setMoreReplies(false); + gsuBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + gsuBuilder.setGroupStats(groupStats); + notifService.pushDelayedNotification(gsuBuilder.build(), 100); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightMeterStatisticsServiceMock.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightMeterStatisticsServiceMock.java new file mode 100644 index 0000000000..2d65d1ebed --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightMeterStatisticsServiceMock.java @@ -0,0 +1,119 @@ +package test.mock.util; + +import com.google.common.util.concurrent.Futures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetMeterFeaturesInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetMeterFeaturesOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetMeterFeaturesOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetMeterStatisticsInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetMeterStatisticsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetMeterStatisticsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterConfigStatsUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStatsKey; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; + +public class OpendaylightMeterStatisticsServiceMock implements OpendaylightMeterStatisticsService { + NotificationProviderServiceHelper notifService; + AtomicLong transNum = new AtomicLong(); + + public OpendaylightMeterStatisticsServiceMock(NotificationProviderServiceHelper notifService) { + this.notifService = notifService; + } + + @Override + public Future> getAllMeterConfigStatistics(GetAllMeterConfigStatisticsInput input) { + GetAllMeterConfigStatisticsOutputBuilder builder = new GetAllMeterConfigStatisticsOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + List meterConfigStats = new ArrayList<>(); + MeterConfigStatsBuilder mcsBuilder = new MeterConfigStatsBuilder(); + mcsBuilder.setMeterId(StatisticsManagerTest.getMeter().getMeterId()); + mcsBuilder.setMeterName(StatisticsManagerTest.getMeter().getMeterName()); + mcsBuilder.setContainerName(StatisticsManagerTest.getMeter().getContainerName()); + meterConfigStats.add(mcsBuilder.build()); + builder.setMeterConfigStats(meterConfigStats); + MeterConfigStatsUpdatedBuilder mscuBuilder = new MeterConfigStatsUpdatedBuilder(); + mscuBuilder.setTransactionId(transId); + mscuBuilder.setMoreReplies(false); + mscuBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + mscuBuilder.setMeterConfigStats(meterConfigStats); + notifService.pushDelayedNotification(mscuBuilder.build(), 100); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getAllMeterStatistics(GetAllMeterStatisticsInput input) { + GetAllMeterStatisticsOutputBuilder builder = new GetAllMeterStatisticsOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + MeterStatsBuilder msBuilder = new MeterStatsBuilder(); + msBuilder.setByteInCount(StatisticsManagerTest.COUNTER_64_TEST_VALUE); + msBuilder.setPacketInCount(StatisticsManagerTest.COUNTER_64_TEST_VALUE); + msBuilder.setKey(new MeterStatsKey(StatisticsManagerTest.getMeter().getMeterId())); + List meterStats = new ArrayList<>(); + meterStats.add(msBuilder.build()); + MeterStatisticsUpdatedBuilder msuBuilder = new MeterStatisticsUpdatedBuilder(); + msuBuilder.setTransactionId(transId); + msuBuilder.setMoreReplies(false); + msuBuilder.setMeterStats(meterStats); + msuBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + notifService.pushDelayedNotification(msuBuilder.build(), 100); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getMeterFeatures(GetMeterFeaturesInput input) { + GetMeterFeaturesOutputBuilder builder = new GetMeterFeaturesOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + MeterFeaturesUpdatedBuilder mfuBuilder = new MeterFeaturesUpdatedBuilder(); + mfuBuilder.setTransactionId(transId); + mfuBuilder.setMoreReplies(false); + mfuBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + mfuBuilder.setMaxMeter(StatisticsManagerTest.COUNTER_32_TEST_VALUE); + notifService.pushDelayedNotification(mfuBuilder.build(), 100); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getMeterStatistics(GetMeterStatisticsInput input) { + GetMeterStatisticsOutputBuilder builder = new GetMeterStatisticsOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + MeterStatsBuilder msBuilder = new MeterStatsBuilder(); + msBuilder.setKey(new MeterStatsKey(input.getMeterId())); + msBuilder.setByteInCount(StatisticsManagerTest.COUNTER_64_TEST_VALUE); + msBuilder.setPacketInCount(StatisticsManagerTest.COUNTER_64_TEST_VALUE); + List meterStats = new ArrayList<>(); + meterStats.add(msBuilder.build()); + MeterStatisticsUpdatedBuilder msuBuilder = new MeterStatisticsUpdatedBuilder(); + msuBuilder.setTransactionId(transId); + msuBuilder.setMoreReplies(false); + msuBuilder.setMeterStats(meterStats); + msuBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + notifService.pushDelayedNotification(msuBuilder.build(), 100); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightPortStatisticsServiceMock.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightPortStatisticsServiceMock.java new file mode 100644 index 0000000000..7164c56c1b --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightPortStatisticsServiceMock.java @@ -0,0 +1,67 @@ +package test.mock.util; + +import com.google.common.util.concurrent.Futures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetNodeConnectorStatisticsInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetNodeConnectorStatisticsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetNodeConnectorStatisticsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMapBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMapKey; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; + +public class OpendaylightPortStatisticsServiceMock implements OpendaylightPortStatisticsService { + NotificationProviderServiceHelper notifService; + AtomicLong transNum = new AtomicLong(); + + public OpendaylightPortStatisticsServiceMock(NotificationProviderServiceHelper notifService) { + this.notifService = notifService; + } + + @Override + public Future> getAllNodeConnectorsStatistics(GetAllNodeConnectorsStatisticsInput input) { + GetAllNodeConnectorsStatisticsOutputBuilder builder = new GetAllNodeConnectorsStatisticsOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + NodeConnectorStatisticsUpdateBuilder ncsuBuilder = new NodeConnectorStatisticsUpdateBuilder(); + NodeConnectorStatisticsAndPortNumberMapBuilder ncsapnmBuilder = new NodeConnectorStatisticsAndPortNumberMapBuilder(); + List nodeConnectorStatisticsAndPortNumberMaps = new ArrayList<>(); + ncsapnmBuilder.setKey(new NodeConnectorStatisticsAndPortNumberMapKey(StatisticsManagerTest.getNodeConnectorId())); + ncsapnmBuilder.setReceiveDrops(StatisticsManagerTest.BIG_INTEGER_TEST_VALUE); + nodeConnectorStatisticsAndPortNumberMaps.add(ncsapnmBuilder.build()); + ncsuBuilder.setTransactionId(new TransactionId(BigInteger.valueOf(1))); + ncsuBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + ncsuBuilder.setNodeConnectorStatisticsAndPortNumberMap(nodeConnectorStatisticsAndPortNumberMaps); + ncsuBuilder.setMoreReplies(true); + notifService.pushDelayedNotification(ncsuBuilder.build(), 0); // 1st notification + ncsuBuilder.setMoreReplies(false); + ncsapnmBuilder.setCollisionCount(StatisticsManagerTest.BIG_INTEGER_TEST_VALUE); + nodeConnectorStatisticsAndPortNumberMaps.clear(); + nodeConnectorStatisticsAndPortNumberMaps.add(ncsapnmBuilder.build()); + ncsuBuilder.setNodeConnectorStatisticsAndPortNumberMap(nodeConnectorStatisticsAndPortNumberMaps); + notifService.pushDelayedNotification(ncsuBuilder.build(), 10); // 2nd notification + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getNodeConnectorStatistics(GetNodeConnectorStatisticsInput input) { + GetNodeConnectorStatisticsOutputBuilder builder = new GetNodeConnectorStatisticsOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightQueueStatisticsServiceMock.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightQueueStatisticsServiceMock.java new file mode 100644 index 0000000000..4f6806b8ca --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightQueueStatisticsServiceMock.java @@ -0,0 +1,83 @@ +package test.mock.util; + +import com.google.common.util.concurrent.Futures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromGivenPortInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromGivenPortOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromGivenPortOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMapBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMapKey; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; + +public class OpendaylightQueueStatisticsServiceMock implements OpendaylightQueueStatisticsService { + NotificationProviderServiceHelper notifService; + AtomicLong transNum = new AtomicLong(); + + public OpendaylightQueueStatisticsServiceMock(NotificationProviderServiceHelper notifService) { + this.notifService = notifService; + } + + @Override + public Future> getAllQueuesStatisticsFromAllPorts(GetAllQueuesStatisticsFromAllPortsInput input) { + GetAllQueuesStatisticsFromAllPortsOutputBuilder builder = new GetAllQueuesStatisticsFromAllPortsOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + QueueStatisticsUpdateBuilder qsuBuilder = new QueueStatisticsUpdateBuilder(); + QueueIdAndStatisticsMapBuilder qiasmBuilder = new QueueIdAndStatisticsMapBuilder(); + List queueIdAndStatisticsMaps = new ArrayList<>(); + qsuBuilder.setMoreReplies(false); + qsuBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + qsuBuilder.setTransactionId(transId); + qiasmBuilder.setTransmittedBytes(StatisticsManagerTest.COUNTER_64_TEST_VALUE); + qiasmBuilder.setKey(new QueueIdAndStatisticsMapKey(StatisticsManagerTest.getNodeConnectorId(), StatisticsManagerTest.getQueue().getQueueId())); + queueIdAndStatisticsMaps.add(qiasmBuilder.build()); + qsuBuilder.setQueueIdAndStatisticsMap(queueIdAndStatisticsMaps); + notifService.pushDelayedNotification(qsuBuilder.build(), 100); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getAllQueuesStatisticsFromGivenPort(GetAllQueuesStatisticsFromGivenPortInput input) { + GetAllQueuesStatisticsFromGivenPortOutputBuilder builder = new GetAllQueuesStatisticsFromGivenPortOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } + + @Override + public Future> getQueueStatisticsFromGivenPort(GetQueueStatisticsFromGivenPortInput input) { + GetQueueStatisticsFromGivenPortOutputBuilder builder = new GetQueueStatisticsFromGivenPortOutputBuilder(); + TransactionId transId = new TransactionId(BigInteger.valueOf(transNum.incrementAndGet())); + builder.setTransactionId(transId); + QueueIdAndStatisticsMapBuilder qiasmBuilder = new QueueIdAndStatisticsMapBuilder(); + List queueIdAndStatisticsMaps = new ArrayList<>(); + qiasmBuilder.setKey(new QueueIdAndStatisticsMapKey(input.getNodeConnectorId(), input.getQueueId())); + qiasmBuilder.setTransmittedBytes(StatisticsManagerTest.COUNTER_64_TEST_VALUE); + queueIdAndStatisticsMaps.add(qiasmBuilder.build()); + QueueStatisticsUpdateBuilder qsuBuilder = new QueueStatisticsUpdateBuilder(); + qsuBuilder.setMoreReplies(false); + qsuBuilder.setTransactionId(transId); + qsuBuilder.setId(input.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId()); + qsuBuilder.setQueueIdAndStatisticsMap(queueIdAndStatisticsMaps); + notifService.pushDelayedNotification(qsuBuilder.build(), 100); + return Futures.immediateFuture(RpcResultBuilder.success(builder.build()).build()); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/PortMockGenerator.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/PortMockGenerator.java new file mode 100644 index 0000000000..4c972173fb --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/PortMockGenerator.java @@ -0,0 +1,23 @@ +package test.mock.util; + + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.CommonPort; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.port.mod.port.Port; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.port.mod.port.PortBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.port.mod.port.PortKey; + +import java.util.Random; + +public class PortMockGenerator { + private static final Random rnd = new Random(); + private static final PortBuilder portBuilder = new PortBuilder(); + + public static Port getRandomPort() { + portBuilder.setKey(new PortKey(TestUtils.nextLong(0, 4294967295L))); + portBuilder.setBarrier(rnd.nextBoolean()); + portBuilder.setPortNumber(new CommonPort.PortNumber(TestUtils.nextLong(0, 4294967295L))); + portBuilder.setConfiguration(new PortConfig(rnd.nextBoolean(), rnd.nextBoolean(), rnd.nextBoolean(), rnd.nextBoolean())); + return portBuilder.build(); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/ProviderContextMock.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/ProviderContextMock.java new file mode 100644 index 0000000000..9b40a7684f --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/ProviderContextMock.java @@ -0,0 +1,69 @@ +package test.mock.util; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; +import org.opendaylight.controller.sal.binding.api.BindingAwareService; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; + +public class ProviderContextMock implements BindingAwareBroker.ProviderContext { + + RpcProviderRegistry rpcProviderMock; + NotificationProviderService notificationProviderService; + DataBroker dataBroker; + + public ProviderContextMock(RpcProviderRegistry rpcProviderMock, DataBroker dataBroker, + NotificationProviderService notificationProviderServiceMock) { + this.rpcProviderMock = rpcProviderMock; + this.dataBroker = dataBroker; + this.notificationProviderService = notificationProviderServiceMock; + } + + @Override + public void registerFunctionality(BindingAwareProvider.ProviderFunctionality functionality) { + + } + + @Override + public void unregisterFunctionality(BindingAwareProvider.ProviderFunctionality functionality) { + + } + + @SuppressWarnings("unchecked") + @Override + public T getSALService(Class service) { + if (service.equals(DataBroker.class)) { + return (T) dataBroker; + } + else if (service.equals(NotificationProviderService.class)) { + return (T) notificationProviderService; + } + return null; + } + + @Override + public BindingAwareBroker.RpcRegistration addRpcImplementation(Class serviceInterface, T implementation) throws IllegalStateException { + return null; + } + + @Override + public BindingAwareBroker.RoutedRpcRegistration addRoutedRpcImplementation(Class serviceInterface, T implementation) throws IllegalStateException { + return null; + } + + @Override + public >> ListenerRegistration registerRouteChangeListener(L listener) { + return null; + } + + @Override + public T getRpcService(Class serviceInterface) { + return rpcProviderMock.getRpcService(serviceInterface); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/QueueMockGenerator.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/QueueMockGenerator.java new file mode 100644 index 0000000000..f140776bf2 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/QueueMockGenerator.java @@ -0,0 +1,27 @@ +package test.mock.util; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId; + +import java.util.Random; + +public class QueueMockGenerator { + private static final Random rnd = new Random(); + private static final QueueBuilder queueBuilder = new QueueBuilder(); + + public static Queue getRandomQueue() { + queueBuilder.setKey(new QueueKey(new QueueId(TestUtils.nextLong(0, 4294967295L)))); + queueBuilder.setPort(TestUtils.nextLong(0, 4294967295L)); + queueBuilder.setProperty(rnd.nextInt(65535)); + return queueBuilder.build(); + } + + public static Queue getRandomQueueWithPortNum(long portNum) { + queueBuilder.setKey(new QueueKey(new QueueId(TestUtils.nextLong(0, 4294967295L)))); + queueBuilder.setPort(portNum); + queueBuilder.setProperty(rnd.nextInt(65535)); + return queueBuilder.build(); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/RpcProviderRegistryMock.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/RpcProviderRegistryMock.java new file mode 100644 index 0000000000..0b2548685e --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/RpcProviderRegistryMock.java @@ -0,0 +1,93 @@ +package test.mock.util; + +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; + +public class RpcProviderRegistryMock implements RpcProviderRegistry { + + OpendaylightFlowStatisticsServiceMock flowStatisticsServiceMock; + OpendaylightFlowTableStatisticsServiceMock flowTableStatisticsServiceMock; + OpendaylightGroupStatisticsServiceMock groupStatisticsServiceMock; + OpendaylightMeterStatisticsServiceMock meterStatisticsServiceMock; + OpendaylightPortStatisticsServiceMock portStatisticsServiceMock; + OpendaylightQueueStatisticsServiceMock queueStatisticsServiceMock; + + public RpcProviderRegistryMock(NotificationProviderServiceHelper notificationProviderService) { + this.flowStatisticsServiceMock = new OpendaylightFlowStatisticsServiceMock(notificationProviderService); + this.flowTableStatisticsServiceMock = new OpendaylightFlowTableStatisticsServiceMock(notificationProviderService); + this.groupStatisticsServiceMock = new OpendaylightGroupStatisticsServiceMock(notificationProviderService); + this.meterStatisticsServiceMock = new OpendaylightMeterStatisticsServiceMock(notificationProviderService); + this.portStatisticsServiceMock = new OpendaylightPortStatisticsServiceMock(notificationProviderService); + this.queueStatisticsServiceMock = new OpendaylightQueueStatisticsServiceMock(notificationProviderService); + } + + @Override + public BindingAwareBroker.RpcRegistration addRpcImplementation(Class serviceInterface, T implementation) throws IllegalStateException { + return null; + } + + @Override + public BindingAwareBroker.RoutedRpcRegistration addRoutedRpcImplementation(Class serviceInterface, T implementation) throws IllegalStateException { + return null; + } + + @Override + public >> ListenerRegistration registerRouteChangeListener(L listener) { + return null; + } + + @SuppressWarnings("unchecked") + @Override + public T getRpcService(Class serviceInterface) { + if (serviceInterface.equals(OpendaylightFlowStatisticsService.class)) { + return (T)flowStatisticsServiceMock; + } else if (serviceInterface.equals(OpendaylightFlowTableStatisticsService.class)) { + return (T) flowTableStatisticsServiceMock; + } else if (serviceInterface.equals(OpendaylightGroupStatisticsService.class)) { + return (T) groupStatisticsServiceMock; + } else if (serviceInterface.equals(OpendaylightMeterStatisticsService.class)) { + return (T) meterStatisticsServiceMock; + } else if (serviceInterface.equals(OpendaylightPortStatisticsService.class)) { + return (T) portStatisticsServiceMock; + } else if (serviceInterface.equals(OpendaylightQueueStatisticsService.class)) { + return (T) queueStatisticsServiceMock; + } else { + return null; + } + } + + public OpendaylightFlowStatisticsServiceMock getFlowStatisticsServiceMock() { + return flowStatisticsServiceMock; + } + + public OpendaylightFlowTableStatisticsServiceMock getFlowTableStatisticsServiceMock() { + return flowTableStatisticsServiceMock; + } + + public OpendaylightGroupStatisticsServiceMock getGroupStatisticsServiceMock() { + return groupStatisticsServiceMock; + } + + public OpendaylightMeterStatisticsServiceMock getMeterStatisticsServiceMock() { + return meterStatisticsServiceMock; + } + + public OpendaylightPortStatisticsServiceMock getPortStatisticsServiceMock() { + return portStatisticsServiceMock; + } + + public OpendaylightQueueStatisticsServiceMock getQueueStatisticsServiceMock() { + return queueStatisticsServiceMock; + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/StatisticsManagerTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/StatisticsManagerTest.java new file mode 100644 index 0000000000..7f266d9c3c --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/StatisticsManagerTest.java @@ -0,0 +1,198 @@ +package test.mock.util; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter32; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter64; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FeatureCapability; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SwitchFeaturesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.port.mod.port.Port; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemovedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; + +public abstract class StatisticsManagerTest extends AbstractDataBrokerTest { + + public static final Counter64 COUNTER_64_TEST_VALUE = new Counter64(BigInteger.valueOf(128)); + public static final Counter32 COUNTER_32_TEST_VALUE = new Counter32(64L); + public static final Long MAX_GROUPS_TEST_VALUE = 2000L; + public static final BigInteger BIG_INTEGER_TEST_VALUE = BigInteger.valueOf(1000); + + private static Flow flow; + private static Group group; + private static Meter meter; + private static Port port; + private static Queue queue; + private static TableId tableId; + private static NodeConnectorId nodeConnectorId; + + private final NotificationProviderServiceHelper notificationMock = new NotificationProviderServiceHelper(); + protected final NodeKey s1Key = new NodeKey(new NodeId("S1")); + protected RpcProviderRegistryMock rpcRegistry; + protected ProviderContextMock providerContext; + + @BeforeClass + public static void setupTests() { + flow = FlowMockGenerator.getRandomFlow(); + group = GroupMockGenerator.getRandomGroup(); + meter = MeterMockGenerator.getRandomMeter(); + port = PortMockGenerator.getRandomPort(); + queue = QueueMockGenerator.getRandomQueueWithPortNum(port.getPortNumber().getUint32()); + tableId = new TableId((short) 2); + nodeConnectorId = new NodeConnectorId("connector.1"); + } + + @Before + public void init() { + rpcRegistry = new RpcProviderRegistryMock(notificationMock); + providerContext = new ProviderContextMock(rpcRegistry, getDataBroker(), notificationMock.getNotifBroker()); + } + + // node with statistics capabilities will enable cyclic statistics collection + @SafeVarargs + protected final void addFlowCapableNodeWithFeatures(final NodeKey nodeKey, final Boolean hasMeterCapabilities, + final Class... capabilities) + throws ExecutionException, InterruptedException { + final Nodes nodes = new NodesBuilder().setNode(Collections.emptyList()).build(); + final InstanceIdentifier flowNodeIdentifier = InstanceIdentifier.create(Nodes.class) + .child(Node.class, nodeKey); + + final FlowCapableNodeBuilder fcnBuilder = new FlowCapableNodeBuilder(); + final SwitchFeaturesBuilder sfBuilder = new SwitchFeaturesBuilder(); + final List> capabilitiyList = new ArrayList<>(); + for (final Class capability : capabilities) { + capabilitiyList.add(capability); + } + sfBuilder.setCapabilities(capabilitiyList); + sfBuilder.setMaxTables((short) 2); + final NodeBuilder nodeBuilder = new NodeBuilder(); + nodeBuilder.setKey(nodeKey); + fcnBuilder.setSwitchFeatures(sfBuilder.build()); + final List
    tables = new ArrayList<>(); + final TableBuilder tBuilder = new TableBuilder(); + tBuilder.setId(getFlow().getTableId()); + tables.add(tBuilder.build()); + fcnBuilder.setTable(tables); + final FlowCapableNode flowCapableNode = fcnBuilder.build(); + nodeBuilder.addAugmentation(FlowCapableNode.class, flowCapableNode); + final Node node = nodeBuilder.build(); + + final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class), nodes); + writeTx.put(LogicalDatastoreType.OPERATIONAL, flowNodeIdentifier, nodeBuilder.build()); + if (hasMeterCapabilities) { + final NodeMeterFeaturesBuilder nmfBuilder = new NodeMeterFeaturesBuilder(); + final MeterFeaturesBuilder mfBuilder = new MeterFeaturesBuilder(); + mfBuilder.setMaxBands((short) 4); + nmfBuilder.setMeterFeatures(mfBuilder.build()); + writeTx.put(LogicalDatastoreType.OPERATIONAL, flowNodeIdentifier.augmentation(NodeMeterFeatures.class), + nmfBuilder.build()); + } + writeTx.put(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Nodes.class), nodes); + writeTx.put(LogicalDatastoreType.CONFIGURATION, flowNodeIdentifier, node); + assertCommit(writeTx.submit()); + + final NodeUpdatedBuilder nuBuilder = new NodeUpdatedBuilder(node); + final FlowCapableNodeUpdatedBuilder fcnuBuilder = new FlowCapableNodeUpdatedBuilder(flowCapableNode); + nuBuilder.setNodeRef(new NodeRef(flowNodeIdentifier)); + nuBuilder.addAugmentation(FlowCapableNodeUpdated.class, fcnuBuilder.build()); + notificationMock.pushNotification(nuBuilder.build()); + } + + public void addFlowCapableNode(final NodeKey nodeKey) throws ExecutionException, InterruptedException { + final Nodes nodes = new NodesBuilder().setNode(Collections.emptyList()).build(); + final InstanceIdentifier flowNodeIdentifier = InstanceIdentifier.create(Nodes.class) + .child(Node.class, nodeKey); + + final FlowCapableNodeBuilder fcnBuilder = new FlowCapableNodeBuilder(); + final NodeBuilder nodeBuilder = new NodeBuilder(); + nodeBuilder.setKey(nodeKey); + final FlowCapableNode flowCapableNode = fcnBuilder.build(); + nodeBuilder.addAugmentation(FlowCapableNode.class, flowCapableNode); + final Node node = nodeBuilder.build(); + + final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class), nodes); + writeTx.put(LogicalDatastoreType.OPERATIONAL, flowNodeIdentifier, node); + writeTx.put(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Nodes.class), nodes); + writeTx.put(LogicalDatastoreType.CONFIGURATION, flowNodeIdentifier, node); + assertCommit(writeTx.submit()); + + final NodeUpdatedBuilder nuBuilder = new NodeUpdatedBuilder(node); + final FlowCapableNodeUpdatedBuilder fcnuBuilder = new FlowCapableNodeUpdatedBuilder(flowCapableNode); + nuBuilder.setNodeRef(new NodeRef(flowNodeIdentifier)); + nuBuilder.addAugmentation(FlowCapableNodeUpdated.class, fcnuBuilder.build()); + notificationMock.pushNotification(nuBuilder.build()); + } + + protected void removeNode(final NodeKey nodeKey) throws ExecutionException, InterruptedException { + final InstanceIdentifier nodeII = InstanceIdentifier.create(Nodes.class).child(Node.class, nodeKey); + + final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.delete(LogicalDatastoreType.OPERATIONAL, nodeII); + writeTx.submit().get(); + + final NodeRemovedBuilder nrBuilder = new NodeRemovedBuilder(); + nrBuilder.setNodeRef(new NodeRef(nodeII)); + notificationMock.pushNotification(nrBuilder.build()); + } + + public static Flow getFlow() { + return flow; + } + + public static Group getGroup() { + return group; + } + + public static Meter getMeter() { + return meter; + } + + public static Port getPort() { + return port; + } + + public static Queue getQueue() { + return queue; + } + + public static TableId getTableId() { + return tableId; + } + + public static NodeConnectorId getNodeConnectorId() { + return nodeConnectorId; + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/TestUtils.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/TestUtils.java new file mode 100644 index 0000000000..e38a25e8e9 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/TestUtils.java @@ -0,0 +1,11 @@ +package test.mock.util; + +import java.util.Random; + +public class TestUtils { + private static Random rnd = new Random(); + + public static long nextLong(long RangeBottom, long rangeTop) { + return RangeBottom + ((long)(rnd.nextDouble()*(rangeTop - RangeBottom))); + } +} diff --git a/opendaylight/md-sal/topology-lldp-discovery/pom.xml b/opendaylight/md-sal/topology-lldp-discovery/pom.xml index 97ed15df19..e6a9a75337 100644 --- a/opendaylight/md-sal/topology-lldp-discovery/pom.xml +++ b/opendaylight/md-sal/topology-lldp-discovery/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT ../ org.opendaylight.controller.md diff --git a/opendaylight/md-sal/topology-manager/pom.xml b/opendaylight/md-sal/topology-manager/pom.xml index fe1813a199..bfef646da1 100644 --- a/opendaylight/md-sal/topology-manager/pom.xml +++ b/opendaylight/md-sal/topology-manager/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller sal-parent - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT org.opendaylight.controller.md topology-manager @@ -40,6 +40,16 @@ org.osgi.core provided + + junit + junit + test + + + org.mockito + mockito-all + test + diff --git a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java index c1996f4691..9b36f9f497 100644 --- a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java +++ b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java @@ -7,17 +7,8 @@ */ package org.opendaylight.md.controller.topology.manager; -import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.getNodeConnectorKey; -import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.getNodeKey; -import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTerminationPoint; -import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTerminationPointId; -import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyLink; -import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNode; -import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNodeId; - -import java.util.Collections; -import java.util.List; - +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; @@ -48,19 +39,25 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; +import java.util.Collections; +import java.util.List; + +import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.getNodeConnectorKey; +import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.getNodeKey; +import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTerminationPoint; +import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTerminationPointId; +import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyLink; +import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNode; +import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNodeId; class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, OpendaylightInventoryListener { - private final Logger LOG = LoggerFactory.getLogger(FlowCapableTopologyExporter.class); + private static final Logger LOG = LoggerFactory.getLogger(FlowCapableTopologyExporter.class); private final InstanceIdentifier topology; private final OperationProcessor processor; - FlowCapableTopologyExporter(final OperationProcessor processor, final InstanceIdentifier topology) { + FlowCapableTopologyExporter(final OperationProcessor processor, + final InstanceIdentifier topology) { this.processor = Preconditions.checkNotNull(processor); this.topology = Preconditions.checkNotNull(topology); } @@ -73,15 +70,14 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open processor.enqueueOperation(new TopologyOperation() { @Override - public void applyOperation(final ReadWriteTransaction transaction) { - removeAffectedLinks(nodeId); + public void applyOperation(ReadWriteTransaction transaction) { + removeAffectedLinks(nodeId, transaction); + transaction.delete(LogicalDatastoreType.OPERATIONAL, nodeInstance); } - }); - processor.enqueueOperation(new TopologyOperation() { @Override - public void applyOperation(ReadWriteTransaction transaction) { - transaction.delete(LogicalDatastoreType.OPERATIONAL, nodeInstance); + public String toString() { + return "onNodeRemoved"; } }); } @@ -97,6 +93,11 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open final InstanceIdentifier path = getNodePath(toTopologyNodeId(notification.getId())); transaction.merge(LogicalDatastoreType.OPERATIONAL, path, node, true); } + + @Override + public String toString() { + return "onNodeUpdated"; + } }); } } @@ -104,28 +105,40 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open @Override public void onNodeConnectorRemoved(final NodeConnectorRemoved notification) { - final InstanceIdentifier tpInstance = toTerminationPointIdentifier(notification - .getNodeConnectorRef()); + final InstanceIdentifier tpInstance = toTerminationPointIdentifier( + notification.getNodeConnectorRef()); + + final InstanceIdentifier node = tpInstance.firstIdentifierOf(Node.class); + + final TpId tpId = toTerminationPointId(getNodeConnectorKey( + notification.getNodeConnectorRef()).getId()); processor.enqueueOperation(new TopologyOperation() { @Override - public void applyOperation(final ReadWriteTransaction transaction) { - final TpId tpId = toTerminationPointId(getNodeConnectorKey(notification.getNodeConnectorRef()).getId()); - removeAffectedLinks(tpId); + public void applyOperation(ReadWriteTransaction transaction) { + Optional nodeOptional = Optional.absent(); + try { + nodeOptional = transaction.read(LogicalDatastoreType.OPERATIONAL, node).checkedGet(); + } catch (ReadFailedException e) { + LOG.error("Error occured when trying to read NodeConnector ", e); + } + if (nodeOptional.isPresent()) { + removeAffectedLinks(tpId, transaction); + transaction.delete(LogicalDatastoreType.OPERATIONAL, tpInstance); + } } - }); - processor.enqueueOperation(new TopologyOperation() { @Override - public void applyOperation(ReadWriteTransaction transaction) { - transaction.delete(LogicalDatastoreType.OPERATIONAL, tpInstance); + public String toString() { + return "onNodeConnectorRemoved"; } }); } @Override public void onNodeConnectorUpdated(final NodeConnectorUpdated notification) { - final FlowCapableNodeConnectorUpdated fcncu = notification.getAugmentation(FlowCapableNodeConnectorUpdated.class); + final FlowCapableNodeConnectorUpdated fcncu = notification.getAugmentation( + FlowCapableNodeConnectorUpdated.class); if (fcncu != null) { processor.enqueueOperation(new TopologyOperation() { @Override @@ -137,9 +150,14 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open transaction.merge(LogicalDatastoreType.OPERATIONAL, path, point, true); if ((fcncu.getState() != null && fcncu.getState().isLinkDown()) || (fcncu.getConfiguration() != null && fcncu.getConfiguration().isPORTDOWN())) { - removeAffectedLinks(point.getTpId()); + removeAffectedLinks(point.getTpId(), transaction); } } + + @Override + public String toString() { + return "onNodeConnectorUpdated"; + } }); } } @@ -151,7 +169,12 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open public void applyOperation(final ReadWriteTransaction transaction) { final Link link = toTopologyLink(notification); final InstanceIdentifier path = linkPath(link); - transaction.merge(LogicalDatastoreType.OPERATIONAL, path, link, true); + transaction.put(LogicalDatastoreType.OPERATIONAL, path, link, true); + } + + @Override + public String toString() { + return "onLinkDiscovered"; } }); } @@ -166,7 +189,22 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open processor.enqueueOperation(new TopologyOperation() { @Override public void applyOperation(final ReadWriteTransaction transaction) { - transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(toTopologyLink(notification))); + Optional linkOptional = Optional.absent(); + try { + // read that checks if link exists (if we do not do this we might get an exception on delete) + linkOptional = transaction.read(LogicalDatastoreType.OPERATIONAL, + linkPath(toTopologyLink(notification))).checkedGet(); + } catch (ReadFailedException e) { + LOG.error("Error occured when trying to read Link ", e); + } + if (linkOptional.isPresent()) { + transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(toTopologyLink(notification))); + } + } + + @Override + public String toString() { + return "onLinkRemoved"; } }); } @@ -188,60 +226,58 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open return tpPath(toTopologyNodeId(invNodeKey.getId()), toTerminationPointId(invNodeConnectorKey.getId())); } - private void removeAffectedLinks(final NodeId id) { - processor.enqueueOperation(new TopologyOperation() { - @Override - public void applyOperation(final ReadWriteTransaction transaction) { - CheckedFuture, ReadFailedException> topologyDataFuture = transaction.read(LogicalDatastoreType.OPERATIONAL, topology); - Futures.addCallback(topologyDataFuture, new FutureCallback>() { - @Override - public void onSuccess(Optional topologyOptional) { - if (topologyOptional.isPresent()) { - List linkList = topologyOptional.get().getLink() != null - ? topologyOptional.get().getLink() : Collections. emptyList(); - for (Link link : linkList) { - if (id.equals(link.getSource().getSourceNode()) || id.equals(link.getDestination().getDestNode())) { - transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(link)); - } - } - } - } + private void removeAffectedLinks(final NodeId id, final ReadWriteTransaction transaction) { + Optional topologyOptional = Optional.absent(); + try { + topologyOptional = transaction.read(LogicalDatastoreType.OPERATIONAL, topology).checkedGet(); + } catch (ReadFailedException e) { + LOG.error("Error reading topology data for topology {}", topology, e); + } + if (topologyOptional.isPresent()) { + removeAffectedLinks(id, topologyOptional, transaction); + } + } - @Override - public void onFailure(Throwable throwable) { - LOG.error("Error reading topology data for topology {}", topology, throwable); - } - }); + private void removeAffectedLinks(final NodeId id, Optional topologyOptional, ReadWriteTransaction transaction) { + if (!topologyOptional.isPresent()) { + return; + } + + List linkList = topologyOptional.get().getLink() != null ? + topologyOptional.get().getLink() : Collections. emptyList(); + for (Link link : linkList) { + if (id.equals(link.getSource().getSourceNode()) || + id.equals(link.getDestination().getDestNode())) { + transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(link)); } - }); + } } - private void removeAffectedLinks(final TpId id) { - processor.enqueueOperation(new TopologyOperation() { - @Override - public void applyOperation(final ReadWriteTransaction transaction) { - CheckedFuture, ReadFailedException> topologyDataFuture = transaction.read(LogicalDatastoreType.OPERATIONAL, topology); - Futures.addCallback(topologyDataFuture, new FutureCallback>() { - @Override - public void onSuccess(Optional topologyOptional) { - if (topologyOptional.isPresent()) { - List linkList = topologyOptional.get().getLink() != null - ? topologyOptional.get().getLink() : Collections. emptyList(); - for (Link link : linkList) { - if (id.equals(link.getSource().getSourceTp()) || id.equals(link.getDestination().getDestTp())) { - transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(link)); - } - } - } - } + private void removeAffectedLinks(final TpId id, final ReadWriteTransaction transaction) { + Optional topologyOptional = Optional.absent(); + try { + topologyOptional = transaction.read(LogicalDatastoreType.OPERATIONAL, topology).checkedGet(); + } catch (ReadFailedException e) { + LOG.error("Error reading topology data for topology {}", topology, e); + } + if (topologyOptional.isPresent()) { + removeAffectedLinks(id, topologyOptional, transaction); + } + } - @Override - public void onFailure(Throwable throwable) { - LOG.error("Error reading topology data for topology {}", topology, throwable); - } - }); + private void removeAffectedLinks(final TpId id, Optional topologyOptional, ReadWriteTransaction transaction) { + if (!topologyOptional.isPresent()) { + return; + } + + List linkList = topologyOptional.get().getLink() != null + ? topologyOptional.get().getLink() : Collections. emptyList(); + for (Link link : linkList) { + if (id.equals(link.getSource().getSourceTp()) || + id.equals(link.getDestination().getDestTp())) { + transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(link)); } - }); + } } private InstanceIdentifier getNodePath(final NodeId nodeId) { diff --git a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/OperationProcessor.java b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/OperationProcessor.java index 1cf648eb97..c009433395 100644 --- a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/OperationProcessor.java +++ b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/OperationProcessor.java @@ -8,20 +8,19 @@ package org.opendaylight.md.controller.topology.manager; import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction; import org.opendaylight.controller.md.sal.common.api.data.TransactionChain; import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + final class OperationProcessor implements AutoCloseable, Runnable, TransactionChainListener { private static final Logger LOG = LoggerFactory.getLogger(OperationProcessor.class); private static final int MAX_TRANSACTION_OPERATIONS = 100; @@ -29,7 +28,8 @@ final class OperationProcessor implements AutoCloseable, Runnable, TransactionCh private final BlockingQueue queue = new LinkedBlockingQueue<>(OPERATION_QUEUE_DEPTH); private final DataBroker dataBroker; - private final BindingTransactionChain transactionChain; + private BindingTransactionChain transactionChain; + private volatile boolean finishing = false; OperationProcessor(final DataBroker dataBroker) { this.dataBroker = Preconditions.checkNotNull(dataBroker); @@ -46,46 +46,56 @@ final class OperationProcessor implements AutoCloseable, Runnable, TransactionCh @Override public void run() { - try { - for (; ; ) { - TopologyOperation op = queue.take(); + while (!finishing) { + try { + TopologyOperation op = queue.take(); - LOG.debug("New operations available, starting transaction"); - final ReadWriteTransaction tx = transactionChain.newReadWriteTransaction(); + LOG.debug("New {} operation available, starting transaction", op); + final ReadWriteTransaction tx = transactionChain.newReadWriteTransaction(); - int ops = 0; - do { - op.applyOperation(tx); + int ops = 0; + do { + op.applyOperation(tx); - ops++; - if (ops < MAX_TRANSACTION_OPERATIONS) { - op = queue.poll(); - } else { - op = null; - } - } while (op != null); + ops++; + if (ops < MAX_TRANSACTION_OPERATIONS) { + op = queue.poll(); + } else { + op = null; + } - LOG.debug("Processed {} operations, submitting transaction", ops); + LOG.debug("Next operation {}", op); + } while (op != null); - final CheckedFuture txResultFuture = tx.submit(); - Futures.addCallback(txResultFuture, new FutureCallback() { - @Override - public void onSuccess(Object o) { - LOG.debug("Topology export successful for tx :{}", tx.getIdentifier()); - } + LOG.debug("Processed {} operations, submitting transaction", ops); - @Override - public void onFailure(Throwable throwable) { - LOG.error("Topology export transaction {} failed", tx.getIdentifier(), throwable.getCause()); + try { + tx.submit().checkedGet(); + } catch (final TransactionCommitFailedException e) { + LOG.warn("Stat DataStoreOperation unexpected State!", e); + transactionChain.close(); + transactionChain = dataBroker.createTransactionChain(this); + cleanDataStoreOperQueue(); } - }); - } - } catch (InterruptedException e) { - LOG.info("Interrupted processing, terminating", e); - } + } catch (final IllegalStateException e) { + LOG.warn("Stat DataStoreOperation unexpected State!", e); + transactionChain.close(); + transactionChain = dataBroker.createTransactionChain(this); + cleanDataStoreOperQueue(); + } catch (final InterruptedException e) { + LOG.warn("Stat Manager DS Operation thread interupted!", e); + finishing = true; + } catch (final Exception e) { + LOG.warn("Stat DataStore Operation executor fail!", e); + } + } // Drain all events, making sure any blocked threads are unblocked + cleanDataStoreOperQueue(); + } + + private void cleanDataStoreOperQueue() { while (!queue.isEmpty()) { queue.poll(); } @@ -94,6 +104,9 @@ final class OperationProcessor implements AutoCloseable, Runnable, TransactionCh @Override public void onTransactionChainFailed(TransactionChain chain, AsyncTransaction transaction, Throwable cause) { LOG.error("Failed to export Topology manager operations, Transaction {} failed.", transaction.getIdentifier(), cause); + transactionChain.close(); + transactionChain = dataBroker.createTransactionChain(this); + cleanDataStoreOperQueue(); } @Override diff --git a/opendaylight/md-sal/topology-manager/src/test/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporterTest.java b/opendaylight/md-sal/topology-manager/src/test/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporterTest.java new file mode 100644 index 0000000000..7f8d021b3b --- /dev/null +++ b/opendaylight/md-sal/topology-manager/src/test/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporterTest.java @@ -0,0 +1,730 @@ +/* + * Copyright (c) 2014 Brocade Communications 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.md.controller.topology.manager; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.SettableFuture; +import com.google.common.util.concurrent.Uninterruptibles; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkDiscoveredBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkRemovedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemovedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemovedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNodeConnector; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Destination; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Source; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +public class FlowCapableTopologyExporterTest { + + @Mock + private DataBroker mockDataBroker; + + @Mock + private BindingTransactionChain mockTxChain; + + private OperationProcessor processor; + + private FlowCapableTopologyExporter exporter; + + private InstanceIdentifier topologyIID; + + private final ExecutorService executor = Executors.newFixedThreadPool(1); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + doReturn(mockTxChain).when(mockDataBroker) + .createTransactionChain(any(TransactionChainListener.class)); + + processor = new OperationProcessor(mockDataBroker); + + topologyIID = InstanceIdentifier.create(NetworkTopology.class) + .child(Topology.class, new TopologyKey(new TopologyId("test"))); + exporter = new FlowCapableTopologyExporter(processor, topologyIID); + + executor.execute(processor); + } + + @After + public void tearDown() { + executor.shutdownNow(); + } + + @SuppressWarnings({ "rawtypes" }) + @Test + public void testOnNodeRemoved() { + + NodeKey topoNodeKey = new NodeKey(new NodeId("node1")); + InstanceIdentifier topoNodeII = topologyIID.child(Node.class, topoNodeKey); + Node topoNode = new NodeBuilder().setKey(topoNodeKey).build(); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue()); + InstanceIdentifier invNodeID = InstanceIdentifier.create(Nodes.class).child( + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, + nodeKey); + + List linkList = Arrays.asList( + newLink("link1", newSourceNode("node1"), newDestNode("dest")), + newLink("link2", newSourceNode("source"), newDestNode("node1")), + newLink("link2", newSourceNode("source2"), newDestNode("dest2"))); + final Topology topology = new TopologyBuilder().setLink(linkList).build(); + + InstanceIdentifier[] expDeletedIIDs = { + topologyIID.child(Link.class, linkList.get(0).getKey()), + topologyIID.child(Link.class, linkList.get(1).getKey()), + topologyIID.child(Node.class, new NodeKey(new NodeId("node1"))) + }; + + SettableFuture> readFuture = SettableFuture.create(); + readFuture.set(Optional.of(topology)); + ReadWriteTransaction mockTx1 = mock(ReadWriteTransaction.class); + doReturn(Futures.makeChecked(readFuture, ReadFailedException.MAPPER)).when(mockTx1) + .read(LogicalDatastoreType.OPERATIONAL, topologyIID); + + SettableFuture> readFutureNode = SettableFuture.create(); + readFutureNode.set(Optional.of(topoNode)); + doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx1) + .read(LogicalDatastoreType.OPERATIONAL, topoNodeII); + + CountDownLatch submitLatch1 = setupStubbedSubmit(mockTx1); + + int expDeleteCalls = expDeletedIIDs.length; + CountDownLatch deleteLatch = new CountDownLatch(expDeleteCalls); + ArgumentCaptor deletedLinkIDs = + ArgumentCaptor.forClass(InstanceIdentifier.class); + setupStubbedDeletes(mockTx1, deletedLinkIDs, deleteLatch); + + doReturn(mockTx1).when(mockTxChain).newReadWriteTransaction(); + + exporter.onNodeRemoved(new NodeRemovedBuilder().setNodeRef(new NodeRef(invNodeID)).build()); + + waitForSubmit(submitLatch1); + + setReadFutureAsync(topology, readFuture); + + waitForDeletes(expDeleteCalls, deleteLatch); + + assertDeletedIDs(expDeletedIIDs, deletedLinkIDs); + + verifyMockTx(mockTx1); + } + + @SuppressWarnings({ "rawtypes" }) + @Test + public void testOnNodeRemovedWithNoTopology() { + + NodeKey topoNodeKey = new NodeKey(new NodeId("node1")); + InstanceIdentifier topoNodeII = topologyIID.child(Node.class, topoNodeKey); + Node topoNode = new NodeBuilder().setKey(topoNodeKey).build(); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue()); + InstanceIdentifier invNodeID = InstanceIdentifier.create(Nodes.class).child( + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, + nodeKey); + + InstanceIdentifier[] expDeletedIIDs = { + topologyIID.child(Node.class, new NodeKey(new NodeId("node1"))) + }; + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx) + .read(LogicalDatastoreType.OPERATIONAL, topologyIID); + CountDownLatch submitLatch = setupStubbedSubmit(mockTx); + + SettableFuture> readFutureNode = SettableFuture.create(); + readFutureNode.set(Optional.of(topoNode)); + doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx) + .read(LogicalDatastoreType.OPERATIONAL, topoNodeII); + + CountDownLatch deleteLatch = new CountDownLatch(1); + ArgumentCaptor deletedLinkIDs = + ArgumentCaptor.forClass(InstanceIdentifier.class); + setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch); + + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + exporter.onNodeRemoved(new NodeRemovedBuilder().setNodeRef(new NodeRef(invNodeID)).build()); + + waitForSubmit(submitLatch); + + waitForDeletes(1, deleteLatch); + + assertDeletedIDs(expDeletedIIDs, deletedLinkIDs); + } + + @SuppressWarnings("rawtypes") + @Test + public void testOnNodeConnectorRemoved() { + + NodeKey topoNodeKey = new NodeKey(new NodeId("node1")); + TerminationPointKey terminationPointKey = new TerminationPointKey(new TpId("tp1")); + + InstanceIdentifier topoNodeII = topologyIID.child(Node.class, topoNodeKey); + Node topoNode = new NodeBuilder().setKey(topoNodeKey).build(); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue()); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = + newInvNodeConnKey(terminationPointKey.getTpId().getValue()); + + InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); + + List linkList = Arrays.asList( + newLink("link1", newSourceTp("tp1"), newDestTp("dest")), + newLink("link2", newSourceTp("source"), newDestTp("tp1")), + newLink("link3", newSourceTp("source2"), newDestTp("dest2"))); + final Topology topology = new TopologyBuilder().setLink(linkList).build(); + + InstanceIdentifier[] expDeletedIIDs = { + topologyIID.child(Link.class, linkList.get(0).getKey()), + topologyIID.child(Link.class, linkList.get(1).getKey()), + topologyIID.child(Node.class, new NodeKey(new NodeId("node1"))) + .child(TerminationPoint.class, new TerminationPointKey(new TpId("tp1"))) + }; + + final SettableFuture> readFuture = SettableFuture.create(); + readFuture.set(Optional.of(topology)); + ReadWriteTransaction mockTx1 = mock(ReadWriteTransaction.class); + doReturn(Futures.makeChecked(readFuture, ReadFailedException.MAPPER)).when(mockTx1) + .read(LogicalDatastoreType.OPERATIONAL, topologyIID); + + SettableFuture> readFutureNode = SettableFuture.create(); + readFutureNode.set(Optional.of(topoNode)); + doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx1) + .read(LogicalDatastoreType.OPERATIONAL, topoNodeII); + + CountDownLatch submitLatch1 = setupStubbedSubmit(mockTx1); + + int expDeleteCalls = expDeletedIIDs.length; + CountDownLatch deleteLatch = new CountDownLatch(expDeleteCalls); + ArgumentCaptor deletedLinkIDs = + ArgumentCaptor.forClass(InstanceIdentifier.class); + setupStubbedDeletes(mockTx1, deletedLinkIDs, deleteLatch); + + doReturn(mockTx1).when(mockTxChain).newReadWriteTransaction(); + + exporter.onNodeConnectorRemoved(new NodeConnectorRemovedBuilder().setNodeConnectorRef( + new NodeConnectorRef(invNodeConnID)).build()); + + waitForSubmit(submitLatch1); + + setReadFutureAsync(topology, readFuture); + + waitForDeletes(expDeleteCalls, deleteLatch); + + assertDeletedIDs(expDeletedIIDs, deletedLinkIDs); + + verifyMockTx(mockTx1); + } + + @SuppressWarnings("rawtypes") + @Test + public void testOnNodeConnectorRemovedWithNoTopology() { + + NodeKey topoNodeKey = new NodeKey(new NodeId("node1")); + TerminationPointKey terminationPointKey = new TerminationPointKey(new TpId("tp1")); + + InstanceIdentifier topoNodeII = topologyIID.child(Node.class, topoNodeKey); + Node topoNode = new NodeBuilder().setKey(topoNodeKey).build(); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue()); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = + newInvNodeConnKey(terminationPointKey.getTpId().getValue()); + + InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); + + InstanceIdentifier[] expDeletedIIDs = { + topologyIID.child(Node.class, new NodeKey(new NodeId("node1"))) + .child(TerminationPoint.class, new TerminationPointKey(new TpId("tp1"))) + }; + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx) + .read(LogicalDatastoreType.OPERATIONAL, topologyIID); + CountDownLatch submitLatch = setupStubbedSubmit(mockTx); + + SettableFuture> readFutureNode = SettableFuture.create(); + readFutureNode.set(Optional.of(topoNode)); + doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx) + .read(LogicalDatastoreType.OPERATIONAL, topoNodeII); + + CountDownLatch deleteLatch = new CountDownLatch(1); + ArgumentCaptor deletedLinkIDs = + ArgumentCaptor.forClass(InstanceIdentifier.class); + setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch); + + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + exporter.onNodeConnectorRemoved(new NodeConnectorRemovedBuilder().setNodeConnectorRef( + new NodeConnectorRef(invNodeConnID)).build()); + + waitForSubmit(submitLatch); + + waitForDeletes(1, deleteLatch); + + assertDeletedIDs(expDeletedIIDs, deletedLinkIDs); + } + + @Test + public void testOnNodeUpdated() { + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey("node1"); + InstanceIdentifier invNodeID = InstanceIdentifier.create(Nodes.class).child( + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, + nodeKey); + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + CountDownLatch submitLatch = setupStubbedSubmit(mockTx); + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + exporter.onNodeUpdated(new NodeUpdatedBuilder().setNodeRef(new NodeRef(invNodeID)) + .setId(nodeKey.getId()).addAugmentation(FlowCapableNodeUpdated.class, + new FlowCapableNodeUpdatedBuilder().build()).build()); + + waitForSubmit(submitLatch); + + ArgumentCaptor mergedNode = ArgumentCaptor.forClass(Node.class); + NodeId expNodeId = new NodeId("node1"); + verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(topologyIID.child(Node.class, + new NodeKey(expNodeId))), mergedNode.capture(), eq(true)); + assertEquals("getNodeId", expNodeId, mergedNode.getValue().getNodeId()); + InventoryNode augmentation = mergedNode.getValue().getAugmentation(InventoryNode.class); + assertNotNull("Missing augmentation", augmentation); + assertEquals("getInventoryNodeRef", new NodeRef(invNodeID), augmentation.getInventoryNodeRef()); + } + + @SuppressWarnings("rawtypes") + @Test + public void testOnNodeConnectorUpdated() { + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey("node1"); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = + newInvNodeConnKey("tp1"); + + InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + CountDownLatch submitLatch = setupStubbedSubmit(mockTx); + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef( + new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation( + FlowCapableNodeConnectorUpdated.class, + new FlowCapableNodeConnectorUpdatedBuilder().build()).build()); + + waitForSubmit(submitLatch); + + ArgumentCaptor mergedNode = ArgumentCaptor.forClass(TerminationPoint.class); + NodeId expNodeId = new NodeId("node1"); + TpId expTpId = new TpId("tp1"); + InstanceIdentifier expTpPath = topologyIID.child( + Node.class, new NodeKey(expNodeId)).child(TerminationPoint.class, + new TerminationPointKey(expTpId)); + verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath), + mergedNode.capture(), eq(true)); + assertEquals("getTpId", expTpId, mergedNode.getValue().getTpId()); + InventoryNodeConnector augmentation = mergedNode.getValue().getAugmentation( + InventoryNodeConnector.class); + assertNotNull("Missing augmentation", augmentation); + assertEquals("getInventoryNodeConnectorRef", new NodeConnectorRef(invNodeConnID), + augmentation.getInventoryNodeConnectorRef()); + } + + @SuppressWarnings("rawtypes") + @Test + public void testOnNodeConnectorUpdatedWithLinkStateDown() { + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey("node1"); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = + newInvNodeConnKey("tp1"); + + InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); + + List linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest"))); + Topology topology = new TopologyBuilder().setLink(linkList).build(); + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx) + .read(LogicalDatastoreType.OPERATIONAL, topologyIID); + setupStubbedSubmit(mockTx); + + CountDownLatch deleteLatch = new CountDownLatch(1); + ArgumentCaptor deletedLinkIDs = + ArgumentCaptor.forClass(InstanceIdentifier.class); + setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch); + + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef( + new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation( + FlowCapableNodeConnectorUpdated.class, + new FlowCapableNodeConnectorUpdatedBuilder().setState( + new StateBuilder().setLinkDown(true).build()).build()).build()); + + waitForDeletes(1, deleteLatch); + + InstanceIdentifier expTpPath = topologyIID.child( + Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class, + new TerminationPointKey(new TpId("tp1"))); + + verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath), + any(TerminationPoint.class), eq(true)); + + assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class, + linkList.get(0).getKey())}, deletedLinkIDs); + } + + + @SuppressWarnings("rawtypes") + @Test + public void testOnNodeConnectorUpdatedWithPortDown() { + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey("node1"); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = + newInvNodeConnKey("tp1"); + + InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); + + List linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest"))); + Topology topology = new TopologyBuilder().setLink(linkList).build(); + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx) + .read(LogicalDatastoreType.OPERATIONAL, topologyIID); + setupStubbedSubmit(mockTx); + + CountDownLatch deleteLatch = new CountDownLatch(1); + ArgumentCaptor deletedLinkIDs = + ArgumentCaptor.forClass(InstanceIdentifier.class); + setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch); + + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef( + new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation( + FlowCapableNodeConnectorUpdated.class, + new FlowCapableNodeConnectorUpdatedBuilder().setConfiguration( + new PortConfig(true, true, true, true)).build()).build()); + + waitForDeletes(1, deleteLatch); + + InstanceIdentifier expTpPath = topologyIID.child( + Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class, + new TerminationPointKey(new TpId("tp1"))); + + verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath), + any(TerminationPoint.class), eq(true)); + + assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class, + linkList.get(0).getKey())}, deletedLinkIDs); + } + + @Test + public void testOnLinkDiscovered() { + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + sourceNodeKey = newInvNodeKey("sourceNode"); + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey + sourceNodeConnKey = newInvNodeConnKey("sourceTP"); + InstanceIdentifier sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + destNodeKey = newInvNodeKey("destNode"); + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey + destNodeConnKey = newInvNodeConnKey("destTP"); + InstanceIdentifier destConnID = newNodeConnID(destNodeKey, destNodeConnKey); + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + CountDownLatch submitLatch = setupStubbedSubmit(mockTx); + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + exporter.onLinkDiscovered(new LinkDiscoveredBuilder().setSource( + new NodeConnectorRef(sourceConnID)).setDestination( + new NodeConnectorRef(destConnID)).build()); + + waitForSubmit(submitLatch); + + ArgumentCaptor mergedNode = ArgumentCaptor.forClass(Link.class); + verify(mockTx).put(eq(LogicalDatastoreType.OPERATIONAL), eq(topologyIID.child( + Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId())))), + mergedNode.capture(), eq(true)); + assertEquals("Source node ID", "sourceNode", + mergedNode.getValue().getSource().getSourceNode().getValue()); + assertEquals("Dest TP ID", "sourceTP", + mergedNode.getValue().getSource().getSourceTp().getValue()); + assertEquals("Dest node ID", "destNode", + mergedNode.getValue().getDestination().getDestNode().getValue()); + assertEquals("Dest TP ID", "destTP", + mergedNode.getValue().getDestination().getDestTp().getValue()); + } + + @Test + public void testOnLinkRemoved() { + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + sourceNodeKey = newInvNodeKey("sourceNode"); + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey + sourceNodeConnKey = newInvNodeConnKey("sourceTP"); + InstanceIdentifier sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + destNodeKey = newInvNodeKey("destNode"); + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey + destNodeConnKey = newInvNodeConnKey("destTP"); + InstanceIdentifier destConnID = newNodeConnID(destNodeKey, destNodeConnKey); + + Link link = newLink(sourceNodeConnKey.getId().getValue(), newSourceTp(sourceNodeConnKey.getId().getValue()), + newDestTp(destNodeConnKey.getId().getValue())); + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + CountDownLatch submitLatch = setupStubbedSubmit(mockTx); + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + doReturn(Futures.immediateCheckedFuture(Optional.of(link))).when(mockTx).read(LogicalDatastoreType.OPERATIONAL, topologyIID.child( + Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId())))); + + exporter.onLinkRemoved(new LinkRemovedBuilder().setSource( + new NodeConnectorRef(sourceConnID)).setDestination( + new NodeConnectorRef(destConnID)).build()); + + waitForSubmit(submitLatch); + + verify(mockTx).delete(LogicalDatastoreType.OPERATIONAL, topologyIID.child( + Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId())))); + } + + @Test + public void testOnLinkRemovedLinkDoesNotExist() { + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + sourceNodeKey = newInvNodeKey("sourceNode"); + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey + sourceNodeConnKey = newInvNodeConnKey("sourceTP"); + InstanceIdentifier sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + destNodeKey = newInvNodeKey("destNode"); + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey + destNodeConnKey = newInvNodeConnKey("destTP"); + InstanceIdentifier destConnID = newNodeConnID(destNodeKey, destNodeConnKey); + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + CountDownLatch submitLatch = setupStubbedSubmit(mockTx); + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx).read(LogicalDatastoreType.OPERATIONAL, topologyIID.child( + Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId())))); + + exporter.onLinkRemoved(new LinkRemovedBuilder().setSource( + new NodeConnectorRef(sourceConnID)).setDestination( + new NodeConnectorRef(destConnID)).build()); + + waitForSubmit(submitLatch); + + verify(mockTx, never()).delete(LogicalDatastoreType.OPERATIONAL, topologyIID.child( + Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId())))); + } + + private void verifyMockTx(ReadWriteTransaction mockTx) { + InOrder inOrder = inOrder(mockTx); + inOrder.verify(mockTx, atLeast(0)).submit(); + inOrder.verify(mockTx, never()).delete(eq(LogicalDatastoreType.OPERATIONAL), + any(InstanceIdentifier.class)); + } + + @SuppressWarnings("rawtypes") + private void assertDeletedIDs(InstanceIdentifier[] expDeletedIIDs, + ArgumentCaptor deletedLinkIDs) { + Set actualIIDs = new HashSet<>(deletedLinkIDs.getAllValues()); + for(InstanceIdentifier id: expDeletedIIDs) { + assertTrue("Missing expected deleted IID " + id, actualIIDs.contains(id)); + } + } + + private void setReadFutureAsync(final Topology topology, + final SettableFuture> readFuture) { + new Thread() { + @Override + public void run() { + Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS); + readFuture.set(Optional.of(topology)); + } + + }.start(); + } + + private void waitForSubmit(CountDownLatch latch) { + assertEquals("Transaction submitted", true, + Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS)); + } + + private void waitForDeletes(int expDeleteCalls, final CountDownLatch latch) { + boolean done = Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS); + if(!done) { + fail("Expected " + expDeleteCalls + " delete calls. Actual: " + + (expDeleteCalls - latch.getCount())); + } + } + + private CountDownLatch setupStubbedSubmit(ReadWriteTransaction mockTx) { + final CountDownLatch latch = new CountDownLatch(1); + doAnswer(new Answer>() { + @Override + public CheckedFuture answer( + InvocationOnMock invocation) { + latch.countDown(); + return Futures.immediateCheckedFuture(null); + } + }).when(mockTx).submit(); + + return latch; + } + + @SuppressWarnings("rawtypes") + private void setupStubbedDeletes(ReadWriteTransaction mockTx, + ArgumentCaptor deletedLinkIDs, final CountDownLatch latch) { + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) { + latch.countDown(); + return null; + } + }).when(mockTx).delete(eq(LogicalDatastoreType.OPERATIONAL), deletedLinkIDs.capture()); + } + + private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + newInvNodeKey(String id) { + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey = + new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey( + new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory. + rev130819.NodeId(id)); + return nodeKey; + } + + private NodeConnectorKey newInvNodeConnKey(String id) { + return new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey( + new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819. + NodeConnectorId(id)); + } + + private KeyedInstanceIdentifier newNodeConnID( + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey, + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey) { + return InstanceIdentifier.create(Nodes.class).child( + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, + nodeKey).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory. + rev130819.node.NodeConnector.class, ncKey); + } + + private Link newLink(String id, Source source, Destination dest) { + return new LinkBuilder().setLinkId(new LinkId(id)) + .setSource(source).setDestination(dest).build(); + } + + private Destination newDestTp(String id) { + return new DestinationBuilder().setDestTp(new TpId(id)).build(); + } + + private Source newSourceTp(String id) { + return new SourceBuilder().setSourceTp(new TpId(id)).build(); + } + + private Destination newDestNode(String id) { + return new DestinationBuilder().setDestNode(new NodeId(id)).build(); + } + + private Source newSourceNode(String id) { + return new SourceBuilder().setSourceNode(new NodeId(id)).build(); + } +} diff --git a/opendaylight/netconf/config-netconf-connector/pom.xml b/opendaylight/netconf/config-netconf-connector/pom.xml index 8a29139854..edba4e11da 100644 --- a/opendaylight/netconf/config-netconf-connector/pom.xml +++ b/opendaylight/netconf/config-netconf-connector/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT config-netconf-connector bundle diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectNameAttributeReadingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectNameAttributeReadingStrategy.java index 8720c654c6..1d12292edb 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectNameAttributeReadingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectNameAttributeReadingStrategy.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attri import com.google.common.base.Preconditions; +import com.google.common.base.Strings; import java.util.List; import java.util.Map; @@ -52,7 +53,7 @@ public class ObjectNameAttributeReadingStrategy extends AbstractAttributeReading public static String checkPrefixAndExtractServiceName(XmlElement typeElement, Map.Entry prefixNamespace) throws NetconfDocumentedException { String serviceName = typeElement.getTextContent(); // FIXME: comparing Entry with String: - Preconditions.checkState(!prefixNamespace.equals(""), "Service %s value not prefixed with namespace", + Preconditions.checkState(!Strings.isNullOrEmpty(prefixNamespace.getKey()), "Service %s value not prefixed with namespace", XmlNetconfConstants.TYPE_KEY); String prefix = prefixNamespace.getKey() + PREFIX_SEPARATOR; Preconditions.checkState(serviceName.startsWith(prefix), diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleIdentityRefAttributeReadingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleIdentityRefAttributeReadingStrategy.java index 8e7ba708c6..94a90a782e 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleIdentityRefAttributeReadingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleIdentityRefAttributeReadingStrategy.java @@ -47,11 +47,11 @@ public class SimpleIdentityRefAttributeReadingStrategy extends SimpleAttributeRe Date revision = null; Map revisions = identityMap.get(namespace); if(revisions.keySet().size() > 1) { - for (Date date : revisions.keySet()) { - if(revisions.get(date).containsIdName(localName)) { + for (Map.Entry revisionToIdentityEntry : revisions.entrySet()) { + if(revisionToIdentityEntry.getValue().containsIdName(localName)) { Preconditions.checkState(revision == null, "Duplicate identity %s, in namespace %s, with revisions: %s, %s detected. Cannot map attribute", - localName, namespace, revision, date); - revision = date; + localName, namespace, revision, revisionToIdentityEntry.getKey()); + revision = revisionToIdentityEntry.getKey(); } } } else { diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java index 5d41b784f5..773e4ee933 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java @@ -60,11 +60,11 @@ public class Config { Map>> retVal = Maps.newLinkedHashMap(); - for (String namespace : configs.keySet()) { + for (Entry> namespaceToModuleToConfigEntry : configs.entrySet()) { Map> innerRetVal = Maps.newHashMap(); - for (Entry mbeEntry : configs.get(namespace).entrySet()) { + for (Entry mbeEntry : namespaceToModuleToConfigEntry.getValue().entrySet()) { String moduleName = mbeEntry.getKey(); Collection instances = moduleToInstances.get(moduleName); @@ -80,7 +80,7 @@ public class Config { } - retVal.put(namespace, innerRetVal); + retVal.put(namespaceToModuleToConfigEntry.getKey(), innerRetVal); } return retVal; } @@ -107,18 +107,18 @@ public class Config { Element modulesElement = XmlUtil.createElement(document, XmlNetconfConstants.MODULES_KEY, Optional.of(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG)); dataElement.appendChild(modulesElement); - for (String moduleNamespace : moduleToInstances.keySet()) { - for (Entry> moduleMappingEntry : moduleToInstances.get(moduleNamespace) + for (Entry>> moduleToInstanceEntry : moduleToInstances.entrySet()) { + for (Entry> moduleMappingEntry : moduleToInstanceEntry.getValue() .entrySet()) { - ModuleConfig mapping = moduleConfigs.get(moduleNamespace).get(moduleMappingEntry.getKey()); + ModuleConfig mapping = moduleConfigs.get(moduleToInstanceEntry.getKey()).get(moduleMappingEntry.getKey()); if (moduleMappingEntry.getValue().isEmpty()) { continue; } for (ObjectName objectName : moduleMappingEntry.getValue()) { - modulesElement.appendChild(mapping.toXml(objectName, document, moduleNamespace)); + modulesElement.appendChild(mapping.toXml(objectName, document, moduleToInstanceEntry.getKey())); } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ServiceRegistryWrapper.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ServiceRegistryWrapper.java index 2b363ea153..8c2c74f2ac 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ServiceRegistryWrapper.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ServiceRegistryWrapper.java @@ -24,7 +24,6 @@ public class ServiceRegistryWrapper { this.configServiceRefRegistry = configServiceRefRegistry; } - public ObjectName getByServiceAndRefName(String namespace, String serviceName, String refName) { Map> serviceNameToRefNameToInstance = getMappedServices().get(namespace); @@ -61,13 +60,13 @@ public class ServiceRegistryWrapper { Map>> retVal = Maps.newHashMap(); Map> serviceMapping = configServiceRefRegistry.getServiceMapping(); - for (String serviceQName : serviceMapping.keySet()){ - for (String refName : serviceMapping.get(serviceQName).keySet()) { + for (Map.Entry> qNameToRefNameEntry : serviceMapping.entrySet()){ + for (String refName : qNameToRefNameEntry.getValue().keySet()) { - ObjectName on = serviceMapping.get(serviceQName).get(refName); + ObjectName on = qNameToRefNameEntry.getValue().get(refName); Services.ServiceInstance si = Services.ServiceInstance.fromObjectName(on); - QName qname = QName.create(serviceQName); + QName qname = QName.create(qNameToRefNameEntry.getKey()); String namespace = qname.getNamespace().toString(); Map> serviceToRefs = retVal.get(namespace); if(serviceToRefs==null) { diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java index 59a1d4fe71..bdb4c1b067 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java @@ -133,9 +133,9 @@ public final class Services { Element root = XmlUtil.createElement(document, XmlNetconfConstants.SERVICES_KEY, Optional.of(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG)); Map>> mappedServices = serviceRegistryWrapper.getMappedServices(); - for (String namespace : mappedServices.keySet()) { + for (Entry>> namespaceToRefEntry : mappedServices.entrySet()) { - for (Entry> serviceEntry : mappedServices.get(namespace).entrySet()) { + for (Entry> serviceEntry : namespaceToRefEntry.getValue().entrySet()) { // service belongs to config.yang namespace Element serviceElement = XmlUtil.createElement(document, SERVICE_KEY, Optional.absent()); root.appendChild(serviceElement); @@ -143,7 +143,7 @@ public final class Services { // type belongs to config.yang namespace String serviceType = serviceEntry.getKey(); Element typeElement = XmlUtil.createTextElementWithNamespacedContent(document, XmlNetconfConstants.TYPE_KEY, - XmlNetconfConstants.PREFIX, namespace, serviceType); + XmlNetconfConstants.PREFIX, namespaceToRefEntry.getKey(), serviceType); serviceElement.appendChild(typeElement); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java index 44227bb4d8..350b0aa247 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java @@ -107,7 +107,7 @@ public class InstanceRuntime { String elementName = jmxToYangChildRbeMapping.get(childMappingEntry.getKey()); - Element innerXml = XmlUtil.createElement(document, elementName, Optional.absent()); + Element innerXml = XmlUtil.createElement(document, elementName, Optional.of(namespace)); childMappingEntry.getValue().toXml(objectName, innerChildRbeOns, document, runtimeInstanceIndex, innerXml, namespace); xml.appendChild(innerXml); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java index 543a2c4a63..c22dcfe67b 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java @@ -148,21 +148,20 @@ public class EditConfig extends AbstractConfigNetconfOperation { Map>> namespaceToServiceNameToRefNameToInstance = services .getNamespaceToServiceNameToRefNameToInstance(); - for (String serviceNamespace : namespaceToServiceNameToRefNameToInstance.keySet()) { - for (String serviceName : namespaceToServiceNameToRefNameToInstance.get(serviceNamespace).keySet()) { + for (Map.Entry>> namespaceToServiceToRefEntry : namespaceToServiceNameToRefNameToInstance.entrySet()) { + for (Map.Entry> serviceToRefEntry : namespaceToServiceToRefEntry.getValue().entrySet()) { - String qnameOfService = getQname(ta, serviceNamespace, serviceName); - Map refNameToInstance = namespaceToServiceNameToRefNameToInstance - .get(serviceNamespace).get(serviceName); + String qnameOfService = getQname(ta, namespaceToServiceToRefEntry.getKey(), serviceToRefEntry.getKey()); + Map refNameToInstance = serviceToRefEntry.getValue(); - for (String refName : refNameToInstance.keySet()) { - ObjectName on = refNameToInstance.get(refName).getObjectName(ta.getTransactionName()); + for (Map.Entry refNameToServiceEntry : refNameToInstance.entrySet()) { + ObjectName on = refNameToServiceEntry.getValue().getObjectName(ta.getTransactionName()); try { - ObjectName saved = ta.saveServiceReference(qnameOfService, refName, on); + ObjectName saved = ta.saveServiceReference(qnameOfService, refNameToServiceEntry.getKey(), on); logger.debug("Saving service {} with on {} under name {} with service on {}", qnameOfService, - on, refName, saved); + on, refNameToServiceEntry.getKey(), saved); } catch (InstanceNotFoundException e) { - throw new NetconfDocumentedException(String.format("Unable to save ref name " + refName + " for instance " + on, e), + throw new NetconfDocumentedException(String.format("Unable to save ref name " + refNameToServiceEntry.getKey() + " for instance " + on, e), ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error); @@ -271,18 +270,18 @@ public class EditConfig extends AbstractConfigNetconfOperation { Map> namespaceToModuleNameToModuleConfig = Maps.newHashMap(); - for (String namespace : mBeanEntries.keySet()) { - for (Map.Entry moduleNameToMbe : mBeanEntries.get(namespace).entrySet()) { + for (Map.Entry> namespaceToModuleToMbe : mBeanEntries.entrySet()) { + for (Map.Entry moduleNameToMbe : namespaceToModuleToMbe.getValue().entrySet()) { String moduleName = moduleNameToMbe.getKey(); ModuleMXBeanEntry moduleMXBeanEntry = moduleNameToMbe.getValue(); ModuleConfig moduleConfig = new ModuleConfig(moduleName, new InstanceConfig(configRegistryClient,moduleMXBeanEntry.getAttributes(), moduleMXBeanEntry.getNullableDummyContainerName())); - Map moduleNameToModuleConfig = namespaceToModuleNameToModuleConfig.get(namespace); + Map moduleNameToModuleConfig = namespaceToModuleNameToModuleConfig.get(namespaceToModuleToMbe.getKey()); if(moduleNameToModuleConfig == null) { moduleNameToModuleConfig = Maps.newHashMap(); - namespaceToModuleNameToModuleConfig.put(namespace, moduleNameToModuleConfig); + namespaceToModuleNameToModuleConfig.put(namespaceToModuleToMbe.getKey(), moduleNameToModuleConfig); } moduleNameToModuleConfig.put(moduleName, moduleConfig); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java index fc95046dfd..9155bb95d2 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java @@ -54,13 +54,13 @@ public class Get extends AbstractConfigNetconfOperation { Map> mBeanEntries) { Map> retVal = Maps.newHashMap(); - for (String namespace : mBeanEntries.keySet()) { + for (Map.Entry> namespaceToModuleEntry : mBeanEntries.entrySet()) { Map innerMap = Maps.newHashMap(); - Map entriesFromNamespace = mBeanEntries.get(namespace); - for (String module : entriesFromNamespace.keySet()) { + Map entriesFromNamespace = namespaceToModuleEntry.getValue(); + for (Map.Entry moduleToMXEntry : entriesFromNamespace.entrySet()) { - ModuleMXBeanEntry mbe = entriesFromNamespace.get(module); + ModuleMXBeanEntry mbe = moduleToMXEntry.getValue(); Map cache = Maps.newHashMap(); RuntimeBeanEntry root = null; @@ -77,10 +77,10 @@ public class Get extends AbstractConfigNetconfOperation { InstanceRuntime rootInstanceRuntime = createInstanceRuntime(root, cache); ModuleRuntime moduleRuntime = new ModuleRuntime(rootInstanceRuntime); - innerMap.put(module, moduleRuntime); + innerMap.put(moduleToMXEntry.getKey(), moduleRuntime); } - retVal.put(namespace, innerMap); + retVal.put(namespaceToModuleEntry.getKey(), innerMap); } return retVal; } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpc.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpc.java index 21021fec55..0d9c61bad7 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpc.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpc.java @@ -81,8 +81,7 @@ public class RuntimeRpc extends AbstractConfigNetconfOperation { final String[] signature = new String[attributes.size()]; int i = 0; - for (final String attrName : attributes.keySet()) { - final AttributeConfigElement attribute = attributes.get(attrName); + for (final AttributeConfigElement attribute : attributes.values()) { final Optional resolvedValueOpt = attribute.getResolvedValue(); params[i] = resolvedValueOpt.isPresent() ? resolvedValueOpt.get() : attribute.getResolvedDefaultValue(); @@ -248,23 +247,23 @@ public class RuntimeRpc extends AbstractConfigNetconfOperation { final Map> map = Maps.newHashMap(); - for (final String namespace : mBeanEntries.keySet()) { + for (final Map.Entry> namespaceToModuleEntry : mBeanEntries.entrySet()) { - Map namespaceToModules = map.get(namespace); + Map namespaceToModules = map.get(namespaceToModuleEntry.getKey()); if (namespaceToModules == null) { namespaceToModules = Maps.newHashMap(); - map.put(namespace, namespaceToModules); + map.put(namespaceToModuleEntry.getKey(), namespaceToModules); } - for (final String moduleName : mBeanEntries.get(namespace).keySet()) { + for (final Map.Entry moduleEntry : namespaceToModuleEntry.getValue().entrySet()) { - ModuleRpcs rpcMapping = namespaceToModules.get(moduleName); + ModuleRpcs rpcMapping = namespaceToModules.get(moduleEntry.getKey()); if (rpcMapping == null) { rpcMapping = new ModuleRpcs(); - namespaceToModules.put(moduleName, rpcMapping); + namespaceToModules.put(moduleEntry.getKey(), rpcMapping); } - final ModuleMXBeanEntry entry = mBeanEntries.get(namespace).get(moduleName); + final ModuleMXBeanEntry entry = moduleEntry.getValue(); for (final RuntimeBeanEntry runtimeEntry : entry.getRuntimeBeans()) { rpcMapping.addNameMapping(runtimeEntry); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java index beab62e997..11d2e748bf 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java @@ -55,7 +55,7 @@ public class TransactionProvider implements AutoCloseable { allOpenedTransactions.clear(); } - public Optional getTransaction() { + public synchronized Optional getTransaction() { if (transaction == null){ return Optional.absent(); diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java index e41b174b66..641881cf9e 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java @@ -662,7 +662,7 @@ public class NetconfMappingTest extends AbstractConfigTest { assertEquals(8 * 4, getElementsSize(response, "inner-inner-running-data")); assertEquals(8 * 4, getElementsSize(response, "deep3")); assertEquals(8 * 4 * 2, getElementsSize(response, "list-of-strings")); - assertEquals(8, getElementsSize(response, "inner-running-data-additional")); + assertEquals(8, getElementsSize(response, "inner-running-data-additional", "urn:opendaylight:params:xml:ns:yang:controller:test:impl")); assertEquals(8, getElementsSize(response, "deep4")); // TODO assert keys @@ -693,6 +693,10 @@ public class NetconfMappingTest extends AbstractConfigTest { return response.getElementsByTagName(elementName).getLength(); } + private int getElementsSize(Document response, String elementName, String namespace) { + return response.getElementsByTagNameNS(namespace, elementName).getLength(); + } + private Document executeOp(final NetconfOperation op, final String filename) throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException { diff --git a/opendaylight/netconf/config-persister-impl/pom.xml b/opendaylight/netconf/config-persister-impl/pom.xml index 2e2b622bd2..2b297fbadd 100644 --- a/opendaylight/netconf/config-persister-impl/pom.xml +++ b/opendaylight/netconf/config-persister-impl/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../ config-persister-impl diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherImpl.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherImpl.java index 5f311b5232..b346522f44 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherImpl.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherImpl.java @@ -10,6 +10,9 @@ package org.opendaylight.controller.netconf.persist.impl; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.base.Function; +import com.google.common.base.Stopwatch; +import com.google.common.collect.Collections2; import java.io.IOException; import java.io.InputStream; import java.util.Collection; @@ -23,10 +26,9 @@ import java.util.TreeMap; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; - +import javax.annotation.Nonnull; import javax.annotation.concurrent.Immutable; import javax.management.MBeanServerConnection; - import org.opendaylight.controller.config.api.ConflictingVersionException; import org.opendaylight.controller.config.persist.api.ConfigPusher; import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; @@ -49,10 +51,6 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; -import com.google.common.base.Function; -import com.google.common.base.Stopwatch; -import com.google.common.collect.Collections2; - @Immutable public class ConfigPusherImpl implements ConfigPusher { private static final Logger logger = LoggerFactory.getLogger(ConfigPusherImpl.class); @@ -200,7 +198,7 @@ public class ConfigPusherImpl implements ConfigPusher { private static Set computeNotFoundCapabilities(Set expectedCapabilities, NetconfOperationService serviceCandidate) { Collection actual = Collections2.transform(serviceCandidate.getCapabilities(), new Function() { @Override - public String apply(Capability input) { + public String apply(@Nonnull final Capability input) { return input.getCapabilityUri(); } }); diff --git a/opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml b/opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml index 330bcc8796..33e4ef0050 100644 --- a/opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml +++ b/opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ietf-netconf-monitoring-extension bundle diff --git a/opendaylight/netconf/ietf-netconf-monitoring/pom.xml b/opendaylight/netconf/ietf-netconf-monitoring/pom.xml index 8d4b99bf03..5a6c66b95c 100644 --- a/opendaylight/netconf/ietf-netconf-monitoring/pom.xml +++ b/opendaylight/netconf/ietf-netconf-monitoring/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ietf-netconf-monitoring bundle diff --git a/opendaylight/netconf/netconf-api/pom.xml b/opendaylight/netconf/netconf-api/pom.xml index a15047224b..c5fd8f1894 100644 --- a/opendaylight/netconf/netconf-api/pom.xml +++ b/opendaylight/netconf/netconf-api/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT netconf-api bundle diff --git a/opendaylight/netconf/netconf-artifacts/pom.xml b/opendaylight/netconf/netconf-artifacts/pom.xml new file mode 100644 index 0000000000..eb3cac18df --- /dev/null +++ b/opendaylight/netconf/netconf-artifacts/pom.xml @@ -0,0 +1,164 @@ + + + + + + 4.0.0 + org.opendaylight.controller + netconf-artifacts + 0.3.0-SNAPSHOT + pom + + + + + ${project.groupId} + netconf-config-dispatcher + ${project.version} + + + ${project.groupId} + config-netconf-connector + ${project.version} + + + ${project.groupId} + config-persister-impl + ${project.version} + + + ${project.groupId} + netconf-api + ${project.version} + + + ${project.groupId} + netconf-auth + ${project.version} + + + ${project.groupId} + netconf-cli + ${project.version} + + + ${project.groupId} + netconf-client + ${project.version} + + + ${project.groupId} + netconf-config + ${project.version} + + + ${project.groupId} + netconf-connector-config + ${project.version} + + + ${project.groupId} + netconf-impl + ${project.version} + + + ${project.groupId} + netconf-mapping-api + ${project.version} + + + ${project.groupId} + netconf-monitoring + ${project.version} + + + ${project.groupId} + netconf-netty-util + ${project.version} + + + ${project.groupId} + netconf-ssh + ${project.version} + + + ${project.groupId} + netconf-tcp + ${project.version} + + + ${project.groupId} + netconf-testtool + ${project.version} + + + ${project.groupId} + netconf-usermanager + ${project.version} + + + ${project.groupId} + netconf-util + ${project.version} + + + + ${project.groupId} + ietf-netconf-monitoring + ${project.version} + + + ${project.groupId} + ietf-netconf-monitoring-extension + ${project.version} + + + + ${project.groupId} + netconf-client + ${project.version} + test-jar + + + ${project.groupId} + netconf-impl + ${project.version} + test-jar + + + ${project.groupId} + netconf-netty-util + ${project.version} + test-jar + + + ${project.groupId} + netconf-ssh + ${project.version} + test-jar + + + ${project.groupId} + netconf-util + ${project.version} + test-jar + + + + ${project.groupId} + features-netconf + ${project.version} + features + xml + runtime + + + + + diff --git a/opendaylight/netconf/netconf-auth/pom.xml b/opendaylight/netconf/netconf-auth/pom.xml index e19359adb8..6f1fafff40 100644 --- a/opendaylight/netconf/netconf-auth/pom.xml +++ b/opendaylight/netconf/netconf-auth/pom.xml @@ -12,7 +12,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../ netconf-auth diff --git a/opendaylight/netconf/netconf-cli/pom.xml b/opendaylight/netconf/netconf-cli/pom.xml index 55a8715000..c292d93206 100644 --- a/opendaylight/netconf/netconf-cli/pom.xml +++ b/opendaylight/netconf/netconf-cli/pom.xml @@ -10,7 +10,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT netconf-cli jar diff --git a/opendaylight/netconf/netconf-client/pom.xml b/opendaylight/netconf/netconf-client/pom.xml index 6bb67d0681..7fbb54165c 100644 --- a/opendaylight/netconf/netconf-client/pom.xml +++ b/opendaylight/netconf/netconf-client/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT netconf-client bundle diff --git a/opendaylight/netconf/netconf-config/pom.xml b/opendaylight/netconf/netconf-config/pom.xml index db5d14d75a..77551f7080 100644 --- a/opendaylight/netconf/netconf-config/pom.xml +++ b/opendaylight/netconf/netconf-config/pom.xml @@ -12,7 +12,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT netconf-config Configuration files for netconf diff --git a/opendaylight/netconf/netconf-connector-config/pom.xml b/opendaylight/netconf/netconf-connector-config/pom.xml index d9cc5eab43..f4e6e99ea0 100644 --- a/opendaylight/netconf/netconf-connector-config/pom.xml +++ b/opendaylight/netconf/netconf-connector-config/pom.xml @@ -12,7 +12,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT netconf-connector-config Configuration files for netconf-connector diff --git a/opendaylight/netconf/netconf-impl/pom.xml b/opendaylight/netconf/netconf-impl/pom.xml index c6544466d4..a987ceefc8 100644 --- a/opendaylight/netconf/netconf-impl/pom.xml +++ b/opendaylight/netconf/netconf-impl/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT netconf-impl bundle diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/SubtreeFilter.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/SubtreeFilter.java index 6e81584133..42a8bae448 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/SubtreeFilter.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/SubtreeFilter.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.impl; import com.google.common.base.Optional; import java.io.IOException; +import java.util.Map; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation.OperationNameAndNamespace; @@ -73,7 +74,7 @@ public class SubtreeFilter { return result; } - private static void addSubtree(XmlElement filter, XmlElement src, XmlElement dst) { + private static void addSubtree(XmlElement filter, XmlElement src, XmlElement dst) throws NetconfDocumentedException { for (XmlElement srcChild : src.getChildElements()) { for (XmlElement filterChild : filter.getChildElements()) { addSubtree2(filterChild, srcChild, dst); @@ -81,7 +82,7 @@ public class SubtreeFilter { } } - private static MatchingResult addSubtree2(XmlElement filter, XmlElement src, XmlElement dstParent) { + private static MatchingResult addSubtree2(XmlElement filter, XmlElement src, XmlElement dstParent) throws NetconfDocumentedException { Document document = dstParent.getDomElement().getOwnerDocument(); MatchingResult matches = matches(src, filter); if (matches != MatchingResult.NO_MATCH && matches != MatchingResult.CONTENT_MISMATCH) { @@ -123,7 +124,7 @@ public class SubtreeFilter { * Shallow compare src node to filter: tag name and namespace must match. * If filter node has no children and has text content, it also must match. */ - private static MatchingResult matches(XmlElement src, XmlElement filter) { + private static MatchingResult matches(XmlElement src, XmlElement filter) throws NetconfDocumentedException { boolean tagMatch = src.getName().equals(filter.getName()) && src.getNamespaceOptionally().equals(filter.getNamespaceOptionally()); MatchingResult result = null; @@ -131,7 +132,7 @@ public class SubtreeFilter { // match text content Optional maybeText = filter.getOnlyTextContentOptionally(); if (maybeText.isPresent()) { - if (maybeText.equals(src.getOnlyTextContentOptionally())) { + if (maybeText.equals(src.getOnlyTextContentOptionally()) || prefixedContentMatches(filter, src)) { result = MatchingResult.CONTENT_MATCH; } else { result = MatchingResult.CONTENT_MISMATCH; @@ -159,10 +160,30 @@ public class SubtreeFilter { if (result == null) { result = MatchingResult.NO_MATCH; } - logger.debug("Matching {} to {} resulted in {}", src, filter, tagMatch); + logger.debug("Matching {} to {} resulted in {}", src, filter, result); return result; } + private static boolean prefixedContentMatches(final XmlElement filter, final XmlElement src) throws NetconfDocumentedException { + final Map.Entry prefixToNamespaceOfFilter = filter.findNamespaceOfTextContent(); + final Map.Entry prefixToNamespaceOfSrc = src.findNamespaceOfTextContent(); + + final String prefix = prefixToNamespaceOfFilter.getKey(); + // If this is not a prefixed content, we do not need to continue since content do not match + if(prefix.equals(XmlElement.DEFAULT_NAMESPACE_PREFIX)) { + return false; + } + // Namespace mismatch + if(!prefixToNamespaceOfFilter.getValue().equals(prefixToNamespaceOfSrc.getValue())) { + return false; + } + + final String unprefixedFilterContent = filter.getTextContent().substring(prefix.length()); + final String unprefixedSrcCOntnet = src.getTextContent().substring(prefix.length()); + // Finally compare unprefixed content + return unprefixedFilterContent.equals(unprefixedSrcCOntnet); + } + enum MatchingResult { NO_MATCH, TAG_MATCH, CONTENT_MATCH, CONTENT_MISMATCH } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfMonitoringServiceImpl.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfMonitoringServiceImpl.java index 81fac5f12f..2a45e1757b 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfMonitoringServiceImpl.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfMonitoringServiceImpl.java @@ -13,6 +13,10 @@ import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import io.netty.util.internal.ConcurrentSet; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import javax.annotation.Nonnull; import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession; import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService; import org.opendaylight.controller.netconf.mapping.api.Capability; @@ -32,11 +36,6 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.mon import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; -import java.util.Collections; -import java.util.List; -import java.util.Set; - public class NetconfMonitoringServiceImpl implements NetconfMonitoringService, SessionMonitoringService { private static final Logger logger = LoggerFactory.getLogger(NetconfMonitoringServiceImpl.class); @@ -134,9 +133,8 @@ public class NetconfMonitoringServiceImpl implements NetconfMonitoringService, S private List transformSessions(Set sessions) { return Lists.newArrayList(Collections2.transform(sessions, new Function() { - @Nullable @Override - public Session apply(@Nullable NetconfManagementSession input) { + public Session apply(@Nonnull NetconfManagementSession input) { return input.toManagementSession(); } })); diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java index ff96ad779f..aa590604b0 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java @@ -48,7 +48,7 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter { this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot; } - private void initNetconfOperations(Set allOperations) { + private synchronized void initNetconfOperations(Set allOperations) { allNetconfOperations = allOperations; } diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/NetconfMonitoringServiceImplTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/NetconfMonitoringServiceImplTest.java new file mode 100644 index 0000000000..1b078be9a4 --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/NetconfMonitoringServiceImplTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.impl; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import io.netty.channel.Channel; +import java.util.List; +import java.util.Set; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession; +import org.opendaylight.controller.netconf.impl.NetconfServerSession; +import org.opendaylight.controller.netconf.impl.NetconfServerSessionListener; +import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl; +import org.opendaylight.controller.netconf.mapping.api.Capability; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; + +public class NetconfMonitoringServiceImplTest { + + private NetconfMonitoringServiceImpl service; + + @Mock + private NetconfOperationProvider operationProvider; + @Mock + private NetconfManagementSession managementSession; + @Mock + private NetconfOperationServiceSnapshot snapshot; + @Mock + private NetconfOperationService operationService; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + service = new NetconfMonitoringServiceImpl(operationProvider); + } + + @Test + public void testSessions() throws Exception { + doReturn("sessToStr").when(managementSession).toString(); + service.onSessionUp(managementSession); + List list = Lists.newArrayList(managementSession); + } + + @Test(expected = RuntimeException.class) + public void testGetSchemas() throws Exception { + doThrow(RuntimeException.class).when(operationProvider).openSnapshot(anyString()); + service.getSchemas(); + } + + @Test(expected = IllegalStateException.class) + public void testGetSchemas2() throws Exception { + doThrow(Exception.class).when(operationProvider).openSnapshot(anyString()); + service.getSchemas(); + } + + @Test + public void testGetSchemas3() throws Exception { + doReturn("").when(managementSession).toString(); + Capability cap = mock(Capability.class); + Set caps = Sets.newHashSet(cap); + Set services = Sets.newHashSet(operationService); + doReturn(snapshot).when(operationProvider).openSnapshot(anyString()); + doReturn(services).when(snapshot).getServices(); + doReturn(caps).when(operationService).getCapabilities(); + Optional opt = mock(Optional.class); + doReturn(opt).when(cap).getCapabilitySchema(); + doReturn(true).when(opt).isPresent(); + doReturn(opt).when(cap).getModuleNamespace(); + doReturn("namespace").when(opt).get(); + Optional optRev = Optional.of("rev"); + doReturn(optRev).when(cap).getRevision(); + doReturn(Optional.of("modName")).when(cap).getModuleName(); + doReturn(Optional.of(Lists.newArrayList("loc"))).when(cap).getLocation(); + doNothing().when(snapshot).close(); + + assertNotNull(service.getSchemas()); + verify(snapshot, times(1)).close(); + + NetconfServerSessionListener sessionListener = mock(NetconfServerSessionListener.class); + Channel channel = mock(Channel.class); + NetconfHelloMessageAdditionalHeader header = new NetconfHelloMessageAdditionalHeader("name", "addr", "2", "tcp", "id"); + NetconfServerSession sm = new NetconfServerSession(sessionListener, channel, 10, header); + doNothing().when(sessionListener).onSessionUp(any(NetconfServerSession.class)); + sm.sessionUp(); + service.onSessionUp(sm); + assertEquals(1, service.getSessions().getSession().size()); + + assertEquals(Long.valueOf(10), service.getSessions().getSession().get(0).getSessionId()); + + service.onSessionDown(sm); + assertEquals(0, service.getSessions().getSession().size()); + } +} diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/SubtreeFilterTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/SubtreeFilterTest.java index b11834386e..5d9470750e 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/SubtreeFilterTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/SubtreeFilterTest.java @@ -36,7 +36,7 @@ public class SubtreeFilterTest { @Parameters public static Collection data() { List result = new ArrayList<>(); - for (int i = 0; i <= 8; i++) { + for (int i = 0; i <= 9; i++) { result.add(new Object[]{i}); } return result; diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSessionTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSessionTest.java new file mode 100644 index 0000000000..ae3d65646f --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSessionTest.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.impl.mapping.operations; + +import org.junit.Test; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; + +public class DefaultCloseSessionTest { + @Test + public void testDefaultCloseSession() throws Exception { + AutoCloseable res = mock(AutoCloseable.class); + doNothing().when(res).close(); + DefaultCloseSession session = new DefaultCloseSession("", res); + Document doc = XmlUtil.newDocument(); + XmlElement elem = XmlElement.fromDomElement(XmlUtil.readXmlToElement("")); + session.handleWithNoSubsequentOperations(doc, elem); + } + + @Test(expected = NetconfDocumentedException.class) + public void testDefaultCloseSession2() throws Exception { + AutoCloseable res = mock(AutoCloseable.class); + doThrow(NetconfDocumentedException.class).when(res).close(); + DefaultCloseSession session = new DefaultCloseSession("", res); + Document doc = XmlUtil.newDocument(); + XmlElement elem = XmlElement.fromDomElement(XmlUtil.readXmlToElement("")); + session.handleWithNoSubsequentOperations(doc, elem); + } +} diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCommitTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCommitTest.java new file mode 100644 index 0000000000..98050de565 --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCommitTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.impl.mapping.operations; + +import com.google.common.collect.Sets; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer; +import org.opendaylight.controller.netconf.impl.NetconfServerSession; +import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider; +import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution; +import org.opendaylight.controller.netconf.util.test.XmlFileLoader; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import static org.mockito.Mockito.*; + +public class DefaultCommitTest { + + private NetconfOperationChainedExecution operation; + private Document requestMessage; + private NetconfOperationRouter router; + private DefaultCommitNotificationProducer notifier; + private CapabilityProvider cap; + private DefaultCommit commit; + + @Before + public void setUp() throws Exception { + operation = mock(NetconfOperationChainedExecution.class); + doReturn(XmlUtil.newDocument()).when(operation).execute(any(Document.class)); + router = mock(NetconfOperationRouter.class); + doReturn(false).when(operation).isExecutionTermination(); + notifier = mock(DefaultCommitNotificationProducer.class); + doNothing().when(notifier).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class)); + cap = mock(CapabilityProvider.class); + doReturn(Sets.newHashSet()).when(cap).getCapabilities(); + Document rpcData = XmlFileLoader.xmlFileToDocument("netconfMessages/editConfig_expectedResult.xml"); + doReturn(rpcData).when(router).onNetconfMessage(any(Document.class), any(NetconfServerSession.class)); + commit = new DefaultCommit(notifier, cap, "", router); + } + + @Test + public void testHandleWithNotification() throws Exception { + requestMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/commit.xml"); + commit.handle(requestMessage, operation); + verify(operation, times(1)).execute(requestMessage); + verify(notifier, times(1)).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class)); + } + + @Test + public void testHandleWithoutNotification() throws Exception { + requestMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/commit.xml"); + Element elem = requestMessage.getDocumentElement(); + elem.setAttribute("notify", "false"); + commit.handle(requestMessage, operation); + verify(operation, times(1)).execute(requestMessage); + verify(notifier, never()).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class)); + } + + @Test(expected = NetconfDocumentedException.class) + public void testHandle() throws Exception { + Document rpcData = XmlFileLoader.xmlFileToDocument("netconfMessages/get.xml"); + doReturn(rpcData).when(router).onNetconfMessage(any(Document.class), any(NetconfServerSession.class)); + requestMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/commit.xml"); + commit.handle(requestMessage, operation); + } +} diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchemaTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchemaTest.java new file mode 100644 index 0000000000..b655e90f2b --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchemaTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.impl.mapping.operations; + +import com.google.common.base.Optional; +import junit.framework.Assert; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.w3c.dom.Document; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; + +public class DefaultGetSchemaTest { + + private CapabilityProvider cap; + private Document doc; + private String getSchema; + + @Before + public void setUp() throws Exception { + cap = mock(CapabilityProvider.class); + doc = XmlUtil.newDocument(); + getSchema = "\n" + + " threadpool-api\n" + + " 2010-09-24\n" + + " ncm:yang\n" + + " \n" + + " "; + } + + @Test(expected = NetconfDocumentedException.class) + public void testDefaultGetSchema() throws Exception { + DefaultGetSchema schema = new DefaultGetSchema(cap, ""); + doThrow(IllegalStateException.class).when(cap).getSchemaForCapability(anyString(), any(Optional.class)); + schema.handleWithNoSubsequentOperations(doc, XmlElement.fromDomElement(XmlUtil.readXmlToElement(getSchema))); + } + + @Test + public void handleWithNoSubsequentOperations() throws Exception { + DefaultGetSchema schema = new DefaultGetSchema(cap, ""); + doReturn("").when(cap).getSchemaForCapability(anyString(), any(Optional.class)); + assertNotNull(schema.handleWithNoSubsequentOperations(doc, XmlElement.fromDomElement(XmlUtil.readXmlToElement(getSchema)))); + } +} diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultStopExiTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultStopExiTest.java new file mode 100644 index 0000000000..b335165706 --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultStopExiTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.impl.mapping.operations; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelPipeline; +import org.junit.Test; +import org.opendaylight.controller.netconf.impl.NetconfServerSession; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.w3c.dom.Document; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.*; + +public class DefaultStopExiTest { + @Test + public void testHandleWithNoSubsequentOperations() throws Exception { + DefaultStopExi exi = new DefaultStopExi(""); + Document doc = XmlUtil.newDocument(); + Channel channel = mock(Channel.class); + ChannelPipeline pipeline = mock(ChannelPipeline.class); + doReturn(pipeline).when(channel).pipeline(); + ChannelHandler channelHandler = mock(ChannelHandler.class); + doReturn(channelHandler).when(pipeline).replace(anyString(), anyString(), any(ChannelHandler.class)); + + NetconfServerSession serverSession = new NetconfServerSession(null, channel, 2L, null); + exi.setNetconfSession(serverSession); + + assertNotNull(exi.handleWithNoSubsequentOperations(doc, XmlElement.fromDomElement(XmlUtil.readXmlToElement("")))); + verify(pipeline, times(1)).replace(anyString(), anyString(), any(ChannelHandler.class)); + } +} diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivatorTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivatorTest.java new file mode 100644 index 0000000000..b59ea884c5 --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivatorTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.impl.osgi; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Dictionary; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider; +import org.osgi.framework.*; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; + +public class NetconfImplActivatorTest { + + @Mock + private BundleContext bundle; + @Mock + private Filter filter; + @Mock + private ServiceReference reference; + @Mock + private ServiceRegistration registration; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn(filter).when(bundle).createFilter(anyString()); + doNothing().when(bundle).addServiceListener(any(ServiceListener.class), anyString()); + + ServiceReference[] refs = new ServiceReference[0]; + doReturn(refs).when(bundle).getServiceReferences(anyString(), anyString()); + doReturn(Arrays.asList(refs)).when(bundle).getServiceReferences(any(Class.class), anyString()); + doReturn("").when(bundle).getProperty(anyString()); + doReturn(registration).when(bundle).registerService(any(Class.class), any(NetconfOperationServiceFactoryListenerImpl.class), any(Dictionary.class)); + doNothing().when(registration).unregister(); + doNothing().when(bundle).removeServiceListener(any(ServiceListener.class)); + } + + @Test + public void testStart() throws Exception { + NetconfImplActivator activator = new NetconfImplActivator(); + activator.start(bundle); + verify(bundle, times(2)).registerService(any(Class.class), any(NetconfOperationServiceFactoryListenerImpl.class), any(Dictionary.class)); + activator.stop(bundle); + } +} diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryTrackerTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryTrackerTest.java new file mode 100644 index 0000000000..374e8aeb9f --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryTrackerTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.impl.osgi; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Filter; +import org.osgi.framework.ServiceReference; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; + +public class NetconfOperationServiceFactoryTrackerTest { + + @Mock + private Filter filter; + @Mock + private BundleContext context; + @Mock + private NetconfOperationServiceFactoryListener listener; + @Mock + private NetconfOperationServiceFactory factory; + @Mock + private ServiceReference reference; + + private NetconfOperationServiceFactoryTracker tracker; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doNothing().when(listener).onRemoveNetconfOperationServiceFactory(any(NetconfOperationServiceFactory.class)); + doReturn(filter).when(context).createFilter(anyString()); + doReturn("").when(reference).toString(); + doReturn(factory).when(context).getService(any(ServiceReference.class)); + doReturn("").when(factory).toString(); + doNothing().when(listener).onAddNetconfOperationServiceFactory(any(NetconfOperationServiceFactory.class)); + tracker = new NetconfOperationServiceFactoryTracker(context, listener); + } + + @Test + public void testNetconfOperationServiceFactoryTracker() throws Exception { + tracker.removedService(null, factory); + verify(listener, times(1)).onRemoveNetconfOperationServiceFactory(any(NetconfOperationServiceFactory.class)); + } + + @Test + public void testAddingService() throws Exception { + assertNotNull(tracker.addingService(reference)); + verify(listener, times(1)).onAddNetconfOperationServiceFactory(any(NetconfOperationServiceFactory.class)); + } +} diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/util/DeserializerExceptionHandlerTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/util/DeserializerExceptionHandlerTest.java new file mode 100644 index 0000000000..6512b4bd33 --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/util/DeserializerExceptionHandlerTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.impl.util; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.util.concurrent.GenericFutureListener; +import org.junit.Before; +import org.junit.Test; + +import static org.mockito.Mockito.*; + +public class DeserializerExceptionHandlerTest { + + private DeserializerExceptionHandler handler; + private ChannelFuture channelFuture; + private ChannelHandlerContext context; + private Channel channel; + + @Before + public void setUp() throws Exception { + handler = new DeserializerExceptionHandler(); + context = mock(ChannelHandlerContext.class); + channel = mock(Channel.class); + doReturn(channel).when(context).channel(); + channelFuture = mock(ChannelFuture.class); + doReturn(channelFuture).when(channelFuture).addListener(any(GenericFutureListener.class)); + doReturn(channelFuture).when(channel).writeAndFlush(anyObject()); + } + + @Test + public void testExceptionCaught() throws Exception { + handler.exceptionCaught(context, new Exception()); + verify(context, times(1)).channel(); + } +} diff --git a/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/post-filter.xml b/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/post-filter.xml new file mode 100644 index 0000000000..afe9655326 --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/post-filter.xml @@ -0,0 +1,14 @@ + + + + + + fred + x:admin + Fred Flintstone + + + + + \ No newline at end of file diff --git a/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/pre-filter.xml b/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/pre-filter.xml new file mode 100644 index 0000000000..eca3241f05 --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/pre-filter.xml @@ -0,0 +1,40 @@ + + + + + + root + superuser + Charlie Root + + 1 + 1 + + + + fred + x:admin + Fred Flintstone + + 2 + 2 + + + + barney + admin + Barney Rubble + + 2 + 3 + + + + + + admin + + + + + \ No newline at end of file diff --git a/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/request.xml b/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/request.xml new file mode 100644 index 0000000000..47da0feec1 --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/request.xml @@ -0,0 +1,19 @@ + + + + + + + + + + fred + a:admin + + + + + + + \ No newline at end of file diff --git a/opendaylight/netconf/netconf-it/pom.xml b/opendaylight/netconf/netconf-it/pom.xml index 272b686fc0..b2c5c4c8f7 100644 --- a/opendaylight/netconf/netconf-it/pom.xml +++ b/opendaylight/netconf/netconf-it/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT netconf-it @@ -68,6 +68,11 @@ config-util test + + ${project.groupId} + sal-netconf-connector + test + ${project.groupId} netconf-api diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java index 4fe5f2a950..f96f557619 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java @@ -10,39 +10,63 @@ package org.opendaylight.controller.netconf.it; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import com.google.common.collect.Lists; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import io.netty.channel.EventLoopGroup; import io.netty.channel.local.LocalAddress; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; +import io.netty.channel.nio.NioEventLoopGroup; import io.netty.util.concurrent.GlobalEventExecutor; import java.io.IOException; import java.net.InetSocketAddress; +import java.nio.file.Files; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import org.apache.sshd.server.PasswordAuthenticator; +import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider; +import org.apache.sshd.server.session.ServerSession; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.auth.AuthProvider; import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl; +import org.opendaylight.controller.netconf.client.NetconfClientSessionListener; import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener; +import org.opendaylight.controller.netconf.client.TestingNetconfClient; import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration; import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder; -import org.opendaylight.controller.netconf.client.TestingNetconfClient; import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler; import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.LoginPassword; -import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; -import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; +import org.opendaylight.controller.netconf.ssh.SshProxyServer; import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.opendaylight.controller.sal.connect.api.RemoteDevice; +import org.opendaylight.controller.sal.connect.api.RemoteDeviceCommunicator; +import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator; +import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionCapabilities; +import org.opendaylight.controller.sal.connect.util.RemoteDeviceId; import org.opendaylight.protocol.framework.NeverReconnectStrategy; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.xml.sax.SAXException; public class NetconfITSecureTest extends AbstractNetconfConfigTest { @@ -52,25 +76,38 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest { public static final String USERNAME = "user"; public static final String PASSWORD = "pwd"; - private NetconfSSHServer sshServer; + private SshProxyServer sshProxyServer; + + private ExecutorService nioExec; + private EventLoopGroup clientGroup; + private ScheduledExecutorService minaTimerEx; @Before public void setUp() throws Exception { - final char[] pem = PEMGenerator.generate().toCharArray(); - sshServer = NetconfSSHServer.start(TLS_ADDRESS.getPort(), NetconfConfigUtil.getNetconfLocalAddress(), getNettyThreadgroup(), pem); - sshServer.setAuthProvider(getAuthProvider()); + nioExec = Executors.newFixedThreadPool(1); + clientGroup = new NioEventLoopGroup(); + minaTimerEx = Executors.newScheduledThreadPool(1); + sshProxyServer = new SshProxyServer(minaTimerEx, clientGroup, nioExec); + sshProxyServer.bind(TLS_ADDRESS, NetconfConfigUtil.getNetconfLocalAddress(), new PasswordAuthenticator() { + @Override + public boolean authenticate(final String username, final String password, final ServerSession session) { + return true; + } + }, new PEMGeneratorHostKeyProvider(Files.createTempFile("prefix", "suffix").toAbsolutePath().toString())); } @After public void tearDown() throws Exception { - sshServer.close(); - sshServer.join(); + sshProxyServer.close(); + clientGroup.shutdownGracefully().await(); + minaTimerEx.shutdownNow(); + nioExec.shutdownNow(); } @Test public void testSecure() throws Exception { final NetconfClientDispatcher dispatch = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer()); - try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, getClientConfiguration())) { + try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, getClientConfiguration(new SimpleNetconfClientSessionListener()))) { NetconfMessage response = netconfClient.sendMessage(getGetConfig()); assertFalse("Unexpected error message " + XmlUtil.toString(response.getDocument()), NetconfMessageUtil.isErrorMessage(response)); @@ -91,29 +128,42 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest { /** * Test all requests are handled properly and no mismatch occurs in listener */ - @Test(timeout = 3*60*1000) + @Test(timeout = 6*60*1000) public void testSecureStress() throws Exception { + final int requests = 4000; + final NetconfClientDispatcher dispatch = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer()); - try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, getClientConfiguration())) { + final NetconfDeviceCommunicator sessionListener = getSessionListener(); + try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, getClientConfiguration(sessionListener))) { final AtomicInteger responseCounter = new AtomicInteger(0); - final List> futures = Lists.newArrayList(); + final List>> futures = Lists.newArrayList(); - final int requests = 1000; for (int i = 0; i < requests; i++) { - final Future netconfMessageFuture = netconfClient.sendRequest(getGetConfig()); + NetconfMessage getConfig = getGetConfig(); + getConfig = changeMessageId(getConfig, i); + final ListenableFuture> netconfMessageFuture = sessionListener.sendRequest(getConfig, QName.create("namespace", "2012-12-12", "get")); futures.add(netconfMessageFuture); - netconfMessageFuture.addListener(new GenericFutureListener>() { + Futures.addCallback(netconfMessageFuture, new FutureCallback>() { @Override - public void operationComplete(final Future future) throws Exception { - assertTrue("Request unsuccessful " + future.cause(), future.isSuccess()); + public void onSuccess(final RpcResult result) { responseCounter.incrementAndGet(); } + + @Override + public void onFailure(final Throwable t) { + throw new RuntimeException(t); + } }); } - for (final Future future : futures) { - future.await(); + // Wait for every future + for (final ListenableFuture> future : futures) { + try { + future.get(3, TimeUnit.MINUTES); + } catch (final TimeoutException e) { + fail("Request " + futures.indexOf(future) + " is not responding"); + } } // Give future listeners some time to finish counter incrementation @@ -123,10 +173,17 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest { } } - public NetconfClientConfiguration getClientConfiguration() throws IOException { + private NetconfMessage changeMessageId(final NetconfMessage getConfig, final int i) throws IOException, SAXException { + String s = XmlUtil.toString(getConfig.getDocument(), false); + s = s.replace("101", Integer.toString(i)); + return new NetconfMessage(XmlUtil.readXmlToDocument(s)); + } + + public NetconfClientConfiguration getClientConfiguration(final NetconfClientSessionListener sessionListener) throws IOException { final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create(); b.withAddress(TLS_ADDRESS); - b.withSessionListener(new SimpleNetconfClientSessionListener()); + // Using session listener from sal-netconf-connector since stress test cannot be performed with simple listener + b.withSessionListener(sessionListener); b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000)); b.withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH); b.withConnectionTimeoutMillis(5000); @@ -134,6 +191,16 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest { return b.build(); } + @Mock + private RemoteDevice mockedRemoteDevice; + + private NetconfDeviceCommunicator getSessionListener() { + MockitoAnnotations.initMocks(this); + doNothing().when(mockedRemoteDevice).onRemoteSessionUp(any(NetconfSessionCapabilities.class), any(RemoteDeviceCommunicator.class)); + doNothing().when(mockedRemoteDevice).onRemoteSessionDown(); + return new NetconfDeviceCommunicator(new RemoteDeviceId("secure-test"), mockedRemoteDevice); + } + public AuthProvider getAuthProvider() throws Exception { final AuthProvider mockAuth = mock(AuthProvider.class); doReturn("mockedAuth").when(mockAuth).toString(); diff --git a/opendaylight/netconf/netconf-it/src/test/resources/logback-test.xml b/opendaylight/netconf/netconf-it/src/test/resources/logback-test.xml index c5037d34ed..91fb805e6a 100644 --- a/opendaylight/netconf/netconf-it/src/test/resources/logback-test.xml +++ b/opendaylight/netconf/netconf-it/src/test/resources/logback-test.xml @@ -7,6 +7,7 @@ + diff --git a/opendaylight/netconf/netconf-mapping-api/pom.xml b/opendaylight/netconf/netconf-mapping-api/pom.xml index 1a510f939c..7d51f6db99 100644 --- a/opendaylight/netconf/netconf-mapping-api/pom.xml +++ b/opendaylight/netconf/netconf-mapping-api/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT netconf-mapping-api diff --git a/opendaylight/netconf/netconf-monitoring/pom.xml b/opendaylight/netconf/netconf-monitoring/pom.xml index 03193b8492..22c61954c3 100644 --- a/opendaylight/netconf/netconf-monitoring/pom.xml +++ b/opendaylight/netconf/netconf-monitoring/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT netconf-monitoring bundle diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSchema.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSchema.java index 078509db40..16b38eca51 100644 --- a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSchema.java +++ b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSchema.java @@ -11,6 +11,7 @@ package org.opendaylight.controller.netconf.monitoring.xml.model; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.Collections2; +import javax.annotation.Nonnull; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Yang; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema; @@ -41,7 +42,7 @@ final class MonitoringSchema { return Collections2.transform(schema.getLocation(), new Function() { @Nullable @Override - public String apply(@Nullable Schema.Location input) { + public String apply(@Nonnull Schema.Location input) { return input.getEnumeration().toString(); } }); diff --git a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivatorTest.java b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivatorTest.java new file mode 100644 index 0000000000..40493569d6 --- /dev/null +++ b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivatorTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.monitoring.osgi; + +import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Filter; +import org.osgi.framework.ServiceListener; +import org.osgi.framework.ServiceReference; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; + +public class NetconfMonitoringActivatorTest { + + @Mock + BundleContext context; + @Mock + Filter filter; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn(filter).when(context).createFilter(anyString()); + doNothing().when(context).addServiceListener(any(ServiceListener.class), anyString()); + ServiceReference[] refs = new ServiceReference[2]; + doReturn(Arrays.asList(refs)).when(context).getServiceReferences(any(Class.class), anyString()); + doReturn(refs).when(context).getServiceReferences(anyString(), anyString()); + } + + @Test + public void testNetconfMonitoringActivator() throws Exception { + NetconfMonitoringActivator activator = new NetconfMonitoringActivator(); + activator.start(context); + verify(context, times(1)).addServiceListener(any(ServiceListener.class), anyString()); + + activator.stop(context); + verify(context, times(1)).removeServiceListener(any(ServiceListener.class)); + } +} diff --git a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringOperationServiceTest.java b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringOperationServiceTest.java new file mode 100644 index 0000000000..b8e35e934b --- /dev/null +++ b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringOperationServiceTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.monitoring.osgi; + +import com.google.common.base.Optional; +import org.junit.Test; +import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService; +import org.opendaylight.controller.netconf.monitoring.MonitoringConstants; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + +public class NetconfMonitoringOperationServiceTest { + @Test + public void testGetters() throws Exception { + NetconfMonitoringService monitor = mock(NetconfMonitoringService.class); + NetconfMonitoringOperationService service = new NetconfMonitoringOperationService(monitor); + + assertEquals(1, service.getNetconfOperations().size()); + + assertEquals(Optional.absent(), service.getCapabilities().iterator().next().getCapabilitySchema()); + assertEquals(Optional.absent(), service.getCapabilities().iterator().next().getLocation()); + assertEquals(Optional.of(MonitoringConstants.MODULE_REVISION), service.getCapabilities().iterator().next().getRevision()); + assertEquals(Optional.of(MonitoringConstants.MODULE_NAME), service.getCapabilities().iterator().next().getModuleName()); + assertEquals(Optional.of(MonitoringConstants.NAMESPACE), service.getCapabilities().iterator().next().getModuleNamespace()); + assertEquals(MonitoringConstants.URI, service.getCapabilities().iterator().next().getCapabilityUri()); + } +} diff --git a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringServiceTrackerTest.java b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringServiceTrackerTest.java new file mode 100644 index 0000000000..2a53a6ce45 --- /dev/null +++ b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringServiceTrackerTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.monitoring.osgi; + +import java.util.Hashtable; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Filter; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyCollection; +import static org.mockito.Mockito.*; + +public class NetconfMonitoringServiceTrackerTest { + + @Mock + private ServiceReference reference; + @Mock + private BundleContext context; + @Mock + private ServiceRegistration serviceRegistration; + @Mock + private Filter filter; + @Mock + private NetconfMonitoringService monitoringService; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn(serviceRegistration).when(context).registerService(any(Class.class), any(NetconfOperationServiceFactory.class), any(Hashtable.class)); + doNothing().when(serviceRegistration).unregister(); + doReturn(filter).when(context).createFilter(anyString()); + doReturn("").when(reference).toString(); + doReturn(monitoringService).when(context).getService(any(ServiceReference.class)); + } + + @Test + public void testAddingService() throws Exception { + NetconfMonitoringServiceTracker tracker = new NetconfMonitoringServiceTracker(context); + tracker.addingService(reference); + verify(context, times(1)).registerService(any(Class.class), any(NetconfOperationServiceFactory.class), any(Hashtable.class)); + tracker.removedService(reference, null); + verify(serviceRegistration, times(1)).unregister(); + } +} diff --git a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java index 08441b4ce5..4b5dcd7d55 100644 --- a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java +++ b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java @@ -69,11 +69,11 @@ public class JaxBSerializerTest { "1" + "0" + "0" + - "loginTime" + + "2010-10-10T12:32:32Z" + "0" + "0" + "client" + - "address/port" + + "192.168.1.1" + "ncme:netconf-tcp" + "username" + "")); @@ -96,8 +96,8 @@ public class JaxBSerializerTest { final Session1 mockedSession1 = mock(Session1.class); doReturn("client").when(mockedSession1).getSessionIdentifier(); doReturn(1L).when(mocked).getSessionId(); - doReturn(new DateAndTime("loginTime")).when(mocked).getLoginTime(); - doReturn(new Host(new DomainName("address/port"))).when(mocked).getSourceHost(); + doReturn(new DateAndTime("2010-10-10T12:32:32Z")).when(mocked).getLoginTime(); + doReturn(new Host(new DomainName("192.168.1.1"))).when(mocked).getSourceHost(); doReturn(new ZeroBasedCounter32(0L)).when(mocked).getInBadRpcs(); doReturn(new ZeroBasedCounter32(0L)).when(mocked).getInRpcs(); doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutNotifications(); diff --git a/opendaylight/netconf/netconf-netty-util/pom.xml b/opendaylight/netconf/netconf-netty-util/pom.xml index cb8461a299..e2afcc42f5 100644 --- a/opendaylight/netconf/netconf-netty-util/pom.xml +++ b/opendaylight/netconf/netconf-netty-util/pom.xml @@ -12,7 +12,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT netconf-netty-util bundle diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandler.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandler.java index 369c013832..fa7d0900ed 100644 --- a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandler.java +++ b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandler.java @@ -8,15 +8,9 @@ package org.opendaylight.controller.netconf.nettyutil.handler.ssh.client; -import com.google.common.base.Preconditions; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelOutboundHandler; -import io.netty.channel.ChannelOutboundHandlerAdapter; -import io.netty.channel.ChannelPromise; import java.io.IOException; import java.net.SocketAddress; + import org.apache.sshd.ClientChannel; import org.apache.sshd.ClientSession; import org.apache.sshd.SshClient; @@ -25,16 +19,17 @@ import org.apache.sshd.client.future.ConnectFuture; import org.apache.sshd.client.future.OpenFuture; import org.apache.sshd.common.future.CloseFuture; import org.apache.sshd.common.future.SshFutureListener; -import org.apache.sshd.common.io.IoInputStream; -import org.apache.sshd.common.io.IoOutputStream; -import org.apache.sshd.common.io.IoReadFuture; -import org.apache.sshd.common.io.IoWriteFuture; -import org.apache.sshd.common.io.WritePendingException; -import org.apache.sshd.common.util.Buffer; import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; + /** * Netty SSH handler class. Acts as interface between Netty and SSH library. */ @@ -56,8 +51,8 @@ public class AsyncSshHandler extends ChannelOutboundHandlerAdapter { private final AuthenticationHandler authenticationHandler; private final SshClient sshClient; - private SshReadAsyncListener sshReadAsyncListener; - private SshWriteAsyncHandler sshWriteAsyncHandler; + private AsyncSshHandlerReader sshReadAsyncListener; + private AsyncSshHandlerWriter sshWriteAsyncHandler; private ClientChannel channel; private ClientSession session; @@ -147,10 +142,23 @@ public class AsyncSshHandler extends ChannelOutboundHandlerAdapter { connectPromise.setSuccess(); connectPromise = null; - sshReadAsyncListener = new SshReadAsyncListener(this, ctx, channel.getAsyncOut()); + // TODO we should also read from error stream and at least log from that + + sshReadAsyncListener = new AsyncSshHandlerReader(new AutoCloseable() { + @Override + public void close() throws Exception { + AsyncSshHandler.this.disconnect(ctx, ctx.newPromise()); + } + }, new AsyncSshHandlerReader.ReadMsgHandler() { + @Override + public void onMessageRead(final ByteBuf msg) { + ctx.fireChannelRead(msg); + } + }, channel.toString(), channel.getAsyncOut()); + // if readAsyncListener receives immediate close, it will close this handler and closing this handler sets channel variable to null if(channel != null) { - sshWriteAsyncHandler = new SshWriteAsyncHandler(this, channel.getAsyncIn()); + sshWriteAsyncHandler = new AsyncSshHandlerWriter(channel.getAsyncIn()); ctx.fireChannelActive(); } } @@ -207,173 +215,4 @@ public class AsyncSshHandler extends ChannelOutboundHandlerAdapter { ctx.fireChannelInactive(); } - /** - * Listener over async input stream from SSH session. - * This listeners schedules reads in a loop until the session is closed or read fails. - */ - private static class SshReadAsyncListener implements SshFutureListener, AutoCloseable { - private static final int BUFFER_SIZE = 8192; - - private final ChannelOutboundHandler asyncSshHandler; - private final ChannelHandlerContext ctx; - - private IoInputStream asyncOut; - private Buffer buf; - private IoReadFuture currentReadFuture; - - public SshReadAsyncListener(final ChannelOutboundHandler asyncSshHandler, final ChannelHandlerContext ctx, final IoInputStream asyncOut) { - this.asyncSshHandler = asyncSshHandler; - this.ctx = ctx; - this.asyncOut = asyncOut; - buf = new Buffer(BUFFER_SIZE); - asyncOut.read(buf).addListener(this); - } - - @Override - public synchronized void operationComplete(final IoReadFuture future) { - if(future.getException() != null) { - if(asyncOut.isClosed() || asyncOut.isClosing()) { - // Ssh dropped - logger.debug("Ssh session dropped on channel: {}", ctx.channel(), future.getException()); - } else { - logger.warn("Exception while reading from SSH remote on channel {}", ctx.channel(), future.getException()); - } - invokeDisconnect(); - return; - } - - if (future.getRead() > 0) { - ctx.fireChannelRead(Unpooled.wrappedBuffer(buf.array(), 0, future.getRead())); - - // Schedule next read - buf = new Buffer(BUFFER_SIZE); - currentReadFuture = asyncOut.read(buf); - currentReadFuture.addListener(this); - } - } - - private void invokeDisconnect() { - try { - asyncSshHandler.disconnect(ctx, ctx.newPromise()); - } catch (final Exception e) { - // This should not happen - throw new IllegalStateException(e); - } - } - - @Override - public synchronized void close() { - // Remove self as listener on close to prevent reading from closed input - if(currentReadFuture != null) { - currentReadFuture.removeListener(this); - } - - asyncOut = null; - } - } - - private static final class SshWriteAsyncHandler implements AutoCloseable { - public static final int MAX_PENDING_WRITES = 100; - - private final ChannelOutboundHandler channelHandler; - private IoOutputStream asyncIn; - - // Counter that holds the amount of pending write messages - // Pending write can occur in case remote window is full - // In such case, we need to wait for the pending write to finish - private int pendingWriteCounter; - // Last write future, that can be pending - private IoWriteFuture lastWriteFuture; - - public SshWriteAsyncHandler(final ChannelOutboundHandler channelHandler, final IoOutputStream asyncIn) { - this.channelHandler = channelHandler; - this.asyncIn = asyncIn; - } - - int c = 0; - - public synchronized void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) { - try { - if(asyncIn == null || asyncIn.isClosed() || asyncIn.isClosing()) { - // If we are closed/closing, set immediate fail - promise.setFailure(new IllegalStateException("Channel closed")); - } else { - lastWriteFuture = asyncIn.write(toBuffer(msg)); - lastWriteFuture.addListener(new SshFutureListener() { - - @Override - public void operationComplete(final IoWriteFuture future) { - ((ByteBuf) msg).release(); - - // Notify success or failure - if (future.isWritten()) { - promise.setSuccess(); - } else { - promise.setFailure(future.getException()); - } - - // Reset last pending future - synchronized (SshWriteAsyncHandler.this) { - lastWriteFuture = null; - } - } - }); - } - } catch (final WritePendingException e) { - // Check limit for pending writes - pendingWriteCounter++; - if(pendingWriteCounter > MAX_PENDING_WRITES) { - promise.setFailure(e); - handlePendingFailed(ctx, new IllegalStateException("Too much pending writes(" + MAX_PENDING_WRITES + ") on channel: " + ctx.channel() + - ", remote window is not getting read or is too small")); - } - - logger.debug("Write pending to SSH remote on channel: {}, current pending count: {}", ctx.channel(), pendingWriteCounter); - - // In case of pending, re-invoke write after pending is finished - Preconditions.checkNotNull(lastWriteFuture, "Write is pending, but there was no previous write attempt", e); - lastWriteFuture.addListener(new SshFutureListener() { - @Override - public void operationComplete(final IoWriteFuture future) { - if (future.isWritten()) { - synchronized (SshWriteAsyncHandler.this) { - // Pending done, decrease counter - pendingWriteCounter--; - } - write(ctx, msg, promise); - } else { - // Cannot reschedule pending, fail - handlePendingFailed(ctx, e); - } - } - - }); - } - } - - private void handlePendingFailed(final ChannelHandlerContext ctx, final Exception e) { - logger.warn("Exception while writing to SSH remote on channel {}", ctx.channel(), e); - try { - channelHandler.disconnect(ctx, ctx.newPromise()); - } catch (final Exception ex) { - // This should not happen - throw new IllegalStateException(ex); - } - } - - @Override - public void close() { - asyncIn = null; - } - - private Buffer toBuffer(final Object msg) { - // TODO Buffer vs ByteBuf translate, Can we handle that better ? - Preconditions.checkState(msg instanceof ByteBuf); - final ByteBuf byteBuf = (ByteBuf) msg; - final byte[] temp = new byte[byteBuf.readableBytes()]; - byteBuf.readBytes(temp, 0, byteBuf.readableBytes()); - return new Buffer(temp); - } - - } } diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerReader.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerReader.java new file mode 100644 index 0000000000..ada15583cd --- /dev/null +++ b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerReader.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.nettyutil.handler.ssh.client; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.apache.sshd.common.future.SshFutureListener; +import org.apache.sshd.common.io.IoInputStream; +import org.apache.sshd.common.io.IoReadFuture; +import org.apache.sshd.common.util.Buffer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Listener on async input stream from SSH session. + * This listeners schedules reads in a loop until the session is closed or read fails. + */ +public final class AsyncSshHandlerReader implements SshFutureListener, AutoCloseable { + + private static final Logger logger = LoggerFactory.getLogger(AsyncSshHandler.class); + + private static final int BUFFER_SIZE = 8192; + + private final AutoCloseable connectionClosedCallback; + private final ReadMsgHandler readHandler; + + private final String channelId; + private IoInputStream asyncOut; + private Buffer buf; + private IoReadFuture currentReadFuture; + + public AsyncSshHandlerReader(final AutoCloseable connectionClosedCallback, final ReadMsgHandler readHandler, final String channelId, final IoInputStream asyncOut) { + this.connectionClosedCallback = connectionClosedCallback; + this.readHandler = readHandler; + this.channelId = channelId; + this.asyncOut = asyncOut; + buf = new Buffer(BUFFER_SIZE); + asyncOut.read(buf).addListener(this); + } + + @Override + public synchronized void operationComplete(final IoReadFuture future) { + if(future.getException() != null) { + if(asyncOut.isClosed() || asyncOut.isClosing()) { + // Ssh dropped + logger.debug("Ssh session dropped on channel: {}", channelId, future.getException()); + } else { + logger.warn("Exception while reading from SSH remote on channel {}", channelId, future.getException()); + } + invokeDisconnect(); + return; + } + + if (future.getRead() > 0) { + final ByteBuf msg = Unpooled.wrappedBuffer(buf.array(), 0, future.getRead()); + if(logger.isTraceEnabled()) { + logger.trace("Reading message on channel: {}, message: {}", channelId, AsyncSshHandlerWriter.byteBufToString(msg)); + } + readHandler.onMessageRead(msg); + + // Schedule next read + buf = new Buffer(BUFFER_SIZE); + currentReadFuture = asyncOut.read(buf); + currentReadFuture.addListener(this); + } + } + + private void invokeDisconnect() { + try { + connectionClosedCallback.close(); + } catch (final Exception e) { + // This should not happen + throw new IllegalStateException(e); + } + } + + @Override + public synchronized void close() { + // Remove self as listener on close to prevent reading from closed input + if(currentReadFuture != null) { + currentReadFuture.removeListener(this); + currentReadFuture = null; + } + + asyncOut = null; + } + + public interface ReadMsgHandler { + + void onMessageRead(ByteBuf msg); + } +} diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerWriter.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerWriter.java new file mode 100644 index 0000000000..8e639bd47c --- /dev/null +++ b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerWriter.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.nettyutil.handler.ssh.client; + +import com.google.common.base.Charsets; +import com.google.common.base.Preconditions; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import java.util.Deque; +import java.util.LinkedList; +import java.util.Queue; +import org.apache.sshd.common.future.SshFutureListener; +import org.apache.sshd.common.io.IoOutputStream; +import org.apache.sshd.common.io.IoWriteFuture; +import org.apache.sshd.common.io.WritePendingException; +import org.apache.sshd.common.util.Buffer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Async Ssh writer. Takes messages(byte arrays) and sends them encrypted to remote server. + * Also handles pending writes by caching requests until pending state is over. + */ +public final class AsyncSshHandlerWriter implements AutoCloseable { + + private static final Logger logger = LoggerFactory + .getLogger(AsyncSshHandlerWriter.class); + + // public static final int MAX_PENDING_WRITES = 1000; + // TODO implement Limiting mechanism for pending writes + // But there is a possible issue with limiting: + // 1. What to do when queue is full ? Immediate Fail for every request ? + // 2. At this level we might be dealing with Chunks of messages(not whole messages) and unexpected behavior might occur + // when we send/queue 1 chunk and fail the other chunks + + private IoOutputStream asyncIn; + + // Order has to be preserved for queued writes + private final Deque pending = new LinkedList<>(); + + public AsyncSshHandlerWriter(final IoOutputStream asyncIn) { + this.asyncIn = asyncIn; + } + + public synchronized void write(final ChannelHandlerContext ctx, + final Object msg, final ChannelPromise promise) { + // TODO check for isClosed, isClosing might be performed by mina SSH internally and is not required here + // If we are closed/closing, set immediate fail + if (asyncIn == null || asyncIn.isClosed() || asyncIn.isClosing()) { + promise.setFailure(new IllegalStateException("Channel closed")); + } else { + final ByteBuf byteBufMsg = (ByteBuf) msg; + if (pending.isEmpty() == false) { + queueRequest(ctx, byteBufMsg, promise); + return; + } + + writeWithPendingDetection(ctx, promise, byteBufMsg); + } + } + + private void writeWithPendingDetection(final ChannelHandlerContext ctx, final ChannelPromise promise, final ByteBuf byteBufMsg) { + try { + if (logger.isTraceEnabled()) { + logger.trace("Writing request on channel: {}, message: {}", ctx.channel(), byteBufToString(byteBufMsg)); + } + asyncIn.write(toBuffer(byteBufMsg)).addListener(new SshFutureListener() { + + @Override + public void operationComplete(final IoWriteFuture future) { + if (logger.isTraceEnabled()) { + logger.trace("Ssh write request finished on channel: {} with result: {}: and ex:{}, message: {}", + ctx.channel(), future.isWritten(), future.getException(), byteBufToString(byteBufMsg)); + } + + // Notify success or failure + if (future.isWritten()) { + promise.setSuccess(); + } else { + logger.warn("Ssh write request failed on channel: {} for message: {}", ctx.channel(), byteBufToString(byteBufMsg), future.getException()); + promise.setFailure(future.getException()); + } + + // Not needed anymore, release + byteBufMsg.release(); + + // Check pending queue and schedule next + // At this time we are guaranteed that we are not in pending state anymore so the next request should succeed + writePendingIfAny(); + } + }); + } catch (final WritePendingException e) { + queueRequest(ctx, byteBufMsg, promise); + } + } + + private synchronized void writePendingIfAny() { + if (pending.peek() == null) { + return; + } + + // In case of pending, reschedule next message from queue + final PendingWriteRequest pendingWrite = pending.poll(); + final ByteBuf msg = pendingWrite.msg; + if (logger.isTraceEnabled()) { + logger.trace("Writing pending request on channel: {}, message: {}", pendingWrite.ctx.channel(), byteBufToString(msg)); + } + + writeWithPendingDetection(pendingWrite.ctx, pendingWrite.promise, msg); + } + + public static String byteBufToString(final ByteBuf msg) { + msg.resetReaderIndex(); + final String s = msg.toString(Charsets.UTF_8); + msg.resetReaderIndex(); + return s; + } + + private void queueRequest(final ChannelHandlerContext ctx, final ByteBuf msg, final ChannelPromise promise) { +// try { + logger.debug("Write pending on channel: {}, queueing, current queue size: {}", ctx.channel(), pending.size()); + if (logger.isTraceEnabled()) { + logger.trace("Queueing request due to pending: {}", byteBufToString(msg)); + } + new PendingWriteRequest(ctx, msg, promise).pend(pending); +// } catch (final Exception ex) { +// logger.warn("Unable to queue write request on channel: {}. Setting fail for the request: {}", ctx.channel(), ex, byteBufToString(msg)); +// msg.release(); +// promise.setFailure(ex); +// } + } + + @Override + public synchronized void close() { + asyncIn = null; + } + + private Buffer toBuffer(final ByteBuf msg) { + // TODO Buffer vs ByteBuf translate, Can we handle that better ? + final byte[] temp = new byte[msg.readableBytes()]; + msg.readBytes(temp, 0, msg.readableBytes()); + return new Buffer(temp); + } + + private static final class PendingWriteRequest { + private final ChannelHandlerContext ctx; + private final ByteBuf msg; + private final ChannelPromise promise; + + public PendingWriteRequest(final ChannelHandlerContext ctx, final ByteBuf msg, final ChannelPromise promise) { + this.ctx = ctx; + // Reset reader index, last write (failed) attempt moved index to the end + msg.resetReaderIndex(); + this.msg = msg; + this.promise = promise; + } + + public void pend(final Queue pending) { + // Preconditions.checkState(pending.size() < MAX_PENDING_WRITES, + // "Too much pending writes(%s) on channel: %s, remote window is not getting read or is too small", + // pending.size(), ctx.channel()); + Preconditions.checkState(pending.offer(this), "Cannot pend another request write (pending count: %s) on channel: %s", + pending.size(), ctx.channel()); + } + } +} diff --git a/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerTest.java b/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerTest.java index 223f2c7f94..212eabb290 100644 --- a/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerTest.java +++ b/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerTest.java @@ -23,12 +23,9 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; import java.io.IOException; import java.net.SocketAddress; -import java.nio.channels.WritePendingException; import org.apache.sshd.ClientChannel; import org.apache.sshd.ClientSession; import org.apache.sshd.SshClient; @@ -46,6 +43,7 @@ import org.apache.sshd.common.io.IoWriteFuture; import org.apache.sshd.common.util.Buffer; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.mockito.Matchers; import org.mockito.Mock; @@ -59,6 +57,8 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; @@ -351,19 +351,16 @@ public class AsyncSshHandlerTest { // make first write stop pending firstWriteListener.operationComplete(ioWriteFuture); - // intercept third listener, this is regular listener for second write to determine success or failure - final ListenableFuture> afterPendingListener = stubAddListener(ioWriteFuture); // notify listener for second write that pending has ended pendingListener.get().operationComplete(ioWriteFuture); - // Notify third listener (regular listener for second write) that second write succeeded - afterPendingListener.get().operationComplete(ioWriteFuture); // verify both write promises successful verify(firstWritePromise).setSuccess(); verify(secondWritePromise).setSuccess(); } + @Ignore("Pending queue is not limited") @Test public void testWritePendingMax() throws Exception { asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise); @@ -389,11 +386,11 @@ public class AsyncSshHandlerTest { final ChannelPromise secondWritePromise = getMockedPromise(); // now make write throw pending exception doThrow(org.apache.sshd.common.io.WritePendingException.class).when(asyncIn).write(any(Buffer.class)); - for (int i = 0; i < 1000; i++) { + for (int i = 0; i < 1001; i++) { asyncSshHandler.write(ctx, Unpooled.copiedBuffer(new byte[]{0, 1, 2, 3, 4, 5}), secondWritePromise); } - verify(ctx).fireChannelInactive(); + verify(secondWritePromise, times(1)).setFailure(any(Throwable.class)); } @Test @@ -462,6 +459,8 @@ public class AsyncSshHandlerTest { private ChannelSubsystem getMockedSubsystemChannel(final IoInputStream asyncOut, final IoOutputStream asyncIn) throws IOException { final ChannelSubsystem subsystemChannel = mock(ChannelSubsystem.class); + doReturn("subsystemChannel").when(subsystemChannel).toString(); + doNothing().when(subsystemChannel).setStreaming(any(ClientChannel.Streaming.class)); final OpenFuture openFuture = mock(OpenFuture.class); diff --git a/opendaylight/netconf/netconf-ssh/pom.xml b/opendaylight/netconf/netconf-ssh/pom.xml index 6dd23776ce..78453b1770 100644 --- a/opendaylight/netconf/netconf-ssh/pom.xml +++ b/opendaylight/netconf/netconf-ssh/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../ netconf-ssh @@ -60,7 +60,6 @@ org.opendaylight.controller netconf-netty-util - test org.opendaylight.controller diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/RemoteNetconfCommand.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/RemoteNetconfCommand.java new file mode 100644 index 0000000000..e642e073a3 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/RemoteNetconfCommand.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.ssh; + +import com.google.common.base.Preconditions; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.local.LocalChannel; +import io.netty.util.concurrent.GenericFutureListener; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import org.apache.sshd.common.NamedFactory; +import org.apache.sshd.common.io.IoInputStream; +import org.apache.sshd.common.io.IoOutputStream; +import org.apache.sshd.server.AsyncCommand; +import org.apache.sshd.server.Command; +import org.apache.sshd.server.Environment; +import org.apache.sshd.server.ExitCallback; +import org.apache.sshd.server.SessionAware; +import org.apache.sshd.server.session.ServerSession; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This command handles all netconf related rpc and forwards to delegate server. + * Uses netty to make a local connection to delegate server. + * + * Command is Apache Mina SSH terminology for objects handling ssh data. + */ +public class RemoteNetconfCommand implements AsyncCommand, SessionAware { + + private static final Logger logger = LoggerFactory.getLogger(RemoteNetconfCommand.class); + + private final EventLoopGroup clientEventGroup; + private final LocalAddress localAddress; + + private IoInputStream in; + private IoOutputStream out; + private ExitCallback callback; + private NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader; + + private Channel clientChannel; + private ChannelFuture clientChannelFuture; + + public RemoteNetconfCommand(final EventLoopGroup clientEventGroup, final LocalAddress localAddress) { + this.clientEventGroup = clientEventGroup; + this.localAddress = localAddress; + } + + @Override + public void setIoInputStream(final IoInputStream in) { + this.in = in; + } + + @Override + public void setIoOutputStream(final IoOutputStream out) { + this.out = out; + } + + @Override + public void setIoErrorStream(final IoOutputStream err) { + // TODO do we want to use error stream in some way ? + } + + @Override + public void setInputStream(final InputStream in) { + throw new UnsupportedOperationException("Synchronous IO is unsupported"); + } + + @Override + public void setOutputStream(final OutputStream out) { + throw new UnsupportedOperationException("Synchronous IO is unsupported"); + + } + + @Override + public void setErrorStream(final OutputStream err) { + throw new UnsupportedOperationException("Synchronous IO is unsupported"); + + } + + @Override + public void setExitCallback(final ExitCallback callback) { + this.callback = callback; + } + + @Override + public void start(final Environment env) throws IOException { + logger.trace("Establishing internal connection to netconf server for client: {}", getClientAddress()); + + final Bootstrap clientBootstrap = new Bootstrap(); + clientBootstrap.group(clientEventGroup).channel(LocalChannel.class); + + clientBootstrap + .handler(new ChannelInitializer() { + @Override + public void initChannel(final LocalChannel ch) throws Exception { + ch.pipeline().addLast(new SshProxyClientHandler(in, out, netconfHelloMessageAdditionalHeader, callback)); + } + }); + clientChannelFuture = clientBootstrap.connect(localAddress); + clientChannelFuture.addListener(new GenericFutureListener() { + + @Override + public void operationComplete(final ChannelFuture future) throws Exception { + if(future.isSuccess()) { + clientChannel = clientChannelFuture.channel(); + } else { + logger.warn("Unable to establish internal connection to netconf server for client: {}", getClientAddress()); + Preconditions.checkNotNull(callback, "Exit callback must be set"); + callback.onExit(1, "Unable to establish internal connection to netconf server for client: "+ getClientAddress()); + } + } + }); + } + + @Override + public void destroy() { + logger.trace("Releasing internal connection to netconf server for client: {} on channel: {}", + getClientAddress(), clientChannel); + + clientChannelFuture.cancel(true); + if(clientChannel != null) { + clientChannel.close().addListener(new GenericFutureListener() { + + @Override + public void operationComplete(final ChannelFuture future) throws Exception { + if (future.isSuccess() == false) { + logger.warn("Unable to release internal connection to netconf server on channel: {}", clientChannel); + } + } + }); + } + } + + private String getClientAddress() { + return netconfHelloMessageAdditionalHeader.getAddress(); + } + + @Override + public void setSession(final ServerSession session) { + final SocketAddress remoteAddress = session.getIoSession().getRemoteAddress(); + String hostName = ""; + String port = ""; + if(remoteAddress instanceof InetSocketAddress) { + hostName = ((InetSocketAddress) remoteAddress).getAddress().getHostAddress(); + port = Integer.toString(((InetSocketAddress) remoteAddress).getPort()); + } + netconfHelloMessageAdditionalHeader = new NetconfHelloMessageAdditionalHeader( + session.getUsername(), hostName, port, "ssh", "client"); + } + + public static class NetconfCommandFactory implements NamedFactory { + + public static final String NETCONF = "netconf"; + + private final EventLoopGroup clientBootstrap; + private final LocalAddress localAddress; + + public NetconfCommandFactory(final EventLoopGroup clientBootstrap, final LocalAddress localAddress) { + + this.clientBootstrap = clientBootstrap; + this.localAddress = localAddress; + } + + @Override + public String getName() { + return NETCONF; + } + + @Override + public RemoteNetconfCommand create() { + return new RemoteNetconfCommand(clientBootstrap, localAddress); + } + } + +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyClientHandler.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyClientHandler.java new file mode 100644 index 0000000000..2b2b3b3e81 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyClientHandler.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.ssh; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import org.apache.sshd.common.io.IoInputStream; +import org.apache.sshd.common.io.IoOutputStream; +import org.apache.sshd.server.ExitCallback; +import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerReader; +import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerWriter; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Netty handler that reads SSH from remote client and writes to delegate server and reads from delegate server and writes to remote client + */ +final class SshProxyClientHandler extends ChannelInboundHandlerAdapter { + + private static final Logger logger = LoggerFactory.getLogger(SshProxyClientHandler.class); + + private final IoInputStream in; + private final IoOutputStream out; + + private AsyncSshHandlerReader asyncSshHandlerReader; + private AsyncSshHandlerWriter asyncSshHandlerWriter; + + private final NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader; + private final ExitCallback callback; + + public SshProxyClientHandler(final IoInputStream in, final IoOutputStream out, + final NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader, + final ExitCallback callback) { + this.in = in; + this.out = out; + this.netconfHelloMessageAdditionalHeader = netconfHelloMessageAdditionalHeader; + this.callback = callback; + } + + @Override + public void channelActive(final ChannelHandlerContext ctx) throws Exception { + writeAdditionalHeader(ctx); + + asyncSshHandlerWriter = new AsyncSshHandlerWriter(out); + asyncSshHandlerReader = new AsyncSshHandlerReader(new AutoCloseable() { + @Override + public void close() throws Exception { + // Close both sessions (delegate server and remote client) + ctx.fireChannelInactive(); + ctx.disconnect(); + ctx.close(); + asyncSshHandlerReader.close(); + asyncSshHandlerWriter.close(); + } + }, new AsyncSshHandlerReader.ReadMsgHandler() { + @Override + public void onMessageRead(final ByteBuf msg) { + if(logger.isTraceEnabled()) { + logger.trace("Forwarding message for client: {} on channel: {}, message: {}", + netconfHelloMessageAdditionalHeader.getAddress(), ctx.channel(), AsyncSshHandlerWriter.byteBufToString(msg)); + } + // Just forward to delegate + ctx.writeAndFlush(msg); + } + }, "ssh" + netconfHelloMessageAdditionalHeader.getAddress(), in); + + + super.channelActive(ctx); + } + + private void writeAdditionalHeader(final ChannelHandlerContext ctx) { + ctx.writeAndFlush(Unpooled.copiedBuffer(netconfHelloMessageAdditionalHeader.toFormattedString().getBytes())); + } + + @Override + public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception { + asyncSshHandlerWriter.write(ctx, msg, ctx.newPromise()); + } + + @Override + public void channelInactive(final ChannelHandlerContext ctx) throws Exception { + logger.debug("Internal connection to netconf server was dropped for client: {} on channel: ", + netconfHelloMessageAdditionalHeader.getAddress(), ctx.channel()); + callback.onExit(1, "Internal connection to netconf server was dropped for client: " + + netconfHelloMessageAdditionalHeader.getAddress() + " on channel: " + ctx.channel()); + super.channelInactive(ctx); + } + + +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServer.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServer.java new file mode 100644 index 0000000000..0b85cf2653 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServer.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.ssh; + +import com.google.common.collect.Lists; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.channels.AsynchronousChannelGroup; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.apache.sshd.SshServer; +import org.apache.sshd.common.FactoryManager; +import org.apache.sshd.common.KeyPairProvider; +import org.apache.sshd.common.NamedFactory; +import org.apache.sshd.common.RuntimeSshException; +import org.apache.sshd.common.io.IoAcceptor; +import org.apache.sshd.common.io.IoConnector; +import org.apache.sshd.common.io.IoHandler; +import org.apache.sshd.common.io.IoServiceFactory; +import org.apache.sshd.common.io.IoServiceFactoryFactory; +import org.apache.sshd.common.io.nio2.Nio2Acceptor; +import org.apache.sshd.common.io.nio2.Nio2Connector; +import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory; +import org.apache.sshd.common.util.CloseableUtils; +import org.apache.sshd.server.Command; +import org.apache.sshd.server.PasswordAuthenticator; + +/** + * Proxy SSH server that just delegates decrypted content to a delegate server within same VM. + * Implemented using Apache Mina SSH lib. + */ +public class SshProxyServer implements AutoCloseable { + + private final SshServer sshServer; + private final ScheduledExecutorService minaTimerExecutor; + private final EventLoopGroup clientGroup; + private final IoServiceFactoryFactory nioServiceWithPoolFactoryFactory; + + public SshProxyServer(final ScheduledExecutorService minaTimerExecutor, final EventLoopGroup clientGroup, final ExecutorService nioExecutor) { + this.minaTimerExecutor = minaTimerExecutor; + this.clientGroup = clientGroup; + this.nioServiceWithPoolFactoryFactory = new NioServiceWithPoolFactory.NioServiceWithPoolFactoryFactory(nioExecutor); + this.sshServer = SshServer.setUpDefaultServer(); + } + + public void bind(final InetSocketAddress bindingAddress, final LocalAddress localAddress, final PasswordAuthenticator authenticator, final KeyPairProvider keyPairProvider) throws IOException { + sshServer.setHost(bindingAddress.getHostString()); + sshServer.setPort(bindingAddress.getPort()); + + sshServer.setPasswordAuthenticator(authenticator); + sshServer.setKeyPairProvider(keyPairProvider); + + sshServer.setIoServiceFactoryFactory(nioServiceWithPoolFactoryFactory); + sshServer.setScheduledExecutorService(minaTimerExecutor); + + final RemoteNetconfCommand.NetconfCommandFactory netconfCommandFactory = + new RemoteNetconfCommand.NetconfCommandFactory(clientGroup, localAddress); + sshServer.setSubsystemFactories(Lists.>newArrayList(netconfCommandFactory)); + sshServer.start(); + } + + @Override + public void close() { + try { + sshServer.stop(true); + } catch (final InterruptedException e) { + throw new RuntimeException("Interrupted while stopping sshServer", e); + } finally { + sshServer.close(true); + } + } + + /** + * Based on Nio2ServiceFactory with one addition: injectable executor + */ + private static final class NioServiceWithPoolFactory extends CloseableUtils.AbstractCloseable implements IoServiceFactory { + + private final FactoryManager manager; + private final AsynchronousChannelGroup group; + + public NioServiceWithPoolFactory(final FactoryManager manager, final ExecutorService executor) { + this.manager = manager; + try { + group = AsynchronousChannelGroup.withThreadPool(executor); + } catch (final IOException e) { + throw new RuntimeSshException(e); + } + } + + public IoConnector createConnector(final IoHandler handler) { + return new Nio2Connector(manager, handler, group); + } + + public IoAcceptor createAcceptor(final IoHandler handler) { + return new Nio2Acceptor(manager, handler, group); + } + + @Override + protected void doCloseImmediately() { + try { + group.shutdownNow(); + group.awaitTermination(5, TimeUnit.SECONDS); + } catch (final Exception e) { + log.debug("Exception caught while closing channel group", e); + } finally { + super.doCloseImmediately(); + } + } + + private static final class NioServiceWithPoolFactoryFactory extends Nio2ServiceFactoryFactory { + + private final ExecutorService nioExecutor; + + private NioServiceWithPoolFactoryFactory(final ExecutorService nioExecutor) { + this.nioExecutor = nioExecutor; + } + + @Override + public IoServiceFactory create(final FactoryManager manager) { + return new NioServiceWithPoolFactory(manager, nioExecutor); + } + } + } + +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/AuthProviderTracker.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/AuthProviderTracker.java new file mode 100644 index 0000000000..97e611c0d2 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/AuthProviderTracker.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.ssh.osgi; + +import com.google.common.base.Preconditions; +import org.apache.sshd.server.PasswordAuthenticator; +import org.apache.sshd.server.session.ServerSession; +import org.opendaylight.controller.netconf.auth.AuthConstants; +import org.opendaylight.controller.netconf.auth.AuthProvider; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class AuthProviderTracker implements ServiceTrackerCustomizer, PasswordAuthenticator { + private static final Logger logger = LoggerFactory.getLogger(AuthProviderTracker.class); + + private final BundleContext bundleContext; + + private Integer maxPreference; + private final ServiceTracker listenerTracker; + private AuthProvider authProvider; + + public AuthProviderTracker(final BundleContext bundleContext) { + this.bundleContext = bundleContext; + listenerTracker = new ServiceTracker<>(bundleContext, AuthProvider.class, this); + listenerTracker.open(); + } + + @Override + public AuthProvider addingService(final ServiceReference reference) { + logger.trace("Service {} added", reference); + final AuthProvider authService = bundleContext.getService(reference); + final Integer newServicePreference = getPreference(reference); + if(isBetter(newServicePreference)) { + maxPreference = newServicePreference; + this.authProvider = authService; + } + return authService; + } + + private Integer getPreference(final ServiceReference reference) { + final Object preferenceProperty = reference.getProperty(AuthConstants.SERVICE_PREFERENCE_KEY); + return preferenceProperty == null ? Integer.MIN_VALUE : Integer.valueOf(preferenceProperty.toString()); + } + + private boolean isBetter(final Integer newServicePreference) { + Preconditions.checkNotNull(newServicePreference); + if(maxPreference == null) { + return true; + } + + return newServicePreference > maxPreference; + } + + @Override + public void modifiedService(final ServiceReference reference, final AuthProvider service) { + final AuthProvider authService = bundleContext.getService(reference); + final Integer newServicePreference = getPreference(reference); + if(isBetter(newServicePreference)) { + logger.trace("Replacing modified service {} in netconf SSH.", reference); + this.authProvider = authService; + } + } + + @Override + public void removedService(final ServiceReference reference, final AuthProvider service) { + logger.trace("Removing service {} from netconf SSH. " + + "SSH won't authenticate users until AuthProvider service will be started.", reference); + maxPreference = null; + this.authProvider = null; + } + + public void stop() { + listenerTracker.close(); + // sshThread should finish normally since sshServer.close stops processing + } + + @Override + public boolean authenticate(final String username, final String password, final ServerSession session) { + return authProvider == null ? false : authProvider.authenticated(username, password); + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java index c686bcbc66..b871d19db8 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java @@ -9,51 +9,51 @@ package org.opendaylight.controller.netconf.ssh.osgi; import static com.google.common.base.Preconditions.checkState; -import com.google.common.base.Preconditions; -import java.io.File; +import com.google.common.base.Optional; +import com.google.common.base.Strings; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.nio.NioEventLoopGroup; import java.io.IOException; import java.net.InetSocketAddress; - +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; import org.apache.commons.io.FilenameUtils; -import org.opendaylight.controller.netconf.auth.AuthConstants; -import org.opendaylight.controller.netconf.auth.AuthProvider; -import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; -import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; +import org.apache.sshd.common.util.ThreadUtils; +import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider; +import org.opendaylight.controller.netconf.ssh.SshProxyServer; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil.InfixProp; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.util.tracker.ServiceTracker; -import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Optional; -import com.google.common.base.Strings; - -import io.netty.channel.EventLoopGroup; -import io.netty.channel.local.LocalAddress; -import io.netty.channel.nio.NioEventLoopGroup; - -/** - * Activator for netconf SSH bundle which creates SSH bridge between netconf client and netconf server. Activator - * starts SSH Server in its own thread. This thread is closed when activator calls stop() method. Server opens socket - * and listens for client connections. Each client connection creation is handled in separate - * {@link org.opendaylight.controller.netconf.ssh.threads.Handshaker} thread. - * This thread creates two additional threads {@link org.opendaylight.controller.netconf.ssh.threads.IOThread} - * forwarding data from/to client.IOThread closes servers session and server connection when it gets -1 on input stream. - * {@link org.opendaylight.controller.netconf.ssh.threads.IOThread}'s run method waits for -1 on input stream to finish. - * All threads are daemons. - */ public class NetconfSSHActivator implements BundleActivator { private static final Logger logger = LoggerFactory.getLogger(NetconfSSHActivator.class); - private static AuthProviderTracker authProviderTracker; - private NetconfSSHServer server; + private static final java.lang.String ALGORITHM = "RSA"; + private static final int KEY_SIZE = 4096; + public static final int POOL_SIZE = 8; + + private ScheduledExecutorService minaTimerExecutor; + private NioEventLoopGroup clientGroup; + private ExecutorService nioExecutor; + private AuthProviderTracker authProviderTracker; + + private SshProxyServer server; @Override public void start(final BundleContext bundleContext) throws IOException { + minaTimerExecutor = Executors.newScheduledThreadPool(POOL_SIZE, new ThreadFactory() { + @Override + public Thread newThread(final Runnable r) { + return new Thread(r, "netconf-ssh-server-mina-timers"); + } + }); + clientGroup = new NioEventLoopGroup(); + nioExecutor = ThreadUtils.newFixedThreadPool("netconf-ssh-server-nio-group", POOL_SIZE); server = startSSHServer(bundleContext); } @@ -66,11 +66,22 @@ public class NetconfSSHActivator implements BundleActivator { if(authProviderTracker != null) { authProviderTracker.stop(); } + + if(nioExecutor!=null) { + nioExecutor.shutdownNow(); + } + + if(clientGroup != null) { + clientGroup.shutdownGracefully(); + } + + if(minaTimerExecutor != null) { + minaTimerExecutor.shutdownNow(); + } } - private static NetconfSSHServer startSSHServer(final BundleContext bundleContext) throws IOException { - final Optional maybeSshSocketAddress = NetconfConfigUtil.extractNetconfServerAddress(bundleContext, - InfixProp.ssh); + private SshProxyServer startSSHServer(final BundleContext bundleContext) throws IOException { + final Optional maybeSshSocketAddress = NetconfConfigUtil.extractNetconfServerAddress(bundleContext, InfixProp.ssh); if (maybeSshSocketAddress.isPresent() == false) { logger.trace("SSH bridge not configured"); @@ -82,91 +93,15 @@ public class NetconfSSHActivator implements BundleActivator { final LocalAddress localAddress = NetconfConfigUtil.getNetconfLocalAddress(); - final String path = FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(bundleContext)); - checkState(!Strings.isNullOrEmpty(path), "Path to ssh private key is blank. Reconfigure %s", NetconfConfigUtil.getPrivateKeyKey()); - final String privateKeyPEMString = PEMGenerator.readOrGeneratePK(new File(path)); - - final EventLoopGroup bossGroup = new NioEventLoopGroup(); - final NetconfSSHServer server = NetconfSSHServer.start(sshSocketAddress.getPort(), localAddress, bossGroup, privateKeyPEMString.toCharArray()); - - authProviderTracker = new AuthProviderTracker(bundleContext, server); + authProviderTracker = new AuthProviderTracker(bundleContext); - return server; - } + final String path = FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(bundleContext)); + checkState(!Strings.isNullOrEmpty(path), "Path to ssh private key is blank. Reconfigure %s", + NetconfConfigUtil.getPrivateKeyKey()); - private static Thread runNetconfSshThread(final NetconfSSHServer server) { - final Thread serverThread = new Thread(server, "netconf SSH server thread"); - serverThread.setDaemon(true); - serverThread.start(); - logger.trace("Netconf SSH bridge up and running."); - return serverThread; + final SshProxyServer sshProxyServer = new SshProxyServer(minaTimerExecutor, clientGroup, nioExecutor); + sshProxyServer.bind(sshSocketAddress, localAddress, authProviderTracker, new PEMGeneratorHostKeyProvider(path, ALGORITHM, KEY_SIZE)); + return sshProxyServer; } - private static class AuthProviderTracker implements ServiceTrackerCustomizer { - private final BundleContext bundleContext; - private final NetconfSSHServer server; - - private Integer maxPreference; - private Thread sshThread; - private final ServiceTracker listenerTracker; - - public AuthProviderTracker(final BundleContext bundleContext, final NetconfSSHServer server) { - this.bundleContext = bundleContext; - this.server = server; - listenerTracker = new ServiceTracker<>(bundleContext, AuthProvider.class, this); - listenerTracker.open(); - } - - @Override - public AuthProvider addingService(final ServiceReference reference) { - logger.trace("Service {} added", reference); - final AuthProvider authService = bundleContext.getService(reference); - final Integer newServicePreference = getPreference(reference); - if(isBetter(newServicePreference)) { - server.setAuthProvider(authService); - if(sshThread == null) { - sshThread = runNetconfSshThread(server); - } - } - return authService; - } - - private Integer getPreference(final ServiceReference reference) { - final Object preferenceProperty = reference.getProperty(AuthConstants.SERVICE_PREFERENCE_KEY); - return preferenceProperty == null ? Integer.MIN_VALUE : Integer.valueOf(preferenceProperty.toString()); - } - - private boolean isBetter(final Integer newServicePreference) { - Preconditions.checkNotNull(newServicePreference); - if(maxPreference == null) { - return true; - } - - return newServicePreference > maxPreference; - } - - @Override - public void modifiedService(final ServiceReference reference, final AuthProvider service) { - final AuthProvider authService = bundleContext.getService(reference); - final Integer newServicePreference = getPreference(reference); - if(isBetter(newServicePreference)) { - logger.trace("Replacing modified service {} in netconf SSH.", reference); - server.setAuthProvider(authService); - } - } - - @Override - public void removedService(final ServiceReference reference, final AuthProvider service) { - logger.trace("Removing service {} from netconf SSH. " + - "SSH won't authenticate users until AuthProvider service will be started.", reference); - maxPreference = null; - server.setAuthProvider(null); - } - - public void stop() { - listenerTracker.close(); - // sshThread should finish normally since sshServer.close stops processing - } - - } } diff --git a/opendaylight/netconf/netconf-tcp/pom.xml b/opendaylight/netconf/netconf-tcp/pom.xml index 3c4ee4728d..8ec33286a7 100644 --- a/opendaylight/netconf/netconf-tcp/pom.xml +++ b/opendaylight/netconf/netconf-tcp/pom.xml @@ -11,7 +11,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../ netconf-tcp diff --git a/opendaylight/netconf/netconf-testtool/pom.xml b/opendaylight/netconf/netconf-testtool/pom.xml index ae0bb76832..0172a28c16 100644 --- a/opendaylight/netconf/netconf-testtool/pom.xml +++ b/opendaylight/netconf/netconf-testtool/pom.xml @@ -14,7 +14,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT netconf-testtool @@ -31,10 +31,22 @@ logback-classic compile + + org.bouncycastle + bcpkix-jdk15on + + + org.bouncycastle + bcprov-jdk15on + ${project.groupId} netconf-netty-util + + ${project.groupId} + netconf-auth + org.opendaylight.controller commons.logback_settings @@ -63,7 +75,10 @@ xmlunit xmlunit - + + com.google.guava + guava + ${project.groupId} config-util @@ -72,10 +87,22 @@ ${project.groupId} netconf-api + + org.opendaylight.controller + ietf-netconf-monitoring + ${project.groupId} netconf-client + + org.opendaylight.yangtools.model + ietf-yang-types-20130715 + + + org.opendaylight.yangtools.model + ietf-inet-types + ${project.groupId} netconf-impl @@ -88,12 +115,10 @@ ${project.groupId} netconf-monitoring - ${project.groupId} netconf-ssh - ${project.groupId} netty-config-api diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/DataList.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/DataList.java new file mode 100644 index 0000000000..d6dd55cb4e --- /dev/null +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/DataList.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.test.tool; + +import java.util.Collections; +import java.util.List; +import org.opendaylight.controller.netconf.util.xml.XmlElement; + +public class DataList { + + private List configList = Collections.emptyList(); + + public List getConfigList() { + return configList; + } + + public void setConfigList(List configList) { + this.configList = configList; + } + + public void resetConfigList() { + configList = Collections.emptyList(); + } + +} diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/Main.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/Main.java index 56e3452a77..681b9a6a2d 100644 --- a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/Main.java +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/Main.java @@ -12,31 +12,38 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import ch.qos.logback.classic.Level; +import com.google.common.base.Charsets; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import com.google.common.io.ByteStreams; +import com.google.common.io.CharStreams; import com.google.common.io.Files; import java.io.File; +import java.io.FileFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.util.Collections; +import java.util.Comparator; import java.util.List; - import java.util.concurrent.TimeUnit; import net.sourceforge.argparse4j.ArgumentParsers; import net.sourceforge.argparse4j.annotation.Arg; import net.sourceforge.argparse4j.inf.ArgumentParser; import net.sourceforge.argparse4j.inf.ArgumentParserException; - +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import com.google.common.base.Charsets; -import com.google.common.io.CharStreams; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; public final class Main { - // TODO add logback config - - // TODO make exi configurable - private static final Logger LOG = LoggerFactory.getLogger(Main.class); static class Params { @@ -56,8 +63,8 @@ public final class Main { @Arg(dest = "generate-config-address") public String generateConfigsAddress; - @Arg(dest = "generate-configs-dir") - public File generateConfigsDir; + @Arg(dest = "distro-folder") + public File distroFolder; @Arg(dest = "generate-configs-batch-size") public int generateConfigBatchSize; @@ -68,9 +75,15 @@ public final class Main { @Arg(dest = "exi") public boolean exi; + @Arg(dest = "debug") + public boolean debug; + static ArgumentParser getParser() { final ArgumentParser parser = ArgumentParsers.newArgumentParser("netconf testool"); - parser.addArgument("--devices-count") + + parser.description("Netconf device simulator. Detailed info can be found at https://wiki.opendaylight.org/view/OpenDaylight_Controller:Netconf:Testtool#Building_testtool"); + + parser.addArgument("--device-count") .type(Integer.class) .setDefault(1) .type(Integer.class) @@ -79,8 +92,7 @@ public final class Main { parser.addArgument("--schemas-dir") .type(File.class) - .required(true) - .help("Directory containing yang schemas to describe simulated devices") + .help("Directory containing yang schemas to describe simulated devices. Some schemas e.g. netconf monitoring and inet types are included by default") .dest("schemas-dir"); parser.addArgument("--starting-port") @@ -91,7 +103,7 @@ public final class Main { parser.addArgument("--generate-config-connection-timeout") .type(Integer.class) - .setDefault((int)TimeUnit.MINUTES.toMillis(5)) + .setDefault((int)TimeUnit.MINUTES.toMillis(30)) .help("Timeout to be generated in initial config files") .dest("generate-config-connection-timeout"); @@ -103,14 +115,14 @@ public final class Main { parser.addArgument("--generate-configs-batch-size") .type(Integer.class) - .setDefault(100) + .setDefault(4000) .help("Number of connector configs per generated file") .dest("generate-configs-batch-size"); - parser.addArgument("--generate-configs-dir") + parser.addArgument("--distribution-folder") .type(File.class) - .help("Directory where initial config files for ODL distribution should be generated") - .dest("generate-configs-dir"); + .help("Directory where the karaf distribution for controller is located") + .dest("distro-folder"); parser.addArgument("--ssh") .type(Boolean.class) @@ -120,10 +132,16 @@ public final class Main { parser.addArgument("--exi") .type(Boolean.class) - .setDefault(false) + .setDefault(true) .help("Whether to use exi to transport xml content") .dest("exi"); + parser.addArgument("--debug") + .type(Boolean.class) + .setDefault(false) + .help("Whether to use debug log level instead of INFO") + .dest("debug"); + return parser; } @@ -131,23 +149,29 @@ public final class Main { checkArgument(deviceCount > 0, "Device count has to be > 0"); checkArgument(startingPort > 1024, "Starting port has to be > 1024"); - checkArgument(schemasDir.exists(), "Schemas dir has to exist"); - checkArgument(schemasDir.isDirectory(), "Schemas dir has to be a directory"); - checkArgument(schemasDir.canRead(), "Schemas dir has to be readable"); + if(schemasDir != null) { + checkArgument(schemasDir.exists(), "Schemas dir has to exist"); + checkArgument(schemasDir.isDirectory(), "Schemas dir has to be a directory"); + checkArgument(schemasDir.canRead(), "Schemas dir has to be readable"); + } } } public static void main(final String[] args) { - ch.ethz.ssh2.log.Logger.enabled = true; - final Params params = parseArgs(args, Params.getParser()); params.validate(); + final ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + root.setLevel(params.debug ? Level.DEBUG : Level.INFO); + final NetconfDeviceSimulator netconfDeviceSimulator = new NetconfDeviceSimulator(); try { final List openDevices = netconfDeviceSimulator.start(params); - if(params.generateConfigsDir != null) { - new ConfigGenerator(params.generateConfigsDir, openDevices).generate(params.ssh, params.generateConfigBatchSize, params.generateConfigsTimeout, params.generateConfigsAddress); + if(params.distroFolder != null) { + final ConfigGenerator configGenerator = new ConfigGenerator(params.distroFolder, openDevices); + final List generated = configGenerator.generate(params.ssh, params.generateConfigBatchSize, params.generateConfigsTimeout, params.generateConfigsAddress); + configGenerator.updateFeatureFile(generated); + configGenerator.changeLoadOrder(); } } catch (final Exception e) { LOG.error("Unhandled exception", e); @@ -165,7 +189,6 @@ public final class Main { } } - private static Params parseArgs(final String[] args, final ArgumentParser parser) { final Params opt = new Params(); try { @@ -187,24 +210,45 @@ public final class Main { public static final String NETCONF_USE_SSH = "false"; public static final String SIM_DEVICE_SUFFIX = "-sim-device"; - private final File directory; + private static final String SIM_DEVICE_CFG_PREFIX = "simulated-devices_"; + private static final String ETC_KARAF_PATH = "etc/"; + private static final String ETC_OPENDAYLIGHT_KARAF_PATH = ETC_KARAF_PATH + "opendaylight/karaf/"; + + public static final String NETCONF_CONNECTOR_ALL_FEATURE = "odl-netconf-connector-all"; + private static final String ORG_OPS4J_PAX_URL_MVN_CFG = "org.ops4j.pax.url.mvn.cfg"; + + private final File configDir; private final List openDevices; + private final File ncFeatureFile; + private final File etcDir; + private final File loadOrderCfgFile; public ConfigGenerator(final File directory, final List openDevices) { - this.directory = directory; + this.configDir = new File(directory, ETC_OPENDAYLIGHT_KARAF_PATH); + this.etcDir = new File(directory, ETC_KARAF_PATH); + this.loadOrderCfgFile = new File(etcDir, ORG_OPS4J_PAX_URL_MVN_CFG); + this.ncFeatureFile = getFeatureFile(directory, "features-netconf-connector"); this.openDevices = openDevices; } - public void generate(final boolean useSsh, final int batchSize, final int generateConfigsTimeout, final String address) { - if(directory.exists() == false) { - checkState(directory.mkdirs(), "Unable to create folder %s" + directory); + public List generate(final boolean useSsh, final int batchSize, final int generateConfigsTimeout, final String address) { + if(configDir.exists() == false) { + Preconditions.checkState(configDir.mkdirs(), "Unable to create directory " + configDir); + } + + for (final File file : configDir.listFiles(new FileFilter() { + @Override + public boolean accept(final File pathname) { + return !pathname.isDirectory() && pathname.getName().startsWith(SIM_DEVICE_CFG_PREFIX); + } + })) { + Preconditions.checkState(file.delete(), "Unable to clean previous generated file %s", file); } try(InputStream stream = Main.class.getResourceAsStream(NETCONF_CONNECTOR_XML)) { checkNotNull(stream, "Cannot load %s", NETCONF_CONNECTOR_XML); String configBlueprint = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8)); - // TODO make address configurable checkState(configBlueprint.contains(NETCONF_CONNECTOR_NAME)); checkState(configBlueprint.contains(NETCONF_CONNECTOR_PORT)); checkState(configBlueprint.contains(NETCONF_USE_SSH)); @@ -223,6 +267,8 @@ public final class Main { StringBuilder b = new StringBuilder(); b.append(before); + final List generatedConfigs = Lists.newArrayList(); + for (final Integer openDevice : openDevices) { if(batchStart == null) { batchStart = openDevice; @@ -236,7 +282,9 @@ public final class Main { connectorCount++; if(connectorCount == batchSize) { b.append(after); - Files.write(b.toString(), new File(directory, String.format("simulated-devices_%d-%d.xml", batchStart, openDevice)), Charsets.UTF_8); + final File to = new File(configDir, String.format(SIM_DEVICE_CFG_PREFIX + "%d-%d.xml", batchStart, openDevice)); + generatedConfigs.add(to); + Files.write(b.toString(), to, Charsets.UTF_8); connectorCount = 0; b = new StringBuilder(); b.append(before); @@ -247,13 +295,100 @@ public final class Main { // Write remaining if(connectorCount != 0) { b.append(after); - Files.write(b.toString(), new File(directory, String.format("simulated-devices_%d-%d.xml", batchStart, openDevices.get(openDevices.size() - 1))), Charsets.UTF_8); + final File to = new File(configDir, String.format(SIM_DEVICE_CFG_PREFIX + "%d-%d.xml", batchStart, openDevices.get(openDevices.size() - 1))); + generatedConfigs.add(to); + Files.write(b.toString(), to, Charsets.UTF_8); } - LOG.info("Config files generated in {}", directory); + LOG.info("Config files generated in {}", configDir); + return generatedConfigs; } catch (final IOException e) { throw new RuntimeException("Unable to generate config files", e); } } + + + public void updateFeatureFile(final List generated) { + // TODO karaf core contains jaxb for feature files, use that for modification + try { + final Document document = XmlUtil.readXmlToDocument(Files.toString(ncFeatureFile, Charsets.UTF_8)); + final NodeList childNodes = document.getDocumentElement().getChildNodes(); + + for (int i = 0; i < childNodes.getLength(); i++) { + final Node item = childNodes.item(i); + if(item instanceof Element == false) { + continue; + } + if(item.getLocalName().equals("feature") ==false) { + continue; + } + + if(NETCONF_CONNECTOR_ALL_FEATURE.equals(((Element) item).getAttribute("name"))) { + final Element ncAllFeatureDefinition = (Element) item; + // Clean previous generated files + for (final XmlElement configfile : XmlElement.fromDomElement(ncAllFeatureDefinition).getChildElements("configfile")) { + ncAllFeatureDefinition.removeChild(configfile.getDomElement()); + } + for (final File file : generated) { + final Element configfile = document.createElement("configfile"); + configfile.setTextContent("file:" + ETC_OPENDAYLIGHT_KARAF_PATH + file.getName()); + configfile.setAttribute("finalname", ETC_OPENDAYLIGHT_KARAF_PATH + file.getName()); + ncAllFeatureDefinition.appendChild(configfile); + } + } + } + + Files.write(XmlUtil.toString(document), ncFeatureFile, Charsets.UTF_8); + LOG.info("Feature file {} updated", ncFeatureFile); + } catch (final IOException e) { + throw new RuntimeException("Unable to load features file as a resource"); + } catch (final SAXException e) { + throw new RuntimeException("Unable to parse features file"); + } + } + + + private static File getFeatureFile(final File distroFolder, final String featureName) { + checkExistingDir(distroFolder, String.format("Folder %s does not exist", distroFolder)); + + final File systemDir = checkExistingDir(new File(distroFolder, "system"), String.format("Folder %s does not contain a karaf distro, folder system is missing", distroFolder)); + final File netconfConnectorFeaturesParentDir = checkExistingDir(new File(systemDir, "org/opendaylight/controller/" + featureName), String.format("Karaf distro in %s does not contain netconf-connector features", distroFolder)); + + // Find newest version for features + final File newestVersionDir = Collections.max( + Lists.newArrayList(netconfConnectorFeaturesParentDir.listFiles(new FileFilter() { + @Override + public boolean accept(final File pathname) { + return pathname.isDirectory(); + } + })), new Comparator() { + @Override + public int compare(final File o1, final File o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + + return newestVersionDir.listFiles(new FileFilter() { + @Override + public boolean accept(final File pathname) { + return pathname.getName().contains(featureName); + } + })[0]; + } + + private static File checkExistingDir(final File folder, final String msg) { + Preconditions.checkArgument(folder.exists(), msg); + Preconditions.checkArgument(folder.isDirectory(), msg); + return folder; + } + + public void changeLoadOrder() { + try { + Files.write(ByteStreams.toByteArray(getClass().getResourceAsStream("/" +ORG_OPS4J_PAX_URL_MVN_CFG)), loadOrderCfgFile); + LOG.info("Load order changed to prefer local bundles/features by rewriting file {}", loadOrderCfgFile); + } catch (IOException e) { + throw new RuntimeException("Unable to rewrite features file " + loadOrderCfgFile, e); + } + } } } diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java index 600baa7431..e8ba769da5 100644 --- a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.test.tool; import com.google.common.base.Charsets; import com.google.common.base.Function; +import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; @@ -17,20 +18,24 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.io.CharStreams; import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.local.LocalAddress; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.util.HashedWheelTimer; import java.io.Closeable; -import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.lang.management.ManagementFactory; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.URI; import java.net.UnknownHostException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.AbstractMap; import java.util.Date; import java.util.HashMap; @@ -39,8 +44,15 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTreeWalker; +import org.apache.sshd.common.util.ThreadUtils; +import org.apache.sshd.server.PasswordAuthenticator; +import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider; +import org.apache.sshd.server.session.ServerSession; import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession; import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer; @@ -55,8 +67,7 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot; import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService; -import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; -import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; +import org.opendaylight.controller.netconf.ssh.SshProxyServer; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException; import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation; @@ -64,6 +75,7 @@ import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource; import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener; +import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider; import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache; import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils; import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder; @@ -78,19 +90,25 @@ public class NetconfDeviceSimulator implements Closeable { private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceSimulator.class); - public static final int CONNECTION_TIMEOUT_MILLIS = 20000; - private final NioEventLoopGroup nettyThreadgroup; private final HashedWheelTimer hashedWheelTimer; private final List devicesChannels = Lists.newArrayList(); + private final List sshWrappers = Lists.newArrayList(); + private final ScheduledExecutorService minaTimerExecutor; + private final ExecutorService nioExecutor; public NetconfDeviceSimulator() { - this(new NioEventLoopGroup(), new HashedWheelTimer()); + // TODO make pool size configurable + this(new NioEventLoopGroup(), new HashedWheelTimer(), + Executors.newScheduledThreadPool(8, new ThreadFactoryBuilder().setNameFormat("netconf-ssh-server-mina-timers-%d").build()), + ThreadUtils.newFixedThreadPool("netconf-ssh-server-nio-group", 8)); } - public NetconfDeviceSimulator(final NioEventLoopGroup eventExecutors, final HashedWheelTimer hashedWheelTimer) { + private NetconfDeviceSimulator(final NioEventLoopGroup eventExecutors, final HashedWheelTimer hashedWheelTimer, final ScheduledExecutorService minaTimerExecutor, final ExecutorService nioExecutor) { this.nettyThreadgroup = eventExecutors; this.hashedWheelTimer = hashedWheelTimer; + this.minaTimerExecutor = minaTimerExecutor; + this.nioExecutor = nioExecutor; } private NetconfServerDispatcher createDispatcher(final Map moduleBuilders, final boolean exi, final int generateConfigsTimeout) { @@ -123,34 +141,36 @@ public class NetconfDeviceSimulator implements Closeable { } private Map toModuleBuilders(final Map> sources) { - final Map asts = Maps.transformValues(sources, new Function, ParserRuleContext>() { - @Override - public ParserRuleContext apply(final Map.Entry input) { - return input.getKey().getAST(); - } - }); - final Map> namespaceContext = BuilderUtils.createYangNamespaceContext( - asts.values(), Optional.absent()); + final Map asts = Maps.transformValues(sources, new Function, ParserRuleContext>() { + @Override + public ParserRuleContext apply(final Map.Entry input) { + return input.getKey().getAST(); + } + }); + final Map> namespaceContext = BuilderUtils.createYangNamespaceContext( + asts.values(), Optional.absent()); - final ParseTreeWalker walker = new ParseTreeWalker(); - final Map sourceToBuilder = new HashMap<>(); + final ParseTreeWalker walker = new ParseTreeWalker(); + final Map sourceToBuilder = new HashMap<>(); - for (final Map.Entry entry : asts.entrySet()) { - final ModuleBuilder moduleBuilder = YangParserListenerImpl.create(namespaceContext, entry.getKey().getName(), - walker, entry.getValue()).getModuleBuilder(); + for (final Map.Entry entry : asts.entrySet()) { + final ModuleBuilder moduleBuilder = YangParserListenerImpl.create(namespaceContext, entry.getKey().getName(), + walker, entry.getValue()).getModuleBuilder(); - try(InputStreamReader stream = new InputStreamReader(sources.get(entry.getKey()).getValue().openStream(), Charsets.UTF_8)) { - sourceToBuilder.put(moduleBuilder, CharStreams.toString(stream)); - } catch (final IOException e) { - throw new RuntimeException(e); - } + try(InputStreamReader stream = new InputStreamReader(sources.get(entry.getKey()).getValue().openStream(), Charsets.UTF_8)) { + sourceToBuilder.put(moduleBuilder, CharStreams.toString(stream)); + } catch (final IOException e) { + throw new RuntimeException(e); } - - return sourceToBuilder; } + return sourceToBuilder; + } + public List start(final Main.Params params) { + LOG.info("Starting {}, {} simulated devices starting on port {}", params.deviceCount, params.ssh ? "SSH" : "TCP", params.startingPort); + final Map moduleBuilders = parseSchemasToModuleBuilders(params); final NetconfServerDispatcher dispatcher = createDispatcher(moduleBuilders, params.exi, params.generateConfigsTimeout); @@ -158,17 +178,31 @@ public class NetconfDeviceSimulator implements Closeable { int currentPort = params.startingPort; final List openDevices = Lists.newArrayList(); + + // Generate key to temp folder + final PEMGeneratorHostKeyProvider keyPairProvider = getPemGeneratorHostKeyProvider(); + for (int i = 0; i < params.deviceCount; i++) { final InetSocketAddress address = getAddress(currentPort); final ChannelFuture server; if(params.ssh) { + final InetSocketAddress bindingAddress = InetSocketAddress.createUnresolved("0.0.0.0", currentPort); final LocalAddress tcpLocalAddress = new LocalAddress(address.toString()); server = dispatcher.createLocalServer(tcpLocalAddress); try { - final NetconfSSHServer sshServer = NetconfSSHServer.start(currentPort, tcpLocalAddress, nettyThreadgroup, getPemArray()); - sshServer.setAuthProvider(new AcceptingAuthProvider()); + final SshProxyServer sshServer = new SshProxyServer(minaTimerExecutor, nettyThreadgroup, nioExecutor); + sshServer.bind(bindingAddress, tcpLocalAddress, + new PasswordAuthenticator() { + @Override + public boolean authenticate(final String username, final String password, final ServerSession session) { + // All connections are accepted + return true; + } + }, keyPairProvider); + + sshWrappers.add(sshServer); } catch (final Exception e) { LOG.warn("Cannot start simulated device on {}, skipping", address, e); // Close local server and continue @@ -210,11 +244,10 @@ public class NetconfDeviceSimulator implements Closeable { devicesChannels.add(server.channel()); openDevices.add(currentPort - 1); - } if(openDevices.size() == params.deviceCount) { - LOG.info("All simulated devices started successfully from port {} to {}", params.startingPort, currentPort); + LOG.info("All simulated devices started successfully from port {} to {}", params.startingPort, currentPort - 1); } else { LOG.warn("Not all simulated devices started successfully. Started devices ar on ports {}", openDevices); } @@ -222,10 +255,12 @@ public class NetconfDeviceSimulator implements Closeable { return openDevices; } - private char[] getPemArray() { + private PEMGeneratorHostKeyProvider getPemGeneratorHostKeyProvider() { try { - return PEMGenerator.readOrGeneratePK(new File("PK")).toCharArray(); + final Path tempFile = Files.createTempFile("tempKeyNetconfTest", "suffix"); + return new PEMGeneratorHostKeyProvider(tempFile.toAbsolutePath().toString()); } catch (final IOException e) { + LOG.error("Unable to generate PEM key", e); throw new RuntimeException(e); } } @@ -251,8 +286,12 @@ public class NetconfDeviceSimulator implements Closeable { public void schemaSourceUnregistered(final PotentialSchemaSource potentialSchemaSource) {} }); - final FilesystemSchemaSourceCache cache = new FilesystemSchemaSourceCache<>(consumer, YangTextSchemaSource.class, params.schemasDir); - consumer.registerSchemaSourceListener(cache); + if(params.schemasDir != null) { + final FilesystemSchemaSourceCache cache = new FilesystemSchemaSourceCache<>(consumer, YangTextSchemaSource.class, params.schemasDir); + consumer.registerSchemaSourceListener(cache); + } + + addDefaultSchemas(consumer); final Map> asts = Maps.newHashMap(); for (final SourceIdentifier loadedSource : loadedSources) { @@ -269,6 +308,36 @@ public class NetconfDeviceSimulator implements Closeable { return toModuleBuilders(asts); } + private void addDefaultSchemas(final SharedSchemaRepository consumer) { + SourceIdentifier sId = new SourceIdentifier("ietf-netconf-monitoring", "2010-10-04"); + registerSource(consumer, "/META-INF/yang/ietf-netconf-monitoring.yang", sId); + + sId = new SourceIdentifier("ietf-yang-types", "2013-07-15"); + registerSource(consumer, "/META-INF/yang/ietf-yang-types@2013-07-15.yang", sId); + + sId = new SourceIdentifier("ietf-inet-types", "2010-09-24"); + registerSource(consumer, "/META-INF/yang/ietf-inet-types.yang", sId); + } + + private void registerSource(final SharedSchemaRepository consumer, final String resource, final SourceIdentifier sourceId) { + consumer.registerSchemaSource(new SchemaSourceProvider() { + @Override + public CheckedFuture getSource(final SourceIdentifier sourceIdentifier) { + return Futures.immediateCheckedFuture(new YangTextSchemaSource(sourceId) { + @Override + protected Objects.ToStringHelper addToStringAttributes(final Objects.ToStringHelper toStringHelper) { + return toStringHelper; + } + + @Override + public InputStream openStream() throws IOException { + return getClass().getResourceAsStream(resource); + } + }); + } + }, PotentialSchemaSource.create(sourceId, YangTextSchemaSource.class, PotentialSchemaSource.Costs.IMMEDIATE.getValue())); + } + private static InetSocketAddress getAddress(final int port) { try { // TODO make address configurable @@ -280,10 +349,15 @@ public class NetconfDeviceSimulator implements Closeable { @Override public void close() { + for (final SshProxyServer sshWrapper : sshWrappers) { + sshWrapper.close(); + } for (final Channel deviceCh : devicesChannels) { deviceCh.close(); } nettyThreadgroup.shutdownGracefully(); + minaTimerExecutor.shutdownNow(); + nioExecutor.shutdownNow(); // close Everything } @@ -332,11 +406,11 @@ public class NetconfDeviceSimulator implements Closeable { static class SimulatedOperationService implements NetconfOperationService { private final Set capabilities; - private static SimulatedGet sGet; + private final long currentSessionId; public SimulatedOperationService(final Set capabilities, final long currentSessionId) { this.capabilities = capabilities; - sGet = new SimulatedGet(String.valueOf(currentSessionId)); + this.currentSessionId = currentSessionId; } @Override @@ -346,7 +420,12 @@ public class NetconfDeviceSimulator implements Closeable { @Override public Set getNetconfOperations() { - return Sets.newHashSet(sGet); + final DataList storage = new DataList(); + final SimulatedGet sGet = new SimulatedGet(String.valueOf(currentSessionId), storage); + final SimulatedEditConfig sEditConfig = new SimulatedEditConfig(String.valueOf(currentSessionId), storage); + final SimulatedGetConfig sGetConfig = new SimulatedGetConfig(String.valueOf(currentSessionId), storage); + final SimulatedCommit sCommit = new SimulatedCommit(String.valueOf(currentSessionId)); + return Sets.newHashSet(sGet, sGetConfig, sEditConfig, sCommit); } @Override diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedCommit.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedCommit.java new file mode 100644 index 0000000000..db3717fab4 --- /dev/null +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedCommit.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.test.tool; + +import com.google.common.base.Optional; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; +import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +class SimulatedCommit extends AbstractConfigNetconfOperation { + + SimulatedCommit(final String netconfSessionIdForReporting) { + super(null, netconfSessionIdForReporting); + } + + @Override + protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException { + return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.absent()); + } + + @Override + protected String getOperationName() { + return XmlNetconfConstants.COMMIT; + } +} diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedEditConfig.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedEditConfig.java new file mode 100644 index 0000000000..e5d068d02c --- /dev/null +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedEditConfig.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.test.tool; + +import com.google.common.base.Optional; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; +import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation; +import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +class SimulatedEditConfig extends AbstractConfigNetconfOperation { + private static final String DELETE_EDIT_CONFIG = "delete"; + private static final String OPERATION = "operation"; + private static final String REMOVE_EDIT_CONFIG = "remove"; + private final DataList storage; + + SimulatedEditConfig(final String netconfSessionIdForReporting, final DataList storage) { + super(null, netconfSessionIdForReporting); + this.storage = storage; + } + + @Override + protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException { + final XmlElement configElementData = operationElement.getOnlyChildElement(XmlNetconfConstants.CONFIG_KEY); + + containsDelete(configElementData); + if(containsDelete(configElementData)){ + storage.resetConfigList(); + } else { + storage.setConfigList(configElementData.getChildElements()); + } + + return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.absent()); + } + + @Override + protected String getOperationName() { + return EditConfigXmlParser.EDIT_CONFIG; + } + + private boolean containsDelete(final XmlElement element) { + for (final Attr o : element.getAttributes().values()) { + if (o.getLocalName().equals(OPERATION) + && (o.getValue().equals(DELETE_EDIT_CONFIG) || o.getValue() + .equals(REMOVE_EDIT_CONFIG))) { + return true; + } + + } + + for (final XmlElement xmlElement : element.getChildElements()) { + if (containsDelete(xmlElement)) { + return true; + } + + } + + return false; + } +} diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGet.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGet.java index b1938c8332..1c24213ca7 100644 --- a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGet.java +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGet.java @@ -19,13 +19,23 @@ import org.w3c.dom.Element; class SimulatedGet extends AbstractConfigNetconfOperation { - SimulatedGet(final String netconfSessionIdForReporting) { + private final DataList storage; + + SimulatedGet(final String netconfSessionIdForReporting, final DataList storage) { super(null, netconfSessionIdForReporting); + this.storage = storage; } @Override protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException { - return XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.absent()); + final Element element = XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.absent()); + + for(final XmlElement e : storage.getConfigList()) { + final Element domElement = e.getDomElement(); + element.appendChild(element.getOwnerDocument().importNode(domElement, true)); + } + + return element; } @Override diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGetConfig.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGetConfig.java new file mode 100644 index 0000000000..cc1258eee4 --- /dev/null +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGetConfig.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.test.tool; + +import com.google.common.base.Optional; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; +import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +class SimulatedGetConfig extends AbstractConfigNetconfOperation { + + private final DataList storage; + + SimulatedGetConfig(final String netconfSessionIdForReporting, final DataList storage) { + super(null, netconfSessionIdForReporting); + this.storage = storage; + } + + @Override + protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException { + final Element element = XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.absent()); + + for(final XmlElement e : storage.getConfigList()) { + final Element domElement = e.getDomElement(); + element.appendChild(element.getOwnerDocument().importNode(domElement, true)); + } + + return element; + } + + @Override + protected String getOperationName() { + return XmlNetconfConstants.GET_CONFIG; + } +} diff --git a/opendaylight/netconf/netconf-testtool/src/main/resources/org.ops4j.pax.url.mvn.cfg b/opendaylight/netconf/netconf-testtool/src/main/resources/org.ops4j.pax.url.mvn.cfg new file mode 100644 index 0000000000..9ee45e4dc4 --- /dev/null +++ b/opendaylight/netconf/netconf-testtool/src/main/resources/org.ops4j.pax.url.mvn.cfg @@ -0,0 +1,106 @@ +################################################################################ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ + +# +# If set to true, the following property will not allow any certificate to be used +# when accessing Maven repositories through SSL +# +#org.ops4j.pax.url.mvn.certificateCheck= + +# +# Path to the local Maven settings file. +# The repositories defined in this file will be automatically added to the list +# of default repositories if the 'org.ops4j.pax.url.mvn.repositories' property +# below is not set. +# The following locations are checked for the existence of the settings.xml file +# * 1. looks for the specified url +# * 2. if not found looks for ${user.home}/.m2/settings.xml +# * 3. if not found looks for ${maven.home}/conf/settings.xml +# * 4. if not found looks for ${M2_HOME}/conf/settings.xml +# +#org.ops4j.pax.url.mvn.settings= + +# +# Path to the local Maven repository which is used to avoid downloading +# artifacts when they already exist locally. +# The value of this property will be extracted from the settings.xml file +# above, or defaulted to: +# System.getProperty( "user.home" ) + "/.m2/repository" +# +org.ops4j.pax.url.mvn.localRepository=${karaf.home}/${karaf.default.repository} + +# +# Default this to false. It's just weird to use undocumented repos +# +org.ops4j.pax.url.mvn.useFallbackRepositories=false + +# +# Uncomment if you don't wanna use the proxy settings +# from the Maven conf/settings.xml file +# +# org.ops4j.pax.url.mvn.proxySupport=false + +# +# Disable aether support by default. This ensure that the defaultRepositories +# below will be used +# +#org.ops4j.pax.url.mvn.disableAether=true + +# +# Comma separated list of repositories scanned when resolving an artifact. +# Those repositories will be checked before iterating through the +# below list of repositories and even before the local repository +# A repository url can be appended with zero or more of the following flags: +# @snapshots : the repository contains snaphots +# @noreleases : the repository does not contain any released artifacts +# +# The following property value will add the system folder as a repo. +# +#org.ops4j.pax.url.mvn.defaultRepositories= + +# Use the default local repo (e.g.~/.m2/repository) as a "remote" repo +org.ops4j.pax.url.mvn.defaultLocalRepoAsRemote=false + +# +# Comma separated list of repositories scanned when resolving an artifact. +# The default list includes the following repositories containing releases: +# http://repo1.maven.org/maven2 +# http://repository.apache.org/content/groups/snapshots-group +# http://svn.apache.org/repos/asf/servicemix/m2-repo +# http://repository.springsource.com/maven/bundles/release +# http://repository.springsource.com/maven/bundles/external +# To add repositories to the default ones, prepend '+' to the list of repositories +# to add. +# A repository url can be appended with zero or more of the following flags: +# @snapshots : the repository contains snaphots +# @noreleases : the repository does not contain any released artifacts +# @id=reponid : the id for the repository, just like in the settings.xml this is optional but recomendet +# +# The default list doesn't contain any repository containing snapshots as it can impact the artifacts resolution. +# You may want to add the following repositories containing snapshots: +# http://repository.apache.org/content/groups/snapshots-group@id=apache@snapshots@noreleases +# http://oss.sonatype.org/content/repositories/snapshots@id=sonatype.snapshots.deploy@snapshots@norelease +# http://oss.sonatype.org/content/repositories/ops4j-snapshots@id=ops4j.sonatype.snapshots.deploy@snapshots@noreleases +# +org.ops4j.pax.url.mvn.repositories= \ + file:${karaf.home}/${karaf.default.repository}@id=system.repository, \ + file:${karaf.data}/kar@id=kar.repository@multi, \ + http://repo1.maven.org/maven2@id=central, \ + http://repository.springsource.com/maven/bundles/release@id=spring.ebr.release, \ + http://repository.springsource.com/maven/bundles/external@id=spring.ebr.external diff --git a/opendaylight/netconf/netconf-usermanager/pom.xml b/opendaylight/netconf/netconf-usermanager/pom.xml index f8c3e5a504..44e6c61472 100644 --- a/opendaylight/netconf/netconf-usermanager/pom.xml +++ b/opendaylight/netconf/netconf-usermanager/pom.xml @@ -12,7 +12,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT ../ netconf-usermanager diff --git a/opendaylight/netconf/netconf-usermanager/src/main/java/org/opendaylight/controller/netconf/auth/usermanager/AuthProviderImpl.java b/opendaylight/netconf/netconf-usermanager/src/main/java/org/opendaylight/controller/netconf/auth/usermanager/AuthProviderImpl.java index d314c31b4f..da5e2090ff 100644 --- a/opendaylight/netconf/netconf-usermanager/src/main/java/org/opendaylight/controller/netconf/auth/usermanager/AuthProviderImpl.java +++ b/opendaylight/netconf/netconf-usermanager/src/main/java/org/opendaylight/controller/netconf/auth/usermanager/AuthProviderImpl.java @@ -71,7 +71,7 @@ public class AuthProviderImpl implements AuthProvider { } @VisibleForTesting - void setNullableUserManager(final IUserManager nullableUserManager) { + synchronized void setNullableUserManager(final IUserManager nullableUserManager) { this.nullableUserManager = nullableUserManager; } } diff --git a/opendaylight/netconf/netconf-util/pom.xml b/opendaylight/netconf/netconf-util/pom.xml index bed58beb0f..de9b2a0a06 100644 --- a/opendaylight/netconf/netconf-util/pom.xml +++ b/opendaylight/netconf/netconf-util/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT netconf-util bundle diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java index 25e0f79265..b6f5854aa3 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java @@ -116,8 +116,8 @@ public abstract class AbstractNetconfOperation implements NetconfOperation { rpcReply.appendChild(responseNS); } - for (String attrName : attributes.keySet()) { - rpcReply.setAttributeNode((Attr) document.importNode(attributes.get(attrName), true)); + for (Attr attribute : attributes.values()) { + rpcReply.setAttributeNode((Attr) document.importNode(attribute, true)); } document.appendChild(rpcReply); return document; diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtil.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtil.java index 3e8040ad8a..c532b7f9a6 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtil.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtil.java @@ -10,7 +10,9 @@ package org.opendaylight.controller.netconf.util.messages; import com.google.common.base.Function; import com.google.common.collect.Collections2; - +import java.util.Collection; +import java.util.List; +import javax.annotation.Nonnull; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; @@ -19,11 +21,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; -import javax.annotation.Nullable; - -import java.util.Collection; -import java.util.List; - public final class NetconfMessageUtil { private static final Logger logger = LoggerFactory.getLogger(NetconfMessageUtil.class); @@ -67,9 +64,8 @@ public final class NetconfMessageUtil { List caps = capabilitiesElement.getChildElements(XmlNetconfConstants.CAPABILITY); return Collections2.transform(caps, new Function() { - @Nullable @Override - public String apply(@Nullable XmlElement input) { + public String apply(@Nonnull XmlElement input) { // Trim possible leading/tailing whitespace try { return input.getTextContent().trim(); diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtil.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtil.java index 333fea3493..c77e0d7da2 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtil.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtil.java @@ -53,29 +53,6 @@ public final class NetconfConfigUtil { } } - /** - * Get extracted address or default. - * - * @throws java.lang.IllegalStateException if neither address is present. - */ - private static InetSocketAddress getNetconfAddress(final InetSocketAddress defaultAddress, Optional extractedAddress, InfixProp infix) { - InetSocketAddress inetSocketAddress; - - if (extractedAddress.isPresent() == false) { - logger.debug("Netconf {} address not found, falling back to default {}", infix, defaultAddress); - - if (defaultAddress == null) { - logger.warn("Netconf {} address not found, default address not provided", infix); - throw new IllegalStateException("Netconf " + infix + " address not found, default address not provided"); - } - inetSocketAddress = defaultAddress; - } else { - inetSocketAddress = extractedAddress.get(); - } - - return inetSocketAddress; - } - public static String getPrivateKeyPath(final BundleContext context) { return getPropertyValue(context, getPrivateKeyKey()); } diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java index 4e3a66b7ec..3c63204881 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java @@ -20,7 +20,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.annotation.Nullable; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException; import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException; @@ -38,6 +37,8 @@ import org.xml.sax.SAXException; public final class XmlElement { + public static final String DEFAULT_NAMESPACE_PREFIX = ""; + private final Element element; private static final Logger logger = LoggerFactory.getLogger(XmlElement.class); @@ -73,16 +74,16 @@ public final class XmlElement { return xmlElement; } - private static Map extractNamespaces(Element typeElement) throws NetconfDocumentedException { + private Map extractNamespaces() throws NetconfDocumentedException { Map namespaces = new HashMap<>(); - NamedNodeMap attributes = typeElement.getAttributes(); + NamedNodeMap attributes = element.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); String attribKey = attribute.getNodeName(); if (attribKey.startsWith(XmlUtil.XMLNS_ATTRIBUTE_KEY)) { String prefix; if (attribKey.equals(XmlUtil.XMLNS_ATTRIBUTE_KEY)) { - prefix = ""; + prefix = DEFAULT_NAMESPACE_PREFIX; } else { if (!attribKey.startsWith(XmlUtil.XMLNS_ATTRIBUTE_KEY + ":")){ throw new NetconfDocumentedException("Attribute doesn't start with :", @@ -95,6 +96,15 @@ public final class XmlElement { namespaces.put(prefix, attribute.getNodeValue()); } } + + // namespace does not have to be defined on this element but inherited + if(!namespaces.containsKey(DEFAULT_NAMESPACE_PREFIX)) { + Optional namespaceOptionally = getNamespaceOptionally(); + if(namespaceOptionally.isPresent()) { + namespaces.put(DEFAULT_NAMESPACE_PREFIX, namespaceOptionally.get()); + } + } + return namespaces; } @@ -133,7 +143,7 @@ public final class XmlElement { } public String getName() { - if (element.getLocalName()!=null && !element.getLocalName().equals("")){ + if (element.getLocalName()!=null && !element.getLocalName().equals(DEFAULT_NAMESPACE_PREFIX)){ return element.getLocalName(); } return element.getTagName(); @@ -204,7 +214,7 @@ public final class XmlElement { return Lists.newArrayList(Collections2.filter(getChildElementsWithinNamespace(namespace), new Predicate() { @Override - public boolean apply(@Nullable XmlElement xmlElement) { + public boolean apply(XmlElement xmlElement) { return xmlElement.getName().equals(childName); } })); @@ -298,7 +308,7 @@ public final class XmlElement { List children = getChildElementsWithinNamespace(namespace); children = Lists.newArrayList(Collections2.filter(children, new Predicate() { @Override - public boolean apply(@Nullable XmlElement xmlElement) { + public boolean apply(XmlElement xmlElement) { return xmlElement.getName().equals(childName); } })); @@ -328,7 +338,7 @@ public final class XmlElement { public String getTextContent() throws NetconfDocumentedException { NodeList childNodes = element.getChildNodes(); if (childNodes.getLength() == 0) { - return ""; + return DEFAULT_NAMESPACE_PREFIX; } for(int i = 0; i < childNodes.getLength(); i++) { Node textChild = childNodes.item(i); @@ -357,7 +367,7 @@ public final class XmlElement { public String getNamespaceAttribute() throws MissingNameSpaceException { String attribute = element.getAttribute(XmlUtil.XMLNS_ATTRIBUTE_KEY); - if (attribute == null || attribute.equals("")){ + if (attribute == null || attribute.equals(DEFAULT_NAMESPACE_PREFIX)){ throw new MissingNameSpaceException(String.format("Element %s must specify namespace", toString()), NetconfDocumentedException.ErrorType.application, @@ -416,14 +426,14 @@ public final class XmlElement { * is found value will be null. */ public Map.Entry findNamespaceOfTextContent() throws NetconfDocumentedException { - Map namespaces = extractNamespaces(element); + Map namespaces = extractNamespaces(); String textContent = getTextContent(); int indexOfColon = textContent.indexOf(':'); String prefix; if (indexOfColon > -1) { prefix = textContent.substring(0, indexOfColon); } else { - prefix = ""; + prefix = DEFAULT_NAMESPACE_PREFIX; } if (!namespaces.containsKey(prefix)) { throw new IllegalArgumentException("Cannot find namespace for " + XmlUtil.toString(element) + ". Prefix from content is " @@ -436,7 +446,7 @@ public final class XmlElement { List children = getChildElementsWithinNamespace(getNamespace()); return Lists.newArrayList(Collections2.filter(children, new Predicate() { @Override - public boolean apply(@Nullable XmlElement xmlElement) { + public boolean apply(XmlElement xmlElement) { return xmlElement.getName().equals(childName); } })); diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/mapping/AbstractLastNetconfOperationTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/mapping/AbstractLastNetconfOperationTest.java new file mode 100644 index 0000000000..62633dd3f2 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/mapping/AbstractLastNetconfOperationTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.util.mapping; + +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +public class AbstractLastNetconfOperationTest { + class LastNetconfOperationImplTest extends AbstractLastNetconfOperation { + + boolean handleWithNoSubsequentOperationsRun; + + protected LastNetconfOperationImplTest(String netconfSessionIdForReporting) { + super(netconfSessionIdForReporting); + handleWithNoSubsequentOperationsRun = false; + } + + @Override + protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws NetconfDocumentedException { + handleWithNoSubsequentOperationsRun = true; + return null; + } + + @Override + protected String getOperationName() { + return ""; + } + } + + LastNetconfOperationImplTest netconfOperation; + + @Before + public void setUp() throws Exception { + netconfOperation = new LastNetconfOperationImplTest(""); + } + + @Test + public void testNetconfOperation() throws Exception { + netconfOperation.handleWithNoSubsequentOperations(null, null); + assertTrue(netconfOperation.handleWithNoSubsequentOperationsRun); + assertEquals(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY, netconfOperation.getHandlingPriority()); + } + + @Test(expected = NetconfDocumentedException.class) + public void testHandle() throws Exception { + NetconfOperationChainedExecution operation = mock(NetconfOperationChainedExecution.class); + doReturn("").when(operation).toString(); + + doReturn(false).when(operation).isExecutionTermination(); + netconfOperation.handle(null, null, operation); + } +} diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperationTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperationTest.java new file mode 100644 index 0000000000..ea4a6e61f2 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperationTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.util.mapping; + +import java.io.IOException; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution; +import org.opendaylight.controller.netconf.util.test.XmlFileLoader; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +public class AbstractNetconfOperationTest { + + class NetconfOperationImpl extends AbstractNetconfOperation { + + public boolean handleRun; + + protected NetconfOperationImpl(String netconfSessionIdForReporting) { + super(netconfSessionIdForReporting); + this.handleRun = false; + } + + @Override + protected String getOperationName() { + return null; + } + + @Override + protected Element handle(Document document, XmlElement message, NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException { + this.handleRun = true; + try { + return XmlUtil.readXmlToElement(""); + } catch (SAXException | IOException e) { + throw new RuntimeException(e); + } + } + } + + private NetconfOperationImpl netconfOperation; + private NetconfOperationChainedExecution operation; + + @Before + public void setUp() throws Exception { + netconfOperation = new NetconfOperationImpl("str"); + operation = mock(NetconfOperationChainedExecution.class); + } + + @Test + public void testAbstractNetconfOperation() throws Exception { + Document helloMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/edit_config.xml"); + assertEquals(netconfOperation.getNetconfSessionIdForReporting(), "str"); + assertNotNull(netconfOperation.canHandle(helloMessage)); + assertEquals(netconfOperation.getHandlingPriority(), HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY); + + netconfOperation.handle(helloMessage, operation); + assertTrue(netconfOperation.handleRun); + } +} diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/mapping/AbstractSingletonNetconfOperationTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/mapping/AbstractSingletonNetconfOperationTest.java new file mode 100644 index 0000000000..d1310de3e2 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/mapping/AbstractSingletonNetconfOperationTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.util.mapping; + +import org.junit.Test; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import static org.junit.Assert.assertEquals; + +public class AbstractSingletonNetconfOperationTest { + class SingletonNCOperationImpl extends AbstractSingletonNetconfOperation { + + protected SingletonNCOperationImpl(String netconfSessionIdForReporting) { + super(netconfSessionIdForReporting); + } + + @Override + protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws NetconfDocumentedException { + return null; + } + + @Override + protected String getOperationName() { + return null; + } + } + + @Test + public void testAbstractSingletonNetconfOperation() throws Exception { + SingletonNCOperationImpl operation = new SingletonNCOperationImpl(""); + assertEquals(operation.getHandlingPriority(), HandlingPriority.HANDLE_WITH_MAX_PRIORITY); + } +} diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageAdditionalHeaderTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageAdditionalHeaderTest.java new file mode 100644 index 0000000000..95c91243af --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageAdditionalHeaderTest.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.util.messages; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class NetconfHelloMessageAdditionalHeaderTest { + + + private String customHeader = "[user;1.1.1.1:40;tcp;client;]"; + private NetconfHelloMessageAdditionalHeader header; + + @Before + public void setUp() throws Exception { + header = new NetconfHelloMessageAdditionalHeader("user", "1.1.1.1", "40", "tcp", "client"); + } + + @Test + public void testGetters() throws Exception { + assertEquals(header.getAddress(), "1.1.1.1"); + assertEquals(header.getUserName(), "user"); + assertEquals(header.getPort(), "40"); + assertEquals(header.getTransport(), "tcp"); + assertEquals(header.getSessionIdentifier(), "client"); + } + + @Test + public void testStaticConstructor() throws Exception { + NetconfHelloMessageAdditionalHeader h = NetconfHelloMessageAdditionalHeader.fromString(customHeader); + assertEquals(h.toString(), header.toString()); + assertEquals(h.toFormattedString(), header.toFormattedString()); + } +} diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageTest.java new file mode 100644 index 0000000000..c39ac8eb10 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.util.messages; + + +import com.google.common.base.Optional; +import java.util.Set; +import org.junit.Before; +import org.junit.Test; +import org.mockito.internal.util.collections.Sets; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class NetconfHelloMessageTest { + + Set caps; + + @Before + public void setUp() throws Exception { + caps = Sets.newSet("cap1"); + } + + @Test + public void testConstructor() throws Exception { + NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("name","host","1","transp","id"); + NetconfHelloMessage message = NetconfHelloMessage.createClientHello(caps, Optional.of(additionalHeader)); + assertTrue(message.isHelloMessage(message)); + assertEquals(Optional.of(additionalHeader), message.getAdditionalHeader()); + + NetconfHelloMessage serverMessage = NetconfHelloMessage.createServerHello(caps, 100L); + assertTrue(serverMessage.isHelloMessage(serverMessage)); + } +} diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageHeaderTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageHeaderTest.java new file mode 100644 index 0000000000..cca89aed59 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageHeaderTest.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.util.messages; + +import com.google.common.base.Charsets; +import java.util.Arrays; +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +public class NetconfMessageHeaderTest { + @Test + public void testGet() throws Exception { + NetconfMessageHeader header = new NetconfMessageHeader(10); + assertEquals(header.getLength(), 10); + + byte[] expectedValue = "\n#10\n".getBytes(Charsets.US_ASCII); + assertArrayEquals(expectedValue, header.toBytes()); + } +} diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtilTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtilTest.java new file mode 100644 index 0000000000..2af34e957e --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtilTest.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.util.messages; + +import java.util.Collection; +import org.junit.Test; +import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.controller.netconf.util.test.XmlFileLoader; +import org.w3c.dom.Document; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class NetconfMessageUtilTest { + @Test + public void testNetconfMessageUtil() throws Exception { + Document okMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/rpc-reply_ok.xml"); + assertTrue(NetconfMessageUtil.isOKMessage(new NetconfMessage(okMessage))); + assertFalse(NetconfMessageUtil.isErrorMessage(new NetconfMessage(okMessage))); + + Document errorMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/communicationError/testClientSendsRpcReply_expectedResponse.xml"); + assertTrue(NetconfMessageUtil.isErrorMessage(new NetconfMessage(errorMessage))); + assertFalse(NetconfMessageUtil.isOKMessage(new NetconfMessage(errorMessage))); + + Document helloMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/client_hello.xml"); + Collection caps = NetconfMessageUtil.extractCapabilitiesFromHello(new NetconfMessage(helloMessage).getDocument()); + assertTrue(caps.contains("urn:ietf:params:netconf:base:1.0")); + assertTrue(caps.contains("urn:ietf:params:netconf:base:1.1")); + } +} diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/SendErrorExceptionUtilTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/SendErrorExceptionUtilTest.java new file mode 100644 index 0000000000..c8d562cb9c --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/SendErrorExceptionUtilTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.util.messages; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.util.concurrent.GenericFutureListener; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.controller.netconf.api.NetconfSession; +import org.opendaylight.controller.netconf.util.test.XmlFileLoader; +import org.w3c.dom.Document; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; + +public class SendErrorExceptionUtilTest { + + NetconfSession netconfSession; + ChannelFuture channelFuture; + Channel channel; + private NetconfDocumentedException exception; + + @Before + public void setUp() throws Exception { + netconfSession = mock(NetconfSession.class); + channelFuture = mock(ChannelFuture.class); + channel = mock(Channel.class); + doReturn(channelFuture).when(netconfSession).sendMessage(any(NetconfMessage.class)); + doReturn(channelFuture).when(channelFuture).addListener(any(GenericFutureListener.class)); + doReturn(channelFuture).when(channel).writeAndFlush(any(NetconfMessage.class)); + exception = new NetconfDocumentedException("err"); + } + + @Test + public void testSendErrorMessage1() throws Exception { + SendErrorExceptionUtil.sendErrorMessage(netconfSession, exception); + verify(channelFuture, times(1)).addListener(any(GenericFutureListener.class)); + verify(netconfSession, times(1)).sendMessage(any(NetconfMessage.class)); + } + + @Test + public void testSendErrorMessage2() throws Exception { + SendErrorExceptionUtil.sendErrorMessage(channel, exception); + verify(channelFuture, times(1)).addListener(any(GenericFutureListener.class)); + } + + @Test + public void testSendErrorMessage3() throws Exception { + Document helloMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/rpc.xml"); + SendErrorExceptionUtil.sendErrorMessage(netconfSession, exception, new NetconfMessage(helloMessage)); + verify(channelFuture, times(1)).addListener(any(GenericFutureListener.class)); + } +} diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtilTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtilTest.java new file mode 100644 index 0000000000..741d0d2452 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtilTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.util.osgi; + +import com.google.common.base.Optional; +import io.netty.channel.local.LocalAddress; +import java.net.InetSocketAddress; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.netconf.util.NetconfUtil; +import org.osgi.framework.BundleContext; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +public class NetconfConfigUtilTest { + + private BundleContext bundleContext; + + @Before + public void setUp() throws Exception { + bundleContext = mock(BundleContext.class); + } + + @Test + public void testNetconfConfigUtil() throws Exception { + assertEquals(NetconfConfigUtil.getNetconfLocalAddress(), new LocalAddress("netconf")); + + doReturn("").when(bundleContext).getProperty("netconf.connectionTimeoutMillis"); + assertEquals(NetconfConfigUtil.extractTimeoutMillis(bundleContext), 5000); + + doReturn("a").when(bundleContext).getProperty("netconf.connectionTimeoutMillis"); + assertEquals(NetconfConfigUtil.extractTimeoutMillis(bundleContext), 5000); + } + + @Test + public void testgetPrivateKeyKey() throws Exception { + assertEquals(NetconfConfigUtil.getPrivateKeyKey(), "netconf.ssh.pk.path"); + } + + @Test + public void testgetNetconfServerAddressKey() throws Exception { + NetconfConfigUtil.InfixProp prop = NetconfConfigUtil.InfixProp.tcp; + assertEquals(NetconfConfigUtil.getNetconfServerAddressKey(prop), "netconf.tcp.address"); + } + + @Test + public void testExtractNetconfServerAddress() throws Exception { + NetconfConfigUtil.InfixProp prop = NetconfConfigUtil.InfixProp.tcp; + doReturn("").when(bundleContext).getProperty(anyString()); + assertEquals(NetconfConfigUtil.extractNetconfServerAddress(bundleContext, prop), Optional.absent()); + } + + @Test + public void testExtractNetconfServerAddress2() throws Exception { + NetconfConfigUtil.InfixProp prop = NetconfConfigUtil.InfixProp.tcp; + doReturn("1.1.1.1").when(bundleContext).getProperty("netconf.tcp.address"); + doReturn("20").when(bundleContext).getProperty("netconf.tcp.port"); + Optional inetSocketAddressOptional = NetconfConfigUtil.extractNetconfServerAddress(bundleContext, prop); + assertTrue(inetSocketAddressOptional.isPresent()); + assertEquals(inetSocketAddressOptional.get(), new InetSocketAddress("1.1.1.1", 20)); + } + + @Test + public void testGetPrivateKeyPath() throws Exception { + doReturn("path").when(bundleContext).getProperty("netconf.ssh.pk.path"); + assertEquals(NetconfConfigUtil.getPrivateKeyPath(bundleContext), "path"); + } + + @Test(expected = IllegalStateException.class) + public void testGetPrivateKeyPath2() throws Exception { + doReturn(null).when(bundleContext).getProperty("netconf.ssh.pk.path"); + assertEquals(NetconfConfigUtil.getPrivateKeyPath(bundleContext), "path"); + } +} diff --git a/opendaylight/netconf/pom.xml b/opendaylight/netconf/pom.xml index 8abf67ec8c..b392c5b672 100644 --- a/opendaylight/netconf/pom.xml +++ b/opendaylight/netconf/pom.xml @@ -5,12 +5,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../commons/opendaylight netconf-subsystem - 0.2.5-SNAPSHOT + 0.3.0-SNAPSHOT pom ${project.artifactId} @@ -37,6 +37,9 @@ netconf-connector-config netconf-auth netconf-usermanager + netconf-testtool + + netconf-artifacts @@ -152,15 +155,5 @@ netconf-it - - - testtool - - false - - - netconf-testtool - - diff --git a/opendaylight/networkconfiguration/neutron/implementation/pom.xml b/opendaylight/networkconfiguration/neutron/implementation/pom.xml index c8f1dd270d..a9061d57d1 100644 --- a/opendaylight/networkconfiguration/neutron/implementation/pom.xml +++ b/opendaylight/networkconfiguration/neutron/implementation/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../../commons/opendaylight networkconfig.neutron.implementation - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle 1.26.2 diff --git a/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronPortInterface.java b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronPortInterface.java index 6dc0e46b61..3294474b49 100644 --- a/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronPortInterface.java +++ b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronPortInterface.java @@ -233,6 +233,9 @@ public class NeutronPortInterface implements INeutronPortCRUD, IConfigurationCon portDB.putIfAbsent(input.getID(), input); // if there are no fixed IPs, allocate one for each subnet in the network INeutronSubnetCRUD systemCRUD = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this); + if (input.getFixedIPs() == null){ + input.setFixedIPs(new ArrayList()); + } if (input.getFixedIPs().size() == 0) { List list = input.getFixedIPs(); Iterator subnetIterator = systemCRUD.getAllSubnets().iterator(); diff --git a/opendaylight/networkconfiguration/neutron/pom.xml b/opendaylight/networkconfiguration/neutron/pom.xml index 998dd4488c..75ab2816cc 100644 --- a/opendaylight/networkconfiguration/neutron/pom.xml +++ b/opendaylight/networkconfiguration/neutron/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight networkconfig.neutron - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle 1.26.2 diff --git a/opendaylight/northbound/archetype-app-northbound/pom.xml b/opendaylight/northbound/archetype-app-northbound/pom.xml index 558bf41915..67c111f94d 100644 --- a/opendaylight/northbound/archetype-app-northbound/pom.xml +++ b/opendaylight/northbound/archetype-app-northbound/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller app-northbound - 0.0.1-SNAPSHOT + 0.1.0-SNAPSHOT maven-archetype app-northbound diff --git a/opendaylight/northbound/archetype-app-northbound/src/main/resources/archetype-resources/pom.xml b/opendaylight/northbound/archetype-app-northbound/src/main/resources/archetype-resources/pom.xml index da1bd41192..adb0c98705 100644 --- a/opendaylight/northbound/archetype-app-northbound/src/main/resources/archetype-resources/pom.xml +++ b/opendaylight/northbound/archetype-app-northbound/src/main/resources/archetype-resources/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.1-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight diff --git a/opendaylight/northbound/bundlescanner/api/pom.xml b/opendaylight/northbound/bundlescanner/api/pom.xml index ee83c93580..78bfd38579 100644 --- a/opendaylight/northbound/bundlescanner/api/pom.xml +++ b/opendaylight/northbound/bundlescanner/api/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../../commons/opendaylight bundlescanner - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/bundlescanner/implementation/pom.xml b/opendaylight/northbound/bundlescanner/implementation/pom.xml index c06f8b4215..5694b2adcf 100644 --- a/opendaylight/northbound/bundlescanner/implementation/pom.xml +++ b/opendaylight/northbound/bundlescanner/implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../../commons/opendaylight bundlescanner.implementation - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/commons/pom.xml b/opendaylight/northbound/commons/pom.xml index cbc1f0c328..9d229e4e70 100644 --- a/opendaylight/northbound/commons/pom.xml +++ b/opendaylight/northbound/commons/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight commons.northbound - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/connectionmanager/pom.xml b/opendaylight/northbound/connectionmanager/pom.xml index ad315ac008..893dcd14f3 100644 --- a/opendaylight/northbound/connectionmanager/pom.xml +++ b/opendaylight/northbound/connectionmanager/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight connectionmanager.northbound - 0.1.2-SNAPSHOT + 0.2.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/containermanager/pom.xml b/opendaylight/northbound/containermanager/pom.xml index 2e6bb7d40c..74fd115dee 100644 --- a/opendaylight/northbound/containermanager/pom.xml +++ b/opendaylight/northbound/containermanager/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight containermanager.northbound - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/controllermanager/pom.xml b/opendaylight/northbound/controllermanager/pom.xml index 89d2b99cad..33f9a06246 100644 --- a/opendaylight/northbound/controllermanager/pom.xml +++ b/opendaylight/northbound/controllermanager/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight controllermanager.northbound - 0.0.2-SNAPSHOT + 0.1.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/flowprogrammer/pom.xml b/opendaylight/northbound/flowprogrammer/pom.xml index 43797f5c65..083a7a2cb8 100644 --- a/opendaylight/northbound/flowprogrammer/pom.xml +++ b/opendaylight/northbound/flowprogrammer/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight flowprogrammer.northbound - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/hosttracker/pom.xml b/opendaylight/northbound/hosttracker/pom.xml index c8415f8b4f..3cd3f36be0 100644 --- a/opendaylight/northbound/hosttracker/pom.xml +++ b/opendaylight/northbound/hosttracker/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight hosttracker.northbound - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/httpservice-bridge/pom.xml b/opendaylight/northbound/httpservice-bridge/pom.xml index c7b9cfc9a0..deeabd9d00 100644 --- a/opendaylight/northbound/httpservice-bridge/pom.xml +++ b/opendaylight/northbound/httpservice-bridge/pom.xml @@ -5,12 +5,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight httpservice-bridge - 0.0.2-SNAPSHOT + 0.1.0-SNAPSHOT bundle HttpService bridge web application diff --git a/opendaylight/northbound/integrationtest/pom.xml b/opendaylight/northbound/integrationtest/pom.xml index 6f0d897f99..df0d1139af 100644 --- a/opendaylight/northbound/integrationtest/pom.xml +++ b/opendaylight/northbound/integrationtest/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.integrationtest - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT ../../commons/integrationtest northbound.integrationtest - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT ch.qos.logback diff --git a/opendaylight/northbound/java-client/pom.xml b/opendaylight/northbound/java-client/pom.xml index ae8924feb6..a4bcde461e 100644 --- a/opendaylight/northbound/java-client/pom.xml +++ b/opendaylight/northbound/java-client/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight northbound.client - 0.0.1-SNAPSHOT + 0.1.0-SNAPSHOT pom diff --git a/opendaylight/northbound/jolokia/pom.xml b/opendaylight/northbound/jolokia/pom.xml index 62af41ab46..07e3a7d36b 100644 --- a/opendaylight/northbound/jolokia/pom.xml +++ b/opendaylight/northbound/jolokia/pom.xml @@ -5,12 +5,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight jolokia-bridge - 0.0.2-SNAPSHOT + 0.1.0-SNAPSHOT bundle Jolokia bridge web application diff --git a/opendaylight/northbound/networkconfiguration/bridgedomain/pom.xml b/opendaylight/northbound/networkconfiguration/bridgedomain/pom.xml index f112978080..8b552ba25a 100644 --- a/opendaylight/northbound/networkconfiguration/bridgedomain/pom.xml +++ b/opendaylight/northbound/networkconfiguration/bridgedomain/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../../commons/opendaylight networkconfig.bridgedomain.northbound - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/networkconfiguration/neutron/pom.xml b/opendaylight/northbound/networkconfiguration/neutron/pom.xml index 728316afab..8111e69c19 100644 --- a/opendaylight/northbound/networkconfiguration/neutron/pom.xml +++ b/opendaylight/northbound/networkconfiguration/neutron/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../../commons/opendaylight networkconfig.neutron.northbound - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle @@ -66,6 +66,7 @@ org.eclipse.persistence.jaxb.rs, com.sun.jersey.spi.container.servlet, javax.ws.rs, + javax.ws.rs.ext, javax.ws.rs.core, javax.xml.bind.annotation, javax.xml.bind, diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolNorthbound.java index 7802dbb906..5235030b4f 100644 --- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolNorthbound.java +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolNorthbound.java @@ -15,7 +15,6 @@ import org.codehaus.enunciate.jaxrs.ResponseCode; import org.codehaus.enunciate.jaxrs.StatusCodes; import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolAware; import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolCRUD; -import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolMemberCRUD; import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces; import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPool; import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPoolMember; @@ -62,8 +61,7 @@ import java.util.List; /** * For now, the LB pool member data is maintained with the INeutronLoadBalancerPoolCRUD, - * although there may be an overlap with INeutronLoadBalancerPoolMemberCRUD's cache. - * TODO: Consolidate and maintain a single copy + * and not duplicated within the INeutronLoadBalancerPoolMemberCRUD's cache. */ @Path("/pools") @@ -393,21 +391,6 @@ public class NeutronLoadBalancerPoolNorthbound { service.neutronLoadBalancerPoolDeleted(singleton); } } - - /* - * remove corresponding members from the member cache too - */ - INeutronLoadBalancerPoolMemberCRUD loadBalancerPoolMemberInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolMemberCRUD(this); - if (loadBalancerPoolMemberInterface != null) { - List allLoadBalancerPoolMembers = new - ArrayList(loadBalancerPoolMemberInterface.getAllNeutronLoadBalancerPoolMembers()); - Iterator i = allLoadBalancerPoolMembers.iterator(); - while (i.hasNext()) { - NeutronLoadBalancerPoolMember member = i.next(); - if (member.getPoolID() == loadBalancerPoolUUID) - loadBalancerPoolMemberInterface.removeNeutronLoadBalancerPoolMember(member.getPoolMemberID()); - } - } return Response.status(204).build(); } } diff --git a/opendaylight/northbound/staticrouting/pom.xml b/opendaylight/northbound/staticrouting/pom.xml index 83f8191e02..761f1f08e9 100644 --- a/opendaylight/northbound/staticrouting/pom.xml +++ b/opendaylight/northbound/staticrouting/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight forwarding.staticrouting.northbound - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/statistics/pom.xml b/opendaylight/northbound/statistics/pom.xml index 7e2919bc44..4ae3d8746c 100644 --- a/opendaylight/northbound/statistics/pom.xml +++ b/opendaylight/northbound/statistics/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight statistics.northbound - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/subnets/pom.xml b/opendaylight/northbound/subnets/pom.xml index 630221fcc2..1efb974b51 100644 --- a/opendaylight/northbound/subnets/pom.xml +++ b/opendaylight/northbound/subnets/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight subnets.northbound - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/swagger-ui/pom.xml b/opendaylight/northbound/swagger-ui/pom.xml index 18eaed98ec..bbb80a7811 100644 --- a/opendaylight/northbound/swagger-ui/pom.xml +++ b/opendaylight/northbound/swagger-ui/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight swagger-ui - 0.0.1-SNAPSHOT + 0.1.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/switchmanager/pom.xml b/opendaylight/northbound/switchmanager/pom.xml index 614ec88476..1b876f4420 100644 --- a/opendaylight/northbound/switchmanager/pom.xml +++ b/opendaylight/northbound/switchmanager/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight switchmanager.northbound - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/topology/pom.xml b/opendaylight/northbound/topology/pom.xml index 3f1a770110..270148420c 100644 --- a/opendaylight/northbound/topology/pom.xml +++ b/opendaylight/northbound/topology/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight topology.northbound - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/northbound/usermanager/pom.xml b/opendaylight/northbound/usermanager/pom.xml index c7ab2fa712..fe32bcf5d3 100644 --- a/opendaylight/northbound/usermanager/pom.xml +++ b/opendaylight/northbound/usermanager/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight usermanager.northbound - 0.0.2-SNAPSHOT + 0.1.0-SNAPSHOT bundle diff --git a/opendaylight/northboundtest/unit_test_suite/pom.xml b/opendaylight/northboundtest/unit_test_suite/pom.xml index 5a0f5f3254..11c885db30 100644 --- a/opendaylight/northboundtest/unit_test_suite/pom.xml +++ b/opendaylight/northboundtest/unit_test_suite/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.0-SNAPSHOT + 1.5.0-SNAPSHOT ../../../opendaylight/commons/opendaylight @@ -16,7 +16,7 @@ org.opendaylight.controller northboundtest - 0.4.0-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/protocol_plugins/openflow/pom.xml b/opendaylight/protocol_plugins/openflow/pom.xml index a8fceec2bf..16fadee1cc 100644 --- a/opendaylight/protocol_plugins/openflow/pom.xml +++ b/opendaylight/protocol_plugins/openflow/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight protocol_plugins.openflow - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/protocol_plugins/stub/pom.xml b/opendaylight/protocol_plugins/stub/pom.xml index 540c9afb2c..4c7b8965fb 100644 --- a/opendaylight/protocol_plugins/stub/pom.xml +++ b/opendaylight/protocol_plugins/stub/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight protocol_plugins.stub - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/routing/dijkstra_implementation/pom.xml b/opendaylight/routing/dijkstra_implementation/pom.xml index b691308e97..b1b68b8cb7 100644 --- a/opendaylight/routing/dijkstra_implementation/pom.xml +++ b/opendaylight/routing/dijkstra_implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight routing.dijkstra_implementation - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/sal/api/pom.xml b/opendaylight/sal/api/pom.xml index 3ee239a0f4..50ac61fccb 100644 --- a/opendaylight/sal/api/pom.xml +++ b/opendaylight/sal/api/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight sal - 0.8.1-SNAPSHOT + 0.9.0-SNAPSHOT bundle diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/action/Action.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/action/Action.java index 1ff7ea1444..981b175e19 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/action/Action.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/action/Action.java @@ -8,6 +8,15 @@ package org.opendaylight.controller.sal.action; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentHashMap; + +import org.opendaylight.controller.sal.core.Property; + import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; @@ -32,6 +41,7 @@ public abstract class Action implements Serializable { @XmlElement protected ActionType type; private transient boolean isValid = true; + private ConcurrentMap props; /* Dummy constructor for JAXB */ public Action() { @@ -83,6 +93,81 @@ public abstract class Action implements Serializable { } } + /** + * Gets the list of metadata currently registered with this match + * + * @return List of metadata currently registered + */ + public List getMetadatas() { + if (this.props != null) { + // Return all the values in the map + Collection res = this.props.values(); + if (res == null) { + return Collections.emptyList(); + } + return new ArrayList(res); + } + return Collections.emptyList(); + } + + /** + * Gets the metadata registered with a name if present + * + * @param name the name of the property to be extracted + * + * @return List of metadata currently registered + */ + public Property getMetadata(String name) { + if (name == null) { + return null; + } + if (this.props != null) { + // Return the Property associated to the name + return this.props.get(name); + } + return null; + } + + /** + * Sets the metadata associated to a name. If the name or prop is NULL, + * an exception NullPointerException will be raised. + * + * @param name the name of the property to be set + * @param prop, property to be set + */ + public void setMetadata(String name, Property prop) { + if (this.props == null) { + props = new ConcurrentHashMap(); + } + + if (this.props != null) { + this.props.put(name, prop); + } + } + + /** + * Remove the metadata associated to a name. If the name is NULL, + * nothing will be removed. + * + * @param name the name of the property to be set + * @param prop, property to be set + * + * @return List of metadata currently registered + */ + public void removeMetadata(String name) { + if (this.props == null) { + return; + } + + if (this.props != null) { + this.props.remove(name); + } + // It's intentional to keep the this.props still allocated + // till the parent data structure will be alive, so to avoid + // unnecessary allocation/deallocation, even if it's holding + // nothing + } + /** * Returns the type of this action * diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/Match.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/Match.java index 910695c1e9..a00c3dcb34 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/Match.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/Match.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -15,18 +14,22 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentHashMap; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; +import org.opendaylight.controller.sal.core.Property; import org.opendaylight.controller.sal.utils.EtherTypes; import org.opendaylight.controller.sal.utils.IPProtocols; import org.opendaylight.controller.sal.utils.NetUtils; @@ -52,7 +55,9 @@ public class Match implements Cloneable, Serializable { reversableMatches = Collections.unmodifiableMap(map); } private Map fields; - private int matches; // concise way to tell which fields the match is set for (may remove if not needed) + private int matches; // concise way to tell which fields the match + // is set for (may remove if not needed) + private ConcurrentMap props; public Match() { fields = new HashMap(); @@ -64,6 +69,81 @@ public class Match implements Cloneable, Serializable { matches = match.matches; } + /** + * Gets the list of metadata currently registered with this match + * + * @return List of metadata currently registered + */ + public List getMetadatas() { + if (this.props != null) { + // Return all the values in the map + Collection res = this.props.values(); + if (res == null) { + return Collections.emptyList(); + } + return new ArrayList(res); + } + return Collections.emptyList(); + } + + /** + * Gets the metadata registered with a name if present + * + * @param name the name of the property to be extracted + * + * @return List of metadata currently registered + */ + public Property getMetadata(String name) { + if (name == null) { + return null; + } + if (this.props != null) { + // Return the Property associated to the name + return this.props.get(name); + } + return null; + } + + /** + * Sets the metadata associated to a name. If the name or prop is NULL, + * an exception NullPointerException will be raised. + * + * @param name the name of the property to be set + * @param prop, property to be set + */ + public void setMetadata(String name, Property prop) { + if (this.props == null) { + props = new ConcurrentHashMap(); + } + + if (this.props != null) { + this.props.put(name, prop); + } + } + + /** + * Remove the metadata associated to a name. If the name is NULL, + * nothing will be removed. + * + * @param name the name of the property to be set + * @param prop, property to be set + * + * @return List of metadata currently registered + */ + public void removeMetadata(String name) { + if (this.props == null) { + return; + } + + if (this.props != null) { + this.props.remove(name); + } + // It's intentional to keep the this.props still allocated + // till the parent data structure will be alive, so to avoid + // unnecessary allocation/deallocation, even if it's holding + // nothing + } + /** * Generic setter for frame/packet/message's header fields against which to match * Note: For MAC addresses, please pass the cloned value to this function diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/ICMP.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/ICMP.java index 35ae71d001..987394402d 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/ICMP.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/ICMP.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013-2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -190,8 +190,9 @@ public class ICMP extends Packet { end += rawPayload.length; } int checksumStartByte = start + getfieldOffset(CHECKSUM) / NetUtils.NumBitsInAByte; + int even = end & ~1; - for (int i = start; i <= (end - 1); i = i + 2) { + for (int i = start; i < even; i = i + 2) { // Skip, if the current bytes are checkSum bytes if (i == checksumStartByte) { continue; @@ -199,7 +200,13 @@ public class ICMP extends Packet { wordData = ((data[i] << 8) & 0xFF00) + (data[i + 1] & 0xFF); sum = sum + wordData; } - carry = (sum >> 16) & 0xFF; + if (even < end) { + // Add the last octet with zero padding. + wordData = (data[even] << 8) & 0xFF00; + sum = sum + wordData; + } + + carry = sum >>> 16; finalSum = (sum & 0xFFFF) + carry; return (short) ~((short) finalSum & 0xFFFF); } diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/IPv4.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/IPv4.java index 3363f423d6..56793c41f6 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/IPv4.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/IPv4.java @@ -260,7 +260,17 @@ public class IPv4 extends Packet { */ public void setHeaderField(String headerField, byte[] readValue) { if (headerField.equals(PROTOCOL)) { - payloadClass = protocolClassMap.get(readValue[0]); + // Don't set payloadClass if framgment offset is not zero. + byte[] fragoff = hdrFieldsMap.get(FRAGOFFSET); + if (fragoff == null || BitBufferHelper.getShort(fragoff) == 0) { + payloadClass = protocolClassMap.get(readValue[0]); + } + } else if (headerField.equals(FRAGOFFSET)) { + if (readValue != null && BitBufferHelper.getShort(readValue) != 0) { + // Clear payloadClass because protocol header is not present + // in this packet. + payloadClass = null; + } } else if (headerField.equals(OPTIONS) && (readValue == null || readValue.length == 0)) { hdrFieldsMap.remove(headerField); diff --git a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/action/ActionTest.java b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/action/ActionTest.java index 14f0d83ff6..edcb3e2761 100644 --- a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/action/ActionTest.java +++ b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/action/ActionTest.java @@ -17,6 +17,9 @@ import org.junit.Test; import org.junit.Assert; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.core.Property; +import org.opendaylight.controller.sal.core.Tables; +import org.opendaylight.controller.sal.core.Tier; import org.opendaylight.controller.sal.utils.EtherTypes; import org.opendaylight.controller.sal.utils.NodeConnectorCreator; import org.slf4j.Logger; @@ -269,4 +272,89 @@ public class ActionTest { .createNodeConnector((short) 5, node)))); Assert.assertFalse(actions.contains(new Controller())); } + + @Test + public void testMetadata() { + Property tier1 = new Tier(1); + Property tier2 = new Tier(2); + Property table1 = new Tables((byte)0x7f); + Action a1 = new PopVlan(); + List resprops = null; + resprops = a1.getMetadatas(); + // This should be an empty list + Assert.assertTrue(resprops.isEmpty()); + a1.setMetadata("tier1", tier1); + a1.setMetadata("tier2", tier2); + a1.setMetadata("table1", table1); + resprops = a1.getMetadatas(); + // Check for the number of elements in it + Assert.assertTrue(resprops.size() == 3); + // Check if the elements are in it + Assert.assertTrue(resprops.contains(tier1)); + Assert.assertTrue(resprops.contains(tier2)); + Assert.assertTrue(resprops.contains(table1)); + // Check for single elements retrieve + Assert.assertTrue(a1.getMetadata("tier1").equals(tier1)); + Assert.assertTrue(a1.getMetadata("tier2").equals(tier2)); + Assert.assertTrue(a1.getMetadata("table1").equals(table1)); + // Now remove an element and make sure the remaining are + // correct + a1.removeMetadata("tier1"); + + resprops = a1.getMetadatas(); + // Check for the number of elements in it + Assert.assertTrue(resprops.size() == 2); + // Check if the elements are in it + Assert.assertFalse(resprops.contains(tier1)); + Assert.assertTrue(resprops.contains(tier2)); + Assert.assertTrue(resprops.contains(table1)); + // Check for single elements retrieve + Assert.assertTrue(a1.getMetadata("table1").equals(table1)); + Assert.assertTrue(a1.getMetadata("tier2").equals(tier2)); + Assert.assertNull(a1.getMetadata("tier1")); + + // Check for an element never existed + Assert.assertNull(a1.getMetadata("table100")); + + // Remove them all + a1.removeMetadata("tier2"); + a1.removeMetadata("table1"); + + // Remove also a non-existent one + a1.removeMetadata("table100"); + + resprops = a1.getMetadatas(); + // Check there are no elements left + Assert.assertTrue(resprops.size() == 0); + + // Now check for exception on setting null values + try { + a1.setMetadata("foo", null); + // The line below should never be reached + Assert.assertTrue(false); + } catch (NullPointerException nue) { + // NPE should be raised for null value + Assert.assertTrue(true); + } + + // Now check on using null key + try { + a1.setMetadata(null, table1); + // The line below should never be reached + Assert.assertTrue(false); + } catch (NullPointerException nue) { + // NPE should be raised for null value + Assert.assertTrue(true); + } + + // Now check on using null key and null value + try { + a1.setMetadata(null, null); + // The line below should never be reached + Assert.assertTrue(false); + } catch (NullPointerException nue) { + // NPE should be raised for null value + Assert.assertTrue(true); + } + } } diff --git a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java index b88ae034d9..b89b27ffe0 100644 --- a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java +++ b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java @@ -11,11 +11,15 @@ package org.opendaylight.controller.sal.match; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; +import java.util.List; import org.junit.Assert; import org.junit.Test; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.core.Property; +import org.opendaylight.controller.sal.core.Tables; +import org.opendaylight.controller.sal.core.Tier; import org.opendaylight.controller.sal.utils.EtherTypes; import org.opendaylight.controller.sal.utils.IPProtocols; import org.opendaylight.controller.sal.utils.NodeConnectorCreator; @@ -638,4 +642,89 @@ public class MatchTest { // No intersection with null match, empty set Assert.assertNull(m6.getIntersection(null)); } + + @Test + public void testMetadata() { + Property tier1 = new Tier(1); + Property tier2 = new Tier(2); + Property table1 = new Tables((byte)0x7f); + Match m1 = new Match(); + List resprops = null; + resprops = m1.getMetadatas(); + // This should be null + Assert.assertTrue(resprops.isEmpty()); + m1.setMetadata("tier1", tier1); + m1.setMetadata("tier2", tier2); + m1.setMetadata("table1", table1); + resprops = m1.getMetadatas(); + // Check for the number of elements in it + Assert.assertTrue(resprops.size() == 3); + // Check if the elements are in it + Assert.assertTrue(resprops.contains(tier1)); + Assert.assertTrue(resprops.contains(tier2)); + Assert.assertTrue(resprops.contains(table1)); + // Check for single elements retrieve + Assert.assertTrue(m1.getMetadata("tier1").equals(tier1)); + Assert.assertTrue(m1.getMetadata("tier2").equals(tier2)); + Assert.assertTrue(m1.getMetadata("table1").equals(table1)); + // Now remove an element and make sure the remaining are + // correct + m1.removeMetadata("tier1"); + + resprops = m1.getMetadatas(); + // Check for the number of elements in it + Assert.assertTrue(resprops.size() == 2); + // Check if the elements are in it + Assert.assertFalse(resprops.contains(tier1)); + Assert.assertTrue(resprops.contains(tier2)); + Assert.assertTrue(resprops.contains(table1)); + // Check for single elements retrieve + Assert.assertTrue(m1.getMetadata("table1").equals(table1)); + Assert.assertTrue(m1.getMetadata("tier2").equals(tier2)); + Assert.assertNull(m1.getMetadata("tier1")); + + // Check for an element never existed + Assert.assertNull(m1.getMetadata("table100")); + + // Remove them all + m1.removeMetadata("tier2"); + m1.removeMetadata("table1"); + + // Remove also a non-existent one + m1.removeMetadata("table100"); + + resprops = m1.getMetadatas(); + // Check there are no elements left + Assert.assertTrue(resprops.size() == 0); + + // Now check for exception on setting null values + try { + m1.setMetadata("foo", null); + // The line below should never be reached + Assert.assertTrue(false); + } catch (NullPointerException nue) { + // NPE should be raised for null value + Assert.assertTrue(true); + } + + // Now check on using null key + try { + m1.setMetadata(null, table1); + // The line below should never be reached + Assert.assertTrue(false); + } catch (NullPointerException nue) { + // NPE should be raised for null value + Assert.assertTrue(true); + } + + // Now check on using null key and null value + try { + m1.setMetadata(null, null); + // The line below should never be reached + Assert.assertTrue(false); + } catch (NullPointerException nue) { + // NPE should be raised for null value + Assert.assertTrue(true); + } + } } diff --git a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/packet/ICMPTest.java b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/packet/ICMPTest.java index e81fbf02cf..287b73ae3c 100644 --- a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/packet/ICMPTest.java +++ b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/packet/ICMPTest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013-2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -9,6 +9,8 @@ package org.opendaylight.controller.sal.packet; +import java.util.Arrays; + import junit.framework.Assert; import org.junit.Test; @@ -74,28 +76,58 @@ public class ICMPTest { (byte) 0x2b, (byte) 0x2c, (byte) 0x2d, (byte) 0x2e, (byte) 0x2f, (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0x35, (byte) 0x36, (byte) 0x37 }; + serializeTest(icmpRawPayload, (short)0xe553); + + serializeTest(null, (short)0xb108); + serializeTest(new byte[0], (short)0xb108); + + byte[] odd = { + (byte)0xba, (byte)0xd4, (byte)0xc7, (byte)0x53, + (byte)0xf8, (byte)0x59, (byte)0x68, (byte)0x77, + (byte)0xfd, (byte)0x27, (byte)0xe0, (byte)0x5b, + (byte)0xd0, (byte)0x2e, (byte)0x28, (byte)0x41, + (byte)0xa3, (byte)0x48, (byte)0x5d, (byte)0x2e, + (byte)0x7d, (byte)0x5b, (byte)0xd3, (byte)0x60, + (byte)0xb3, (byte)0x88, (byte)0x8d, (byte)0x0f, + (byte)0x1d, (byte)0x87, (byte)0x51, (byte)0x0f, + (byte)0x6a, (byte)0xff, (byte)0xf7, (byte)0xd4, + (byte)0x40, (byte)0x35, (byte)0x4e, (byte)0x01, + (byte)0x36, + }; + serializeTest(odd, (short)0xd0ad); + + // Large payload that causes 16-bit checksum overflow more than + // 255 times. + byte[] largeEven = new byte[1024]; + Arrays.fill(largeEven, (byte)0xff); + serializeTest(largeEven, (short)0xb108); + + byte[] largeOdd = new byte[1021]; + Arrays.fill(largeOdd, (byte)0xff); + serializeTest(largeOdd, (short)0xb207); + } - short checksum = (short)0xe553; - - // Create ICMP object + private void serializeTest(byte[] payload, short checksum) + throws PacketException { ICMP icmp = new ICMP(); - icmp.setType((byte)8); - icmp.setCode((byte)0); - icmp.setIdentifier((short) 0x46f5); - icmp.setSequenceNumber((short) 2); - icmp.setRawPayload(icmpRawPayload); - //icmp.setChecksum(checksum); + icmp.setType((byte)8).setCode((byte)0). + setIdentifier((short)0x46f5).setSequenceNumber((short)2); + int payloadSize = 0; + if (payload != null) { + icmp.setRawPayload(payload); + payloadSize = payload.length; + } // Serialize - byte[] stream = icmp.serialize(); - Assert.assertTrue(stream.length == 64); + byte[] data = icmp.serialize(); + Assert.assertEquals(payloadSize + 8, data.length); // Deserialize ICMP icmpDes = new ICMP(); - icmpDes.deserialize(stream, 0, stream.length); + icmpDes.deserialize(data, 0, data.length); Assert.assertFalse(icmpDes.isCorrupted()); - Assert.assertTrue(icmpDes.getChecksum() == checksum); - Assert.assertTrue(icmp.equals(icmpDes)); + Assert.assertEquals(checksum, icmpDes.getChecksum()); + Assert.assertEquals(icmp, icmpDes); } } diff --git a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/packet/IPv4Test.java b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/packet/IPv4Test.java index f5298711b6..b98342831c 100644 --- a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/packet/IPv4Test.java +++ b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/packet/IPv4Test.java @@ -12,9 +12,9 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; -import junit.framework.Assert; - +import org.junit.Assert; import org.junit.Test; + import org.opendaylight.controller.sal.match.Match; import org.opendaylight.controller.sal.match.MatchType; import org.opendaylight.controller.sal.utils.EtherTypes; @@ -481,4 +481,200 @@ public class IPv4Test { Assert.assertEquals(protocol, (byte) match.getField(MatchType.NW_PROTO).getValue()); Assert.assertEquals(tos, (byte) match.getField(MatchType.NW_TOS).getValue()); } + + @Test + public void testFragment() throws Exception { + byte[] payload1 = new byte[0]; + byte[] payload2 = { + (byte)0x61, (byte)0xd1, (byte)0x3d, (byte)0x51, + (byte)0x1b, (byte)0x75, (byte)0xa7, (byte)0x83, + }; + byte[] payload3 = { + (byte)0xe7, (byte)0x0f, (byte)0x2d, (byte)0x7e, + (byte)0x15, (byte)0xba, (byte)0xe7, (byte)0x6d, + (byte)0xb5, (byte)0xc5, (byte)0xb5, (byte)0x37, + (byte)0x59, (byte)0xbc, (byte)0x91, (byte)0x43, + (byte)0xb5, (byte)0xb7, (byte)0xe4, (byte)0x28, + (byte)0xec, (byte)0x62, (byte)0x6b, (byte)0x6a, + (byte)0xd1, (byte)0xcb, (byte)0x79, (byte)0x1e, + (byte)0xfc, (byte)0x82, (byte)0xf5, (byte)0xb4, + }; + + // Ensure that the payload is not deserialized if the fragment offset + // is not zero. + byte proto = IPProtocols.TCP.byteValue(); + fragmentTest(payload1, proto, (short)0xf250); + fragmentTest(payload2, proto, (short)0xf248); + fragmentTest(payload3, proto, (short)0xf230); + + proto = IPProtocols.UDP.byteValue(); + fragmentTest(payload1, proto, (short)0xf245); + fragmentTest(payload2, proto, (short)0xf23d); + fragmentTest(payload3, proto, (short)0xf225); + + proto = IPProtocols.ICMP.byteValue(); + fragmentTest(payload1, proto, (short)0xf255); + fragmentTest(payload2, proto, (short)0xf24d); + fragmentTest(payload3, proto, (short)0xf235); + + // Ensure that the protocol header in the first fragment is + // deserialized. + proto = IPProtocols.TCP.byteValue(); + TCP tcp = new TCP(); + tcp.setSourcePort((short)1234).setDestinationPort((short)32000). + setSequenceNumber((int)0xd541f5f8).setAckNumber((int)0x58da787d). + setDataOffset((byte)5).setReserved((byte)0). + setHeaderLenFlags((short)0x18).setWindowSize((short)0x40e8). + setUrgentPointer((short)0x15f7).setChecksum((short)0x0d4e); + firstFragmentTest(tcp, payload1, proto, (short)0xdfe6); + tcp.setChecksum((short)0xab2a); + firstFragmentTest(tcp, payload2, proto, (short)0xdfde); + tcp.setChecksum((short)0x1c75); + firstFragmentTest(tcp, payload3, proto, (short)0xdfc6); + + proto = IPProtocols.UDP.byteValue(); + UDP udp = new UDP(); + udp.setSourcePort((short)53).setDestinationPort((short)45383). + setLength((short)(payload1.length + 8)).setChecksum((short)0); + firstFragmentTest(udp, payload1, proto, (short)0xdfe7); + udp.setLength((short)(payload2.length + 8)); + firstFragmentTest(udp, payload2, proto, (short)0xdfdf); + udp.setLength((short)(payload3.length + 8)); + firstFragmentTest(udp, payload3, proto, (short)0xdfc7); + + proto = IPProtocols.ICMP.byteValue(); + ICMP icmp = new ICMP(); + icmp.setType((byte)8).setCode((byte)0).setIdentifier((short)0x3d1e). + setSequenceNumber((short)1); + firstFragmentTest(icmp, payload1, proto, (short)0xdff7); + firstFragmentTest(icmp, payload2, proto, (short)0xdfef); + firstFragmentTest(icmp, payload3, proto, (short)0xdfd7); + } + + private void fragmentTest(byte[] payload, byte proto, short checksum) + throws Exception { + // Construct a fragmented raw IPv4 packet. + int ipv4Len = 20; + byte[] rawIp = new byte[ipv4Len + payload.length]; + + byte ipVersion = 4; + byte dscp = 35; + byte ecn = 2; + byte tos = (byte)((dscp << 2) | ecn); + short totalLen = (short)rawIp.length; + short id = 22143; + short offset = 0xb9; + byte ttl = 64; + byte[] srcIp = {(byte)0x0a, (byte)0x00, (byte)0x00, (byte)0x01}; + byte[] dstIp = {(byte)0xc0, (byte)0xa9, (byte)0x66, (byte)0x23}; + + rawIp[0] = (byte)((ipVersion << 4) | (ipv4Len >> 2)); + rawIp[1] = tos; + rawIp[2] = (byte)(totalLen >>> Byte.SIZE); + rawIp[3] = (byte)totalLen; + rawIp[4] = (byte)(id >>> Byte.SIZE); + rawIp[5] = (byte)id; + rawIp[6] = (byte)(offset >>> Byte.SIZE); + rawIp[7] = (byte)offset; + rawIp[8] = ttl; + rawIp[9] = proto; + rawIp[10] = (byte)(checksum >>> Byte.SIZE); + rawIp[11] = (byte)checksum; + System.arraycopy(srcIp, 0, rawIp, 12, srcIp.length); + System.arraycopy(dstIp, 0, rawIp, 16, srcIp.length); + System.arraycopy(payload, 0, rawIp, ipv4Len, payload.length); + + // Deserialize. + IPv4 ipv4 = new IPv4(); + ipv4.deserialize(rawIp, 0, rawIp.length * Byte.SIZE); + + Assert.assertEquals(ipVersion, ipv4.getVersion()); + Assert.assertEquals(ipv4Len, ipv4.getHeaderLen()); + Assert.assertEquals(dscp, ipv4.getDiffServ()); + Assert.assertEquals(ecn, ipv4.getECN()); + Assert.assertEquals(totalLen, ipv4.getTotalLength()); + Assert.assertEquals(id, ipv4.getIdentification()); + Assert.assertEquals((byte)0, ipv4.getFlags()); + Assert.assertEquals(offset, ipv4.getFragmentOffset()); + Assert.assertEquals(ttl, ipv4.getTtl()); + Assert.assertEquals(proto, ipv4.getProtocol()); + Assert.assertEquals(checksum, ipv4.getChecksum()); + Assert.assertEquals(NetUtils.byteArray4ToInt(srcIp), + ipv4.getSourceAddress()); + Assert.assertEquals(NetUtils.byteArray4ToInt(dstIp), + ipv4.getDestinationAddress()); + Assert.assertFalse(ipv4.isCorrupted()); + + // payloadClass should not be set if fragment offset is not zero. + Assert.assertEquals(null, ipv4.getPayload()); + Assert.assertArrayEquals(payload, ipv4.getRawPayload()); + } + + private void firstFragmentTest(Packet payload, byte[] rawPayload, + byte proto, short checksum) + throws Exception { + // Construct a raw IPv4 packet with MF flag. + int ipv4Len = 20; + payload.setRawPayload(rawPayload); + byte[] payloadBytes = payload.serialize(); + byte[] rawIp = new byte[ipv4Len + payloadBytes.length]; + + byte ipVersion = 4; + byte dscp = 13; + byte ecn = 1; + byte tos = (byte)((dscp << 2) | ecn); + short totalLen = (short)rawIp.length; + short id = 19834; + byte flags = 0x1; + short offset = 0; + short off = (short)(((short)flags << 13) | offset); + byte ttl = 64; + byte[] srcIp = {(byte)0xac, (byte)0x23, (byte)0x5b, (byte)0xfd}; + byte[] dstIp = {(byte)0xc0, (byte)0xa8, (byte)0x64, (byte)0x71}; + + rawIp[0] = (byte)((ipVersion << 4) | (ipv4Len >> 2)); + rawIp[1] = tos; + rawIp[2] = (byte)(totalLen >>> Byte.SIZE); + rawIp[3] = (byte)totalLen; + rawIp[4] = (byte)(id >>> Byte.SIZE); + rawIp[5] = (byte)id; + rawIp[6] = (byte)(off >>> Byte.SIZE); + rawIp[7] = (byte)off; + rawIp[8] = ttl; + rawIp[9] = proto; + rawIp[10] = (byte)(checksum >>> Byte.SIZE); + rawIp[11] = (byte)checksum; + System.arraycopy(srcIp, 0, rawIp, 12, srcIp.length); + System.arraycopy(dstIp, 0, rawIp, 16, srcIp.length); + System.arraycopy(payloadBytes, 0, rawIp, ipv4Len, payloadBytes.length); + + // Deserialize. + IPv4 ipv4 = new IPv4(); + ipv4.deserialize(rawIp, 0, rawIp.length * Byte.SIZE); + + Assert.assertEquals(ipVersion, ipv4.getVersion()); + Assert.assertEquals(ipv4Len, ipv4.getHeaderLen()); + Assert.assertEquals(dscp, ipv4.getDiffServ()); + Assert.assertEquals(ecn, ipv4.getECN()); + Assert.assertEquals(totalLen, ipv4.getTotalLength()); + Assert.assertEquals(id, ipv4.getIdentification()); + Assert.assertEquals(flags, ipv4.getFlags()); + Assert.assertEquals(offset, ipv4.getFragmentOffset()); + Assert.assertEquals(ttl, ipv4.getTtl()); + Assert.assertEquals(proto, ipv4.getProtocol()); + Assert.assertEquals(checksum, ipv4.getChecksum()); + Assert.assertEquals(NetUtils.byteArray4ToInt(srcIp), + ipv4.getSourceAddress()); + Assert.assertEquals(NetUtils.byteArray4ToInt(dstIp), + ipv4.getDestinationAddress()); + Assert.assertFalse(ipv4.isCorrupted()); + + // Protocol header in the first fragment should be deserialized. + Assert.assertEquals(null, ipv4.getRawPayload()); + + Packet desPayload = ipv4.getPayload(); + Assert.assertEquals(payload, desPayload); + Assert.assertFalse(desPayload.isCorrupted()); + Assert.assertArrayEquals(rawPayload, desPayload.getRawPayload()); + } } diff --git a/opendaylight/sal/connection/api/pom.xml b/opendaylight/sal/connection/api/pom.xml index b194f76a45..780631791d 100644 --- a/opendaylight/sal/connection/api/pom.xml +++ b/opendaylight/sal/connection/api/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../../commons/opendaylight sal.connection - 0.1.2-SNAPSHOT + 0.2.0-SNAPSHOT bundle diff --git a/opendaylight/sal/connection/implementation/pom.xml b/opendaylight/sal/connection/implementation/pom.xml index 7150683597..a7d5dfafb9 100644 --- a/opendaylight/sal/connection/implementation/pom.xml +++ b/opendaylight/sal/connection/implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../../commons/opendaylight sal.connection.implementation - 0.1.2-SNAPSHOT + 0.2.0-SNAPSHOT bundle diff --git a/opendaylight/sal/implementation/pom.xml b/opendaylight/sal/implementation/pom.xml index 88986dcdd0..3f1aa86be8 100644 --- a/opendaylight/sal/implementation/pom.xml +++ b/opendaylight/sal/implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight sal.implementation - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/sal/networkconfiguration/api/pom.xml b/opendaylight/sal/networkconfiguration/api/pom.xml index 5b2269ae6d..4b18349745 100644 --- a/opendaylight/sal/networkconfiguration/api/pom.xml +++ b/opendaylight/sal/networkconfiguration/api/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../../commons/opendaylight sal.networkconfiguration - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT bundle diff --git a/opendaylight/sal/networkconfiguration/implementation/pom.xml b/opendaylight/sal/networkconfiguration/implementation/pom.xml index 508c9bd3f5..bf476a924a 100644 --- a/opendaylight/sal/networkconfiguration/implementation/pom.xml +++ b/opendaylight/sal/networkconfiguration/implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../../commons/opendaylight sal.networkconfiguration.implementation - 0.0.3-SNAPSHOT + 0.1.0-SNAPSHOT bundle diff --git a/opendaylight/samples/clustersession/pom.xml b/opendaylight/samples/clustersession/pom.xml index f72e47b283..10ae20ca63 100644 --- a/opendaylight/samples/clustersession/pom.xml +++ b/opendaylight/samples/clustersession/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight org.opendaylight.controller clustersession - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT bundle @@ -43,7 +43,7 @@ org.opendaylight.controller clustering.services - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT org.slf4j diff --git a/opendaylight/samples/loadbalancer/pom.xml b/opendaylight/samples/loadbalancer/pom.xml index 7939083891..a7b41096d7 100644 --- a/opendaylight/samples/loadbalancer/pom.xml +++ b/opendaylight/samples/loadbalancer/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight samples.loadbalancer - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT bundle diff --git a/opendaylight/samples/northbound/loadbalancer/pom.xml b/opendaylight/samples/northbound/loadbalancer/pom.xml index d39241757f..18aa4e1d62 100644 --- a/opendaylight/samples/northbound/loadbalancer/pom.xml +++ b/opendaylight/samples/northbound/loadbalancer/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../../commons/opendaylight samples.loadbalancer.northbound - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/samples/simpleforwarding/pom.xml b/opendaylight/samples/simpleforwarding/pom.xml index 1208506bd5..50410f85af 100644 --- a/opendaylight/samples/simpleforwarding/pom.xml +++ b/opendaylight/samples/simpleforwarding/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight samples.simpleforwarding - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/security/pom.xml b/opendaylight/security/pom.xml index 896e7184b2..49889de7f1 100644 --- a/opendaylight/security/pom.xml +++ b/opendaylight/security/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../commons/opendaylight security - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/statisticsmanager/api/pom.xml b/opendaylight/statisticsmanager/api/pom.xml index aa9b88e1b2..23edfa3991 100644 --- a/opendaylight/statisticsmanager/api/pom.xml +++ b/opendaylight/statisticsmanager/api/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight statisticsmanager - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT bundle diff --git a/opendaylight/statisticsmanager/implementation/pom.xml b/opendaylight/statisticsmanager/implementation/pom.xml index 10abb3d251..08db43a0f0 100644 --- a/opendaylight/statisticsmanager/implementation/pom.xml +++ b/opendaylight/statisticsmanager/implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight statisticsmanager.implementation - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/statisticsmanager/integrationtest/pom.xml b/opendaylight/statisticsmanager/integrationtest/pom.xml index 2946e698fe..22696b71e6 100644 --- a/opendaylight/statisticsmanager/integrationtest/pom.xml +++ b/opendaylight/statisticsmanager/integrationtest/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.integrationtest - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT ../../commons/integrationtest statisticsmanager.integrationtest - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT ../implementation/target/jacoco-it.exec diff --git a/opendaylight/switchmanager/api/pom.xml b/opendaylight/switchmanager/api/pom.xml index 94ba0216cc..a29341ee6f 100644 --- a/opendaylight/switchmanager/api/pom.xml +++ b/opendaylight/switchmanager/api/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight switchmanager - 0.7.1-SNAPSHOT + 0.8.0-SNAPSHOT bundle diff --git a/opendaylight/switchmanager/implementation/pom.xml b/opendaylight/switchmanager/implementation/pom.xml index a0718db48a..fe7a0c0bcb 100644 --- a/opendaylight/switchmanager/implementation/pom.xml +++ b/opendaylight/switchmanager/implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight switchmanager.implementation - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/Activator.java b/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/Activator.java index 0f11284e53..deecf26e0d 100644 --- a/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/Activator.java +++ b/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/Activator.java @@ -77,7 +77,7 @@ public class Activator extends ComponentActivatorAbstractBase { c.add(createContainerServiceDependency(containerName).setService( IInventoryService.class).setCallbacks( "setInventoryService", "unsetInventoryService") - .setRequired(false)); + .setRequired(true)); c.add(createContainerServiceDependency(containerName).setService( IStatisticsManager.class).setCallbacks( "setStatisticsManager", "unsetStatisticsManager") diff --git a/opendaylight/switchmanager/integrationtest/pom.xml b/opendaylight/switchmanager/integrationtest/pom.xml index 4a8d93f3b3..708ac32763 100644 --- a/opendaylight/switchmanager/integrationtest/pom.xml +++ b/opendaylight/switchmanager/integrationtest/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.integrationtest - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT ../../commons/integrationtest switchmanager.integrationtest - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT ../implementation/target/jacoco-it.exec diff --git a/opendaylight/topologymanager/implementation/pom.xml b/opendaylight/topologymanager/implementation/pom.xml index 746135891e..430dfca74d 100644 --- a/opendaylight/topologymanager/implementation/pom.xml +++ b/opendaylight/topologymanager/implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight topologymanager - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/topologymanager/integrationtest/pom.xml b/opendaylight/topologymanager/integrationtest/pom.xml index e278ecffd9..ce6422c8c1 100644 --- a/opendaylight/topologymanager/integrationtest/pom.xml +++ b/opendaylight/topologymanager/integrationtest/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.integrationtest - 0.5.2-SNAPSHOT + 0.6.0-SNAPSHOT ../../commons/integrationtest topologymanager.integrationtest - 0.4.1-SNAPSHOT + 0.5.0-SNAPSHOT ../implementaiton/target/jacoco-it.exec diff --git a/opendaylight/topologymanager/shell/pom.xml b/opendaylight/topologymanager/shell/pom.xml index 078b55c596..2de8c5c26c 100644 --- a/opendaylight/topologymanager/shell/pom.xml +++ b/opendaylight/topologymanager/shell/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight topologymanager.shell diff --git a/opendaylight/usermanager/api/pom.xml b/opendaylight/usermanager/api/pom.xml index c932a7cb31..e21337242a 100644 --- a/opendaylight/usermanager/api/pom.xml +++ b/opendaylight/usermanager/api/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight usermanager - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/usermanager/implementation/pom.xml b/opendaylight/usermanager/implementation/pom.xml index 9567db0293..d973f670b2 100644 --- a/opendaylight/usermanager/implementation/pom.xml +++ b/opendaylight/usermanager/implementation/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight usermanager.implementation - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/web/brandfragment/pom.xml b/opendaylight/web/brandfragment/pom.xml index 541dbcadfd..25f62f059e 100644 --- a/opendaylight/web/brandfragment/pom.xml +++ b/opendaylight/web/brandfragment/pom.xml @@ -6,7 +6,7 @@ org.opendaylight.controller commons.opendaylight - 1.4.0-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight @@ -17,7 +17,7 @@ org.opendaylight.controller web.brandfragment - 0.4.0-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/web/devices/pom.xml b/opendaylight/web/devices/pom.xml index 8906946423..8e7c9248dd 100644 --- a/opendaylight/web/devices/pom.xml +++ b/opendaylight/web/devices/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight devices.web - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/web/flows/pom.xml b/opendaylight/web/flows/pom.xml index f62c6ac4d4..99238c6aad 100644 --- a/opendaylight/web/flows/pom.xml +++ b/opendaylight/web/flows/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight flows.web - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/web/osgi-brandfragment/pom.xml b/opendaylight/web/osgi-brandfragment/pom.xml index fc04088961..adea8ace62 100644 --- a/opendaylight/web/osgi-brandfragment/pom.xml +++ b/opendaylight/web/osgi-brandfragment/pom.xml @@ -5,12 +5,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight osgi-brandfragment.web - 0.0.2-SNAPSHOT + 0.1.0-SNAPSHOT bundle OSGi management web application brand fragment diff --git a/opendaylight/web/root/pom.xml b/opendaylight/web/root/pom.xml index 6f0a0989b8..cd82f8b07f 100644 --- a/opendaylight/web/root/pom.xml +++ b/opendaylight/web/root/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight web - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/web/topology/pom.xml b/opendaylight/web/topology/pom.xml index e65c19ff84..24b53db767 100644 --- a/opendaylight/web/topology/pom.xml +++ b/opendaylight/web/topology/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight topology.web - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/opendaylight/web/troubleshoot/pom.xml b/opendaylight/web/troubleshoot/pom.xml index b66889284d..14817bd186 100644 --- a/opendaylight/web/troubleshoot/pom.xml +++ b/opendaylight/web/troubleshoot/pom.xml @@ -4,12 +4,12 @@ org.opendaylight.controller commons.opendaylight - 1.4.2-SNAPSHOT + 1.5.0-SNAPSHOT ../../commons/opendaylight troubleshoot.web - 0.4.2-SNAPSHOT + 0.5.0-SNAPSHOT bundle diff --git a/pom.xml b/pom.xml index 10c05e254f..bb8ad1dbeb 100644 --- a/pom.xml +++ b/pom.xml @@ -4,11 +4,11 @@ org.opendaylight.controller commons.parent - 1.0.2-SNAPSHOT + 1.1.0-SNAPSHOT opendaylight/commons/parent releasepom - 0.1.2-SNAPSHOT + 0.2.0-SNAPSHOT pom 3.0 diff --git a/third-party/commons/thirdparty/pom.xml b/third-party/commons/thirdparty/pom.xml index 3fc3a3bd6a..ad3c27523e 100644 --- a/third-party/commons/thirdparty/pom.xml +++ b/third-party/commons/thirdparty/pom.xml @@ -6,7 +6,7 @@ org.opendaylight.controller commons.thirdparty - 1.1.2-SNAPSHOT + 1.2.0-SNAPSHOT pom scm:git:ssh://git.opendaylight.org:29418/controller.git diff --git a/third-party/ganymed/pom.xml b/third-party/ganymed/pom.xml index f67828bdab..676e2a24f1 100644 --- a/third-party/ganymed/pom.xml +++ b/third-party/ganymed/pom.xml @@ -5,13 +5,13 @@ org.opendaylight.controller commons.thirdparty - 1.1.2-SNAPSHOT + 1.2.0-SNAPSHOT ../commons/thirdparty org.opendaylight.controller.thirdparty ganymed - 1.1-SNAPSHOT + 1.2.0-SNAPSHOT bundle diff --git a/third-party/jersey-servlet/pom.xml b/third-party/jersey-servlet/pom.xml index 7e944c15da..27d503e898 100644 --- a/third-party/jersey-servlet/pom.xml +++ b/third-party/jersey-servlet/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.thirdparty - 1.1.1-SNAPSHOT + 1.2.0-SNAPSHOT ../commons/thirdparty @@ -17,7 +17,7 @@ 4.0.0 org.opendaylight.controller.thirdparty com.sun.jersey.jersey-servlet - 1.18-SNAPSHOT + 1.19.0-SNAPSHOT bundle diff --git a/third-party/net.sf.jung2/pom.xml b/third-party/net.sf.jung2/pom.xml index fe15316023..63455dc8be 100644 --- a/third-party/net.sf.jung2/pom.xml +++ b/third-party/net.sf.jung2/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.thirdparty - 1.1.1-SNAPSHOT + 1.2.0-SNAPSHOT ../commons/thirdparty @@ -17,7 +17,7 @@ 4.0.0 org.opendaylight.controller.thirdparty net.sf.jung2 - 2.0.2-SNAPSHOT + 2.1.0-SNAPSHOT bundle diff --git a/third-party/openflowj/pom.xml b/third-party/openflowj/pom.xml index 8d8724dceb..9e04a70b83 100644 --- a/third-party/openflowj/pom.xml +++ b/third-party/openflowj/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.opendaylight.controller.thirdparty org.openflow.openflowj - 1.0.3-SNAPSHOT + 1.1.0-SNAPSHOT OpenFlow Java A Java implemention of the OpenFlow v1.0 protocol @@ -10,7 +10,7 @@ org.opendaylight.controller commons.thirdparty - 1.1.1-SNAPSHOT + 1.2.0-SNAPSHOT ../commons/thirdparty diff --git a/third-party/org.apache.catalina.filters.CorsFilter/pom.xml b/third-party/org.apache.catalina.filters.CorsFilter/pom.xml index 85e631686e..78996da2cb 100644 --- a/third-party/org.apache.catalina.filters.CorsFilter/pom.xml +++ b/third-party/org.apache.catalina.filters.CorsFilter/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller commons.thirdparty - 1.1.1-SNAPSHOT + 1.2.0-SNAPSHOT ../commons/thirdparty @@ -16,7 +16,7 @@ 4.0.0 org.opendaylight.controller.thirdparty org.apache.catalina.filters.CorsFilter - 7.0.43-SNAPSHOT + 7.1.0-SNAPSHOT bundle