Merge "Prevent password hash from being shown"
authorAlessandro Boch <aboch@cisco.com>
Mon, 9 Dec 2013 20:00:15 +0000 (20:00 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 9 Dec 2013 20:00:15 +0000 (20:00 +0000)
178 files changed:
opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigSnapshotHolder.java
opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigSnapshotHolderImpl.java [new file with mode: 0644]
opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/Persister.java
opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java
opendaylight/config/config-persister-directory-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapterTest.java
opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedCapabilities.txt [moved from opendaylight/config/config-persister-directory-adapter/src/test/resources/expectedCapabilities.txt with 100% similarity]
opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedSnapshot.xml [moved from opendaylight/config/config-persister-directory-adapter/src/test/resources/expectedSnapshot.xml with 100% similarity]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedCapabilities.txt [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedSnapshot.xml [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedCapabilities.txt [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedSnapshot.xml [new file with mode: 0644]
opendaylight/config/config-persister-file-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapter.java
opendaylight/config/config-persister-file-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapterTest.java
opendaylight/config/logback-config/src/main/yang/config-logging.yang
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/FtlFilePersister.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/Field.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/ModuleField.java
opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/module_abs_template_new.ftl
opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java
opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ModuleMXBeanEntryTemplatesTest.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractDependencyAttribute.java [new file with mode: 0644]
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/Dependency.java [new file with mode: 0644]
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/DependencyAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListDependenciesAttribute.java [new file with mode: 0644]
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java
opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryNameConflictTest.java
opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryTest.java
opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/SchemaContextTest.java
opendaylight/config/yang-jmx-generator/src/test/resources/duplicates/config-test-duplicate-attribute-in-runtime-and-mxbean.yang [new file with mode: 0644]
opendaylight/config/yang-jmx-generator/src/test/resources/test-config-threads-java.yang
opendaylight/config/yang-test/src/main/yang/config-test-impl.yang
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/00-netty.conf
opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.conf
opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/FlowConfig.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FRMUtil.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FlowConsumerImpl.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/GroupConsumerImpl.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/MeterConsumerImpl.java
opendaylight/md-sal/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/statistics/DataBrokerRuntimeMXBeanImpl.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentitityCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java
opendaylight/md-sal/sal-binding-broker/src/main/yang/opendaylight-binding-broker-impl.yang
opendaylight/md-sal/sal-binding-dom-it/pom.xml
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/AbstractConsumer.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/AbstractProvider.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/statistics/DomBrokerRuntimeMXBeanImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfMapping.xtend
opendaylight/md-sal/sal-remoterpc-connector/implementation/pom.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModuleFactory.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/Client.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/Context.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcClient.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProvider.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcServer.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RoutingTableProvider.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RpcSocket.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/Sender.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/SocketManager.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/SocketPair.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/CompositeNodeImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/Message.java [moved from opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/router/zeromq/Message.java with 88% similarity]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/MessageWrapper.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/RouteIdentifierImpl.java [moved from opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/router/zeromq/RouteIdentifierImpl.java with 54% similarity]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/RpcRequestImpl.java [moved from opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/router/zeromq/RpcRequestImpl.java with 94% similarity]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/util/XmlUtils.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/scala/org/opendaylight/controller/sal/connector/remoterpc/Client.scala [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/yang/odl-sal-dom-rpc-remote-cfg.yang [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/ClientTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RouteIdentifierImplTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RpcSocketTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/SerilizationTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/SocketManagerTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/resources/FourSimpleChildren.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/pom.xml [moved from opendaylight/md-sal/test/zeromq-test-consumer/pom.xml with 87% similarity]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/FourSimpleChildren.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/InvalidCompositeChild.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/InvalidSimpleChild.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/OneSimpleChild.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/OneSimpleOneCompositeChild.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/TwoCompositeChildren.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/TwoSimpleChildren.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/pom.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/pom.xml [moved from opendaylight/md-sal/test/zeromq-test-provider/pom.xml with 89% similarity]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/pom.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/RouterTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/resources/controller.config [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/resources/logback.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqrouter/rest/Router.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/src/main/resources/WEB-INF/web.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlMapper.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlProvidersTest.java
opendaylight/md-sal/sal-zeromq-connector/pom.xml [deleted file]
opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChange.java [deleted file]
opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/router/zeromq/Activator.java [deleted file]
opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/router/zeromq/ZeroMqRpcRouter.java [deleted file]
opendaylight/md-sal/test/pom.xml [deleted file]
opendaylight/md-sal/test/zeromq-test-consumer/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java [deleted file]
opendaylight/md-sal/test/zeromq-test-it/pom.xml [deleted file]
opendaylight/md-sal/test/zeromq-test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/ServiceConsumerController.java [deleted file]
opendaylight/md-sal/test/zeromq-test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/ServiceProviderController.java [deleted file]
opendaylight/md-sal/test/zeromq-test-provider/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java [deleted file]
opendaylight/md-sal/zeromq-routingtable/implementation/pom.xml
opendaylight/netconf/config-netconf-connector/pom.xml
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/AbstractAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/AttributeConfigElement.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectXmlReader.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleBinaryAttributeReadingStrategy.java [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleCompositeAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/CompositeAttributeResolvingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectResolver.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectXmlWriter.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleBinaryAttributeWritingStrategy.java [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/NoOpStorageAdapter.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/Util.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandlerTest.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/DummyAdapter.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java
opendaylight/netconf/netconf-client/src/main/resources/client_hello.xml
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/client_hello.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_differentNamespaceTO.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_sameAttrDifferentNamespaces.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_sameAttrDifferentNamespacesList.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_typeNameConfigAttributeMatching.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised2.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised3.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised4.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised5.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised6.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised7.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised8.xml
opendaylight/web/flows/src/main/java/org/opendaylight/controller/flows/web/Flows.java

index 654326a898cc735c9d0cf69529cbfc992d1069b3..37d29d746e41f82ba63a940976e373b523e5f275 100644 (file)
@@ -4,14 +4,15 @@ import java.util.SortedSet;
 
 public interface ConfigSnapshotHolder {
 
-        /**
-         * Get part of get-config document that contains just
-         */
-        String getConfigSnapshot();
+    /**
+     * Get part of get-config document that contains just
+     */
+    String getConfigSnapshot();
 
 
-        /**
-         * Get only required capabilities referenced by the snapshot.
-         */
-        SortedSet<String> getCapabilities();
-    }
+    /**
+     * Get only required capabilities referenced by the snapshot.
+     */
+    SortedSet<String> getCapabilities();
+
+}
diff --git a/opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigSnapshotHolderImpl.java b/opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigSnapshotHolderImpl.java
new file mode 100644 (file)
index 0000000..a0586df
--- /dev/null
@@ -0,0 +1,39 @@
+package org.opendaylight.controller.config.persist.api;
+
+import java.util.SortedSet;
+
+public class ConfigSnapshotHolderImpl implements ConfigSnapshotHolder {
+
+    private final String snapshot;
+    private final SortedSet<String> caps;
+    private final String fileName;
+
+    public ConfigSnapshotHolderImpl(String configSnapshot, SortedSet<String> capabilities, String fileName) {
+        this.snapshot = configSnapshot;
+        this.caps = capabilities;
+        this.fileName = fileName;
+    }
+
+    @Override
+    public String getConfigSnapshot() {
+        return snapshot;
+    }
+
+    @Override
+    public SortedSet<String> getCapabilities() {
+        return caps;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    @Override
+    public String toString() {
+        return "ConfigSnapshotHolderImpl{" +
+                "snapshot='" + snapshot + '\'' +
+                ", caps=" + caps +
+                ", fileName='" + fileName + '\'' +
+                '}';
+    }
+}
index 1448e553e3017a478ee57a8e833b0ee3a9a63577..5509c9943745a2cc658b0c29a3bfc90797300da8 100644 (file)
@@ -8,9 +8,8 @@
 
 package org.opendaylight.controller.config.persist.api;
 
-import com.google.common.base.Optional;
-
 import java.io.IOException;
+import java.util.List;
 
 /**
  * Base interface for persister implementation.
@@ -19,7 +18,7 @@ public interface Persister extends AutoCloseable {
 
     void persistConfig(ConfigSnapshotHolder configSnapshotHolder) throws IOException;
 
-    Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException;
+    List<ConfigSnapshotHolder> loadLastConfigs() throws IOException;
 
     @Override
     void close();
index 25628b6041de94cc099eef49314756b77171324d..39595edb0b728de43917e32d9d7a71283499f293 100644 (file)
@@ -8,10 +8,10 @@
 package org.opendaylight.controller.config.persist.storage.directory;
 
 import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
 import com.google.common.io.Files;
 import org.apache.commons.io.IOUtils;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolderImpl;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -64,30 +64,25 @@ public class DirectoryPersister implements Persister {
     }
 
     @Override
-    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
         File[] filesArray = storage.listFiles();
-        if (filesArray.length == 0) {
-            return Optional.absent();
+        if (filesArray == null || filesArray.length == 0) {
+            return Collections.emptyList();
         }
         List<File> sortedFiles = new ArrayList<>(Arrays.asList(filesArray));
         Collections.sort(sortedFiles);
         // combine all found files
+        logger.debug("Reading files in following order: {}", sortedFiles);
 
-        SortedSet<String> combinedCapabilities = new TreeSet<>();
-        StringBuilder modulesBuilder = new StringBuilder(), servicesBuilder = new StringBuilder();
+        List<ConfigSnapshotHolder> result = new ArrayList<>();
         for (File file : sortedFiles) {
             logger.trace("Adding file '{}' to combined result", file);
 
             final MyLineProcessor lineProcessor = new MyLineProcessor(file.getAbsolutePath());
             Files.readLines(file, ENCODING, lineProcessor);
-
-            modulesBuilder.append(lineProcessor.getModules());
-            servicesBuilder.append(lineProcessor.getServices());
-            combinedCapabilities.addAll(lineProcessor.getCapabilities());
+            result.add(lineProcessor.getConfigSnapshotHolder(header, middle, footer));
         }
-        String combinedSnapshot = header + modulesBuilder.toString() + middle + servicesBuilder.toString() + footer;
-        ConfigSnapshotHolder result = new ConfigSnapshotHolderImpl(combinedSnapshot, combinedCapabilities);
-        return Optional.of(result);
+        return result;
     }
 
 
@@ -165,25 +160,11 @@ class MyLineProcessor implements com.google.common.io.LineProcessor<String> {
         return caps;
     }
 
-}
-
-class ConfigSnapshotHolderImpl implements ConfigSnapshotHolder {
-
-    private final String snapshot;
-    private final SortedSet<String> caps;
-
-    public ConfigSnapshotHolderImpl(String configSnapshot, SortedSet<String> capabilities) {
-        this.snapshot = configSnapshot;
-        this.caps = capabilities;
-    }
-
-    @Override
-    public String getConfigSnapshot() {
-        return snapshot;
+    ConfigSnapshotHolder getConfigSnapshotHolder(String header, String middle, String footer) {
+        String combinedSnapshot = header + getModules() + middle + getServices() + footer;
+        ConfigSnapshotHolder result = new ConfigSnapshotHolderImpl(combinedSnapshot, getCapabilities(), fileNameForReporting);
+        return result;
     }
 
-    @Override
-    public SortedSet<String> getCapabilities() {
-        return caps;
-    }
 }
+
index 53ab4c210ef22497ffaa6a4b9a41d20894d719a7..f17e414c495e376b7316f9fcc79a1891313ad1a6 100644 (file)
@@ -8,14 +8,13 @@
 
 package org.opendaylight.controller.config.persist.storage.directory;
 
-import com.google.common.base.Optional;
 import org.apache.commons.io.IOUtils;
-import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 
 import java.io.File;
-import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
@@ -25,21 +24,13 @@ import static org.junit.Assert.fail;
 
 public class DirectoryStorageAdapterTest {
     DirectoryPersister tested;
-    SortedSet<String> expectedCapabilities;
-    String expectedSnapshot;
-
-    @Before
-    public void setUp() throws Exception {
-        expectedCapabilities = new TreeSet<>(IOUtils.readLines(getClass().getResourceAsStream("/expectedCapabilities.txt")));
-        expectedSnapshot = IOUtils.toString(getClass().getResourceAsStream("/expectedSnapshot.xml"));
-    }
 
     @Test
     public void testEmptyDirectory() throws Exception {
         File folder = new File("target/emptyFolder");
         folder.mkdir();
         tested = new DirectoryPersister((folder));
-        assertEquals(Optional.<ConfigSnapshotHolder>absent(), tested.loadLastConfig());
+        assertEquals(Collections.<ConfigSnapshotHolder>emptyList(), tested.loadLastConfigs());
 
         try {
             tested.persistConfig(new ConfigSnapshotHolder() {
@@ -70,22 +61,28 @@ public class DirectoryStorageAdapterTest {
     public void testOneFile() throws Exception {
         File folder = getFolder("oneFile");
         tested = new DirectoryPersister((folder));
-        assertExpected();
+        List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+        assertEquals(1, results.size());
+        ConfigSnapshotHolder result = results.get(0);
+        assertSnapshot(result, "oneFileExpected");
     }
 
-    private void assertExpected() throws IOException {
-        Optional<ConfigSnapshotHolder> maybeResult = tested.loadLastConfig();
-        assertTrue(maybeResult.isPresent());
-        ConfigSnapshotHolder result = maybeResult.get();
-        assertEquals(expectedCapabilities, result.getCapabilities());
-        assertEquals(expectedSnapshot, result.getConfigSnapshot());
-    }
 
     @Test
     public void testTwoFiles() throws Exception {
         File folder = getFolder("twoFiles");
         tested = new DirectoryPersister((folder));
-        assertExpected();
+        List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+        assertEquals(2, results.size());
+        assertSnapshot(results.get(0), "twoFilesExpected1");
+        assertSnapshot(results.get(1), "twoFilesExpected2");
+    }
+
+    private void assertSnapshot(ConfigSnapshotHolder result, String directory) throws Exception {
+        SortedSet<String> expectedCapabilities = new TreeSet<>(IOUtils.readLines(getClass().getResourceAsStream("/" + directory + "/expectedCapabilities.txt")));
+        String expectedSnapshot = IOUtils.toString(getClass().getResourceAsStream("/" + directory + "/expectedSnapshot.xml"));
+        assertEquals(expectedCapabilities, result.getCapabilities());
+        assertEquals(expectedSnapshot, result.getConfigSnapshot());
     }
 
 }
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedCapabilities.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedCapabilities.txt
new file mode 100644 (file)
index 0000000..ef35fdd
--- /dev/null
@@ -0,0 +1 @@
+urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedSnapshot.xml b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedSnapshot.xml
new file mode 100644 (file)
index 0000000..2b1d06e
--- /dev/null
@@ -0,0 +1,84 @@
+<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
+            <name>yang-schema-service</name>
+        </module>
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
+            <name>hash-map-data-store</name>
+        </module>
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+            <name>dom-broker</name>
+            <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+                <name>ref_hash-map-data-store</name>
+            </data-store>
+        </module>
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
+            <name>binding-broker-impl</name>
+            <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+                <name>ref_binding-notification-broker</name>
+            </notification-service>
+            <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+                <name>ref_binding-data-broker</name>
+            </data-broker>
+        </module>
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+            <name>runtime-mapping-singleton</name>
+        </module>
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+            <name>binding-notification-broker</name>
+        </module>
+    </modules>
+    <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <service>
+            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+            <instance>
+                <name>ref_yang-schema-service</name>
+                <provider>/config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']</provider>
+            </instance>
+        </service>
+        <service>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+            <instance>
+                <name>ref_binding-notification-broker</name>
+                <provider>/config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']</provider>
+            </instance>
+        </service>
+        <service>
+            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+            <instance>
+                <name>ref_hash-map-data-store</name>
+                <provider>/config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']</provider>
+            </instance>
+        </service>
+        <service>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+            <instance>
+                <name>ref_binding-broker-impl</name>
+                <provider>/config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']</provider>
+            </instance>
+        </service>
+        <service>
+            <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
+            <instance>
+                <name>ref_runtime-mapping-singleton</name>
+                <provider>/config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']</provider>
+            </instance>
+        </service>
+        <service>
+            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+            <instance>
+                <name>ref_dom-broker</name>
+                <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']</provider>
+            </instance>
+        </service>
+    </services>
+</data>
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedCapabilities.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedCapabilities.txt
new file mode 100644 (file)
index 0000000..9924111
--- /dev/null
@@ -0,0 +1,19 @@
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&revision=2013-04-09
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05
+urn:ietf:params:netconf:capability:candidate:1.0
+urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04
+urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12
+urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28
+urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24
+urn:ietf:params:netconf:capability:rollback-on-error:1.0
+urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24
+urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl?module=threadpool-impl&revision=2013-04-05
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16
+urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09
+urn:opendaylight:params:xml:ns:yang:iana?module=iana&revision=2013-08-16
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:ieee754?module=ieee754&revision=2013-08-19
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedSnapshot.xml b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedSnapshot.xml
new file mode 100644 (file)
index 0000000..887cb2c
--- /dev/null
@@ -0,0 +1,25 @@
+<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
+            <name>binding-data-broker</name>
+            <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                <name>ref_dom-broker</name>
+            </dom-broker>
+            <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+                <name>ref_runtime-mapping-singleton</name>
+            </mapping-service>
+        </module>
+    </modules>
+    <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <service>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+            <instance>
+                <name>ref_binding-data-broker</name>
+                <provider>/config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']</provider>
+            </instance>
+        </service>
+    </services>
+</data>
index 66d0414d9a18485990ca709dd5ddc9832f1d4cf2..3ec8713b476514349c001f1854a4b9c05cc00ccf 100644 (file)
@@ -15,17 +15,19 @@ import com.google.common.base.Preconditions;
 import com.google.common.io.Files;
 import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolderImpl;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.api.PropertiesProvider;
 import org.opendaylight.controller.config.persist.api.StorageAdapter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.xml.sax.SAXException;
 
-import javax.xml.parsers.ParserConfigurationException;
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
@@ -105,7 +107,7 @@ public class FileStorageAdapter implements StorageAdapter, Persister {
         } else {
             numberOfStoredBackups = Integer.MAX_VALUE;
         }
-
+        logger.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups);
         return result;
     }
 
@@ -164,27 +166,23 @@ public class FileStorageAdapter implements StorageAdapter, Persister {
     }
 
     @Override
-    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
         Preconditions.checkNotNull(storage, "Storage file is null");
 
         if (!storage.exists()) {
-            return Optional.absent();
+            return Collections.emptyList();
         }
 
         final LineProcessor lineProcessor = new LineProcessor();
-        String result = Files.readLines(storage, ENCODING, lineProcessor);
-
-        try {
-            if (lineProcessor.getConfigSnapshot().isPresent() == false) {
-                return Optional.absent();
-            } else {
-                return Optional.<ConfigSnapshotHolder> of(new PersistedConfigImpl(lineProcessor.getConfigSnapshot(),
-                        lineProcessor.getCapabilities()));
-            }
+        Files.readLines(storage, ENCODING, lineProcessor);
 
-        } catch (ParserConfigurationException | SAXException e) {
-            throw new IOException("Unable to load last config ", e);
+        if (lineProcessor.getConfigSnapshot().isPresent() == false) {
+            return Collections.emptyList();
+        } else {
+            return Arrays.<ConfigSnapshotHolder>asList(new ConfigSnapshotHolderImpl(lineProcessor.getConfigSnapshot().get(),
+                    lineProcessor.getCapabilities(), storage.getAbsolutePath()));
         }
+
     }
 
     private static final class LineProcessor implements com.google.common.io.LineProcessor<String> {
@@ -227,15 +225,16 @@ public class FileStorageAdapter implements StorageAdapter, Persister {
             return true;
         }
 
-        Optional<String> getConfigSnapshot() throws IOException, SAXException, ParserConfigurationException {
+        Optional<String> getConfigSnapshot() {
             final String xmlContent = snapshotBuffer.toString();
-            if (xmlContent == null || xmlContent.equals("")) {
+            if (xmlContent.equals("")) {
                 return Optional.absent();
-            } else
+            } else {
                 return Optional.of(xmlContent);
+            }
         }
 
-        SortedSet<String> getCapabilities() throws IOException, SAXException, ParserConfigurationException {
+        SortedSet<String> getCapabilities() {
             return caps;
         }
 
@@ -251,25 +250,4 @@ public class FileStorageAdapter implements StorageAdapter, Persister {
         return "FileStorageAdapter [storage=" + storage + "]";
     }
 
-    private class PersistedConfigImpl implements ConfigSnapshotHolder {
-
-        private final String snapshot;
-        private final SortedSet<String> caps;
-
-        public PersistedConfigImpl(Optional<String> configSnapshot, SortedSet<String> capabilities) {
-            this.snapshot = configSnapshot.get();
-            this.caps = capabilities;
-        }
-
-        @Override
-        public String getConfigSnapshot() {
-            return snapshot;
-        }
-
-        @Override
-        public SortedSet<String> getCapabilities() {
-            return caps;
-        }
-    }
-
 }
index ed50184aa7ad50d7e825fa6df2895271a99be834..0236598f2b877d995639072266beb042e9673c2e 100644 (file)
@@ -9,7 +9,6 @@
 package org.opendaylight.controller.config.persist.storage.file;
 
 import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import org.junit.Before;
@@ -20,11 +19,11 @@ import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import java.io.File;
 import java.nio.file.Files;
 import java.util.Collection;
+import java.util.List;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
 import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
@@ -75,11 +74,12 @@ public class FileStorageAdapterTest {
                 });
         assertEquals(14, readLines.size());
 
-        Optional<ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
-        assertTrue(lastConf.isPresent());
+        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+        assertEquals(1, lastConf.size());
+        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
         assertEquals("<config>2</config>",
-                lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
-        assertEquals(createCaps(), lastConf.get().getCapabilities());
+                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
+        assertEquals(createCaps(), configSnapshotHolder.getCapabilities());
     }
 
     private SortedSet<String> createCaps() {
@@ -123,10 +123,11 @@ public class FileStorageAdapterTest {
                 });
         assertEquals(7, readLines.size());
 
-        Optional<ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
-        assertTrue(lastConf.isPresent());
+        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+        assertEquals(1, lastConf.size());
+        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
         assertEquals("<config>2</config>",
-                lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
+                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
     }
 
     @Test
@@ -163,10 +164,11 @@ public class FileStorageAdapterTest {
 
         assertEquals(14, readLines.size());
 
-        Optional<ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
-        assertTrue(lastConf.isPresent());
+        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+        assertEquals(1, lastConf.size());
+        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
         assertEquals("<config>3</config>",
-               lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
+                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
         assertFalse(readLines.contains(holder.getConfigSnapshot()));
     }
 
@@ -178,14 +180,14 @@ public class FileStorageAdapterTest {
         FileStorageAdapter storage = new FileStorageAdapter();
         storage.setFileStorage(file);
 
-        Optional<ConfigSnapshotHolder> elementOptional = storage.loadLastConfig();
-        assertThat(elementOptional.isPresent(), is(false));
+        List<ConfigSnapshotHolder> elementOptional = storage.loadLastConfigs();
+        assertThat(elementOptional.size(), is(0));
     }
 
     @Test(expected = NullPointerException.class)
     public void testNoProperties() throws Exception {
         FileStorageAdapter storage = new FileStorageAdapter();
-        storage.loadLastConfig();
+        storage.loadLastConfigs();
     }
 
     @Test(expected = NullPointerException.class)
index 7f4ea39dd4ccb66d5e65979ce994848b884d2dd0..3b28b574696683540391dd53ab041b0b40dd7ebb 100644 (file)
@@ -51,6 +51,7 @@ module config-logging {
                     type string;
                     mandatory true;
                 }
+                key name;
                 config:java-name-prefix FileAppenderTO;
             }
             
@@ -89,6 +90,7 @@ module config-logging {
                     type string;
                     mandatory true;
                 }
+                key name;
 
                 leaf file-name-pattern {
                     type string;
@@ -107,7 +109,7 @@ module config-logging {
                 
                 leaf clean-history-on-start {
                     type boolean;
-                    default 0;
+                    default false;
                 }
                 config:java-name-prefix RollingFileAppenderTO;
             }
@@ -128,6 +130,8 @@ module config-logging {
                     type string;
                     mandatory true;
                 }
+                key name;
+
                 config:java-name-prefix ConsoleAppenderTO;
             }
 
@@ -136,6 +140,7 @@ module config-logging {
                     type string;
                     mandatory true;
                 }
+                key logger-name;
 
                 leaf level {
                     type string;
index b0b6f3d74c131bb83c15cd0b6f5c3cd778ca3bb4..f721895921a8300b7afb0a368c0685e8a56ce871 100644 (file)
@@ -7,19 +7,9 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl;
 
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.regex.Pattern;
-
+import com.google.common.annotations.VisibleForTesting;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.directives.AnnotationsDirective;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.directives.ConstructorsDirective;
@@ -33,11 +23,18 @@ import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.directives
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.annotations.VisibleForTesting;
-
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-import freemarker.template.TemplateException;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
 
 public class FtlFilePersister {
     private static final Logger logger = LoggerFactory
@@ -56,7 +53,7 @@ public class FtlFilePersister {
                         ftlFile.getFtlTempleteLocation());
                 try {
                     template.process(ftlFile, writer);
-                } catch (TemplateException e) {
+                } catch (Throwable e) {
                     throw new IllegalStateException(
                             "Template error while generating " + ftlFile, e);
                 }
index 3a6ff18081961b9c6c15b68cc53e45a3e01369e0..115bb85b618020b61282c83c3c692c9dafca6251 100644 (file)
@@ -21,13 +21,13 @@ import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
 import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute.Dependency;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.Dependency;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.VoidAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation.Parameter;
@@ -39,6 +39,7 @@ import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Meth
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
+import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
 
 import javax.management.openmbean.SimpleType;
@@ -112,8 +113,8 @@ public class TemplateFactory {
 
             // convert attributes to getters
             for (AttributeIfc attributeIfc : entry.getAttributes()) {
-                String returnType = null;
-                returnType = getReturnType(entry, attributeIfc);
+                String returnType;
+                returnType = getReturnType(attributeIfc);
                 String getterName = "get"
                         + attributeIfc.getUpperCaseCammelCase();
                 MethodDeclaration getter = new MethodDeclaration(returnType,
@@ -128,11 +129,11 @@ public class TemplateFactory {
                 for (JavaAttribute ja : rpc.getParameters()) {
                     Field field = new Field(Collections.<String> emptyList(),
                             ja.getType().getFullyQualifiedName(),
-                            ja.getLowerCaseCammelCase());
+                            ja.getLowerCaseCammelCase(), ja.getNullableDefaultWrappedForCode());
                     fields.add(field);
                 }
                 MethodDeclaration operation = new MethodDeclaration(
-                        getReturnType(entry, rpc.getReturnType()), rpc.getName(), fields);
+                        getReturnType(rpc.getReturnType()), rpc.getName(), fields);
                 methods.add(operation);
             }
 
@@ -150,28 +151,35 @@ public class TemplateFactory {
         return result;
     }
 
-    private static String getReturnType(RuntimeBeanEntry entry, AttributeIfc attributeIfc) {
+    // FIXME: put into Type.toString
+    static String serializeType(Type type) {
+        if (type instanceof ParameterizedType){
+            ParameterizedType parameterizedType = (ParameterizedType) type;
+            StringBuffer sb = new StringBuffer();
+            sb.append(parameterizedType.getRawType().getFullyQualifiedName());
+            sb.append("<");
+            boolean first = true;
+            for(Type parameter: parameterizedType.getActualTypeArguments()) {
+                if (first) {
+                    first = false;
+                } else {
+                    sb.append(",");
+                }
+                sb.append(serializeType(parameter));
+            }
+            sb.append(">");
+            return sb.toString();
+        } else {
+            return type.getFullyQualifiedName();
+        }
+    }
+
+
+    private static String getReturnType(AttributeIfc attributeIfc) {
         String returnType;
         if (attributeIfc instanceof TypedAttribute) {
-            returnType = ((TypedAttribute) attributeIfc).getType()
-                    .getFullyQualifiedName();
-        } else if (attributeIfc instanceof TOAttribute) {
-            String fullyQualifiedName = FullyQualifiedNameHelper
-                    .getFullyQualifiedName(entry.getPackageName(),
-                            attributeIfc.getUpperCaseCammelCase());
-
-            returnType = fullyQualifiedName;
-        } else if (attributeIfc instanceof ListAttribute) {
-            AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
-                    .getInnerAttribute();
-
-            String innerTpe = innerAttr instanceof TypedAttribute ? ((TypedAttribute) innerAttr)
-                    .getType().getFullyQualifiedName()
-                    : FullyQualifiedNameHelper.getFullyQualifiedName(
-                            entry.getPackageName(),
-                            attributeIfc.getUpperCaseCammelCase());
-
-            returnType = "java.util.List<" + innerTpe + ">";
+            Type type = ((TypedAttribute) attributeIfc).getType();
+            returnType = serializeType(type);
         } else if (attributeIfc == VoidAttribute.getInstance()) {
             return "void";
         } else {
@@ -292,8 +300,7 @@ public class TemplateFactory {
     public static GeneralInterfaceTemplate mXBeanInterfaceTemplateFromMbe(
             ModuleMXBeanEntry mbe) {
         MXBeanInterfaceAttributesProcessor attrProcessor = new MXBeanInterfaceAttributesProcessor();
-        attrProcessor.processAttributes(mbe.getAttributes(),
-                mbe.getPackageName());
+        attrProcessor.processAttributes(mbe.getAttributes());
         GeneralInterfaceTemplate ifcTemplate = new GeneralInterfaceTemplate(
                 getHeaderFromEntry(mbe), mbe.getPackageName(),
                 mbe.getMXBeanInterfaceName(), Lists.<String> newArrayList(),
@@ -306,7 +313,7 @@ public class TemplateFactory {
             ModuleMXBeanEntry mbe) {
         Map<String, GeneralClassTemplate> retVal = Maps.newHashMap();
         TOAttributesProcessor processor = new TOAttributesProcessor();
-        processor.processAttributes(mbe.getAttributes(), mbe.getPackageName());
+        processor.processAttributes(mbe.getAttributes());
         for (org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory.TOAttributesProcessor.TOInternal to : processor
                 .getTOs()) {
             List<Constructor> constructors = Lists.newArrayList();
@@ -345,7 +352,7 @@ public class TemplateFactory {
             yangPropertiesToTypesMap.put(returnType.getAttributeYangName(), returnType);
         }
 
-        processor.processAttributes(yangPropertiesToTypesMap, rbe.getPackageName());
+        processor.processAttributes(yangPropertiesToTypesMap);
         for (org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory.TOAttributesProcessor.TOInternal to : processor
                 .getTOs()) {
             List<Constructor> constructors = Lists.newArrayList();
@@ -372,36 +379,29 @@ public class TemplateFactory {
 
         private final List<TOInternal> tos = Lists.newArrayList();
 
-        void processAttributes(Map<String, AttributeIfc> attributes,
-                String packageName) {
+        void processAttributes(Map<String, AttributeIfc> attributes) {
             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
                 AttributeIfc attributeIfc = attrEntry.getValue();
                 if (attributeIfc instanceof TOAttribute) {
-                    createTOInternal(packageName, attributeIfc);
+                    createTOInternal((TOAttribute) attributeIfc);
                 }
                 if (attributeIfc instanceof ListAttribute) {
                     AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
                             .getInnerAttribute();
                     if (innerAttr instanceof TOAttribute) {
-                        createTOInternal(packageName, innerAttr);
+                        createTOInternal((TOAttribute) innerAttr);
                     }
                 }
             }
         }
 
-        private void createTOInternal(String packageName,
-                AttributeIfc attributeIfc) {
-            String fullyQualifiedName = FullyQualifiedNameHelper
-                    .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
+        private void createTOInternal(TOAttribute toAttribute) {
 
-            String type = fullyQualifiedName;
-            String name = attributeIfc.getUpperCaseCammelCase();
-            Map<String, AttributeIfc> attrs = ((TOAttribute) attributeIfc)
-                    .getCapitalizedPropertiesToTypesMap();
-            // recursive processing
-            processAttributes(attrs, packageName);
+            Map<String, AttributeIfc> attrs = toAttribute.getCapitalizedPropertiesToTypesMap();
+            // recursive processing of TO's attributes
+            processAttributes(attrs);
 
-            tos.add(new TOInternal(type, name, attrs, packageName));
+            tos.add(new TOInternal(toAttribute.getType(), attrs));
         }
 
         List<TOInternal> getTOs() {
@@ -409,20 +409,22 @@ public class TemplateFactory {
         }
 
         private static class TOInternal {
-            private final String type, name;
+            private final String fullyQualifiedName, name;
             private List<Field> fields;
             private List<MethodDefinition> methods;
 
-            public TOInternal(String type, String name,
+            public TOInternal(Type type, Map<String, AttributeIfc> attrs) {
+                this(type.getFullyQualifiedName(), type.getName(), attrs, type.getPackageName());
+            }
+
+            public TOInternal(String fullyQualifiedName, String name,
                     Map<String, AttributeIfc> attrs, String packageName) {
-                super();
-                this.type = type;
+                this.fullyQualifiedName = fullyQualifiedName;
                 this.name = name;
                 processAttrs(attrs, packageName);
             }
 
-            private void processAttrs(Map<String, AttributeIfc> attrs,
-                    String packageName) {
+            private void processAttrs(Map<String, AttributeIfc> attrs, String packageName) {
                 fields = Lists.newArrayList();
                 methods = Lists.newArrayList();
 
@@ -431,26 +433,18 @@ public class TemplateFactory {
                     String varName = BindingGeneratorUtil
                             .parseToValidParamName(attrEntry.getKey());
 
-                    String fullyQualifiedName = null;
+                    String fullyQualifiedName, nullableDefault = null;
                     if (attrEntry.getValue() instanceof TypedAttribute) {
-                        Type innerType = ((TypedAttribute) attrEntry.getValue())
-                                .getType();
-                        fullyQualifiedName = innerType.getFullyQualifiedName();
-                    } else if (attrEntry.getValue() instanceof ListAttribute) {
-                        AttributeIfc innerAttr = ((ListAttribute) attrEntry
-                                .getValue()).getInnerAttribute();
-
-                        String innerTpe = innerAttr instanceof TypedAttribute ? ((TypedAttribute) innerAttr)
-                                .getType().getFullyQualifiedName()
-                                : FullyQualifiedNameHelper
-                                        .getFullyQualifiedName(packageName, attrEntry.getValue().getUpperCaseCammelCase());
-
-                        fullyQualifiedName = "java.util.List<" + innerTpe + ">";
-                    } else
+                        Type type = ((TypedAttribute) attrEntry.getValue()).getType();
+                        fullyQualifiedName = serializeType(type);
+                        if(attrEntry.getValue() instanceof JavaAttribute) {
+                            nullableDefault = ((JavaAttribute)attrEntry.getValue()).getNullableDefaultWrappedForCode();
+                        }
+                    } else {
                         fullyQualifiedName = FullyQualifiedNameHelper
                                 .getFullyQualifiedName(packageName, attrEntry.getValue().getUpperCaseCammelCase());
-
-                    fields.add(new Field(fullyQualifiedName, varName));
+                    }
+                    fields.add(new Field(fullyQualifiedName, varName, nullableDefault));
 
                     String getterName = "get" + innerName;
                     MethodDefinition getter = new MethodDefinition(
@@ -470,7 +464,7 @@ public class TemplateFactory {
             }
 
             String getType() {
-                return type;
+                return fullyQualifiedName;
             }
 
             String getName() {
@@ -488,38 +482,16 @@ public class TemplateFactory {
     }
 
     private static class MXBeanInterfaceAttributesProcessor {
-        private static final String STRING_FULLY_QUALIFIED_NAME = "java.util.List";
         private final List<MethodDeclaration> methods = Lists.newArrayList();
 
-        void processAttributes(Map<String, AttributeIfc> attributes,
-                String packageName) {
+        void processAttributes(Map<String, AttributeIfc> attributes) {
             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
                 String returnType;
                 AttributeIfc attributeIfc = attrEntry.getValue();
 
                 if (attributeIfc instanceof TypedAttribute) {
-                    returnType = ((TypedAttribute) attributeIfc).getType()
-                            .getFullyQualifiedName();
-                } else if (attributeIfc instanceof TOAttribute) {
-                    String fullyQualifiedName = FullyQualifiedNameHelper
-                            .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
-
-                    returnType = fullyQualifiedName;
-                } else if (attributeIfc instanceof ListAttribute) {
-                    String fullyQualifiedName = null;
-
-                    AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
-                            .getInnerAttribute();
-                    if (innerAttr instanceof JavaAttribute) {
-                        fullyQualifiedName = ((JavaAttribute) innerAttr)
-                                .getType().getFullyQualifiedName();
-                    } else if (innerAttr instanceof TOAttribute) {
-                        fullyQualifiedName = FullyQualifiedNameHelper
-                                .getFullyQualifiedName(packageName, innerAttr.getUpperCaseCammelCase());
-                    }
-
-                    returnType = STRING_FULLY_QUALIFIED_NAME.concat("<")
-                            .concat(fullyQualifiedName).concat(">");
+                    TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
+                    returnType = serializeType(typedAttribute.getType());
                 } else {
                     throw new UnsupportedOperationException(
                             "Attribute not supported: "
@@ -562,23 +534,25 @@ public class TemplateFactory {
                 String packageName) {
             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
                 String type;
+                String nullableDefaultWrapped = null;
                 AttributeIfc attributeIfc = attrEntry.getValue();
 
                 if (attributeIfc instanceof TypedAttribute) {
-                    type = ((TypedAttribute) attributeIfc).getType()
-                            .getFullyQualifiedName();
+                    TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
+                    type = serializeType(typedAttribute.getType());
                 } else if (attributeIfc instanceof TOAttribute) {
                     String fullyQualifiedName = FullyQualifiedNameHelper
                             .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
 
                     type = fullyQualifiedName;
-                } else if (attributeIfc instanceof ListAttribute) {
+                } else if (attributeIfc instanceof ListAttribute) {  //FIXME: listAttribute might extend TypedAttribute
                     String fullyQualifiedName = null;
                     AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
                             .getInnerAttribute();
                     if (innerAttr instanceof JavaAttribute) {
                         fullyQualifiedName = ((JavaAttribute) innerAttr)
                                 .getType().getFullyQualifiedName();
+                        nullableDefaultWrapped = ((JavaAttribute) innerAttr).getNullableDefaultWrappedForCode();
                     } else if (innerAttr instanceof TOAttribute) {
                         fullyQualifiedName = FullyQualifiedNameHelper
                                 .getFullyQualifiedName(packageName, innerAttr.getUpperCaseCammelCase());
@@ -594,7 +568,7 @@ public class TemplateFactory {
                 }
 
                 fields.add(new Field(type, attributeIfc
-                        .getUpperCaseCammelCase()));
+                        .getUpperCaseCammelCase(), nullableDefaultWrapped));
             }
         }
 
@@ -613,12 +587,16 @@ public class TemplateFactory {
         void processAttributes(Map<String, AttributeIfc> attributes,
                 String packageName) {
             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
-                String type;
+                String type, nullableDefaultWrapped = null;
                 AttributeIfc attributeIfc = attrEntry.getValue();
 
                 if (attributeIfc instanceof TypedAttribute) {
-                    type = ((TypedAttribute) attributeIfc).getType()
-                            .getFullyQualifiedName();
+                    TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
+                    type = serializeType(typedAttribute.getType());
+                    if (attributeIfc instanceof JavaAttribute) {
+                        nullableDefaultWrapped = ((JavaAttribute) attributeIfc).getNullableDefaultWrappedForCode();
+                    }
+
                 } else if (attributeIfc instanceof TOAttribute) {
                     String fullyQualifiedName = FullyQualifiedNameHelper
                             .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
@@ -631,6 +609,7 @@ public class TemplateFactory {
                     if (innerAttr instanceof JavaAttribute) {
                         fullyQualifiedName = ((JavaAttribute) innerAttr)
                                 .getType().getFullyQualifiedName();
+                        nullableDefaultWrapped = ((JavaAttribute) innerAttr).getNullableDefaultWrappedForCode();
                     } else if (innerAttr instanceof TOAttribute) {
                         fullyQualifiedName = FullyQualifiedNameHelper
                                 .getFullyQualifiedName(packageName, innerAttr.getUpperCaseCammelCase());
@@ -651,9 +630,9 @@ public class TemplateFactory {
                 List<Annotation> annotations = Lists
                         .newArrayList(overrideAnnotation);
 
-                if (attributeIfc instanceof DependencyAttribute) {
+                if (attributeIfc instanceof AbstractDependencyAttribute) {
                     isDependency = true;
-                    dependency = ((DependencyAttribute) attributeIfc)
+                    dependency = ((AbstractDependencyAttribute) attributeIfc)
                             .getDependency();
                     annotations.add(Annotation
                             .createRequireIfcAnnotation(dependency.getSie()));
@@ -662,8 +641,7 @@ public class TemplateFactory {
                 String varName = BindingGeneratorUtil
                         .parseToValidParamName(attrEntry.getKey());
                 moduleFields.add(new ModuleField(type, varName, attributeIfc
-                        .getUpperCaseCammelCase(), attributeIfc
-                        .getNullableDefault(), isDependency, dependency));
+                        .getUpperCaseCammelCase(), nullableDefaultWrapped, isDependency, dependency));
 
                 String getterName = "get"
                         + attributeIfc.getUpperCaseCammelCase();
index fe9e885b6fab8edcc457008b479f534512073386..0857ec6f8da64e16e64119d44d78834fd477cb9c 100644 (file)
@@ -7,10 +7,10 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model;
 
-import java.util.List;
-
 import com.google.common.collect.Lists;
 
+import java.util.List;
+
 public class Field {
     private final String type;
     private final String name;
@@ -21,6 +21,10 @@ public class Field {
         this(Lists.<String> newArrayList(), type, name, null);
     }
 
+    public Field(String type, String name, String definition) {
+        this(Lists.<String> newArrayList(), type, name, definition);
+    }
+
     public Field(List<String> modifiers, String type, String name) {
         this(modifiers, type, name, null);
     }
index 293696d10e0887e3157412d9653bc87878791ef8..5624e169da81d0f69dc2bca15f7dce1de71fab6a 100644 (file)
@@ -7,11 +7,13 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model;
 
+
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.Dependency;
+
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute.Dependency;
-
 public class ModuleField extends Field {
 
     private final String nullableDefault, attributeName;
@@ -22,10 +24,14 @@ public class ModuleField extends Field {
             String attributeName, String nullableDefault, boolean isDependency,
             Dependency dependency) {
         super(modifiers, type, name);
-        this.nullableDefault = nullableDefault;
         this.dependent = isDependency;
         this.dependency = dependency;
         this.attributeName = attributeName;
+        if (type.startsWith(List.class.getName()) && nullableDefault == null) {
+            String generics = type.substring(List.class.getName().length());
+            nullableDefault = "new " + ArrayList.class.getName() + generics + "()";
+        }
+        this.nullableDefault = nullableDefault;
     }
 
     public ModuleField(String type, String name, String attributeName,
@@ -49,4 +55,5 @@ public class ModuleField extends Field {
     public String getAttributeName() {
         return attributeName;
     }
+
 }
index d0646f467a50416a71bb7d5f5c0c42cdfd343abf..f7197d1582ca70193cb21591922f8c77529a31ed 100644 (file)
@@ -52,8 +52,14 @@ package ${packageName};
     public void validate(){
     <#list moduleFields as field>
         <#if field.dependent==true && field.dependency.mandatory==true>
+        <#if field.type?starts_with("java.util.List")>
+        for(javax.management.ObjectName dep : ${field.name}) {
+            dependencyResolver.validateDependency(${field.dependency.sie.fullyQualifiedName}.class, dep, ${field.name}JmxAttribute);
+        }
+        <#else>
         dependencyResolver.validateDependency(${field.dependency.sie.fullyQualifiedName}.class, ${field.name}, ${field.name}JmxAttribute);
         </#if>
+        </#if>
     </#list>
         customValidation();
     }
@@ -65,10 +71,17 @@ package ${packageName};
     // caches of resolved dependencies
     <#list moduleFields as field>
     <#if field.dependent==true>
+        <#if field.type?starts_with("java.util.List")>
+        private java.util.List<${field.dependency.sie.exportedOsgiClassName}> ${field.name}Dependency = new java.util.ArrayList<${field.dependency.sie.exportedOsgiClassName}>();
+        protected final java.util.List<${field.dependency.sie.exportedOsgiClassName}> get${field.attributeName}Dependency(){
+            return ${field.name}Dependency;
+        }
+        <#else>
         private ${field.dependency.sie.exportedOsgiClassName} ${field.name}Dependency;
         protected final ${field.dependency.sie.exportedOsgiClassName} get${field.attributeName}Dependency(){
             return ${field.name}Dependency;
         }
+        </#if>
     </#if>
     </#list>
 
@@ -79,12 +92,18 @@ package ${packageName};
 
             <#list moduleFields as field>
                 <#if field.dependent==true>
-
                     <#if field.dependency.mandatory==false>
                         if(${field.name}!=null) {
                     </#if>
 
-                    ${field.name}Dependency = dependencyResolver.resolveInstance(${field.dependency.sie.exportedOsgiClassName}.class, ${field.name}, ${field.name}JmxAttribute);
+                    <#if field.type?starts_with("java.util.List")>
+            ${field.name}Dependency = new java.util.ArrayList<${field.dependency.sie.exportedOsgiClassName}>();
+            for(javax.management.ObjectName dep : ${field.name}) {
+                ${field.name}Dependency.add(dependencyResolver.resolveInstance(${field.dependency.sie.exportedOsgiClassName}.class, dep, ${field.name}JmxAttribute));
+            }
+                    <#else>
+            ${field.name}Dependency = dependencyResolver.resolveInstance(${field.dependency.sie.exportedOsgiClassName}.class, ${field.name}, ${field.name}JmxAttribute);
+                    </#if>
 
                     <#if field.dependency.mandatory==false>
                         }
index 0d6ec3cccbeedf872bbd61c8649f6c66cf743a63..1945cac1c270919d10b59481139581e848c87f0a 100644 (file)
@@ -75,6 +75,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 
+//TODO: refactor
 public class JMXGeneratorTest extends AbstractGeneratorTest {
 
     JMXGenerator jmxGenerator;
@@ -84,19 +85,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
     File generatedResourcesDir;
 
     private static final List<String> expectedModuleFileNames = ServiceInterfaceEntryTest
-            .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, " +
-                    "AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, " +
-                    "AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, " +
-                    "AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, " +
-                    "AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, " +
-                    "AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, " +
-                    "AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, " +
-                    "DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, " +
-                    "DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, " +
-                    "DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, " +
-                    "EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, " +
-                    "InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, " +
-                    "NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
+            .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
 
     private static final List<String> expectedBGPNames = ServiceInterfaceEntryTest
             .toFileNames("[AbstractBgpListenerImplModule.java, " + "AbstractBgpListenerImplModuleFactory.java, " +
@@ -119,38 +108,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
                     "NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
                     "NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java]");
     private static final List<String> expectedAllFileNames = ServiceInterfaceEntryTest
-            .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, " +
-                    "AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, " +
-                    "AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, " +
-                    "AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, " +
-                    "AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, " +
-                    "AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, " +
-                    "AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, " +
-                    "AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, " +
-                    "AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, " +
-                    "AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, " +
-                    "AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AsyncEventBusModule.java, " +
-                    "AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, " +
-                    "AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, " +
-                    "AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, " +
-                    "BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java," +
-                    " BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, " +
-                    "BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, " +
-                    "DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, " +
-                    "DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, " +
-                    "DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, " +
-                    "DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, " +
-                    "EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, " +
-                    "EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, " +
-                    "InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, " +
-                    "NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, " +
-                    "NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, " +
-                    "NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, " +
-                    "NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, " +
-                    "NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, " +
-                    "NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, " +
-                    "NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
-                    "NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, NetconfTestImplModule.java, NetconfTestImplModuleFactory.java, NetconfTestImplModuleMXBean.java, NetconfTestImplRuntimeMXBean.java, NetconfTestImplRuntimeRegistration.java, NetconfTestImplRuntimeRegistrator.java, Peer.java, Peer.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java, ScheduledThreadPoolServiceInterface.java, SimpleList.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java, TestImplModule.java, TestImplModuleFactory.java, TestImplModuleMXBean.java, TestImplRuntimeMXBean.java, TestImplRuntimeRegistration.java, TestImplRuntimeRegistrator.java, ThreadFactoryServiceInterface.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
+            .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, NetconfTestImplModule.java, NetconfTestImplModuleFactory.java, NetconfTestImplModuleMXBean.java, NetconfTestImplRuntimeMXBean.java, NetconfTestImplRuntimeRegistration.java, NetconfTestImplRuntimeRegistrator.java, Peer.java, Peer.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java, ScheduledThreadPoolServiceInterface.java, SimpleList.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java, TestImplModule.java, TestImplModuleFactory.java, TestImplModuleMXBean.java, TestImplRuntimeMXBean.java, TestImplRuntimeRegistration.java, TestImplRuntimeRegistrator.java, ThreadFactoryServiceInterface.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
     private static final List<String> expectedGenerateMBEsListNames = ServiceInterfaceEntryTest
             .toFileNames("[AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java]");
 
@@ -381,7 +339,11 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
                         + ".threads.java.DynamicThreadPoolModuleFactory",//
                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
-                        + ".threads.java.NamingThreadFactoryModuleFactory");
+                        + ".threads.java.NamingThreadFactoryModuleFactory", //
+                PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+                        + ".threads.java.ThreadPoolRegistryImplModuleFactory");
+
+
         assertThat(lines, equalTo(expectedLines));
 
     }
@@ -572,7 +534,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
         assertDeclaredField(fieldDeclarations,
                 "private java.util.concurrent.ThreadFactory threadfactoryDependency");
         assertDeclaredField(fieldDeclarations,
-                "private java.lang.Long keepAlive=10");
+                "private java.lang.Long keepAlive=new java.lang.Long(\"10\")");
         assertDeclaredField(fieldDeclarations,
                 "private java.lang.Long coreSize");
         assertDeclaredField(fieldDeclarations, "private byte[] binary");
index 3c479318968e35cc6a132e9c6b88ae8d6700ff72..48d5b30eb282731bc7adabe46427384352272bf4 100644 (file)
@@ -7,14 +7,7 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.plugin;
 
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-import java.util.Collections;
-import java.util.Map;
-
+import com.google.common.collect.Maps;
 import org.junit.Test;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
@@ -23,7 +16,13 @@ import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractFa
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
 
-import com.google.common.collect.Maps;
+import java.util.Collections;
+import java.util.Map;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 
 public class ModuleMXBeanEntryTemplatesTest {
 
@@ -61,6 +60,7 @@ public class ModuleMXBeanEntryTemplatesTest {
         doReturn("package.type").when(typeA).getFullyQualifiedName();
         doReturn(typeA).when(attr).getType();
         doReturn("Type").when(attr).getUpperCaseCammelCase();
+        doReturn("new Default()").when(attr).getNullableDefault();
         return attr;
     }
 
index 70a4edde41b70aa82852482fb24455ef0fee264d..4eba739b469d52b675b7208e0621c9ddc9f4a845 100644 (file)
@@ -7,12 +7,27 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Sets;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static java.lang.String.format;
+import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException;
@@ -21,6 +36,7 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 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.IdentitySchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
@@ -37,20 +53,9 @@ import org.opendaylight.yangtools.yang.model.api.UsesNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static java.lang.String.format;
-import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
 
 /**
  * Represents part of yang model that describes a module.
@@ -180,8 +185,9 @@ public class ModuleMXBeanEntry extends AbstractEntry {
     }
 
     /**
-     * @return services implemented by this module. Keys are fully qualified java names of generated
-     * ServiceInterface classes, values are identity local names.
+     * @return services implemented by this module. Keys are fully qualified
+     *         java names of generated ServiceInterface classes, values are
+     *         identity local names.
      */
     public Map<String, QName> getProvidedServices() {
         return providedServices;
@@ -338,7 +344,7 @@ public class ModuleMXBeanEntry extends AbstractEntry {
                                 moduleLocalNameFromXPath);
                         yangToAttributes = fillConfiguration(choiceCaseNode,
                                 currentModule, typeProviderWrapper,
-                                qNamesToSIEs, schemaContext);
+                                qNamesToSIEs, schemaContext, packageName);
                         checkUniqueAttributesWithGeneratedClass(
                                 uniqueGeneratedClassesNames, when.getQName(),
                                 yangToAttributes);
@@ -356,7 +362,6 @@ public class ModuleMXBeanEntry extends AbstractEntry {
                                     e.getConflictingName(), when.getQName(),
                                     when.getQName());
                         }
-
                         checkUniqueRuntimeBeansGeneratedClasses(
                                 uniqueGeneratedClassesNames, when, runtimeBeans);
                         Set<RuntimeBeanEntry> runtimeBeanEntryValues = Sets
@@ -411,6 +416,11 @@ public class ModuleMXBeanEntry extends AbstractEntry {
                         .<RuntimeBeanEntry> emptyList());
             }
         }
+        // check attributes name uniqueness
+        for (Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
+            checkUniqueRuntimeBeanAttributesName(entry.getValue(),
+                    uniqueGeneratedClassesNames);
+        }
         if (unaugmentedModuleIdentities.size() > 0) {
             logger.warn("Augmentation not found for all module identities: {}",
                     unaugmentedModuleIdentities.keySet());
@@ -439,6 +449,25 @@ public class ModuleMXBeanEntry extends AbstractEntry {
         }
     }
 
+    private static void checkUniqueRuntimeBeanAttributesName(
+            ModuleMXBeanEntry mxBeanEntry,
+            Map<String, QName> uniqueGeneratedClassesNames) {
+        for (RuntimeBeanEntry runtimeBeanEntry : mxBeanEntry.getRuntimeBeans()) {
+            for (String runtimeAttName : runtimeBeanEntry
+                    .getYangPropertiesToTypesMap().keySet()) {
+                if (mxBeanEntry.getAttributes().keySet()
+                        .contains(runtimeAttName)) {
+                    QName qName1 = uniqueGeneratedClassesNames
+                            .get(runtimeBeanEntry.getJavaNameOfRuntimeMXBean());
+                    QName qName2 = uniqueGeneratedClassesNames.get(mxBeanEntry
+                            .getGloballyUniqueName());
+                    throw new NameConflictException(runtimeAttName, qName1,
+                            qName2);
+                }
+            }
+        }
+    }
+
     private static void checkUniqueAttributesWithGeneratedClass(
             Map<String, QName> uniqueGeneratedClassNames, QName parentQName,
             Map<String, AttributeIfc> yangToAttributes) {
@@ -484,12 +513,12 @@ public class ModuleMXBeanEntry extends AbstractEntry {
             ChoiceCaseNode choiceCaseNode, Module currentModule,
             TypeProviderWrapper typeProviderWrapper,
             Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
-            SchemaContext schemaContext) {
+            SchemaContext schemaContext, String packageName) {
         Map<String, AttributeIfc> yangToAttributes = new HashMap<>();
         for (DataSchemaNode attrNode : choiceCaseNode.getChildNodes()) {
             AttributeIfc attributeValue = getAttributeValue(attrNode,
                     currentModule, qNamesToSIEs, typeProviderWrapper,
-                    schemaContext);
+                    schemaContext, packageName);
             yangToAttributes.put(attributeValue.getAttributeYangName(),
                     attributeValue);
         }
@@ -549,11 +578,12 @@ public class ModuleMXBeanEntry extends AbstractEntry {
         }
     }
 
-    private static int getChildNodeSizeWithoutUses(ContainerSchemaNode csn) {
+    private static int getChildNodeSizeWithoutUses(DataNodeContainer csn) {
         int result = 0;
         for (DataSchemaNode dsn : csn.getChildNodes()) {
-            if (dsn.isAddedByUses() == false)
+            if (dsn.isAddedByUses() == false) {
                 result++;
+            }
         }
         return result;
     }
@@ -561,7 +591,8 @@ public class ModuleMXBeanEntry extends AbstractEntry {
     private static AttributeIfc getAttributeValue(DataSchemaNode attrNode,
             Module currentModule,
             Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
-            TypeProviderWrapper typeProviderWrapper, SchemaContext schemaContext) {
+            TypeProviderWrapper typeProviderWrapper,
+            SchemaContext schemaContext, String packageName) {
 
         if (attrNode instanceof LeafSchemaNode) {
             // simple type
@@ -570,49 +601,80 @@ public class ModuleMXBeanEntry extends AbstractEntry {
         } else if (attrNode instanceof ContainerSchemaNode) {
             // reference or TO
             ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) attrNode;
-            if (containerSchemaNode.getUses().size() == 1
-                    && getChildNodeSizeWithoutUses(containerSchemaNode) == 0) {
-                // reference
-                UsesNode usesNode = containerSchemaNode.getUses().iterator()
-                        .next();
-                checkState(usesNode.getRefines().size() == 1,
-                        "Unexpected 'refine' child node size of "
-                                + containerSchemaNode);
-                LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines()
-                        .values().iterator().next();
-                checkState(refine.getUnknownSchemaNodes().size() == 1,
-                        "Unexpected unknown schema node size of " + refine);
-                UnknownSchemaNode requiredIdentity = refine
-                        .getUnknownSchemaNodes().iterator().next();
-                checkState(
-                        ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity
-                                .getNodeType()),
-                        "Unexpected language extension " + requiredIdentity);
-                String prefixAndIdentityLocalName = requiredIdentity
-                        .getNodeParameter();
-                // import should point to a module
-                ServiceInterfaceEntry serviceInterfaceEntry = findSIE(
-                        prefixAndIdentityLocalName, currentModule,
-                        qNamesToSIEs, schemaContext);
-                boolean mandatory = refine.getConstraints().isMandatory();
-                return new DependencyAttribute(attrNode, serviceInterfaceEntry,
-                        mandatory, attrNode.getDescription());
+            Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
+                    containerSchemaNode, attrNode, currentModule, qNamesToSIEs,
+                    schemaContext);
+            if (dependencyAttributeOptional.isPresent()) {
+                return dependencyAttributeOptional.get();
             } else {
                 return TOAttribute.create(containerSchemaNode,
-                        typeProviderWrapper);
+                        typeProviderWrapper, packageName);
             }
+
         } else if (attrNode instanceof LeafListSchemaNode) {
             return ListAttribute.create((LeafListSchemaNode) attrNode,
                     typeProviderWrapper);
         } else if (attrNode instanceof ListSchemaNode) {
-            return ListAttribute.create((ListSchemaNode) attrNode,
-                    typeProviderWrapper);
+            ListSchemaNode listSchemaNode = (ListSchemaNode) attrNode;
+            Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
+                    listSchemaNode, attrNode, currentModule, qNamesToSIEs,
+                    schemaContext);
+            if (dependencyAttributeOptional.isPresent()) {
+                return dependencyAttributeOptional.get();
+            } else {
+                return ListAttribute.create(listSchemaNode,
+                        typeProviderWrapper, packageName);
+            }
         } else {
             throw new UnsupportedOperationException(
                     "Unknown configuration node " + attrNode.toString());
         }
     }
 
+    private static Optional<? extends AbstractDependencyAttribute> extractDependency(
+            DataNodeContainer dataNodeContainer, DataSchemaNode attrNode,
+            Module currentModule,
+            Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
+            SchemaContext schemaContext) {
+        if (dataNodeContainer.getUses().size() == 1
+                && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) {
+            // reference
+            UsesNode usesNode = dataNodeContainer.getUses().iterator().next();
+            checkState(usesNode.getRefines().size() == 1,
+                    "Unexpected 'refine' child node size of "
+                            + dataNodeContainer);
+            LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines()
+                    .values().iterator().next();
+            checkState(refine.getUnknownSchemaNodes().size() == 1,
+                    "Unexpected unknown schema node size of " + refine);
+            UnknownSchemaNode requiredIdentity = refine.getUnknownSchemaNodes()
+                    .iterator().next();
+            checkState(
+                    ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity
+                            .getNodeType()), "Unexpected language extension "
+                            + requiredIdentity);
+            String prefixAndIdentityLocalName = requiredIdentity
+                    .getNodeParameter();
+            // import should point to a module
+            ServiceInterfaceEntry serviceInterfaceEntry = findSIE(
+                    prefixAndIdentityLocalName, currentModule, qNamesToSIEs,
+                    schemaContext);
+            boolean mandatory = refine.getConstraints().isMandatory();
+            AbstractDependencyAttribute reference;
+            if (dataNodeContainer instanceof ContainerSchemaNode) {
+                reference = new DependencyAttribute(attrNode,
+                        serviceInterfaceEntry, mandatory,
+                        attrNode.getDescription());
+            } else {
+                reference = new ListDependenciesAttribute(attrNode,
+                        serviceInterfaceEntry, mandatory,
+                        attrNode.getDescription());
+            }
+            return Optional.of(reference);
+        }
+        return Optional.absent();
+    }
+
     private static ServiceInterfaceEntry findSIE(
             String prefixAndIdentityLocalName, Module currentModule,
             Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
index 9b82f123caf97f88a40b813d507c29ab2a06ee00..f19a46d0f461e35a1ecf9dd97e05aa1500a821df 100644 (file)
@@ -67,7 +67,7 @@ public class RuntimeBeanEntry {
     private final Set<Rpc> rpcs;
 
     @VisibleForTesting
-    public RuntimeBeanEntry(String packageName,
+    RuntimeBeanEntry(String packageName,
             DataSchemaNode nodeForReporting, String yangName,
             String javaNamePrefix, boolean isRoot,
             Optional<String> keyYangName, List<AttributeIfc> attributes,
@@ -228,7 +228,7 @@ public class RuntimeBeanEntry {
                 ContainerSchemaNode container = (ContainerSchemaNode) child;
                 // this can be either TO or hierarchical RB
                 TOAttribute toAttribute = TOAttribute.create(container,
-                        typeProviderWrapper);
+                        typeProviderWrapper, packageName);
                 attributes.add(toAttribute);
             } else if (child instanceof ListSchemaNode) {
                 if (isInnerStateBean(child)) {
@@ -239,7 +239,7 @@ public class RuntimeBeanEntry {
                     runtimeBeanEntries.add(hierarchicalChild);
                 } else /* ordinary list attribute */{
                     ListAttribute listAttribute = ListAttribute.create(
-                            (ListSchemaNode) child, typeProviderWrapper);
+                            (ListSchemaNode) child, typeProviderWrapper, packageName);
                     attributes.add(listAttribute);
                 }
 
@@ -280,7 +280,7 @@ public class RuntimeBeanEntry {
                     } else if (rpcDefinition.getOutput().getChildNodes().size() == 1) {
                         DataSchemaNode returnDSN = rpcDefinition.getOutput()
                                 .getChildNodes().iterator().next();
-                        returnType = getReturnTypeAttribute(returnDSN, typeProviderWrapper);
+                        returnType = getReturnTypeAttribute(returnDSN, typeProviderWrapper, packageName);
 
                     } else {
                         throw new IllegalArgumentException(
@@ -311,16 +311,17 @@ public class RuntimeBeanEntry {
                 attributes, rpcs);
     }
 
-    private static AttributeIfc getReturnTypeAttribute(DataSchemaNode child, TypeProviderWrapper typeProviderWrapper) {
+    private static AttributeIfc getReturnTypeAttribute(DataSchemaNode child, TypeProviderWrapper typeProviderWrapper,
+                                                       String packageName) {
         if (child instanceof LeafSchemaNode) {
             LeafSchemaNode leaf = (LeafSchemaNode) child;
             return new JavaAttribute(leaf, typeProviderWrapper);
         } else if (child instanceof ContainerSchemaNode) {
             ContainerSchemaNode container = (ContainerSchemaNode) child;
-            TOAttribute toAttribute = TOAttribute.create(container, typeProviderWrapper);
+            TOAttribute toAttribute = TOAttribute.create(container, typeProviderWrapper, packageName);
             return toAttribute;
         } else if (child instanceof ListSchemaNode) {
-            return ListAttribute.create((ListSchemaNode) child, typeProviderWrapper);
+            return ListAttribute.create((ListSchemaNode) child, typeProviderWrapper, packageName);
         } else if (child instanceof LeafListSchemaNode) {
             return ListAttribute.create((LeafListSchemaNode) child, typeProviderWrapper);
         } else {
index a2238d1a13da854c07df8278c697e8fddd15bdd2..764ecd38868c7b224c1c8e0065d7989f8126fa37 100644 (file)
@@ -26,6 +26,10 @@ public class TypeProviderWrapper {
         return getType(leaf, type);
     }
 
+    public String getDefault(LeafSchemaNode node) {
+        return typeProvider.getTypeDefaultConstruction(node);
+    }
+
     public Type getType(SchemaNode leaf, TypeDefinition<?> type) {
         Type javaType;
         try {
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
new file mode 100644 (file)
index 0000000..eb1c9e4
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yangjmxgenerator.attribute;
+
+import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+public abstract class AbstractDependencyAttribute extends AbstractAttribute  implements TypedAttribute  {
+
+    protected final Dependency dependency;
+    protected final String nullableDescription, nullableDefault;
+
+    public AbstractDependencyAttribute(DataSchemaNode attrNode,
+                                       ServiceInterfaceEntry sie, boolean mandatory,
+                                       String nullableDescription) {
+        super(attrNode);
+        dependency = new Dependency(sie, mandatory);
+        this.nullableDescription = nullableDescription;
+        nullableDefault = null;
+    }
+
+    public Dependency getDependency() {
+        return dependency;
+    }
+
+    @Override
+    public String getNullableDescription() {
+        return nullableDescription;
+    }
+
+    @Override
+    public String getNullableDefault() {
+        return nullableDefault;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        if (!super.equals(o))
+            return false;
+
+        AbstractDependencyAttribute that = (AbstractDependencyAttribute) o;
+
+        if (dependency != null ? !dependency.equals(that.dependency)
+                : that.dependency != null)
+            return false;
+        if (nullableDefault != null ? !nullableDefault
+                .equals(that.nullableDefault) : that.nullableDefault != null)
+            return false;
+        if (nullableDescription != null ? !nullableDescription
+                .equals(that.nullableDescription)
+                : that.nullableDescription != null)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = 31 * result + (dependency != null ? dependency.hashCode() : 0);
+        result = 31
+                * result
+                + (nullableDescription != null ? nullableDescription.hashCode()
+                        : 0);
+        result = 31 * result
+                + (nullableDefault != null ? nullableDefault.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getName() + "{" + getAttributeYangName() + ","
+                + "dependency=" + dependency + '}';
+    }
+
+
+}
diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/Dependency.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/Dependency.java
new file mode 100644 (file)
index 0000000..38de6e1
--- /dev/null
@@ -0,0 +1,45 @@
+package org.opendaylight.controller.config.yangjmxgenerator.attribute;
+
+import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
+
+public class Dependency {
+        private final ServiceInterfaceEntry sie;
+        private final boolean mandatory;
+
+        public Dependency(ServiceInterfaceEntry sie, boolean mandatory) {
+            this.sie = sie;
+            this.mandatory = mandatory;
+        }
+
+        public ServiceInterfaceEntry getSie() {
+            return sie;
+        }
+
+        public boolean isMandatory() {
+            return mandatory;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            Dependency that = (Dependency) o;
+
+            if (mandatory != that.mandatory)
+                return false;
+            if (!sie.equals(that.sie))
+                return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = sie.hashCode();
+            result = 31 * result + (mandatory ? 1 : 0);
+            return result;
+        }
+    }
index 1912b75e0ee740c31634c2e709650a7d0c33728a..d8df78af0ae7103660241e8842064d0def753c47 100644 (file)
@@ -15,19 +15,13 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import javax.management.ObjectName;
 import javax.management.openmbean.SimpleType;
 
-public class DependencyAttribute extends AbstractAttribute implements
-        TypedAttribute {
+public class DependencyAttribute extends AbstractDependencyAttribute {
 
-    private final Dependency dependency;
-    private final String nullableDescription, nullableDefault;
 
     public DependencyAttribute(DataSchemaNode attrNode,
             ServiceInterfaceEntry sie, boolean mandatory,
             String nullableDescription) {
-        super(attrNode);
-        dependency = new Dependency(sie, mandatory);
-        this.nullableDescription = nullableDescription;
-        nullableDefault = null;
+        super(attrNode, sie, mandatory, nullableDescription);
     }
 
     @Override
@@ -35,109 +29,9 @@ public class DependencyAttribute extends AbstractAttribute implements
         return Types.typeForClass(ObjectName.class);
     }
 
-    public Dependency getDependency() {
-        return dependency;
-    }
-
-    @Override
-    public String getNullableDescription() {
-        return nullableDescription;
-    }
-
-    @Override
-    public String getNullableDefault() {
-        return nullableDefault;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        if (o == null || getClass() != o.getClass())
-            return false;
-        if (!super.equals(o))
-            return false;
-
-        DependencyAttribute that = (DependencyAttribute) o;
-
-        if (dependency != null ? !dependency.equals(that.dependency)
-                : that.dependency != null)
-            return false;
-        if (nullableDefault != null ? !nullableDefault
-                .equals(that.nullableDefault) : that.nullableDefault != null)
-            return false;
-        if (nullableDescription != null ? !nullableDescription
-                .equals(that.nullableDescription)
-                : that.nullableDescription != null)
-            return false;
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = super.hashCode();
-        result = 31 * result + (dependency != null ? dependency.hashCode() : 0);
-        result = 31
-                * result
-                + (nullableDescription != null ? nullableDescription.hashCode()
-                        : 0);
-        result = 31 * result
-                + (nullableDefault != null ? nullableDefault.hashCode() : 0);
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "DependencyAttribute{" + getAttributeYangName() + ","
-                + "dependency=" + dependency + '}';
-    }
-
     @Override
     public SimpleType<?> getOpenType() {
         return SimpleType.OBJECTNAME;
     }
 
-    public static class Dependency {
-        private final ServiceInterfaceEntry sie;
-        private final boolean mandatory;
-
-        public Dependency(ServiceInterfaceEntry sie, boolean mandatory) {
-            this.sie = sie;
-            this.mandatory = mandatory;
-        }
-
-        public ServiceInterfaceEntry getSie() {
-            return sie;
-        }
-
-        public boolean isMandatory() {
-            return mandatory;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o)
-                return true;
-            if (o == null || getClass() != o.getClass())
-                return false;
-
-            Dependency that = (Dependency) o;
-
-            if (mandatory != that.mandatory)
-                return false;
-            if (!sie.equals(that.sie))
-                return false;
-
-            return true;
-        }
-
-        @Override
-        public int hashCode() {
-            int result = sie.hashCode();
-            result = 31 * result + (mandatory ? 1 : 0);
-            return result;
-        }
-    }
-
 }
index 325ca9ee06fd1bd9d29d56a94cedc0871aac77c7..3e20e4a55ad47f58e538a33594d1f5d4f0e70d32 100644 (file)
@@ -22,7 +22,7 @@ import javax.management.openmbean.SimpleType;
 public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
 
     private final Type type;
-    private final String nullableDescription, nullableDefault;
+    private final String nullableDescription, nullableDefault, nullableDefaultWrappedForCode;
     private final TypeProviderWrapper typeProviderWrapper;
     private final TypeDefinition<?> typeDefinition;
 
@@ -33,6 +33,7 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
         this.typeDefinition = leaf.getType();
         this.typeProviderWrapper = typeProviderWrapper;
         this.nullableDefault = leaf.getDefault();
+        this.nullableDefaultWrappedForCode = leaf.getDefault() == null ? null : typeProviderWrapper.getDefault(leaf);
         this.nullableDescription = leaf.getDescription();
     }
 
@@ -42,10 +43,14 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
         this.type = typeProviderWrapper.getType(leaf);
         this.typeDefinition = leaf.getType();
         this.typeProviderWrapper = typeProviderWrapper;
-        this.nullableDefault = null;
+        this.nullableDefault = nullableDefaultWrappedForCode = null;
         this.nullableDescription = leaf.getDescription();
     }
 
+    public TypeDefinition<?> getTypeDefinition() {
+        return typeDefinition;
+    }
+
     /**
      * Returns the most base type
      */
@@ -56,6 +61,10 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
         return baseType;
     }
 
+    public String getNullableDefaultWrappedForCode() {
+        return nullableDefaultWrappedForCode;
+    }
+
     @Override
     public Type getType() {
         return type;
index 083b0b53e9777c2391acafb65e72011267800183..73b557e291c03385823fb214fb0a96054d2b6610 100644 (file)
@@ -7,24 +7,27 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.attribute;
 
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.OpenType;
-
 import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
+import org.opendaylight.yangtools.binding.generator.util.Types;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 
-public class ListAttribute extends AbstractAttribute {
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import java.util.List;
+
+public class ListAttribute extends AbstractAttribute implements TypedAttribute {
 
     private final String nullableDescription, nullableDefault;
-    private final AttributeIfc innerAttribute;
+    private final TypedAttribute innerAttribute;
 
     public static ListAttribute create(ListSchemaNode node,
-            TypeProviderWrapper typeProvider) {
+            TypeProviderWrapper typeProvider, String packageName) {
 
-        AttributeIfc innerAttribute = TOAttribute.create(node, typeProvider);
+        TOAttribute innerAttribute = TOAttribute.create(node, typeProvider, packageName);
 
         return new ListAttribute(node, innerAttribute, node.getDescription());
     }
@@ -32,12 +35,12 @@ public class ListAttribute extends AbstractAttribute {
     public static ListAttribute create(LeafListSchemaNode node,
             TypeProviderWrapper typeProvider) {
 
-        AttributeIfc innerAttribute = new JavaAttribute(node, typeProvider);
+        JavaAttribute innerAttribute = new JavaAttribute(node, typeProvider);
 
         return new ListAttribute(node, innerAttribute, node.getDescription());
     }
 
-    ListAttribute(DataSchemaNode attrNode, AttributeIfc innerAttribute,
+    ListAttribute(DataSchemaNode attrNode, TypedAttribute innerAttribute,
             String description) {
         super(attrNode);
         this.nullableDescription = description;
@@ -99,14 +102,24 @@ public class ListAttribute extends AbstractAttribute {
         return true;
     }
 
+
+    @Override
+    public Type getType() {
+        return Types.parameterizedTypeFor(Types.typeForClass(List.class), innerAttribute.getType());
+    }
+
     @Override
     public ArrayType<?> getOpenType() {
-        OpenType<?> inerOpenType = innerAttribute.getOpenType();
+        OpenType<?> innerOpenType = innerAttribute.getOpenType();
+        return constructArrayType(innerOpenType);
+    }
+
+    static ArrayType<?> constructArrayType(OpenType<?> innerOpenType){
         try {
-            return new ArrayType<>(1, inerOpenType);
+            return new ArrayType<>(1, innerOpenType);
         } catch (OpenDataException e) {
             throw new RuntimeException("Unable to create " + ArrayType.class
-                    + " with inner element of type " + inerOpenType, e);
+                    + " with inner element of type " + innerOpenType, e);
         }
     }
 
diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListDependenciesAttribute.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListDependenciesAttribute.java
new file mode 100644 (file)
index 0000000..641099a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.config.yangjmxgenerator.attribute;
+
+import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
+import org.opendaylight.yangtools.binding.generator.util.Types;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+import javax.management.ObjectName;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import java.util.List;
+
+public class ListDependenciesAttribute extends AbstractDependencyAttribute {
+
+    public ListDependenciesAttribute(DataSchemaNode attrNode, ServiceInterfaceEntry sie, boolean mandatory, String nullableDescription) {
+        super(attrNode, sie, mandatory, nullableDescription);
+    }
+
+    @Override
+    public Type getType() {
+        return Types.parameterizedTypeFor(Types.typeForClass(List.class), Types.typeForClass(ObjectName.class));
+    }
+
+    @Override
+    public ArrayType<?> getOpenType() {
+        OpenType<?> innerOpenType = SimpleType.OBJECTNAME;
+        return ListAttribute.constructArrayType(innerOpenType);
+    }
+
+}
index 96656338df130f30ef569fbb54537727ff9a0b3a..6a540b50b21dab04433dcb349eb905a9a2cd303b 100644 (file)
@@ -13,6 +13,8 @@ import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
@@ -29,11 +31,12 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
-public class TOAttribute extends AbstractAttribute {
+public class TOAttribute extends AbstractAttribute implements TypedAttribute {
 
     private final String nullableDescription, nullableDefault;
     private final Map<String, AttributeIfc> yangNameToAttributeMap;
     private final Map<String, String> attributeNameMap;
+    private final String packageName;
 
     private static final Set<Class<? extends DataSchemaNode>> ALLOWED_CHILDREN = Sets
             .newHashSet();
@@ -45,7 +48,7 @@ public class TOAttribute extends AbstractAttribute {
     }
 
     public static <T extends DataNodeContainer & AugmentationTarget & DataSchemaNode> TOAttribute create(
-            T containerSchemaNode, TypeProviderWrapper typeProviderWrapper) {
+            T containerSchemaNode, TypeProviderWrapper typeProviderWrapper, String packageName) {
         // Transfer Object: get the leaves
         Map<String, AttributeIfc> map = new HashMap<>();
         Map<String, String> attributeNameMap = new HashMap<>();
@@ -55,18 +58,18 @@ public class TOAttribute extends AbstractAttribute {
                 String yangName = dataSchemaNode.getQName().getLocalName();
                 map.put(yangName,
                         createInnerAttribute(dataSchemaNode,
-                                typeProviderWrapper));
+                                typeProviderWrapper, packageName));
             } catch (IllegalArgumentException e) {
                 throw new IllegalStateException("Unable to create TO", e);
             }
         }
         return new TOAttribute(containerSchemaNode, map, attributeNameMap,
-                containerSchemaNode.getDescription());
+                containerSchemaNode.getDescription(), packageName);
     }
 
     private static AttributeIfc createInnerAttribute(
             DataSchemaNode dataSchemaNode,
-            TypeProviderWrapper typeProviderWrapper) {
+            TypeProviderWrapper typeProviderWrapper, String packageName) {
         Class<? extends DataSchemaNode> type = isAllowedType(dataSchemaNode);
 
         if (type.equals(LeafSchemaNode.class))
@@ -74,13 +77,13 @@ public class TOAttribute extends AbstractAttribute {
                     typeProviderWrapper);
         else if (type.equals(ListSchemaNode.class))
             return ListAttribute.create((ListSchemaNode) dataSchemaNode,
-                    typeProviderWrapper);
+                    typeProviderWrapper, packageName);
         else if (type.equals(LeafListSchemaNode.class))
             return ListAttribute.create((LeafListSchemaNode) dataSchemaNode,
                     typeProviderWrapper);
         else if (type.equals(ContainerSchemaNode.class))
             return TOAttribute.create((ContainerSchemaNode) dataSchemaNode,
-                    typeProviderWrapper);
+                    typeProviderWrapper, packageName);
 
         throw new IllegalStateException("This should never happen");
     }
@@ -98,12 +101,13 @@ public class TOAttribute extends AbstractAttribute {
 
     private TOAttribute(DataSchemaNode attrNode,
             Map<String, AttributeIfc> transferObject,
-            Map<String, String> attributeNameMap, String nullableDescription) {
+            Map<String, String> attributeNameMap, String nullableDescription, String packageName) {
         super(attrNode);
         yangNameToAttributeMap = transferObject;
         this.attributeNameMap = attributeNameMap;
         this.nullableDescription = nullableDescription;
         nullableDefault = null;
+        this.packageName = packageName;
     }
 
     public Map<String, String> getAttributeNameMap() {
@@ -197,6 +201,12 @@ public class TOAttribute extends AbstractAttribute {
                 + yangNameToAttributeMap + '}';
     }
 
+    @Override
+    public Type getType() {
+        // TODO: ReferencedTypeImpl from Types
+        return new ReferencedTypeImpl(packageName, getUpperCaseCammelCase());
+    }
+
     @Override
     public CompositeType getOpenType() {
         String description = getNullableDescription() == null ? getAttributeYangName()
@@ -222,6 +232,10 @@ public class TOAttribute extends AbstractAttribute {
         }
     }
 
+    public String getPackageName() {
+        return packageName;
+    }
+
     private static final class FunctionImpl implements
             Function<Entry<String, AttributeIfc>, OpenType<?>> {
         private final String[] itemNames;
index deef08a292e6d5a7853796effeaa85fc5096773e..9032a2c9306ca38f537028984f05812ca24f6e2a 100644 (file)
@@ -100,6 +100,9 @@ public class ModuleMXBeanEntryNameConflictTest extends AbstractYangTest {
         testedYangModulesToExpectedConflictingName.put(
                 "config-test-runtime-bean-name-conflict2",
                 "StateARuntimeMXBean");
+        testedYangModulesToExpectedConflictingName.put(
+                "config-test-duplicate-attribute-in-runtime-and-mxbean",
+                "port");
     }
 
     private String getYangModuleName(String name) {
index 661dbd7da344e6006e393313cd3f80a2ea9b90cd..e86c87616941d297cb3752a6f727203269a09b3d 100644 (file)
@@ -7,38 +7,14 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.SimpleType;
-
+import com.google.common.collect.Sets;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute;
 import org.opendaylight.yangtools.binding.generator.util.Types;
@@ -48,13 +24,37 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
 
-import com.google.common.collect.Sets;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.SimpleType;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 
 public class ModuleMXBeanEntryTest extends AbstractYangTest {
     public static final String EVENTBUS_MXB_NAME = "eventbus";
     public static final String ASYNC_EVENTBUS_MXB_NAME = "async-eventbus";
     public static final String THREADFACTORY_NAMING_MXB_NAME = "threadfactory-naming";
     public static final String THREADPOOL_DYNAMIC_MXB_NAME = "threadpool-dynamic";
+    public static final String THREADPOOL_REGISTRY_IMPL_NAME = "threadpool-registry-impl";
 
     public static final String BGP_LISTENER_IMPL_MXB_NAME = "bgp-listener-impl";
 
@@ -87,7 +87,7 @@ public class ModuleMXBeanEntryTest extends AbstractYangTest {
         assertNotNull(namesToMBEs);
         Set<String> expectedMXBeanNames = Sets.newHashSet(EVENTBUS_MXB_NAME,
                 ASYNC_EVENTBUS_MXB_NAME, THREADFACTORY_NAMING_MXB_NAME,
-                THREADPOOL_DYNAMIC_MXB_NAME);
+                THREADPOOL_DYNAMIC_MXB_NAME, THREADPOOL_REGISTRY_IMPL_NAME);
         assertThat(namesToMBEs.keySet(), is(expectedMXBeanNames));
         return namesToMBEs;
     }
@@ -299,6 +299,15 @@ public class ModuleMXBeanEntryTest extends AbstractYangTest {
             }
 
         }
+        { // test multiple dependencies
+            ModuleMXBeanEntry threadPoolRegistry = namesToMBEs.get(THREADPOOL_REGISTRY_IMPL_NAME);
+            Map<String, AttributeIfc> attributes = threadPoolRegistry.getAttributes();
+            assertEquals(1, attributes.size());
+            AttributeIfc threadpoolsAttr = attributes.get("threadpools");
+            assertNotNull(threadpoolsAttr);
+            assertTrue(threadpoolsAttr instanceof ListDependenciesAttribute);
+            ListDependenciesAttribute threadpools = (ListDependenciesAttribute) threadpoolsAttr;
+        }
     }
 
 }
index 24c025755bdc906219d247c2cfe033cacffa5be8..14ec7e0fdc9bfae4b97dd5ffe2705f67834b0e61 100644 (file)
@@ -100,10 +100,15 @@ public class SchemaContextTest extends AbstractYangTest {
 
     @Test
     public void testReadingIdentities_threadsJavaModule() {
-        Map<String /* identity name */, Optional<QName>> expectedIdentitiesToBases = ImmutableMap
-                .of("eventbus", Optional.of(MODULE_TYPE_Q_NAME), "async-eventbus", Optional.of(MODULE_TYPE_Q_NAME),
-                        "threadfactory-naming", Optional.of(MODULE_TYPE_Q_NAME), "threadpool-dynamic",
-                        Optional.of(MODULE_TYPE_Q_NAME), "thread-rpc-context", Optional.<QName>absent());
+        Map<String /* identity name */, Optional<QName>> expectedIdentitiesToBases = new HashMap(){{
+            put(ModuleMXBeanEntryTest.EVENTBUS_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+            put(ModuleMXBeanEntryTest.ASYNC_EVENTBUS_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+            put(ModuleMXBeanEntryTest.THREADFACTORY_NAMING_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+            put(ModuleMXBeanEntryTest.THREADPOOL_DYNAMIC_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+            put("thread-rpc-context", Optional.absent());
+            put(ModuleMXBeanEntryTest.THREADPOOL_REGISTRY_IMPL_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+        }};
+
         assertAllIdentitiesAreExpected(threadsJavaModule,
                 expectedIdentitiesToBases);
     }
diff --git a/opendaylight/config/yang-jmx-generator/src/test/resources/duplicates/config-test-duplicate-attribute-in-runtime-and-mxbean.yang b/opendaylight/config/yang-jmx-generator/src/test/resources/duplicates/config-test-duplicate-attribute-in-runtime-and-mxbean.yang
new file mode 100644 (file)
index 0000000..58c3af2
--- /dev/null
@@ -0,0 +1,57 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module config-test-duplicate-attribute-in-runtime-and-mxbean {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:jmx:duplicate:runtime";
+    prefix "th-java";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import rpc-context { prefix rpcx; revision-date 2013-06-17; }
+    import ietf-inet-types { prefix inet; revision-date 2010-09-24;}
+
+
+    description
+        "This module contains the base YANG definitions for NS-OS
+         thread services pure Java implementation.";
+
+    revision "2013-04-05" {
+        description
+            "Updated to work with new anchors.";
+    }
+
+    revision "2013-04-03" {
+        description
+            "Initial revision.";
+    }
+
+   identity async-eventbus {
+        base config:module-type;
+        config:java-name-prefix AsyncEventBus;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case async-eventbus {
+            when "/config:modules/config:module/config:type = 'async-eventbus'";
+            leaf port {
+                type string;
+            }
+            leaf core-size {
+                type uint32;
+            }
+            leaf simple-int3 {
+                type uint16;
+            }
+        }
+    }
+
+    augment "/config:modules/config:module/config:state" {
+        case async-eventbus {
+            when "/config:modules/config:module/config:type = 'async-eventbus'";
+            leaf simple-arg {
+                type uint32;
+            }
+            leaf port {
+                type inet:port-number;
+            }
+        }
+    }
+}
\ No newline at end of file
index 2972cec04fc7eefe607fd94e0441a92656ca93b1..4af5b9569a445dfba4d601d18c7f76bf0f64ba0a 100644 (file)
@@ -241,4 +241,25 @@ module config-threads-java {
             }
         }
     }
+
+    identity threadpool-registry-impl {
+        base config:module-type;
+        config:java-name-prefix ThreadPoolRegistryImpl;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case threadpool-registry-impl {
+            when "/config:modules/config:module/config:type = 'threadpool-registry-impl'";
+
+            // list of dependencies:
+            list threadpools {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity th2:threadpool;
+                    }
+                }
+            }
+        }
+    }
 }
index ba5021ea099361fd5d548e318a6448811020177f..9ad7a44915b15bdfbce7a64cbdaf2eb02f8bba14 100644 (file)
@@ -48,28 +48,40 @@ module config-test-impl {
            container dto-a {
                 leaf simple-arg {
                     type uint32;
+                    default 1;
                 }
 
                 leaf port {
                     type inet:port-number;
+                    default 8080;
                 }
 
+                leaf ip4 {
+                    type inet:ipv4-address;
+                    default 127.0.0.1;
+                }
+
+                leaf ip {
+                    type inet:ip-address;
+                    // TODO defaults for union default 0:0:0:0:0:0:0:1;
+                }
             }
 
             leaf as-number {
-                mandatory true;
                 type inet:as-number;
+                default 44;
             }
 
 
             leaf simpleInt {
                 type uint32;
-                default 99L;
+                default 99;
             }
 
             container dto_b {
                 leaf simple-int1 {
                     type uint32;
+                    default 32;
                 }
 
                 leaf simple-int2 {
@@ -101,28 +113,34 @@ module config-test-impl {
             when "/config:modules/config:module/config:type = 'impl-netconf'";
             leaf binaryLeaf {
                 type binary;
+                default ZGVmYXVsdEJpbg==;
             }
 
             leaf type {
                 type string;
+                default "default-string";
             }
 
             leaf extended {
                 type tt:extend-once;
+                default 1;
             }
 
             leaf extended-twice {
                 type tt:extend-twice;
+                default 2;
             }
 
             leaf extended-enum {
                 type tt:extend-enum;
+                default ONE;
             }
 
             leaf sleep-factor {
                 type decimal64 {
                     fraction-digits 2;
                 }
+                default 2.00;
             }
 
            container dto-c {
@@ -153,23 +171,28 @@ module config-test-impl {
             }
 
             leaf simple-long {
-                type int64  ;
+                type int64;
+                default -45;
             }
 
             leaf simple-long-2 {
                 type uint32;
+                default 445;
             }
 
             leaf simple-BigInteger {
                 type uint64;
+                default 545454;
             }
 
             leaf simple-byte {
                 type int8;
+                default -4;
             }
 
             leaf simple-short {
                 type uint8;
+                default 45;
             }
 
             leaf simple-test {
@@ -209,6 +232,7 @@ module config-test-impl {
                     container deep {
                         leaf simple-int3 {
                             type uint16;
+                            default 0;
                         }
                     }
                 }
@@ -242,6 +266,15 @@ module config-test-impl {
                     }
                 }
             }
+
+            list testing-deps {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity test:testing;
+                    }
+                }
+            }
         }
     }
 
@@ -384,6 +417,7 @@ module config-test-impl {
             container retValContainer {
                 leaf v1 {
                     type string;
+                    default "from rpc";
                 }
 
                 leaf v2 {
index adc0c0973f76309d60b474c5e1dfbddc5fa23e9d..4c0b81f7d71a4e4ce9a15c527050bfe23977740c 100644 (file)
          <groupId>org.opendaylight.controller.thirdparty</groupId>
          <artifactId>ganymed</artifactId>
         </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-remoterpc-connector</artifactId>
+          <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>
+                  zeromq-routingtable.implementation
+              </artifactId>
+              <version>0.4.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+              <groupId>org.zeromq</groupId>
+              <artifactId>jeromq</artifactId>
+              <version>0.3.1</version>
+          </dependency>
       </dependencies>
     </profile>
     <profile>
index e83fdcc5c885eac73f9d9837e0f5758ea2240499..c2f9bc311dc18b8cbde89c2c964c1fde73ad5939 100644 (file)
                <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-threadgroup</type>
                <instance>
                        <name>global-boss-group</name>
-                       <provider>/config/modules/module[name='netty-threadgroup-fixed']/instance[name='global-boss-group']</provider>
+                       <provider>/modules/module[type='netty-threadgroup-fixed'][name='global-boss-group']</provider>
                </instance>
                <instance>
                        <name>global-worker-group</name>
-                       <provider>/config/modules/module[name='netty-threadgroup-fixed']/instance[name='global-worker-group']</provider>
+                       <provider>/modules/module[type='netty-threadgroup-fixed'][name='global-worker-group']</provider>
                </instance>
        </service>
        <service>
                <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-event-executor</type>
                <instance>
                        <name>global-event-executor</name>
-                       <provider>/config/modules/module[name='netty-global-event-executor']/instance[name='global-event-executor']</provider>
+                       <provider>/modules/module[type='netty-global-event-executor'][name='global-event-executor']</provider>
                </instance>
        </service>
        <service>
                <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-timer</type>
                <instance>
                        <name>global-timer</name>
-                       <provider>/config/modules/module[name='netty-hashed-wheel-timer']/instance[name='global-timer']</provider>
+                       <provider>/modules/module[type='netty-hashed-wheel-timer'][name='global-timer']</provider>
                </instance>
        </service>
 //CAPABILITIES START
index 430a278a6061b332e885df89094b3ac4271b7ac8..fa33215ea6e9454d5c016e5e2f2fb58474099b55 100644 (file)
                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
                <instance>
                        <name>ref_yang-schema-service</name>
-                       <provider>/config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']</provider>
+                       <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
                </instance>
        </service>
        <service>
                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
                <instance>
                        <name>ref_binding-notification-broker</name>
-                       <provider>/config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']</provider>
+                       <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
                </instance>
        </service>
        <service>
                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
                <instance>
                        <name>ref_hash-map-data-store</name>
-                       <provider>/config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']</provider>
+                       <provider>/modules/module[type='hash-map-data-store'][name='hash-map-data-store']</provider>
                </instance>
                <instance>
-            <name>ref_cluster-data-store</name>
-            <provider>/config/modules/module[name='dom-clustered-store-impl']/instance[name='cluster-data-store']</provider>
-        </instance>
+                       <name>ref_cluster-data-store</name>
+                       <provider>/modules/module[type='dom-clustered-store-impl'][name='cluster-data-store']</provider>
+               </instance>
        </service>
        <service>
                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
                <instance>
                        <name>ref_binding-broker-impl</name>
-                       <provider>/config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']</provider>
+                       <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
                </instance>
        </service>
        <service>
                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
                <instance>
-                       <name>ref_binding-rpc-broker</name>
-                       <provider>/config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']</provider>
+                       <name>binding-rpc-broker</name>
+                       <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
                </instance>
        </service>
        <service>
                <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
                <instance>
                        <name>ref_runtime-mapping-singleton</name>
-                       <provider>/config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']</provider>
+                       <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
                </instance>
        </service>
        <service>
        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
                <instance>
                        <name>ref_dom-broker</name>
-                       <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']</provider>
+                       <provider>/modules/module[type='dom-broker-impl'][name='dom-broker']</provider>
                </instance>
        </service>
        <service>
                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
                <instance>
                        <name>ref_binding-data-broker</name>
-                       <provider>/config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']</provider>
+                       <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
                </instance>
        </service>
 //CAPABILITIES START
index de7597730f9062a85d7071b3986044c4874a4e7a..3ec9f8443a1264063ef79c4f192c0a9c9ea727ca 100644 (file)
@@ -836,21 +836,14 @@ public class FlowConfig implements Serializable {
                 sstr = Pattern.compile("OUTPUT=(.*)").matcher(actiongrp);
                 if (sstr.matches()) {
                     for (String t : sstr.group(1).split(",")) {
-                        Matcher n = Pattern.compile("(?:(\\d+))").matcher(t);
-                        if (n.matches()) {
-                            String port = n.group(1);
-                            if (port != null) {
-                                if (!isPortValid(sw, port)) {
-                                    String msg = String.format("Output port %s is not valid for this switch", port);
-                                    if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
-                                        msg += " in Container " + containerName;
-                                    }
-                                    return new Status(StatusCode.BADREQUEST, msg);
+                        if (t != null) {
+                            if (!isPortValid(sw, t)) {
+                                String msg = String.format("Output port %s is not valid for this switch", t);
+                                if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
+                                    msg += " in Container " + containerName;
                                 }
+                                return new Status(StatusCode.BADREQUEST, msg);
                             }
-                        } else {
-                            String msg = String.format("Output port %s is not valid", t);
-                            return new Status(StatusCode.BADREQUEST, msg);
                         }
                     }
                     continue;
@@ -859,21 +852,15 @@ public class FlowConfig implements Serializable {
                 sstr = Pattern.compile("ENQUEUE=(.*)").matcher(actiongrp);
                 if (sstr.matches()) {
                     for (String t : sstr.group(1).split(",")) {
-                        Matcher n = Pattern.compile("(?:(\\d+:\\d+))").matcher(t);
-                        if (n.matches()) {
-                            if (n.group(1) != null) {
-                                String port = n.group(1).split(":")[0];
-                                if (!isPortValid(sw, port)) {
-                                    String msg = String.format("Output port %d is not valid for this switch", port);
-                                    if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
-                                        msg += " in Container " + containerName;
-                                    }
-                                    return new Status(StatusCode.BADREQUEST, msg);
+                        if (t != null) {
+                            String port = t.split(":")[0];
+                            if (!isPortValid(sw, port)) {
+                                String msg = String.format("Output port %d is not valid for this switch", port);
+                                if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
+                                    msg += " in Container " + containerName;
                                 }
+                                return new Status(StatusCode.BADREQUEST, msg);
                             }
-                        } else {
-                            String msg = String.format("Enqueue port %s is not valid", t);
-                            return new Status(StatusCode.BADREQUEST, msg);
                         }
                     }
                     continue;
@@ -1102,12 +1089,9 @@ public class FlowConfig implements Serializable {
                 sstr = Pattern.compile(ActionType.OUTPUT + "=(.*)").matcher(actiongrp);
                 if (sstr.matches()) {
                     for (String t : sstr.group(1).split(",")) {
-                        Matcher n = Pattern.compile("(?:(\\d+))").matcher(t);
-                        if (n.matches()) {
-                            if (n.group(1) != null) {
-                                String nc = String.format("%s|%s@%s", node.getType(), n.group(1), node.toString());
-                                actionList.add(new Output(NodeConnector.fromString(nc)));
-                            }
+                        if (t != null) {
+                            String nc = String.format("%s|%s@%s", node.getType(), t, node.toString());
+                            actionList.add(new Output(NodeConnector.fromString(nc)));
                         }
                     }
                     continue;
@@ -1116,17 +1100,14 @@ public class FlowConfig implements Serializable {
                 sstr = Pattern.compile(ActionType.ENQUEUE + "=(.*)").matcher(actiongrp);
                 if (sstr.matches()) {
                     for (String t : sstr.group(1).split(",")) {
-                        Matcher n = Pattern.compile("(?:(\\d+:\\d+))").matcher(t);
-                        if (n.matches()) {
-                            if (n.group(1) != null) {
-                                String parts[] = n.group(1).split(":");
-                                String nc = String.format("%s|%s@%s", node.getType(), parts[0], node.toString());
-                                if (parts.length == 1) {
-                                    actionList.add(new Enqueue(NodeConnector.fromString(nc)));
-                                } else {
-                                    actionList
-                                            .add(new Enqueue(NodeConnector.fromString(nc), Integer.parseInt(parts[1])));
-                                }
+                        if (t != null) {
+                            String parts[] = t.split(":");
+                            String nc = String.format("%s|%s@%s", node.getType(), parts[0], node.toString());
+                            if (parts.length == 1) {
+                                actionList.add(new Enqueue(NodeConnector.fromString(nc)));
+                            } else {
+                                actionList
+                                .add(new Enqueue(NodeConnector.fromString(nc), Integer.parseInt(parts[1])));
                             }
                         }
                     }
index 24bfc4fdf4c09079230189c43e9d33a428ab0cbf..84b3e53e065cfea03f225cc1c6fe0f8ebaa27582 100644 (file)
@@ -260,13 +260,13 @@ public class FRMUtil {
                 }
             } else if (action instanceof SetDlDstAction) {
                 MacAddress address = ((SetDlDstAction) action).getAddress();
-                if (address != null && !isL2AddressValid(address.toString())) {
+                if (address != null && !isL2AddressValid(address.getValue())) {
                     logger.error("SetDlDstAction: Address not valid");
                     return false;
                 }
             } else if (action instanceof SetDlSrcAction) {
                 MacAddress address = ((SetDlSrcAction) action).getAddress();
-                if (address != null && !isL2AddressValid(address.toString())) {
+                if (address != null && !isL2AddressValid(address.getValue())) {
                     logger.error("SetDlSrcAction: Address not valid");
                     return false;
                 }
index 19c366d014b66d5d33af1e84003c1c8f8daee256..d2f2420a7cb58814444de25af8944e57f2e80abb 100644 (file)
@@ -2,50 +2,37 @@ package org.opendaylight.controller.forwardingrulesmanager.consumer.impl;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.EnumSet;
-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 java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Future;
-
-import org.opendaylight.controller.clustering.services.CacheConfigException;
-import org.opendaylight.controller.clustering.services.CacheExistException;
-import org.opendaylight.controller.clustering.services.IClusterContainerServices;
-import org.opendaylight.controller.clustering.services.IClusterServices;
+
 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
 import org.opendaylight.controller.sal.common.util.Rpcs;
-import org.opendaylight.controller.sal.core.IContainer;
-import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAdded;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeErrorNotification;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeExperimenterErrorNotification;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SwitchFlowRemoved;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
-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;
-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.table.config.rev131024.Tables;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.tables.TableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableRef;
 import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -55,32 +42,13 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class FlowConsumerImpl implements IForwardingRulesManager {
+public class FlowConsumerImpl {
     protected static final Logger logger = LoggerFactory.getLogger(FlowConsumerImpl.class);
     private final FlowEventListener flowEventListener = new FlowEventListener();
     private Registration<NotificationListener> listener1Reg;
     private SalFlowService flowService;
     // private FlowDataListener listener;
-    private FlowDataCommitHandler commitHandler;
-    private static ConcurrentHashMap<FlowKey, Flow> originalSwView;
-    private static ConcurrentMap<FlowKey, Flow> installedSwView;
-    private IClusterContainerServices clusterContainerService = null;
-    private IContainer container;
-    private static final String NAMEREGEX = "^[a-zA-Z0-9]+$";
-    private static ConcurrentMap<Integer, Flow> staticFlows;
-    private static ConcurrentMap<Integer, Integer> staticFlowsOrdinal = new ConcurrentHashMap<Integer, Integer>();
-    /*
-     * Inactive flow list. This is for the global instance of FRM It will
-     * contain all the flow entries which were installed on the global container
-     * when the first container is created.
-     */
-    private static ConcurrentMap<FlowKey, Flow> inactiveFlows;
-
-    /*
-     * /* Per node indexing
-     */
-    private static ConcurrentMap<Node, List<Flow>> nodeFlows;
-    private boolean inContainerMode; // being used by global instance only
+    private FlowDataCommitHandler commitHandler;    
 
     public FlowConsumerImpl() {
         InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Flows.class).toInstance();
@@ -90,17 +58,7 @@ public class FlowConsumerImpl implements IForwardingRulesManager {
             logger.error("Consumer SAL Service is down or NULL. FRM may not function as intended");
             return;
         }
-
-        // listener = new FlowDataListener();
-
-        // if (null ==
-        // FRMConsumerImpl.getDataBrokerService().registerDataChangeListener(path,
-        // listener)) {
-        // logger.error("Failed to listen on flow data modifcation events");
-        // System.out.println("Consumer SAL Service is down or NULL.");
-        // return;
-        // }
-
+        
         // For switch events
         listener1Reg = FRMConsumerImpl.getNotificationService().registerNotificationListener(flowEventListener);
 
@@ -110,66 +68,9 @@ public class FlowConsumerImpl implements IForwardingRulesManager {
         }
         // addFlowTest();
         commitHandler = new FlowDataCommitHandler();
-        FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
-        clusterContainerService = (IClusterContainerServices) ServiceHelper.getGlobalInstance(
-                IClusterContainerServices.class, this);
-        allocateCaches();
-        /*
-         * If we are not the first cluster node to come up, do not initialize
-         * the static flow entries ordinal
-         */
-        if (staticFlowsOrdinal.size() == 0) {
-            staticFlowsOrdinal.put(0, Integer.valueOf(0));
-        }
+        FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);        
     }
-
-    private void allocateCaches() {
-
-        if (this.clusterContainerService == null) {
-            logger.warn("Un-initialized clusterContainerService, can't create cache");
-            return;
-        }
-
-        try {
-            clusterContainerService.createCache("frm.originalSwView",
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-            clusterContainerService.createCache("frm.installedSwView",
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-            clusterContainerService
-                    .createCache("frm.staticFlows", EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-            clusterContainerService.createCache("frm.staticFlowsOrdinal",
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-            clusterContainerService.createCache("frm.inactiveFlows",
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-            clusterContainerService.createCache("frm.nodeFlows", EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-            clusterContainerService.createCache("frm.groupFlows", EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-        } catch (CacheConfigException cce) {
-            logger.error("CacheConfigException");
-        } catch (CacheExistException cce) {
-            logger.error("CacheExistException");
-        }
-    }
-
-    private void addFlowTest() {
-        try {
-            NodeRef nodeOne = createNodeRef("foo:node:1");
-            AddFlowInputBuilder input1 = new AddFlowInputBuilder();
-
-            input1.setNode(nodeOne);
-            AddFlowInput firstMsg = input1.build();
-
-            if (null == flowService) {
-                logger.error("ConsumerFlowService is NULL");
-            }
-            @SuppressWarnings("unused")
-            Future<RpcResult<AddFlowOutput>> result1 = flowService.addFlow(firstMsg);
-
-        } catch (Exception e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-    }
-
+    
     /**
      * Adds flow to the southbound plugin and our internal database
      *
@@ -179,42 +80,11 @@ public class FlowConsumerImpl implements IForwardingRulesManager {
     private void addFlow(InstanceIdentifier<?> path, Flow dataObject) {
 
         AddFlowInputBuilder input = new AddFlowInputBuilder();
-
+        input.fieldsFrom(dataObject);
         input.setNode((dataObject).getNode());
-        input.setPriority((dataObject).getPriority());
-        input.setMatch((dataObject).getMatch());
-        input.setCookie((dataObject).getCookie());
-        input.setInstructions((dataObject).getInstructions());
-        input.setBufferId(dataObject.getBufferId());
-        input.setTableId(dataObject.getTableId());
-        input.setOutPort(dataObject.getOutPort());
-        input.setOutGroup(dataObject.getOutGroup());
-        input.setIdleTimeout(dataObject.getIdleTimeout());
-        input.setHardTimeout(dataObject.getHardTimeout());
-        input.setFlowName(dataObject.getFlowName());
-        input.setFlags(dataObject.getFlags());
-        input.setCookieMask(dataObject.getCookieMask());
-        input.setContainerName(dataObject.getContainerName());
-        input.setBarrier(dataObject.isBarrier());
-        input.setInstallHw(dataObject.isInstallHw());
-        input.setStrict(dataObject.isStrict());
-
-        // updating the staticflow cache
-        /*
-         * Commented out... as in many other places... use of ClusteringServices
-         * is breaking things insufficient time to debug Integer ordinal =
-         * staticFlowsOrdinal.get(0); staticFlowsOrdinal.put(0, ++ordinal);
-         * staticFlows.put(ordinal, dataObject);
-         */
-
+        input.setFlowTable(new FlowTableRef(createTableInstance(dataObject.getId(), dataObject.getNode())));
         // We send flow to the sounthbound plugin
-
         flowService.addFlow(input.build());
-
-        /*
-         * Commented out as this will also break due to improper use of
-         * ClusteringServices updateLocalDatabase((NodeFlow) dataObject, true);
-         */
     }
 
     /**
@@ -224,41 +94,14 @@ public class FlowConsumerImpl implements IForwardingRulesManager {
      * @param dataObject
      */
     private void removeFlow(InstanceIdentifier<?> path, Flow dataObject) {
-
+        
         RemoveFlowInputBuilder input = new RemoveFlowInputBuilder();
+        input.fieldsFrom(dataObject);
         input.setNode((dataObject).getNode());
-        input.setPriority((dataObject).getPriority());
-        input.setMatch((dataObject).getMatch());
-        input.setCookie((dataObject).getCookie());
-        input.setInstructions((dataObject).getInstructions());
-        input.setBufferId(dataObject.getBufferId());
         input.setTableId(dataObject.getTableId());
-        input.setOutPort(dataObject.getOutPort());
-        input.setOutGroup(dataObject.getOutGroup());
-        input.setIdleTimeout(dataObject.getIdleTimeout());
-        input.setHardTimeout(dataObject.getHardTimeout());
-        input.setFlowName(dataObject.getFlowName());
-        input.setFlags(dataObject.getFlags());
-        input.setCookieMask(dataObject.getCookieMask());
-        input.setContainerName(dataObject.getContainerName());
-        input.setBarrier(dataObject.isBarrier());
-        input.setInstallHw(dataObject.isInstallHw());
-        input.setStrict(dataObject.isStrict());
-        // updating the staticflow cache
-        /*
-         * Commented out due to problems caused by improper use of
-         * ClusteringServices Integer ordinal = staticFlowsOrdinal.get(0);
-         * staticFlowsOrdinal.put(0, ++ordinal); staticFlows.put(ordinal,
-         * dataObject);
-         */
-
+        input.setFlowTable(new FlowTableRef(createTableInstance((long)dataObject.getTableId(), (dataObject).getNode())));
         // We send flow to the sounthbound plugin
         flowService.removeFlow(input.build());
-
-        /*
-         * Commented out due to problems caused by improper use of
-         * ClusteringServices updateLocalDatabase((NodeFlow) dataObject, false);
-         */
     }
 
     /**
@@ -267,32 +110,19 @@ public class FlowConsumerImpl implements IForwardingRulesManager {
      * @param path
      * @param dataObject
      */
-    private void updateFlow(InstanceIdentifier<?> path, Flow dataObject) {
+    private void updateFlow(InstanceIdentifier<?> path, Flow updatedFlow, Flow originalFlow) {
 
         UpdateFlowInputBuilder input = new UpdateFlowInputBuilder();
         UpdatedFlowBuilder updatedflowbuilder = new UpdatedFlowBuilder();
-        updatedflowbuilder.fieldsFrom(dataObject);
-        input.setNode(dataObject.getNode());
-        input.setUpdatedFlow(updatedflowbuilder.build());
-
-        // updating the staticflow cache
-        /*
-         * Commented out due to problems caused by improper use of
-         * ClusteringServices. Integer ordinal = staticFlowsOrdinal.get(0);
-         * staticFlowsOrdinal.put(0, ++ordinal); staticFlows.put(ordinal,
-         * dataObject);
-         */
-
+        updatedflowbuilder.fieldsFrom(updatedFlow);
+        input.setNode(updatedFlow.getNode());
+        input.setUpdatedFlow(updatedflowbuilder.build());  
+        OriginalFlowBuilder ofb = new OriginalFlowBuilder(originalFlow);
+        input.setOriginalFlow(ofb.build());
         // We send flow to the sounthbound plugin
         flowService.updateFlow(input.build());
-
-        /*
-         * Commented out due to problems caused by improper use of
-         * ClusteringServices. updateLocalDatabase((NodeFlow) dataObject, true);
-         */
     }
-
-    @SuppressWarnings("unchecked")
     private void commitToPlugin(internalTransaction transaction) {
         Set<Entry<InstanceIdentifier<?>, DataObject>> createdEntries = transaction.getModification()
                 .getCreatedConfigurationData().entrySet();
@@ -320,16 +150,17 @@ public class FlowConsumerImpl implements IForwardingRulesManager {
                 addFlow(entry.getKey(), (Flow) entry.getValue());
             }
         }
-        for (@SuppressWarnings("unused")
-        Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) {
+       
+        for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) {
             if (entry.getValue() instanceof Flow) {
                 logger.debug("Coming update cc in FlowDatacommitHandler");
-                Flow flow = (Flow) entry.getValue();
-                boolean status = validate(flow);
+                Flow updatedFlow = (Flow) entry.getValue();
+                Flow originalFlow = (Flow) transaction.modification.getOriginalConfigurationData().get(entry.getKey());
+                boolean status = validate(updatedFlow);
                 if (!status) {
                     return;
                 }
-                updateFlow(entry.getKey(), (Flow) entry.getValue());
+                updateFlow(entry.getKey(), updatedFlow, originalFlow);
             }
         }
 
@@ -339,21 +170,20 @@ public class FlowConsumerImpl implements IForwardingRulesManager {
                 logger.debug("Coming remove cc in FlowDatacommitHandler");
                 Flow flow = (Flow) removeValue;
                 boolean status = validate(flow);
+                
                 if (!status) {
                     return;
                 }
+                
                 removeFlow(instanceId, (Flow) removeValue);
-
             }
         }
-
     }
 
-    private final class FlowDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
-
+    private final class FlowDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {   
+     
         @SuppressWarnings("unchecked")
-        @Override
-        public DataCommitTransaction requestCommit(DataModification<InstanceIdentifier<?>, DataObject> modification) {
+        public DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(DataModification<InstanceIdentifier<?>, DataObject> modification) {
             // We should verify transaction
             logger.debug("Coming in FlowDatacommitHandler");
             internalTransaction transaction = new internalTransaction(modification);
@@ -374,54 +204,23 @@ public class FlowConsumerImpl implements IForwardingRulesManager {
         public internalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
             this.modification = modification;
         }
-
-        Map<InstanceIdentifier<?>, Flow> additions = new HashMap<>();
-        Map<InstanceIdentifier<?>, Flow> updates = new HashMap<>();
-        Map<InstanceIdentifier<?>, Flow> removals = new HashMap<>();
-
+        
         /**
          * We create a plan which flows will be added, which will be updated and
          * which will be removed based on our internal state.
          *
          */
-        void prepareUpdate() {
+        void prepareUpdate() {          
 
-            Set<Entry<InstanceIdentifier<?>, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet();
-            for (Entry<InstanceIdentifier<?>, DataObject> entry : puts) {
-            }
-
-            // removals = modification.getRemovedConfigurationData();
-            Set<InstanceIdentifier<?>> removedData = modification.getRemovedConfigurationData();
-            for (InstanceIdentifier<?> removal : removedData) {
-                DataObject value = modification.getOriginalConfigurationData().get(removal);
-                if (value instanceof Flow) {
-                    removals.put(removal, (Flow) value);
-                }
-            }
-
-        }
-
-        private void preparePutEntry(InstanceIdentifier<?> key, Flow flow) {
-            Flow original = originalSwView.get(key);
-            if (original != null) {
-                // It is update for us
-                updates.put(key, flow);
-            } else {
-                // It is addition for us
-                additions.put(key, flow);
-            }
         }
-
+       
         /**
          * We are OK to go with execution of plan
          *
          */
         @Override
         public RpcResult<Void> finish() throws IllegalStateException {
-
-            commitToPlugin(this);
-            // We return true if internal transaction is successful.
-            // return Rpcs.getRpcResult(true, null, Collections.emptySet());
+            commitToPlugin(this);            
             return Rpcs.getRpcResult(true, null, Collections.<RpcError> emptySet());
         }
 
@@ -431,26 +230,47 @@ public class FlowConsumerImpl implements IForwardingRulesManager {
          *
          */
         @Override
-        public RpcResult<Void> rollback() throws IllegalStateException {
-            // NOOP - we did not modified any internal state during
-            // requestCommit phase
-            // return Rpcs.getRpcResult(true, null, Collections.emptySet());
+        public RpcResult<Void> rollback() throws IllegalStateException {       
+            rollBackFlows(modification);
             return Rpcs.getRpcResult(true, null, Collections.<RpcError> emptySet());
 
-        }
+        }       
+    }
 
-        private boolean flowEntryExists(Flow flow) {
-            // Flow name has to be unique on per table id basis
-            for (ConcurrentMap.Entry<FlowKey, Flow> entry : originalSwView.entrySet()) {
-                if (entry.getValue().getFlowName().equals(flow.getFlowName())
-                        && entry.getValue().getTableId().equals(flow.getTableId())) {
-                    return true;
-                }
-            }
-            return false;
+    private void rollBackFlows(DataModification<InstanceIdentifier<?>, DataObject> modification) {
+     Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries = modification.getCreatedConfigurationData().entrySet();
+
+    /*
+     * This little dance is because updatedEntries contains both created and modified entries
+     * The reason I created a new HashSet is because the collections we are returned are immutable.
+     */
+    Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
+    updatedEntries.addAll(modification.getUpdatedConfigurationData().entrySet());
+    updatedEntries.removeAll(createdEntries);
+
+    Set<InstanceIdentifier<? >> removeEntriesInstanceIdentifiers = modification.getRemovedConfigurationData();
+    for (Entry<InstanceIdentifier<?>, DataObject> entry : createdEntries) {
+        if(entry.getValue() instanceof Flow) {
+            removeFlow(entry.getKey(),(Flow) entry.getValue()); // because we are rolling back, remove what we would have added.
         }
     }
+    
+    for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) {
+        if(entry.getValue() instanceof Flow) {            
+            Flow updatedFlow = (Flow) entry.getValue();
+            Flow originalFlow = (Flow) modification.getOriginalConfigurationData().get(entry.getKey());
+            updateFlow(entry.getKey(), updatedFlow ,originalFlow);// because we are rolling back, replace the updated with the original
+        }
+    }
+
+    for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {
+        DataObject removeValue = (Flow) modification.getOriginalConfigurationData().get(instanceId);
+        if(removeValue instanceof Flow) {
+            addFlow(instanceId,(Flow) removeValue);// because we are rolling back, add what we would have removed.
 
+        }
+    }
+}
     final class FlowEventListener implements SalFlowListener {
 
         List<FlowAdded> addedFlows = new ArrayList<>();
@@ -489,58 +309,18 @@ public class FlowConsumerImpl implements IForwardingRulesManager {
             // TODO Auto-generated method stub
 
         }
-
     }
 
-    // Commented out DataChangeListene - to be used by Stats
-
-    // final class FlowDataListener implements DataChangeListener {
-    // private SalFlowService flowService;
-    //
-    // public FlowDataListener() {
-    //
-    // }
-    //
-    // @Override
-    // public void onDataChanged(
-    // DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
-    // System.out.println("Coming in onDataChange..............");
-    // @SuppressWarnings("unchecked")
-    // Collection<DataObject> additions = (Collection<DataObject>)
-    // change.getCreatedConfigurationData();
-    // // we can check for getCreated, getDeleted or getUpdated from DataChange
-    // Event class
-    // for (DataObject dataObject : additions) {
-    // if (dataObject instanceof NodeFlow) {
-    // NodeRef nodeOne = createNodeRef("foo:node:1");
-    // // validating the dataObject here
-    // AddFlowInputBuilder input = new AddFlowInputBuilder();
-    // input.setNode(((NodeFlow) dataObject).getNode());
-    // input.setNode(nodeOne);
-    // // input.setPriority(((NodeFlow) dataObject).getPriority());
-    // //input.setMatch(((NodeFlow) dataObject).getMatch());
-    // //input.setFlowTable(((NodeFlow) dataObject).getFlowTable());
-    // //input.setCookie(((NodeFlow) dataObject).getCookie());
-    // //input.setAction(((NodeFlow) dataObject).getAction());
-    //
-    // @SuppressWarnings("unused")
-    // Future<RpcResult<java.lang.Void>> result =
-    // flowService.addFlow(input.build());
-    // }
-    // }
-    // }
-    // }
-
     public boolean validate(Flow flow) {
-
         String msg = ""; // Specific part of warn/error log
 
         boolean result = true;
         // flow Name validation
-        if (flow.getFlowName() == null || flow.getFlowName().trim().isEmpty() || !flow.getFlowName().matches(NAMEREGEX)) {
+        if (!FRMUtil.isNameValid(flow.getFlowName())) {
             msg = "Invalid Flow name";
             result = false;
         }
+        
         // Node Validation
         if (result == true && flow.getNode() == null) {
             msg = "Node is null";
@@ -556,20 +336,7 @@ public class FlowConsumerImpl implements IForwardingRulesManager {
                 result = false;
             }
         }
-
-        // Presence check
-        /*
-         * This is breaking due to some improper use of caches...
-         *
-         * if (flowEntryExists(flow)) { String error =
-         * "Entry with this name on specified table already exists";
-         * logger.warn(
-         * "Entry with this name on specified table already exists: {}" ,
-         * entry); logger.error(error); return; } if
-         * (originalSwView.containsKey(entry)) { logger.warn(
-         * "Operation Rejected: A flow with same match and priority exists on the target node"
-         * ); logger.trace("Aborting to install {}", entry); continue; }
-         */
+       
         if (!FRMUtil.validateMatch(flow)) {
             logger.error("Not a valid Match");
             result = false;
@@ -584,92 +351,15 @@ public class FlowConsumerImpl implements IForwardingRulesManager {
         }
         return result;
     }
-
-    private static void updateLocalDatabase(NodeFlow entry, boolean add) {
-
-        updateSwViewes(entry, add);
-
-        updateNodeFlowsDB(entry, add);
-
-    }
-
-    /*
-     * Update the node mapped flows database
-     */
-    private static void updateSwViewes(NodeFlow entry, boolean add) {
-        if (add) {
-            FlowConsumerImpl.originalSwView.put((FlowKey) entry, (Flow) entry);
-            installedSwView.put((FlowKey) entry, (Flow) entry);
-        } else {
-            originalSwView.remove(entry);
-            installedSwView.remove(entry);
-
-        }
-    }
-
-    @Override
-    public List<DataObject> get() {
-
-        List<DataObject> orderedList = new ArrayList<DataObject>();
-        ConcurrentMap<Integer, Flow> flowMap = staticFlows;
-        int maxKey = staticFlowsOrdinal.get(0).intValue();
-        for (int i = 0; i <= maxKey; i++) {
-            Flow entry = flowMap.get(i);
-            if (entry != null) {
-                orderedList.add(entry);
-            }
-        }
-        return orderedList;
-    }
-
-    @Override
-    public DataObject getWithName(String name, org.opendaylight.controller.sal.core.Node n) {
-        if (this instanceof FlowConsumerImpl) {
-            for (ConcurrentMap.Entry<Integer, Flow> flowEntry : staticFlows.entrySet()) {
-                Flow flow = flowEntry.getValue();
-                if (flow.getNode().equals(n) && flow.getFlowName().equals(name)) {
-
-                    return flowEntry.getValue();
-                }
-            }
-        }
-        return null;
-    }
-
-    /*
-     * Update the node mapped flows database
-     */
-    private static void updateNodeFlowsDB(NodeFlow entry, boolean add) {
-        Node node = (Node) entry.getNode();
-
-        List<Flow> nodeIndeces = nodeFlows.get(node);
-        if (nodeIndeces == null) {
-            if (!add) {
-                return;
-            } else {
-                nodeIndeces = new ArrayList<Flow>();
-            }
-        }
-
-        if (add) {
-            nodeIndeces.add((Flow) entry);
-        } else {
-            nodeIndeces.remove(entry);
-        }
-
-        // Update cache across cluster
-        if (nodeIndeces.isEmpty()) {
-            nodeFlows.remove(node);
-        } else {
-            nodeFlows.put(node, nodeIndeces);
-        }
-    }
-
-    private static NodeRef createNodeRef(String string) {
-        NodeKey key = new NodeKey(new NodeId(string));
-        InstanceIdentifier<Node> path = InstanceIdentifier.builder().node(Nodes.class).node(Node.class, key)
-                .toInstance();
-
-        return new NodeRef(path);
+    
+    private InstanceIdentifier<?> createTableInstance(Long tableId, NodeRef nodeRef) {        
+        Table table;
+        InstanceIdentifier<Table> tableInstance;
+        TableBuilder builder = new TableBuilder();
+        builder.setId(tableId);
+        builder.setKey(new TableKey(tableId, nodeRef));
+        table = builder.build();
+        tableInstance = InstanceIdentifier.builder(Tables.class).child(Table.class, table.getKey()).toInstance();
+        return tableInstance;
     }
 }
\ No newline at end of file
index 6fbbd4d6e289ce87de6f3ee0e9b119fdaa795e5b..f4064f22ceeeda56740468d11451da999d6a1a5d 100644 (file)
@@ -132,25 +132,22 @@ public class GroupConsumerImpl {
      * @param dataObject
      */
     private void updateGroup(InstanceIdentifier<?> path, 
-        Group originalGroupDataObject, Group updatedGroupDataObject) {
-        
-        GroupKey groupKey = updatedGroupDataObject.getKey();
-       // Node nodeInstanceID = path.firstIdentifierOf("Node");
+        Group updatedGroupDataObject, Group originalGroupDataObject) {
         UpdatedGroupBuilder updateGroupBuilder = null;
         Status groupOperationStatus = validateGroup(updatedGroupDataObject);
-
+        
         if (!groupOperationStatus.isSuccess()) {
             logger.error("Group data object validation failed %s" + updatedGroupDataObject.getGroupName());
             return;
         }
         
-        UpdateGroupInputBuilder groupInputBuilder = new UpdateGroupInputBuilder();
+        UpdateGroupInputBuilder groupInputBuilder = new UpdateGroupInputBuilder();        
+        updateGroupBuilder = new UpdatedGroupBuilder(updatedGroupDataObject);        
+        updateGroupBuilder.setGroupId(new GroupId(updatedGroupDataObject.getId())); 
         groupInputBuilder.setNode(updatedGroupDataObject.getNode());
-        updateGroupBuilder = new UpdatedGroupBuilder(updatedGroupDataObject);
-        updateGroupBuilder.setGroupId(new GroupId(updatedGroupDataObject.getId()));        
         groupInputBuilder.setUpdatedGroup(updateGroupBuilder.build());       
         OriginalGroupBuilder originalGroupBuilder = new OriginalGroupBuilder(originalGroupDataObject);
-        groupInputBuilder.setOriginalGroup(originalGroupBuilder.build());
+        groupInputBuilder.setOriginalGroup(originalGroupBuilder.build());     
         groupService.updateGroup(groupInputBuilder.build());
         return;
     }
@@ -171,10 +168,8 @@ public class GroupConsumerImpl {
         }
         
         AddGroupInputBuilder groupData = new AddGroupInputBuilder();
-        groupData.setBuckets(groupAddDataObject.getBuckets());
-        groupData.setContainerName(groupAddDataObject.getContainerName());
-        groupData.setGroupId(new GroupId(groupAddDataObject.getId()));
-        groupData.setGroupType(groupAddDataObject.getGroupType());
+        groupData.fieldsFrom(groupAddDataObject);       
+        groupData.setGroupId(new GroupId(groupAddDataObject.getId()));     
         groupData.setNode(groupAddDataObject.getNode());    
         groupService.addGroup(groupData.build());
         return;
@@ -196,11 +191,9 @@ public class GroupConsumerImpl {
         }
        
         RemoveGroupInputBuilder groupData = new RemoveGroupInputBuilder();
-        groupData.setBuckets(groupRemoveDataObject.getBuckets());
-        groupData.setContainerName(groupRemoveDataObject.getContainerName());
-        groupData.setGroupId(new GroupId(groupRemoveDataObject.getId()));
-        groupData.setGroupType(groupRemoveDataObject.getGroupType());
-        groupData.setNode(groupRemoveDataObject.getNode());    
+        groupData.fieldsFrom(groupRemoveDataObject);
+        groupData.setGroupId(new GroupId(groupRemoveDataObject.getId()));    
+        groupData.setNode(groupRemoveDataObject.getNode());
         groupService.removeGroup(groupData.build());  
         return;
     }
index 42d0897fb11ae85182f6a87e83f3015e191f716c..bf8c8b7f05b912b3075c81a52a1f978fb76a284f 100644 (file)
@@ -27,6 +27,13 @@ import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.Meters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.Meter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.MeterKey;
@@ -38,6 +45,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.Rem
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterListener;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeterBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.BandType;
@@ -53,35 +61,17 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class MeterConsumerImpl implements IForwardingRulesManager {
+public class MeterConsumerImpl {
     protected static final Logger logger = LoggerFactory.getLogger(MeterConsumerImpl.class);
     private final MeterEventListener meterEventListener = new MeterEventListener();
     private Registration<NotificationListener> meterListener;
     private SalMeterService meterService;
     private MeterDataCommitHandler commitHandler;
 
-    private ConcurrentMap<MeterKey, Meter> originalSwMeterView;
-    @SuppressWarnings("unused")
-    private ConcurrentMap<MeterKey, Meter> installedSwMeterView;
-    @SuppressWarnings("unused")
-    private ConcurrentMap<Node, List<Meter>> nodeMeters;
-    @SuppressWarnings("unused")
-    private ConcurrentMap<MeterKey, Meter> inactiveMeters;
-    @SuppressWarnings("unused")
-    private IContainer container;
-    private IClusterContainerServices clusterMeterContainerService = null;    
-
     public MeterConsumerImpl() {
         InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Meters.class).toInstance();
         meterService = FRMConsumerImpl.getProviderSession().getRpcService(SalMeterService.class);
-        clusterMeterContainerService = FRMConsumerImpl.getClusterContainerService();
-        container = FRMConsumerImpl.getContainer();
-
-        if (!(cacheStartup())) {
-            logger.error("Unable to allocate/retrieve meter cache");
-            System.out.println("Unable to allocate/retrieve meter cache");
-        }
-
+        
         if (null == meterService) {
             logger.error("Consumer SAL Meter Service is down or NULL. FRM may not function as intended");
             System.out.println("Consumer SAL Meter Service is down or NULL.");
@@ -100,110 +90,7 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
         commitHandler = new MeterDataCommitHandler();
         FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
     }
-
-    private boolean allocateMeterCaches() {
-        if (this.clusterMeterContainerService == null) {
-            logger.warn("Meter: Un-initialized clusterMeterContainerService, can't create cache");
-            return false;
-        }
-
-        try {
-            clusterMeterContainerService.createCache("frm.originalSwMeterView",
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
-            clusterMeterContainerService.createCache("frm.installedSwMeterView",
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
-            clusterMeterContainerService.createCache("frm.inactiveMeters",
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
-            clusterMeterContainerService.createCache("frm.nodeMeters",
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
-            // TODO for cluster mode
-            /*
-             * clusterMeterContainerService.createCache(WORK_STATUS_CACHE,
-             * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
-             * IClusterServices.cacheMode.ASYNC));
-             *
-             * clusterMeterContainerService.createCache(WORK_ORDER_CACHE,
-             * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
-             * IClusterServices.cacheMode.ASYNC));
-             */
-
-        } catch (CacheConfigException cce) {
-            logger.error("Meter CacheConfigException");
-            return false;
-
-        } catch (CacheExistException cce) {
-            logger.error(" Meter CacheExistException");
-        }
-
-        return true;
-    }
-
-    private void nonClusterMeterObjectCreate() {
-        originalSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
-        installedSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
-        nodeMeters = new ConcurrentHashMap<Node, List<Meter>>();
-        inactiveMeters = new ConcurrentHashMap<MeterKey, Meter>();
-    }
-
-    @SuppressWarnings({ "unchecked" })
-    private boolean retrieveMeterCaches() {
-        ConcurrentMap<?, ?> map;
-
-        if (this.clusterMeterContainerService == null) {
-            logger.warn("Meter: un-initialized clusterMeterContainerService, can't retrieve cache");
-            nonClusterMeterObjectCreate();
-            return false;
-        }
-
-        map = clusterMeterContainerService.getCache("frm.originalSwMeterView");
-        if (map != null) {
-            originalSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
-        } else {
-            logger.error("Retrieval of cache(originalSwMeterView) failed");
-            return false;
-        }
-
-        map = clusterMeterContainerService.getCache("frm.installedSwMeterView");
-        if (map != null) {
-            installedSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
-        } else {
-            logger.error("Retrieval of cache(installedSwMeterView) failed");
-            return false;
-        }
-
-        map = clusterMeterContainerService.getCache("frm.inactiveMeters");
-        if (map != null) {
-            inactiveMeters = (ConcurrentMap<MeterKey, Meter>) map;
-        } else {
-            logger.error("Retrieval of cache(inactiveMeters) failed");
-            return false;
-        }
-
-        map = clusterMeterContainerService.getCache("frm.nodeMeters");
-        if (map != null) {
-            nodeMeters = (ConcurrentMap<Node, List<Meter>>) map;
-        } else {
-            logger.error("Retrieval of cache(nodeMeter) failed");
-            return false;
-        }
-
-        return true;
-    }
-
-    private boolean cacheStartup() {
-        if (allocateMeterCaches()) {
-            if (retrieveMeterCaches()) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
+    
     /**
      * Adds Meter to the southbound plugin and our internal database
      *
@@ -213,11 +100,9 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
     private Status addMeter(InstanceIdentifier<?> path, Meter meterAddDataObject) {
         MeterKey meterKey = meterAddDataObject.getKey();
         
-        if (null != meterKey && validateMeter(meterAddDataObject, FRMUtil.operation.ADD).isSuccess()) {                 
+        if (null != meterKey && validateMeter(meterAddDataObject).isSuccess()) {                
             AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder();
-            meterBuilder.setContainerName(meterAddDataObject.getContainerName());
-            meterBuilder.setFlags(meterAddDataObject.getFlags());
-            meterBuilder.setMeterBandHeaders(meterAddDataObject.getMeterBandHeaders());
+            meterBuilder.fieldsFrom(meterAddDataObject);            
             meterBuilder.setMeterId(new MeterId(meterAddDataObject.getId()));
             meterBuilder.setNode(meterAddDataObject.getNode());           
             meterService.addMeter(meterBuilder.build());
@@ -235,16 +120,19 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
      *
      * @param dataObject
      */
-    private Status updateMeter(InstanceIdentifier<?> path, Meter meterUpdateDataObject) {
-        MeterKey meterKey = meterUpdateDataObject.getKey();
+    private Status updateMeter(InstanceIdentifier<?> path, 
+                Meter updatedMeter, Meter originalMeter) {        
         UpdatedMeterBuilder updateMeterBuilder = null;
         
-        if (null != meterKey && validateMeter(meterUpdateDataObject, FRMUtil.operation.UPDATE).isSuccess()) {                UpdateMeterInputBuilder updateMeterInputBuilder = new UpdateMeterInputBuilder();
+        if (validateMeter(updatedMeter).isSuccess()) {                
+            UpdateMeterInputBuilder updateMeterInputBuilder = new UpdateMeterInputBuilder();
+            updateMeterInputBuilder.setNode(updatedMeter.getNode());
             updateMeterBuilder = new UpdatedMeterBuilder();
-            updateMeterBuilder.fieldsFrom(meterUpdateDataObject);
-            updateMeterBuilder.setMeterId(new MeterId(meterUpdateDataObject.getId()));
-            
+            updateMeterBuilder.fieldsFrom(updatedMeter);            
+            updateMeterBuilder.setMeterId(new MeterId(updatedMeter.getId()));            
             updateMeterInputBuilder.setUpdatedMeter(updateMeterBuilder.build());
+            OriginalMeterBuilder originalMeterBuilder = new OriginalMeterBuilder(originalMeter);
+            updateMeterInputBuilder.setOriginalMeter(originalMeterBuilder.build());
             meterService.updateMeter(updateMeterInputBuilder.build());
         } else {
             return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
@@ -263,14 +151,11 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
     private Status removeMeter(InstanceIdentifier<?> path, Meter meterRemoveDataObject) {
         MeterKey meterKey = meterRemoveDataObject.getKey();
 
-        if (null != meterKey && validateMeter(meterRemoveDataObject, FRMUtil.operation.DELETE).isSuccess()) {            
+        if (null != meterKey && validateMeter(meterRemoveDataObject).isSuccess()) {            
             RemoveMeterInputBuilder meterBuilder = new RemoveMeterInputBuilder();
-            meterBuilder.setContainerName(meterRemoveDataObject.getContainerName());
-            meterBuilder.setNode(meterRemoveDataObject.getNode());
-            meterBuilder.setFlags(meterRemoveDataObject.getFlags());
-            meterBuilder.setMeterBandHeaders(meterRemoveDataObject.getMeterBandHeaders());
-            meterBuilder.setMeterId(new MeterId(meterRemoveDataObject.getId()));
-            meterBuilder.setNode(meterRemoveDataObject.getNode());        
+            meterBuilder.fieldsFrom(meterRemoveDataObject);
+            meterBuilder.setNode(meterRemoveDataObject.getNode());            
+            meterBuilder.setMeterId(new MeterId(meterRemoveDataObject.getId()));           
             meterService.removeMeter(meterBuilder.build());
         } else {
             return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
@@ -279,22 +164,11 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
         return new Status(StatusCode.SUCCESS);
     }
 
-    public Status validateMeter(Meter meter, FRMUtil.operation operation) {
-        String containerName;
+    public Status validateMeter(Meter meter) {        
         String meterName;
         Status returnStatus = null;
 
         if (null != meter) {
-            containerName = meter.getContainerName();
-
-            if (null == containerName) {
-                containerName = GlobalConstants.DEFAULT.toString();
-            } else if (!FRMUtil.isNameValid(containerName)) {
-                logger.error("Container Name is invalid %s" + containerName);
-                returnStatus = new Status(StatusCode.BADREQUEST, "Container Name is invalid");
-                return returnStatus;
-            }
-
             meterName = meter.getMeterName();
             if (!FRMUtil.isNameValid(meterName)) {
                 logger.error("Meter Name is invalid %s" + meterName);
@@ -303,7 +177,7 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
             }
 
             for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
-                if (!meter.getFlags().isMeterBurst()) {
+                if (null != meter.getFlags() && !meter.getFlags().isMeterBurst()) {
                     if (0 < meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBurstSize()) {
                         logger.error("Burst size should only be associated when Burst FLAG is set");
                         returnStatus = new Status(StatusCode.BADREQUEST,
@@ -315,7 +189,7 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
 
             if (null != returnStatus && !returnStatus.isSuccess()) {
                 return returnStatus;
-            } else {
+            } else if (null != meter.getMeterBandHeaders()) {
                 BandType setBandType = null;
                 DscpRemark dscpRemark = null;
                 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
@@ -338,6 +212,47 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
         return new Status(StatusCode.SUCCESS);
     }
 
+    private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
+        DataModification<InstanceIdentifier<?>, DataObject> modification = transaction.modification;         
+        //get created entries      
+        Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries = 
+                                        modification.getCreatedConfigurationData().entrySet();
+        
+        //get updated entries
+        Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = 
+                    new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>(); 
+        
+        updatedEntries.addAll(modification.getUpdatedConfigurationData().entrySet());
+        updatedEntries.removeAll(createdEntries);
+
+        //get removed entries
+        Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers = 
+                                                    modification.getRemovedConfigurationData();
+        
+        for (Entry<InstanceIdentifier<? extends DataObject >, DataObject> entry : createdEntries) { 
+            if(entry.getValue() instanceof Meter) {   
+                addMeter(entry.getKey(), (Meter)entry.getValue());   
+            }   
+        } 
+        
+        for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) { 
+            if(entry.getValue() instanceof Meter) {   
+                Meter originalMeter = (Meter) modification.getOriginalConfigurationData().get(entry.getKey());    
+                Meter updatedMeter = (Meter) entry.getValue(); 
+                updateMeter(entry.getKey(), originalMeter, updatedMeter);   
+            }   
+        }   
+
+        for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {    
+            DataObject removeValue = modification.getOriginalConfigurationData().get(instanceId);   
+            if(removeValue instanceof Meter) {   
+                removeMeter(instanceId, (Meter)removeValue); 
+            }   
+        }
+
+        return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
+    }
+    
     final class InternalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
 
         private final DataModification<InstanceIdentifier<?>, DataObject> modification;
@@ -351,38 +266,13 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
             this.modification = modification;
         }
 
-        Map<InstanceIdentifier<?>, Meter> additions = new HashMap<>();
-        Map<InstanceIdentifier<?>, Meter> updates = new HashMap<>();
-        Set<InstanceIdentifier<?>> removals = new HashSet<>();
-
         /**
          * We create a plan which flows will be added, which will be updated and
          * which will be removed based on our internal state.
          *
          */
-        void prepareUpdate() {
-            
-            Set<Entry<InstanceIdentifier<?>, DataObject>> addMeter = modification.getCreatedConfigurationData().entrySet();
-            for (Entry<InstanceIdentifier<?>, DataObject> entry : addMeter) {
-                if (entry.getValue() instanceof Meter) {
-                    Meter meter = (Meter) entry.getValue();
-                    additions.put(entry.getKey(), meter);                    
-                }
-
-            }
+        void prepareUpdate() {           
             
-            Set<Entry<InstanceIdentifier<?>, DataObject>> updateMeter = modification.getUpdatedConfigurationData().entrySet();
-            for (Entry<InstanceIdentifier<?>, DataObject> entry : updateMeter) {
-                if (entry.getValue() instanceof Meter) {
-                    Meter meter = (Meter) entry.getValue();
-                  ///will be fixed once getUpdatedConfigurationData returns only updated data not created data with it.
-                    if (!additions.containsKey(entry.getKey())) {
-                       updates.put(entry.getKey(), meter);       
-                    }
-                }
-            }
-
-            removals = modification.getRemovedConfigurationData();
         }
 
         /**
@@ -392,9 +282,7 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
         @Override
         public RpcResult<Void> finish() throws IllegalStateException {
 
-            RpcResult<Void> rpcStatus = commitToPlugin(this);
-            // We return true if internal transaction is successful.
-            // return Rpcs.getRpcResult(true, null, Collections.emptySet());
+            RpcResult<Void> rpcStatus = commitToPlugin(this);           
             return rpcStatus;
         }
 
@@ -404,43 +292,13 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
          *
          */
         @Override
-        public RpcResult<Void> rollback() throws IllegalStateException {
-            // NOOP - we did not modified any internal state during
-            // requestCommit phase
-            // return Rpcs.getRpcResult(true, null, Collections.emptySet());
+        public RpcResult<Void> rollback() throws IllegalStateException {            
             return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
 
         }
 
     }
     
-    private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
-        for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.additions.entrySet()) {
-
-            if (!addMeter(entry.getKey(), entry.getValue()).isSuccess()) {
-                return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
-            }
-        }
-        for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.updates.entrySet()) {
-
-            if (!updateMeter(entry.getKey(), entry.getValue()).isSuccess()) {
-                return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
-            }
-        }
-
-        for (InstanceIdentifier<?> meterId : transaction.removals) {
-            DataObject removeValue = transaction.getModification().getOriginalConfigurationData().get(meterId);        
-                
-                if(removeValue instanceof Meter) {
-                    if(!removeMeter(meterId, (Meter)removeValue).isSuccess()) {
-                        return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
-                        }
-                }    
-        }
-
-        return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
-    }
-
     private final class MeterDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
         @Override
         public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
@@ -475,32 +333,5 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
             // TODO Auto-generated method stub
 
         }
-    }
-
-    @Override
-    public List<DataObject> get() {
-
-        List<DataObject> orderedList = new ArrayList<DataObject>();
-        Collection<Meter> meterList = originalSwMeterView.values();
-        for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
-            orderedList.add(iterator.next());
-        }
-        return orderedList;
-    }
-
-    @Override
-    public DataObject getWithName(String name, Node n) {
-        if (this instanceof MeterConsumerImpl) {
-            Collection<Meter> meterList = originalSwMeterView.values();
-            for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
-                Meter meter = iterator.next();
-                if (meter.getNode().equals(n) && meter.getMeterName().equals(name)) {
-
-                    return meter;
-                }
-            }
-        }
-        
-        return null;
-    }
+    }   
 }
index 0e78598c1137a339c7368be40b0b7a7e39427b9a..b34621d02d6f8da7a7b24e6e60cff5e641b9a8d4 100644 (file)
@@ -12,7 +12,7 @@
     </scm>
 
     <modules>
-        <!--  Common APIs & Implementation -->
+        <!-- Common APIs & Implementation -->
         <module>sal-common</module>
         <module>sal-common-api</module>
         <module>sal-common-impl</module>
         <module>sal-connector-api</module>
         <module>sal-rest-connector</module>
         <module>sal-netconf-connector</module>
-        
+
+        <module>zeromq-routingtable/implementation</module>
+        <module>sal-remoterpc-connector/implementation</module>
         <!-- Clustered Data Store -->
         <module>clustered-data-store/implementation</module>
 
         <module>inventory-manager</module>
         <module>statistics-manager</module>
         <module>forwardingrules-manager</module>
-        
+
         <!-- Compability Packages -->
         <module>compatibility</module>
-        <module>zeromq-routingtable/implementation</module>
-        <module>sal-zeromq-connector</module>
     </modules>
 
 
     <profiles>
         <profile>
-           <id>integrationtests</id>
-           <activation>
-               <activeByDefault>false</activeByDefault>
-           </activation>
+            <id>integrationtests</id>
+            <activation>
+                <activeByDefault>false</activeByDefault>
+            </activation>
             <modules>
                 <module>sal-binding-it</module>
-                <module>zeromq-routingtable/integrationtest</module>
                 <module>clustered-data-store/integrationtest</module>
-                <module>test</module>
+                <!--module>zeromq-routingtable/integrationtest</module -->
+                <!--module>sal-remoterpc-connector/integrationtest</module -->
+                <!--module>test/sal-rest-connector-it</modulei -->
             </modules>
         </profile>
         <profile>
-          <id>IDE</id>
-          <activation>
-            <property>
-              <name>m2e.version</name>
-            </property>
-          </activation>
-          <build>
-            <!-- Put the IDE's build output in a folder other than target, so that IDE builds don't interact with Maven builds -->
-            <directory>target-ide</directory>
-          </build>
+            <id>IDE</id>
+            <activation>
+                <property>
+                    <name>m2e.version</name>
+                </property>
+            </activation>
+            <build>
+                <!-- Put the IDE's build output in a folder other than target, 
+                    so that IDE builds don't interact with Maven builds -->
+                <directory>target-ide</directory>
+            </build>
         </profile>
     </profiles>
 
         <guava.version>14.0.1</guava.version>
         <osgi.core.version>5.0.0</osgi.core.version>
         <junit.version>4.8.1</junit.version>
+        <powermock.version>1.5.1</powermock.version>
+        <mockito.version>1.9.5</mockito.version>
         <xtend.version>2.4.3</xtend.version>
         <maven.clean.plugin.version>2.5</maven.clean.plugin.version>
         <jacoco.version>0.5.3.201107060350</jacoco.version>
+        <sal.version>0.5.1-SNAPSHOT</sal.version>  <!-- AD Sal version -->
+
         <!-- Sonar properties using jacoco to retrieve integration test results -->
         <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
         <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
     <pluginRepositories>
         <!-- OpenDayLight Repo Mirror -->
         <pluginRepository>
-          <id>opendaylight-mirror</id>
-          <name>opendaylight-mirror</name>
-          <url>${nexusproxy}/groups/public/</url>
-          <snapshots>
-              <enabled>false</enabled>
-          </snapshots>
-          <releases>
-              <enabled>true</enabled>
-              <updatePolicy>never</updatePolicy>
-          </releases>
+            <id>opendaylight-mirror</id>
+            <name>opendaylight-mirror</name>
+            <url>${nexusproxy}/groups/public/</url>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+            <releases>
+                <enabled>true</enabled>
+                <updatePolicy>never</updatePolicy>
+            </releases>
         </pluginRepository>
         <!-- OpenDayLight Snapshot artifact -->
         <pluginRepository>
-          <id>opendaylight-snapshot</id>
-          <name>opendaylight-snapshot</name>
-          <url> ${nexusproxy}/repositories/opendaylight.snapshot/</url>
-          <snapshots>
-              <enabled>true</enabled>
-          </snapshots>
-          <releases>
-              <enabled>false</enabled>
-          </releases>
+            <id>opendaylight-snapshot</id>
+            <name>opendaylight-snapshot</name>
+            <url> ${nexusproxy}/repositories/opendaylight.snapshot/</url>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+            <releases>
+                <enabled>false</enabled>
+            </releases>
         </pluginRepository>
     </pluginRepositories>
 
     <repositories>
         <!-- OpenDayLight Repo Mirror -->
         <repository>
-          <id>opendaylight-mirror</id>
-          <name>opendaylight-mirror</name>
-          <url>${nexusproxy}/groups/public/</url>
-          <snapshots>
-              <enabled>false</enabled>
-          </snapshots>
-          <releases>
-              <enabled>true</enabled>
-              <updatePolicy>never</updatePolicy>
-          </releases>
+            <id>opendaylight-mirror</id>
+            <name>opendaylight-mirror</name>
+            <url>${nexusproxy}/groups/public/</url>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+            <releases>
+                <enabled>true</enabled>
+                <updatePolicy>never</updatePolicy>
+            </releases>
         </repository>
         <!-- OpenDayLight Snapshot artifact -->
         <repository>
-          <id>opendaylight-snapshot</id>
-          <name>opendaylight-snapshot</name>
-          <url> ${nexusproxy}/repositories/opendaylight.snapshot/</url>
-          <snapshots>
-              <enabled>true</enabled>
-          </snapshots>
-          <releases>
-              <enabled>false</enabled>
-          </releases>
+            <id>opendaylight-snapshot</id>
+            <name>opendaylight-snapshot</name>
+            <url> ${nexusproxy}/repositories/opendaylight.snapshot/</url>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+            <releases>
+                <enabled>false</enabled>
+            </releases>
         </repository>
     </repositories>
 
                 <artifactId>yang-data-api</artifactId>
                 <version>${yang.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-data-impl</artifactId>
+                <version>${yang.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-model-api</artifactId>
                 <artifactId>sal-connector-api</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>sal</artifactId>
+                <version>${sal.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.osgi</groupId>
+                        <artifactId>org.osgi.compendium</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
 
             <!-- Supporting Libraries -->
             <dependency>
                 <artifactId>org.eclipse.xtend.lib</artifactId>
                 <version>${xtend.version}</version>
             </dependency>
-
+            <dependency>
+                <groupId>org.osgi</groupId>
+                <artifactId>org.osgi.core</artifactId>
+                <version>${osgi.core.version}</version>
+            </dependency>
             <!-- Testing Dependencies -->
             <dependency>
                 <groupId>junit</groupId>
             <dependency>
                 <groupId>org.mockito</groupId>
                 <artifactId>mockito-all</artifactId>
-                <version>1.9.5</version>
+                <version>${mockito.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.powermock</groupId>
+                <artifactId>powermock-module-junit4</artifactId>
+                <version>${powermock.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.powermock</groupId>
+                <artifactId>powermock-api-mockito</artifactId>
+                <version>${powermock.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.powermock</groupId>
+                <artifactId>powermock-core</artifactId>
+                <version>${powermock.version}</version>
                 <scope>test</scope>
             </dependency>
         </dependencies>
                     <artifactId>maven-bundle-plugin</artifactId>
                     <version>${bundle.plugin.version}</version>
                     <extensions>true</extensions>
-                    <!--executions>
-                        <execution>
-                            <id>bundle-manifest</id>
-                            <phase>process-classes</phase>
-                            <goals>
-                                <goal>manifest</goal>
-                            </goals>
-                        </execution>
-                    </executions-->
+                    <!--executions> <execution> <id>bundle-manifest</id> 
+                        <phase>process-classes</phase> <goals> <goal>manifest</goal> </goals> </execution> 
+                        </executions -->
                     <configuration>
                         <instructions>
                             <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
                     <artifactId>jacoco-maven-plugin</artifactId>
                     <version>${jacoco.version}</version>
                 </plugin>
-                <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
+                <!--This plugin's configuration is used to store Eclipse 
+                    m2e settings only. It has no influence on the Maven build itself. -->
                 <plugin>
                     <groupId>org.eclipse.m2e</groupId>
                     <artifactId>lifecycle-mapping</artifactId>
                                         </goals>
                                     </pluginExecutionFilter>
                                     <action>
-                                        <ignore/>
+                                        <ignore />
                                     </action>
                                 </pluginExecution>
                                 <pluginExecution>
                                         </goals>
                                     </pluginExecutionFilter>
                                     <action>
-                                      <ignore/>
+                                        <ignore />
                                     </action>
                                 </pluginExecution>
                                 <pluginExecution>
                                         </goals>
                                     </pluginExecutionFilter>
                                     <action>
-                                        <ignore/>
+                                        <ignore />
                                     </action>
                                 </pluginExecution>
                             </pluginExecutions>
index a1a24ebc8a55447a96ca8368320b8156bded9c68..5da084e9bd6b68823d35adccc82e86d8008d1a37 100644 (file)
@@ -1,14 +1,15 @@
 package org.opendaylight.controller.config.yang.md.sal.binding.statistics;\r
 \r
+import org.opendaylight.controller.config.yang.md.sal.binding.impl.Data;\r
 import org.opendaylight.controller.config.yang.md.sal.binding.impl.DataBrokerImplRuntimeMXBean;\r
 import org.opendaylight.controller.config.yang.md.sal.binding.impl.Transactions;\r
 import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;\r
 \r
 public class DataBrokerRuntimeMXBeanImpl extends DataBrokerImpl implements DataBrokerImplRuntimeMXBean {\r
     \r
-    private Transactions transactions = new Transactions();\r
+    private final Transactions transactions = new Transactions();\r
+    private final Data data = new Data();\r
     \r
-    @Override\r
     public Transactions getTransactions() {\r
         transactions.setCreated(getCreatedTransactionsCount().get());\r
         transactions.setSubmitted(getSubmittedTransactionsCount().get());\r
@@ -16,4 +17,14 @@ public class DataBrokerRuntimeMXBeanImpl extends DataBrokerImpl implements DataB
         transactions.setFailed(getFailedTransactionsCount().get());\r
         return transactions;\r
     }\r
+\r
+    @Override\r
+    public Data getData() {\r
+        transactions.setCreated(getCreatedTransactionsCount().get());\r
+        transactions.setSubmitted(getSubmittedTransactionsCount().get());\r
+        transactions.setSuccessful(getFinishedTransactionsCount().get());\r
+        transactions.setFailed(getFailedTransactionsCount().get());\r
+        data.setTransactions(transactions);\r
+        return data;\r
+    }\r
 }\r
index a31d3eedd2ee5ba0e08b203fdbb77647ea39e523..b9a4fe87ac80518d054372b5d1056227ea683efb 100644 (file)
@@ -2,6 +2,7 @@ package org.opendaylight.controller.sal.binding.dom.serializer.api;
 
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.Identifier;
 
@@ -14,6 +15,8 @@ import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCode
 public interface CodecRegistry {
 
     InstanceIdentifierCodec getInstanceIdentifierCodec();
+    
+    IdentitityCodec<?> getIdentityCodec();
 
     <T extends DataContainer> DataContainerCodec<T> getCodecForDataObject(Class<T> object);
 
@@ -22,6 +25,8 @@ public interface CodecRegistry {
     <T extends Identifier<?>> IdentifierCodec<T> getCodecForIdentifier(Class<T> object);
 
     <T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object);
+    
+    <T extends BaseIdentity> IdentitityCodec<T> getCodecForIdentity(Class<T> codec);
 
     Class<?> getClassForPath(List<QName> names);
 
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentitityCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentitityCodec.java
new file mode 100644 (file)
index 0000000..0c480f5
--- /dev/null
@@ -0,0 +1,14 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public interface IdentitityCodec<T extends BaseIdentity> extends BindingCodec<QName, Class<T>>{
+
+    @Override
+    public QName serialize(Class<T> input);
+    
+    @Override
+    public Class<T> deserialize(QName input);
+}
index 172fb05292043e49612a8bee700750c6ca68810f..fa2d32a1387d95aa6a65c251279465ca3aaf27f6 100644 (file)
@@ -3,6 +3,7 @@ package org.opendaylight.controller.sal.binding.dom.serializer.impl;
 import java.lang.reflect.Field;
 import java.util.Map;
 
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentitityCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec;
 import org.opendaylight.yangtools.yang.binding.BindingCodec;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -15,6 +16,8 @@ public class CodecMapping {
     private static final Logger LOG = LoggerFactory.getLogger(CodecMapping.class);
     
     public static final String INSTANCE_IDENTIFIER_CODEC = "INSTANCE_IDENTIFIER_CODEC";
+    public static final String IDENTITYREF_CODEC = "IDENTITYREF_CODEC";
+    
     public static final String CLASS_TO_CASE_MAP = "CLASS_TO_CASE";
     public static final String COMPOSITE_TO_CASE = "COMPOSITE_TO_CASE";
     public static final String AUGMENTATION_CODEC = "AUGMENTATION_CODEC";
@@ -27,7 +30,22 @@ public class CodecMapping {
                 instanceIdField.set(null, codec);
             }
         } catch (NoSuchFieldException e) {
-           LOG.debug("Instance identifier codec is not needed for {}",obj.getName(),e);
+           LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e);
+        } catch (SecurityException | IllegalAccessException e) {
+            LOG.error("Instance identifier could not be set for {}",obj.getName(),e);
+        }
+    }
+
+
+    public static void setIdentityRefCodec(Class<?> obj,IdentitityCodec<?> codec) {
+        Field instanceIdField;
+        try {
+            instanceIdField = obj.getField(IDENTITYREF_CODEC);
+            if(obj != null) {
+                instanceIdField.set(null, codec);
+            }
+        } catch (NoSuchFieldException e) {
+           LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e);
         } catch (SecurityException | IllegalAccessException e) {
             LOG.error("Instance identifier could not be set for {}",obj.getName(),e);
         }
@@ -71,4 +89,18 @@ public class CodecMapping {
                 LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e);
             }
     }
+    
+    
+    public static BindingCodec<?,?> getAugmentationCodec(Class<? extends BindingCodec<?,?>> dataCodec) {
+            Field instanceIdField;
+            try {
+                instanceIdField = dataCodec.getField(AUGMENTATION_CODEC);
+                return (BindingCodec<?,?>) instanceIdField.get(null);
+            } catch (NoSuchFieldException e) {
+                LOG.debug("BUG: Augmentation codec is not needed for {}",dataCodec.getName(),e);
+            } catch (SecurityException | IllegalAccessException e) {
+                LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e);
+            }
+            return null;
+    }
 }
index d0b114e3c37930727146fa6c3cb7a1e191a2ef61..04b8674727ced600871d3e9c44b05657c95d6658 100644 (file)
@@ -13,7 +13,10 @@ class IntermediateMapping {
     
     
     
-    static def Node<?> toNode(Map map) {
+    static def Node<?> toNode(Map<?,?> map) {
+        if(map instanceof Node<?>) {
+            return map as Node<?>;
+        }
         val nodeMap = map as Map<QName,Object>;
         Preconditions.checkArgument(map.size == 1);
         val elem = nodeMap.entrySet.iterator.next;
@@ -22,10 +25,15 @@ class IntermediateMapping {
         toNodeImpl(qname, value);
     }
 
+
     static def dispatch Node<?> toNodeImpl(QName name, List<?> objects) {
         val values = new ArrayList<Node<?>>(objects.size);
         for (obj : objects) {
-            values.add(toNode(obj as Map));
+            if(obj instanceof Node<?>) {
+                values.add(obj as Node<?>);
+            } else if(obj instanceof Map<?,?>) {
+                values.add(toNode(obj as Map<?,?>));
+            }
         }
         return new CompositeNodeTOImpl(name, null, values);
     }
index d33272d6413bfa90628f49a459671eab756ef2d0..39bd0816f50fb63e68bbbdb85ca7cbdce74812b6 100644 (file)
@@ -1,7 +1,9 @@
 package org.opendaylight.controller.sal.binding.dom.serializer.impl;
 
+import java.awt.CompositeContext;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -12,11 +14,13 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.Set;
 import java.util.WeakHashMap;
 
+import org.apache.commons.lang3.text.translate.AggregateTranslator;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCaseCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCodec;
@@ -24,6 +28,7 @@ import org.opendaylight.controller.sal.binding.dom.serializer.api.CodecRegistry;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.DomCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentitityCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName;
 import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils;
@@ -34,6 +39,7 @@ import org.opendaylight.yangtools.concepts.Delegator;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.binding.Augmentable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.BindingCodec;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -41,6 +47,7 @@ import org.opendaylight.yangtools.yang.binding.Identifier;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
@@ -61,10 +68,12 @@ import static org.opendaylight.controller.sal.binding.dom.serializer.impl.Interm
 import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext;
 import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.CycleDetectingLockFactory.WithExplicitOrdering;
 
 public class LazyGeneratedCodecRegistry implements //
@@ -76,27 +85,31 @@ public class LazyGeneratedCodecRegistry implements //
     private final static LateMixinCodec NOT_READY_CODEC = new LateMixinCodec();
 
     private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this);
+    private final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec();
 
     private TransformerGenerator generator;
 
     // Concrete class to codecs
-    private Map<Class<?>, DataContainerCodec<?>> containerCodecs = new WeakHashMap<>();
-    private Map<Class<?>, IdentifierCodec<?>> identifierCodecs = new WeakHashMap<>();
-    private Map<Class<?>, ChoiceCodecImpl<?>> choiceCodecs = new WeakHashMap<>();
-    private Map<Class<?>, ChoiceCaseCodecImpl<?>> caseCodecs = new WeakHashMap<>();
-    private Map<Class<?>, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>();
-
+    private static final Map<Class<?>, DataContainerCodec<?>> containerCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, IdentifierCodec<?>> identifierCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, ChoiceCodecImpl<?>> choiceCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, ChoiceCaseCodecImpl<?>> caseCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, AugmentationCodec<?>> augmentationCodecs = new WeakHashMap<>();
+    private static final Map<Class<?>, QName> identityQNames = new WeakHashMap<>();
+    private static final Map<QName, Type> qnamesToIdentityMap = new ConcurrentHashMap<>();
     /** Binding type to encountered classes mapping **/
     @SuppressWarnings("rawtypes")
-    Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
+    private static final Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
 
     @SuppressWarnings("rawtypes")
-    private ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
+    private static final ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
 
     private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
 
-    Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
-    Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
+    private static final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
+    private static final Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
+    private static final Map<Type, QName> typeToQname = new ConcurrentHashMap<>();
 
     private SchemaContext currentSchema;
 
@@ -115,8 +128,56 @@ public class LazyGeneratedCodecRegistry implements //
 
     @Override
     public <T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object) {
-        // TODO Auto-generated method stub
-        return null;
+        AugmentationCodec<T> codec = null;
+        @SuppressWarnings("rawtypes")
+        AugmentationCodec potentialCodec = augmentationCodecs.get(object);
+        if (potentialCodec != null) {
+            codec = potentialCodec;
+        } else
+            try {
+                Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentRawCodec = generator
+                        .augmentationTransformerFor(object);
+                BindingCodec<Map<QName, Object>, Object> rawCodec = augmentRawCodec.newInstance();
+                codec = new AugmentationCodecWrapper<T>(rawCodec);
+                augmentationCodecs.put(augmentRawCodec, codec);
+            } catch (InstantiationException e) {
+                LOG.error("Can not instantiate raw augmentation codec {}", object.getSimpleName(), e);
+            } catch (IllegalAccessException e) {
+                LOG.debug("BUG: Constructor for {} is not accessible.", object.getSimpleName(), e);
+            }
+        Class<? extends Augmentable<?>> objectSupertype = getAugmentableArgumentFrom(object);
+        if (objectSupertype != null) {
+            getAugmentableCodec(objectSupertype).addAugmentationCodec(object, codec);
+        } else {
+            LOG.warn("Could not find augmentation target for augmentation {}", object);
+        }
+        return codec;
+    }
+
+    private static Class<? extends Augmentable<?>> getAugmentableArgumentFrom(
+            final Class<? extends Augmentation<?>> augmentation) {
+        try {
+            Class<? extends Augmentable<?>> ret = ClassLoaderUtils.withClassLoader(augmentation.getClassLoader(),
+                    new Callable<Class<? extends Augmentable<?>>>() {
+                        @Override
+                        @SuppressWarnings("unchecked")
+                        public Class<? extends Augmentable<?>> call() throws Exception {
+                            for (java.lang.reflect.Type supertype : augmentation.getGenericInterfaces()) {
+                                if (supertype instanceof ParameterizedType
+                                        && Augmentation.class.equals(((ParameterizedType) supertype).getRawType())) {
+                                    ParameterizedType augmentationGeneric = (ParameterizedType) supertype;
+                                    return (Class<? extends Augmentable<?>>) augmentationGeneric
+                                            .getActualTypeArguments()[0];
+                                }
+                            }
+                            return null;
+                        }
+                    });
+            return ret;
+        } catch (Exception e) {
+            LOG.error("Could not find augmentable for {}", augmentation, e);
+            return null;
+        }
     }
 
     @Override
@@ -165,7 +226,6 @@ public class LazyGeneratedCodecRegistry implements //
         return newWrapper;
     }
 
-    @Override
     @SuppressWarnings("rawtypes")
     public void bindingClassEncountered(Class cls) {
 
@@ -268,9 +328,21 @@ public class LazyGeneratedCodecRegistry implements //
         return newWrapper;
     }
 
+    @Override
+    public IdentitityCodec<?> getIdentityCodec() {
+        return identityRefCodec;
+    }
+
+    @Override
+    public <T extends BaseIdentity> IdentitityCodec<T> getCodecForIdentity(Class<T> codec) {
+        bindingClassEncountered(codec);
+        return identityRefCodec;
+    }
+
     @Override
     public void onCodecCreated(Class<?> cls) {
         CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec);
+        CodecMapping.setIdentityRefCodec(cls, identityRefCodec);
     }
 
     @Override
@@ -316,6 +388,10 @@ public class LazyGeneratedCodecRegistry implements //
 
     public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) {
         pathToType.putAll(context.getChildNodes());
+        qnamesToIdentityMap.putAll(context.getIdentities());
+        for(Entry<QName, GeneratedTOBuilder> identity : context.getIdentities().entrySet()) {
+            typeToQname.put(new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()),identity.getKey());
+        }
         captureCases(context.getCases(), schemaContext);
     }
 
@@ -324,7 +400,6 @@ public class LazyGeneratedCodecRegistry implements //
             ReferencedTypeImpl typeref = new ReferencedTypeImpl(caseNode.getValue().getPackageName(), caseNode
                     .getValue().getName());
 
-            LOG.info("Case path: {} Type : {}", caseNode.getKey(), caseNode.getValue().getFullyQualifiedName());
             pathToType.put(caseNode.getKey(), caseNode.getValue());
 
             ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey());
@@ -371,10 +446,10 @@ public class LazyGeneratedCodecRegistry implements //
             if (path != null && (type = pathToType.get(path)) != null) {
                 ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
                 ChoiceCaseCodecImpl partialCodec = typeToCaseCodecs.get(typeref);
-                if(partialCodec.getSchema() == null ) {
+                if (partialCodec.getSchema() == null) {
                     partialCodec.setSchema(caseNode);
                 }
-                
+
                 Class<?> caseClass = ClassLoaderUtils.tryToLoadClassWithTCCL(type.getFullyQualifiedName());
                 if (caseClass != null) {
                     getCaseCodecFor(caseClass);
@@ -402,7 +477,7 @@ public class LazyGeneratedCodecRegistry implements //
 
     }
 
-    private AugmentableCompositeCodec getAugmentableCodec(Class<?> dataClass) {
+    public AugmentableCompositeCodec getAugmentableCodec(Class<?> dataClass) {
         AugmentableCompositeCodec ret = augmentableCodecs.get(dataClass);
         if (ret != null) {
             return ret;
@@ -739,7 +814,7 @@ public class LazyGeneratedCodecRegistry implements //
 
         private final Class augmentableType;
 
-        Map<Class, BindingCodec> rawAugmentationCodecs = new WeakHashMap<>();
+        Map<Class, AugmentationCodec<?>> localAugmentationCodecs = new WeakHashMap<>();
 
         public AugmentableCompositeCodec(Class type) {
             checkArgument(Augmentable.class.isAssignableFrom(type));
@@ -772,53 +847,33 @@ public class LazyGeneratedCodecRegistry implements //
         private List serializeImpl(Map<Class, Augmentation> input) {
             List ret = new ArrayList<>();
             for (Entry<Class, Augmentation> entry : input.entrySet()) {
-                BindingCodec codec = getRawCodecForAugmentation(entry.getKey());
-                List output = (List) codec.serialize(new ValueWithQName(null, entry.getValue()));
-                ret.addAll(output);
+                AugmentationCodec codec = getCodecForAugmentation(entry.getKey());
+                CompositeNode node = codec.serialize(new ValueWithQName(null, entry.getValue()));
+                ret.addAll(node.getChildren());
             }
             return ret;
         }
 
-        private BindingCodec getRawCodecForAugmentation(Class key) {
-            BindingCodec ret = rawAugmentationCodecs.get(key);
-            if (ret != null) {
-                return ret;
-            }
-            try {
-                Class<? extends BindingCodec> retClass = generator.augmentationTransformerFor(key);
-                ret = retClass.newInstance();
-                rawAugmentationCodecs.put(key, ret);
-                return ret;
-            } catch (InstantiationException e) {
-                LOG.error("Can not instantiate raw augmentation codec {}", key.getSimpleName(), e);
-            } catch (IllegalAccessException e) {
-                LOG.debug("BUG: Constructor for {} is not accessible.", key.getSimpleName(), e);
-            }
-            return null;
+        public synchronized <T extends Augmentation<?>> void addAugmentationCodec(Class<T> augmentationClass,
+                AugmentationCodec<T> value) {
+            localAugmentationCodecs.put(augmentationClass, value);
         }
 
         @Override
         public Map<Class, Augmentation> deserialize(Object input) {
             Map<Class, Augmentation> ret = new HashMap<>();
             if (input instanceof CompositeNode) {
-                for (Entry<Class, BindingCodec> codec : rawAugmentationCodecs.entrySet()) {
-                    Augmentation value = (Augmentation) codec.getValue().deserialize(input);
-                    if (value != null) {
-                        ret.put(codec.getKey(), value);
+                List<Entry<Class, AugmentationCodec<?>>> codecs = new ArrayList<>(localAugmentationCodecs.entrySet());
+                for (Entry<Class, AugmentationCodec<?>> codec : codecs) {
+                    ValueWithQName<?> value = codec.getValue().deserialize((CompositeNode) input);
+                    if (value != null && value.getValue() != null) {
+                        ret.put(codec.getKey(), (Augmentation) value.getValue());
                     }
                 }
             }
             return ret;
         }
 
-        public Map<Class, BindingCodec> getRawAugmentationCodecs() {
-            return rawAugmentationCodecs;
-        }
-
-        public void setRawAugmentationCodecs(Map<Class, BindingCodec> rawAugmentationCodecs) {
-            this.rawAugmentationCodecs = rawAugmentationCodecs;
-        }
-
         public Class getAugmentableType() {
             return augmentableType;
         }
@@ -847,4 +902,82 @@ public class LazyGeneratedCodecRegistry implements //
             return getDelegate().serialize(input);
         }
     }
+
+    private static class AugmentationCodecWrapper<T extends Augmentation<?>> implements AugmentationCodec<T>,
+            Delegator<BindingCodec> {
+
+        private BindingCodec delegate;
+
+        public AugmentationCodecWrapper(BindingCodec<Map<QName, Object>, Object> rawCodec) {
+            this.delegate = rawCodec;
+        }
+
+        @Override
+        public BindingCodec getDelegate() {
+            return delegate;
+        }
+
+        @Override
+        public CompositeNode serialize(ValueWithQName<T> input) {
+            @SuppressWarnings("unchecked")
+            List<Map<QName, Object>> rawValues = (List<Map<QName, Object>>) getDelegate().serialize(input);
+            List<Node<?>> serialized = new ArrayList<>(rawValues.size());
+            for (Map<QName, Object> val : rawValues) {
+                serialized.add(toNode(val));
+            }
+            return new CompositeNodeTOImpl(input.getQname(), null, serialized);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public ValueWithQName<T> deserialize(Node<?> input) {
+            Object rawCodecValue = getDelegate().deserialize((Map<QName, Object>) input);
+            return new ValueWithQName<T>(input.getNodeType(), (T) rawCodecValue);
+        }
+    }
+
+    private class IdentityCompositeCodec implements IdentitityCodec {
+
+        @Override
+        public Object deserialize(Object input) {
+            checkArgument(input instanceof QName);
+            return deserialize((QName) input);
+        }
+
+        @Override
+        public Class<?> deserialize(QName input) {
+            Type type = qnamesToIdentityMap.get(input);
+            if(type == null) {
+                return null;
+            }
+            ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+            WeakReference<Class> softref = typeToClass.get(typeref);
+            if(softref == null) {
+                return null;
+            }
+            return softref.get();
+        }
+
+        @Override
+        public QName serialize(Class input) {
+            checkArgument(BaseIdentity.class.isAssignableFrom(input));
+            bindingClassEncountered(input);
+            QName qname = identityQNames.get(input);
+            if(qname != null) {
+                return qname;
+            }
+            ConcreteType typeref = Types.typeForClass(input);
+            qname = typeToQname.get(typeref);
+            if(qname != null) {
+                identityQNames.put(input, qname);
+            }
+            return qname;
+        }
+
+        @Override
+        public Object serialize(Object input) {
+            checkArgument(input instanceof Class);
+            return serialize((Class) input);
+        }
+    }
 }
\ No newline at end of file
index cb25f4da8bb9247845c251ed95b67ee6ffeca4d5..13975cad4c807abc636870f99fbea2a921e4a312 100644 (file)
@@ -37,6 +37,12 @@ import org.opendaylight.controller.sal.binding.impl.connect.dom.DeserializationE
 import java.util.concurrent.Callable
 import org.opendaylight.yangtools.yang.binding.Augmentation
 import org.opendaylight.controller.sal.binding.impl.util.YangSchemaUtils
+import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
 
 class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
 
@@ -112,9 +118,21 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
 
     override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
         Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
+        
+        try {
         val key = toDataDom(entry.key)
-        val data = toCompositeNodeImpl(entry.value);
+        var CompositeNode data;
+        if(Augmentation.isAssignableFrom(entry.key.targetType)) {
+            data = toCompositeNodeImpl(key,entry.value);
+        } else {
+          data = toCompositeNodeImpl(entry.value);
+        }
         return new SimpleEntry(key, data);
+        
+        } catch (Exception e) {
+            LOG.error("Error during serialization for {}.", entry.key,e);
+            throw e;
+        }
     }
 
     private def CompositeNode toCompositeNodeImpl(DataObject object) {
@@ -124,6 +142,26 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
         val ret = codec.serialize(new ValueWithQName(null, object));
         return ret as CompositeNode;
     }
+    
+    
+    private def CompositeNode toCompositeNodeImpl(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,DataObject object) {
+       
+        //val cls = object.implementedInterface;
+        //waitForSchema(cls);
+        val last = identifier.path.last;
+        val codec = registry.getCodecForAugmentation(object.implementedInterface as Class) as AugmentationCodec;
+        val ret = codec.serialize(new ValueWithQName(last.nodeType, object));
+        if(last instanceof NodeIdentifierWithPredicates) {
+            val predicates = last as NodeIdentifierWithPredicates;
+            val newNodes = new ArrayList<Node<?>>(predicates.keyValues.size);
+            for(predicate : predicates.keyValues.entrySet) {
+                newNodes.add(new SimpleNodeTOImpl(predicate.key,null,predicate.value));
+            }
+            newNodes.addAll(ret.children);
+            return new CompositeNodeTOImpl(last.nodeType,null,newNodes);
+        }
+        return ret as CompositeNode;
+    }
 
     private def void waitForSchema(Class<? extends DataContainer> class1) {
         if(Augmentation.isAssignableFrom(class1)) {
index 0316614aa1269a93eb8d6aa3f7d2e3fd2a4438a7..b2d25af8850bd5b40a369e136baf710d9e669735 100644 (file)
@@ -91,6 +91,8 @@ class TransformerGenerator {
 
     @Property
     var GeneratorListener listener;
+    
+    public static val CLASS_TYPE = Types.typeForClass(Class);
 
     public new(ClassPool pool) {
         classPool = pool;
@@ -269,6 +271,7 @@ class TransformerGenerator {
             val ctCls = createClass(inputType.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
                 staticQNameField(node.QName);
                 implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
@@ -351,6 +354,7 @@ class TransformerGenerator {
                 staticQNameField(node.QName);
                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
                 staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
@@ -409,6 +413,7 @@ class TransformerGenerator {
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
                 staticQNameField(node.QName);
                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
                 staticField(it, AUGMENTATION_CODEC, BindingCodec)
                 implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
@@ -459,6 +464,7 @@ class TransformerGenerator {
                 staticQNameField(node.augmentationQName);
                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
                 staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
                 implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
@@ -466,7 +472,7 @@ class TransformerGenerator {
                         {
                             //System.out.println("Qname " + $1);
                             //System.out.println("Value " + $2);
-                            Â«QName.name» _resultName = Â«QName.name».create($1,QNAME.getLocalName());
+                            Â«QName.name» _resultName = Â«QName.name».create(QNAME,QNAME.getLocalName());
                             java.util.List _childNodes = new java.util.ArrayList();
                             Â«type.resolvedName» value = («type.resolvedName») $2;
                             Â«FOR child : node.childNodes»
@@ -540,6 +546,7 @@ class TransformerGenerator {
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
                 //staticQNameField(inputType);
                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
                 staticField(it, CLASS_TO_CASE_MAP, Map)
                 staticField(it, COMPOSITE_TO_CASE, Map)
                 //staticField(it,QNAME_TO_CASE_MAP,BindingCodec)
@@ -828,6 +835,7 @@ class TransformerGenerator {
                 if (hasYangBinding) {
                     implementsType(BINDING_CODEC)
                     staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                    staticField(it, IDENTITYREF_CODEC, BindingCodec)
                     implementsType(BindingDeserializer.asCtClass)
                 }
                 method(Object, "toDomValue", Object) [
@@ -1020,10 +1028,10 @@ class TransformerGenerator {
 
     private def dispatch String deserializeValue(Type type, String domParameter) {
         if (INSTANCE_IDENTIFIER.equals(type)) {
-
             return '''(«InstanceIdentifier.name») Â«INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)'''
+        } else if (CLASS_TYPE.equals(type)) {
+            return '''(«Class.name») Â«IDENTITYREF_CODEC».deserialize(«domParameter»)'''
         }
-
         return '''(«type.resolvedName») Â«domParameter»'''
 
     }
@@ -1192,6 +1200,8 @@ class TransformerGenerator {
     private def dispatch serializeValue(Type signature, String property) {
         if (INSTANCE_IDENTIFIER == signature) {
             return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)'''
+        }else if (CLASS_TYPE.equals(signature)) {
+            return '''(«QName.resolvedName») Â«IDENTITYREF_CODEC».serialize(«property»)'''
         }
         return '''«property»''';
     }
index 5f3189f7d2a196593ec2c903c1a2eb717c488ac5..9eff29f8cc4e256f6d9c3163cb551650e226b02f 100644 (file)
@@ -22,6 +22,8 @@ import org.opendaylight.controller.sal.core.api.Provider;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
 import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcError;
@@ -61,8 +63,22 @@ public class BindingIndependentDataServiceConnector implements //
     public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
         try {
             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
+            
+            
             CompositeNode result = biDataService.readOperationalData(biPath);
+            Class<? extends DataObject> targetType = path.getTargetType();
+            
+            if(Augmentation.class.isAssignableFrom(targetType)) {
+                path = mappingService.fromDataDom(biPath);
+                Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
+                DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
+                if(parentTo instanceof Augmentable<?>) {
+                    return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
+                }
+                
+            }
             return mappingService.dataObjectFromDataDom(path, result);
+            
         } catch (DeserializationException e) {
             throw new IllegalStateException(e);
         }
@@ -116,7 +132,7 @@ public class BindingIndependentDataServiceConnector implements //
                 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
                 target.putConfigurationData(baKey, baData);
             } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry.getKey(), e);
+                LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
             }
         }
         for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
@@ -127,7 +143,7 @@ public class BindingIndependentDataServiceConnector implements //
                 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
                 target.putOperationalData(baKey, baData);
             } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry.getKey(), e);
+                LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
             }
         }
         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
@@ -136,7 +152,7 @@ public class BindingIndependentDataServiceConnector implements //
                 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
                 target.removeConfigurationData(baEntry);
             } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry, e);
+                LOG.error("Ommiting from BA transaction: {}.", entry, e);
             }
         }
         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
@@ -145,7 +161,7 @@ public class BindingIndependentDataServiceConnector implements //
                 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
                 target.removeOperationalData(baEntry);
             } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry, e);
+                LOG.error("Ommiting from BA transaction: {}.", entry, e);
             }
         }
         return target;
index 9da073f71b44545694350d17c15f588ea2c36af3..b040aa025e2bd05450f5458922df34f85c46fa30 100644 (file)
@@ -121,7 +121,9 @@ module opendaylight-sal-binding-broker-impl {
     augment "/config:modules/config:module/config:state" {
         case binding-data-broker {
             when "/config:modules/config:module/config:type = 'binding-data-broker'";
-            uses common:data-state;
+            container data {
+                uses common:data-state;
+            }
         }
     }
     augment "/config:modules/config:module/config:state" {
index 9a143d3f008f5843ce36676f16afc5a293bf6143..6525fa078ed991ed26bed4e9491b79b4dd4ebe95 100644 (file)
@@ -49,7 +49,7 @@
     </build>
 
     <dependencies>
-    <dependency>
+        <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-binding-broker-impl</artifactId>
             <version>1.0-SNAPSHOT</version>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+            <version>1.7.2</version>
+        </dependency>
     </dependencies>
 </project>
diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java
new file mode 100644 (file)
index 0000000..96d0361
--- /dev/null
@@ -0,0 +1,176 @@
+package org.opendaylight.controller.sal.binding.test.bugfix;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+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.FlowCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionTypeBuilder;
+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.NodeBuilder;
+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.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+import static org.junit.Assert.*;
+
+public class PutAugmentationTest extends AbstractDataServiceTest implements DataChangeListener {
+
+    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+    private static final String NODE_ID = "openflow:1";
+
+    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+
+    private static final Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
+            NODE_ID);
+
+    private static final InstanceIdentifier<Nodes> NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+            .toInstance();
+
+
+    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier//
+            .builder(NODES_INSTANCE_ID_BA) //
+            .child(Node.class, NODE_KEY).toInstance();
+    
+    
+    private static final InstanceIdentifier<SupportedActions> SUPPORTED_ACTIONS_INSTANCE_ID_BA = InstanceIdentifier//
+            .builder(NODES_INSTANCE_ID_BA) //
+            .child(Node.class, NODE_KEY) //
+            .augmentation(FlowCapableNode.class) //
+            .child(SupportedActions.class)
+            .toInstance();
+    
+
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = //
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+            .toInstance();
+    private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, SupportedActions.QNAME.getLocalName());
+
+    
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BI = //
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+                    .node(Nodes.QNAME) //
+                    .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+                    .node(SUPPORTED_ACTIONS_QNAME) //
+                    .toInstance();
+    
+    private DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedChangeEvent;
+
+    
+    
+    /**
+     * Test for Bug 148
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void putNodeAndAugmentation() throws Exception {
+
+        baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
+        
+        NodeBuilder nodeBuilder = new NodeBuilder();
+        nodeBuilder.setId(new NodeId(NODE_ID));
+        nodeBuilder.setKey(NODE_KEY);
+        DataModificationTransaction baseTransaction = baDataService.beginTransaction();
+        baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build());
+        RpcResult<TransactionStatus> result = baseTransaction.commit().get();
+        assertEquals(TransactionStatus.COMMITED, result.getResult());
+        assertNotNull(receivedChangeEvent);
+        Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+        assertNotNull(node);
+        assertEquals(NODE_KEY, node.getKey());
+        
+        FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder();
+        fnub.setHardware("Hardware Foo");
+        fnub.setManufacturer("Manufacturer Foo");
+        fnub.setSerialNumber("Serial Foo");
+        fnub.setDescription("Description Foo");
+        fnub.setSoftware("JUnit emulated");
+        FlowCapableNode fnu = fnub.build();
+        InstanceIdentifier<FlowCapableNode> augmentIdentifier = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance();
+        DataModificationTransaction augmentedTransaction = baDataService.beginTransaction();
+        augmentedTransaction.putOperationalData(augmentIdentifier, fnu);
+        
+        result = augmentedTransaction.commit().get();
+        assertEquals(TransactionStatus.COMMITED, result.getResult());
+        
+        
+        Node augmentedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+        assertNotNull(node);
+        assertEquals(NODE_KEY, augmentedNode.getKey());
+        System.out.println("Before assertion");
+        assertNotNull(augmentedNode.getAugmentation(FlowCapableNode.class));
+        FlowCapableNode readedAugmentation = augmentedNode.getAugmentation(FlowCapableNode.class);
+        assertEquals(fnu.getDescription(), readedAugmentation.getDescription());
+        assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
+        testNodeRemove();
+    }
+
+    
+    private void testNodeRemove() throws Exception {
+        DataModificationTransaction transaction = baDataService.beginTransaction();
+        transaction.removeOperationalData(NODE_INSTANCE_ID_BA);
+        RpcResult<TransactionStatus> result = transaction.commit().get();
+        assertEquals(TransactionStatus.COMMITED, result.getResult());
+        
+        Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+        assertNull(node);
+    }
+
+    private void verifyNodes(Nodes nodes,Node original) {
+        assertNotNull(nodes);
+        assertNotNull(nodes.getNode());
+        assertEquals(1, nodes.getNode().size());
+        Node readedNode = nodes.getNode().get(0);
+        assertEquals(original.getId(), readedNode.getId());
+        assertEquals(original.getKey(), readedNode.getKey());
+        
+        FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class);
+        FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class);
+        assertNotNull(fnu);
+        assertEquals(fnu.getDescription(), readedAugment.getDescription());
+        assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber());
+        
+    }
+
+    private void assertBindingIndependentVersion(
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) {
+        CompositeNode node = biDataService.readOperationalData(nodeId);
+        assertNotNull(node);
+    }
+
+    private Nodes checkForNodes() {
+        return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
+    }
+    
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        receivedChangeEvent = change;
+    }
+
+}
index 7fe5f0c5bea91336c103ce3f6224ed6986d9c545..7111501b5392e174d25b16d456da6493cdfe3d77 100644 (file)
@@ -116,6 +116,7 @@ public class ChangeOriginatedInDomBrokerTest extends AbstractDataServiceTest {
     
     @Test
     public void simpleModifyOperation() throws Exception {
+        assertNull(biDataService.readConfigurationData(FLOW_INSTANCE_ID_BI));
         
         registerCommitHandler();
         
@@ -123,7 +124,7 @@ public class ChangeOriginatedInDomBrokerTest extends AbstractDataServiceTest {
         DataModificationTransaction biTransaction = biDataService.beginTransaction();
         biTransaction.putConfigurationData(FLOW_INSTANCE_ID_BI, domflow);
         RpcResult<TransactionStatus> biResult = biTransaction.commit().get();
-        
+        assertEquals(TransactionStatus.COMMITED, biResult.getResult());
         assertNotNull(modificationCapture);
         Flow flow = (Flow) modificationCapture.getCreatedConfigurationData().get(FLOW_INSTANCE_ID_BA);
         assertNotNull(flow);
index e46b566522e26232081cd1fd72a96d873bdebae5..54e1a065f4b45374848bbc53a27b534864d98f7d 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.sal.common.util;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -20,7 +21,7 @@ public class Rpcs {
         return ret;
     }
 
-    private static class RpcResultTO<T> implements RpcResult<T> {
+    private static class RpcResultTO<T> implements RpcResult<T>, Serializable {
 
         private final Collection<RpcError> errors;
         private final T result;
index 1fb73bc9a9fd9a1799a502051bcd1548c3917a1b..99a38ca43a5be68fd3c9bad328e20ab98d0578a4 100644 (file)
@@ -13,17 +13,24 @@ import java.util.Collections;
 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;
 
-public abstract class AbstractConsumer implements Consumer, BundleActivator {
+public abstract class AbstractConsumer implements Consumer, BundleActivator,ServiceTrackerCustomizer<Broker, Broker> {
+
+    
+    
+    
+    private BundleContext context;
+    private ServiceTracker<Broker, Broker> tracker;
+    private Broker broker;
 
-    Broker broker;
-    ServiceReference<Broker> brokerRef;
     @Override
     public final void start(BundleContext context) throws Exception {
+        this.context = context;
         this.startImpl(context);
-        brokerRef = context.getServiceReference(Broker.class);
-        broker = context.getService(brokerRef);
-        broker.registerConsumer(this,context);
+        tracker = new ServiceTracker<>(context, Broker.class, this);
+        tracker.open();
     }
 
 
@@ -32,9 +39,7 @@ public abstract class AbstractConsumer implements Consumer, BundleActivator {
     public final void stop(BundleContext context) throws Exception {
         stopImpl(context);
         broker = null;
-        if(brokerRef != null) {
-            context.ungetService(brokerRef);
-        }
+        tracker.close();
     }
 
     protected void startImpl(BundleContext context) {
@@ -49,4 +54,25 @@ public abstract class AbstractConsumer implements Consumer, BundleActivator {
         return Collections.emptySet();
     }
 
+    
+    @Override
+    public Broker addingService(ServiceReference<Broker> reference) {
+        if(broker == null) {
+            broker = context.getService(reference);
+            broker.registerConsumer(this, context);
+            return broker;
+        }
+        
+        return null;
+    }
+    
+    @Override
+    public void modifiedService(ServiceReference<Broker> reference, Broker service) {
+        // NOOP
+    }
+    
+    @Override
+    public void removedService(ServiceReference<Broker> reference, Broker service) {
+        stopImpl(context);
+    }
 }
index 621ef92132a636aabc347e87b69f6b8ac89c3c8f..1cb1a2bc8522b65301e3f70470e2c41e06d3b32c 100644 (file)
@@ -10,16 +10,20 @@ package org.opendaylight.controller.sal.core.api;
 import java.util.Collection;
 import java.util.Collections;
 
+import javax.naming.Context;
+
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 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;
 
-public abstract class AbstractProvider implements BundleActivator, Provider {
+public abstract class AbstractProvider implements BundleActivator, Provider,ServiceTrackerCustomizer<Broker, Broker> {
 
-    private ServiceReference<Broker> brokerRef;
     private Broker broker;
-
+    private BundleContext context;
+    private ServiceTracker<Broker, Broker> tracker;
     @Override
     public Collection<ProviderFunctionality> getProviderFunctionality() {
         return Collections.emptySet();
@@ -27,12 +31,10 @@ public abstract class AbstractProvider implements BundleActivator, Provider {
 
     @Override
     public final void start(BundleContext context) throws Exception {
-        brokerRef = context.getServiceReference(Broker.class);
-        broker = context.getService(brokerRef);
-
+        this.context = context;
         this.startImpl(context);
-
-        broker.registerProvider(this,context);
+        tracker = new ServiceTracker<>(context, Broker.class, this);
+        tracker.open();
     }
 
     protected void startImpl(BundleContext context) {
@@ -44,7 +46,31 @@ public abstract class AbstractProvider implements BundleActivator, Provider {
 
     @Override
     public final void stop(BundleContext context) throws Exception {
+        broker = null;
+        tracker.close();
+        tracker = null;
         stopImpl(context);
     }
 
+    @Override
+    public Broker addingService(ServiceReference<Broker> reference) {
+        if(broker == null) {
+            broker = context.getService(reference);
+            broker.registerProvider(this, context);
+            return broker;
+        }
+        
+        return null;
+    }
+    
+    @Override
+    public void modifiedService(ServiceReference<Broker> reference, Broker service) {
+        // NOOP
+    }
+    
+    @Override
+    public void removedService(ServiceReference<Broker> reference, Broker service) {
+        stopImpl(context);
+    }
+    
 }
index 050966faa0496a81715388352c0ccefb38fe3567..9a2a90445e0ad1f72d37fc11b4308b0a74452ae8 100644 (file)
@@ -9,10 +9,12 @@
 */
 package org.opendaylight.controller.config.yang.md.sal.dom.impl;
 
+import org.opendaylight.controller.config.yang.md.sal.dom.statistics.DomBrokerRuntimeMXBeanImpl;
 import org.opendaylight.controller.sal.core.api.data.DataStore;
 import org.opendaylight.controller.sal.dom.broker.BrokerConfigActivator;
 import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
 import org.osgi.framework.BundleContext;
+
 import static com.google.common.base.Preconditions.*;
 
 /**
@@ -37,14 +39,15 @@ public final class DomBrokerImplModule extends org.opendaylight.controller.confi
         checkArgument(getDataStore() != null, "Data Store needs to be provided for DomBroker");
     }
     
-    
-
     @Override
     public java.lang.AutoCloseable createInstance() {
-        BrokerImpl broker = new BrokerImpl();
-        BrokerConfigActivator activator = new BrokerConfigActivator();
-        DataStore store = getDataStoreDependency();
-        activator.start(broker, store,getBundleContext());
+        final BrokerImpl broker = new BrokerImpl();
+        final BrokerConfigActivator activator = new BrokerConfigActivator();
+        final DataStore store = getDataStoreDependency();
+        activator.start(broker, store, getBundleContext());
+        
+        final DomBrokerImplRuntimeMXBean domBrokerRuntimeMXBean = new DomBrokerRuntimeMXBeanImpl(activator.getDataService());
+        getRootRuntimeBeanRegistratorWrapper().register(domBrokerRuntimeMXBean);
         return broker;
     }
 
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/statistics/DomBrokerRuntimeMXBeanImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/statistics/DomBrokerRuntimeMXBeanImpl.java
new file mode 100644 (file)
index 0000000..bc13979
--- /dev/null
@@ -0,0 +1,36 @@
+package org.opendaylight.controller.config.yang.md.sal.dom.statistics;
+
+import org.opendaylight.controller.config.yang.md.sal.dom.impl.Data;
+import org.opendaylight.controller.config.yang.md.sal.dom.impl.DomBrokerImplRuntimeMXBean;
+import org.opendaylight.controller.config.yang.md.sal.dom.impl.Transactions;
+import org.opendaylight.controller.sal.dom.broker.DataBrokerImpl;
+
+public class DomBrokerRuntimeMXBeanImpl implements
+        DomBrokerImplRuntimeMXBean {
+    
+    private final DataBrokerImpl dataService;
+    private final Transactions transactions = new Transactions();
+    private final Data data = new Data();
+    
+    public DomBrokerRuntimeMXBeanImpl(DataBrokerImpl dataService) {
+        this.dataService = dataService; 
+    }
+
+    public Transactions getTransactions() {
+        transactions.setCreated(dataService.getCreatedTransactionsCount().get());
+        transactions.setSubmitted(dataService.getSubmittedTransactionsCount().get());
+        transactions.setSuccessful(dataService.getFinishedTransactionsCount().get());
+        transactions.setFailed(dataService.getFailedTransactionsCount().get());
+        return transactions;
+    }
+
+    @Override
+    public Data getData() {
+        transactions.setCreated(dataService.getCreatedTransactionsCount().get());
+        transactions.setSubmitted(dataService.getSubmittedTransactionsCount().get());
+        transactions.setSuccessful(dataService.getFinishedTransactionsCount().get());
+        transactions.setFailed(dataService.getFailedTransactionsCount().get());
+        data.setTransactions(transactions);
+        return data;
+    }
+}
index da7cccb156d9ac1437474a01e8cc1260c8ee9bcf..dc116ca9795537e9d97a7e8de7fac804cda8b041 100644 (file)
@@ -14,20 +14,22 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
 import org.opendaylight.controller.sal.core.api.data.DataStore
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter
 import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
+import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl
 
 class BrokerConfigActivator implements AutoCloseable {
     
     
     private static val ROOT = InstanceIdentifier.builder().toInstance();
+
+    @Property
+    private var DataBrokerImpl dataService;
     
     private var ServiceRegistration<SchemaService> schemaReg;
     private var ServiceRegistration<DataBrokerService> dataReg;
     private var ServiceRegistration<DataProviderService> dataProviderReg;
     private var ServiceRegistration<MountService> mountReg;
     private var ServiceRegistration<MountProvisionService> mountProviderReg;
-    
     private var SchemaServiceImpl schemaService;
-    private var DataBrokerImpl dataService;
     private var MountPointManagerImpl mountService;
     
     SchemaAwareDataStoreAdapter wrappedStore
@@ -36,7 +38,7 @@ class BrokerConfigActivator implements AutoCloseable {
         val emptyProperties = new Hashtable<String, String>();
         broker.setBundleContext(context);
         
-
+        broker.setRouter(new RpcRouterImpl("Rpc router"))
         schemaService = new SchemaServiceImpl();
         schemaService.setContext(context);
         schemaService.setParser(new YangParserImpl());
index ac5313a9caa99fdaf4fdb5c29fd7690b08e3589c..56eae97848b71c9556c0eb3108c6d7f92e38b200 100644 (file)
@@ -2,7 +2,6 @@ package org.opendaylight.controller.sal.dom.broker;
 
 import java.util.concurrent.atomic.AtomicLong;
 
-import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
 import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;
 import org.opendaylight.controller.sal.common.DataStoreIdentifier;
@@ -15,17 +14,23 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
 public class DataBrokerImpl extends AbstractDataBroker<InstanceIdentifier, CompositeNode, DataChangeListener> implements
-        DataProviderService {
+        DataProviderService, AutoCloseable {
 
+    private AtomicLong nextTransaction = new AtomicLong();
+    private final AtomicLong createdTransactionsCount = new AtomicLong();
+    
     public DataBrokerImpl() {
         setDataReadRouter(new DataReaderRouter());
     }
-
-    private AtomicLong nextTransaction = new AtomicLong();
+    
+    public AtomicLong getCreatedTransactionsCount() {
+        return createdTransactionsCount;
+    }
     
     @Override
     public DataTransactionImpl beginTransaction() {
         String transactionId = "DOM-" + nextTransaction.getAndIncrement();
+        createdTransactionsCount.getAndIncrement();
         return new DataTransactionImpl(transactionId,this);
     }
 
@@ -66,4 +71,9 @@ public class DataBrokerImpl extends AbstractDataBroker<InstanceIdentifier, Compo
         throw new UnsupportedOperationException("Deprecated");
     }
 
+    @Override
+    public void close() throws Exception {
+        
+    }
+
 }
\ No newline at end of file
index bf12ac4f011fc656529b7131027114c67b4e6b31..9ae9c9ce6d4fe65571b4aad1640b3b8782e82930 100644 (file)
@@ -5,6 +5,7 @@ module opendaylight-sal-dom-broker-impl {
 
        import config { prefix config; revision-date 2013-04-05; }
        import opendaylight-md-sal-dom {prefix sal;}
+       import opendaylight-md-sal-common {prefix common;}
 
     description
         "Service definition for Binding Aware MD-SAL.";
@@ -18,7 +19,7 @@ module opendaylight-sal-dom-broker-impl {
         base config:module-type;
         config:provided-service sal:dom-broker-osgi-registry;
         config:java-name-prefix DomBrokerImpl;
-    }
+    }    
     
     identity hash-map-data-store {
         base config:module-type;
@@ -58,4 +59,12 @@ module opendaylight-sal-dom-broker-impl {
         }
     }
     
+    augment "/config:modules/config:module/config:state" {
+        case dom-broker-impl {
+            when "/config:modules/config:module/config:type = 'dom-broker-impl'";
+            container data {
+                uses common:data-state;
+            } 
+        }
+    }
 }
\ No newline at end of file
index 4d0a1ac6b663e3ecf7aee035ab5b47157de1aed8..55a1fbfe486a03f033ba961586675cb21beea2d6 100644 (file)
@@ -10,6 +10,7 @@
 package org.opendaylight.controller.config.yang.md.sal.connector.netconf;
 
 import io.netty.channel.EventLoopGroup;
+import io.netty.util.concurrent.GlobalEventExecutor;
 
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
@@ -21,6 +22,8 @@ import org.opendaylight.controller.netconf.client.NetconfSshClientDispatcher;
 import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.controller.netconf.util.handler.ssh.authentication.LoginPassword;
 import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.TimedReconnectStrategy;
 import org.osgi.framework.BundleContext;
 
 import static com.google.common.base.Preconditions.*;
@@ -62,6 +65,8 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
         String addressValue = getAddress();
         
         
+        int attemptMsTimeout = 60*1000;
+        int connectionAttempts = 5;
         /*
          * Uncomment after Switch to IP Address
         if(getAddress().getIpv4Address() != null) {
@@ -71,6 +76,12 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
         }
         
         */
+        ReconnectStrategy strategy = new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, attemptMsTimeout, 1000, 1.0, null,
+                Long.valueOf(connectionAttempts), null);
+        
+        
+        device.setStrategy(strategy);
+        
         InetAddress addr = InetAddresses.forString(addressValue);
         InetSocketAddress socketAddress = new InetSocketAddress(addr , getPort().intValue());
         device.setSocketAddress(socketAddress);
index 49d9757f421058cb05ffed90f81922f6509ff688..7c4bf5facad6a3dd94b0f1bd6a73e301a7820143 100644 (file)
@@ -22,8 +22,16 @@ import org.opendaylight.controller.sal.core.api.data.DataBrokerService
 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction
 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.protocol.framework.ReconnectStrategy
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
+import org.opendaylight.controller.md.sal.common.api.data.DataModification
 
-class NetconfDevice implements Provider, DataReader<InstanceIdentifier, CompositeNode>, RpcImplementation, AutoCloseable {
+class NetconfDevice implements 
+    Provider, // 
+    DataReader<InstanceIdentifier, CompositeNode>, //
+    DataCommitHandler<InstanceIdentifier, CompositeNode>, //
+    RpcImplementation, //
+    AutoCloseable {
 
     var NetconfClient client;
 
@@ -36,14 +44,17 @@ class NetconfDevice implements Provider, DataReader<InstanceIdentifier, Composit
     @Property
     var InstanceIdentifier path;
 
-    Registration<DataReader<InstanceIdentifier, CompositeNode>> operReaderReg
+    @Property
+    var ReconnectStrategy strategy;
 
+    Registration<DataReader<InstanceIdentifier, CompositeNode>> operReaderReg
     Registration<DataReader<InstanceIdentifier, CompositeNode>> confReaderReg
-
-    String name
-
+    Registration<DataCommitHandler<InstanceIdentifier, CompositeNode>> commitHandlerReg
+    
+    val String name
     MountProvisionService mountService
-
+    
+    
     public new(String name) {
         this.name = name;
         this.path = InstanceIdentifier.builder(INVENTORY_PATH).nodeWithKey(INVENTORY_NODE,
@@ -51,13 +62,14 @@ class NetconfDevice implements Provider, DataReader<InstanceIdentifier, Composit
     }
 
     def start(NetconfClientDispatcher dispatcher) {
-        client = new NetconfClient(name, socketAddress, dispatcher);
+        client = NetconfClient.clientFor(name, socketAddress, strategy, dispatcher);
         confReaderReg = mountInstance.registerConfigurationReader(path, this);
         operReaderReg = mountInstance.registerOperationalReader(path, this);
+        //commitHandlerReg = mountInstance.registerCommitHandler(path,this);
     }
 
     override readConfigurationData(InstanceIdentifier path) {
-        val result = invokeRpc(NETCONF_GET_CONFIG_QNAME, wrap(NETCONF_GET_CONFIG_QNAME, path.toFilterStructure()));
+        val result = invokeRpc(NETCONF_GET_CONFIG_QNAME, wrap(NETCONF_GET_CONFIG_QNAME, CONFIG_SOURCE_RUNNING, path.toFilterStructure()));
         val data = result.result.getFirstCompositeByName(NETCONF_DATA_QNAME);
         return data?.findNode(path) as CompositeNode;
     }
@@ -133,6 +145,10 @@ class NetconfDevice implements Provider, DataReader<InstanceIdentifier, Composit
         return current;
     }
 
+    override requestCommit(DataModification<InstanceIdentifier, CompositeNode> modification) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
     override close() {
         confReaderReg?.close()
         operReaderReg?.close()
index d23ec1cd61ae65ee507693638e03be9043b3e937..78f6d59f77ed2b2a7025b578d6090929ceead2dd 100644 (file)
@@ -18,6 +18,8 @@ import java.util.concurrent.atomic.AtomicInteger
 import org.w3c.dom.Document
 import org.w3c.dom.Element
 import org.opendaylight.controller.sal.common.util.Rpcs
+import java.util.List
+import com.google.common.collect.ImmutableList
 
 class NetconfMapping {
 
@@ -26,12 +28,18 @@ class NetconfMapping {
     public static val NETCONF_RPC_QNAME = new QName(NETCONF_QNAME,"rpc");
     public static val NETCONF_GET_QNAME = new QName(NETCONF_QNAME,"get");
     public static val NETCONF_GET_CONFIG_QNAME = new QName(NETCONF_QNAME,"get-config");
+    public static val NETCONF_SOURCE_QNAME = new QName(NETCONF_QNAME,"source");
+    public static val NETCONF_RUNNING_QNAME = new QName(NETCONF_QNAME,"running");
     public static val NETCONF_RPC_REPLY_QNAME = new QName(NETCONF_QNAME,"rpc-reply");
     public static val NETCONF_OK_QNAME = new QName(NETCONF_QNAME,"ok");
     public static val NETCONF_DATA_QNAME = new QName(NETCONF_QNAME,"data");
     
+     static List<Node<?>> RUNNING = Collections.<Node<?>>singletonList(new SimpleNodeTOImpl(NETCONF_RUNNING_QNAME,null,null));
+    public static val CONFIG_SOURCE_RUNNING = new CompositeNodeTOImpl(NETCONF_SOURCE_QNAME,null,RUNNING);
 
     static val messageId = new AtomicInteger(0);
+    
+   
 
 
 
@@ -88,6 +96,15 @@ class NetconfMapping {
         }
     }
     
+        static def wrap(QName name,Node<?> additional,Node<?> node) {
+        if(node != null) {
+            return new CompositeNodeTOImpl(name,null,ImmutableList.of(additional,node));
+        }
+        else {
+            return new CompositeNodeTOImpl(name,null,ImmutableList.of(additional));
+        }
+    }
+    
     
     public static def Node<?> toCompositeNode(Document document) {
         return XmlDocumentUtils.toCompositeNode(document) as Node<?>
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/implementation/pom.xml
new file mode 100644 (file)
index 0000000..b8e0938
--- /dev/null
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-parent</artifactId>
+        <relativePath>../..</relativePath>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>sal-remoterpc-connector</artifactId>
+    <packaging>bundle</packaging>
+
+  <properties>
+    <zeromq.version>0.3.1</zeromq.version>
+    <jackson.version>1.9.8</jackson.version>
+    <stax.version>1.0.1</stax.version>
+  </properties>
+
+  <dependencies>
+    <!-- MD Sal interdependencies -->
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>sal-core-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>sal-connector-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>sal-common-util</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>zeromq-routingtable.implementation</artifactId>
+      <!-- TODO: fix the version. Why is it not MD Sal project version?-->
+      <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+
+    <!-- AD Sal -->
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+    </dependency>
+
+    <!-- Yang tools -->
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-common</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-common</artifactId>
+    </dependency>
+
+    <!-- Third Party -->
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.zeromq</groupId>
+      <artifactId>jeromq</artifactId>
+      <version>${zeromq.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+    <dependency>
+      <groupId> org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.jackson</groupId>
+      <artifactId>jackson-core-asl</artifactId>
+      <version>${jackson.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.jackson</groupId>
+      <artifactId>jackson-mapper-asl</artifactId>
+      <version>${jackson.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>stax</groupId>
+      <artifactId>stax-api</artifactId>
+      <version>${stax.version}</version>
+    </dependency>
+
+    <!-- Tests -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-core</artifactId>
+    </dependency>
+
+  </dependencies>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${bundle.plugin.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Import-Package>
+                            *,
+                            !org.codehaus.enunciate.jaxrs
+                        </Import-Package>
+                        <Export-Package>
+                            org.opendaylight.controller.config.yang.md.sal.remote.rpc,
+                            org.opendaylight.controller.sal.connector.remoterpc,
+                            org.opendaylight.controller.sal.connector.remoterpc.*
+                        </Export-Package>
+                        <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                    </instructions>
+                </configuration>
+            </plugin>
+           
+
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.9-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>
+                                            urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
+                                        </namespaceToPackage1>
+                                    </additionalConfiguration>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl</codeGeneratorClass>
+                                    <outputBaseDir>target/site/models</outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-jmx-generator-plugin</artifactId>
+                        <version>0.2.3-SNAPSHOT</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.opendaylight.yangtools</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>0.6.0-SNAPSHOT</version>
+                        <type>jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java
new file mode 100644 (file)
index 0000000..606f282
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+* Generated file
+
+* Generated from: yang module name: odl-sal-dom-rpc-remote-cfg  yang module local name: remote-zeromq-rpc-server
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Thu Dec 05 14:25:21 CET 2013
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.md.sal.remote.rpc;
+
+import org.opendaylight.controller.sal.connector.remoterpc.Client;
+import org.opendaylight.controller.sal.connector.remoterpc.RemoteRpcProvider;
+import org.opendaylight.controller.sal.connector.remoterpc.RoutingTableProvider;
+import org.opendaylight.controller.sal.connector.remoterpc.ServerImpl;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.osgi.framework.BundleContext;
+
+/**
+*
+*/
+public final class ZeroMQServerModule extends org.opendaylight.controller.config.yang.md.sal.remote.rpc.AbstractZeroMQServerModule
+ {
+
+    private static final Integer ZEROMQ_ROUTER_PORT = 5554;
+    private BundleContext bundleContext;
+
+    public ZeroMQServerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public ZeroMQServerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            ZeroMQServerModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    protected void customValidation(){
+        // Add custom validation for module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        
+        Broker broker = getDomBrokerDependency();
+        RoutingTableProvider provider = new RoutingTableProvider(bundleContext);
+        
+        
+        final int port = getPort() != null ? getPort() : ZEROMQ_ROUTER_PORT;
+
+        ServerImpl serverImpl = new ServerImpl(port);
+        
+        Client clientImpl = new Client();
+        RemoteRpcProvider facade = new RemoteRpcProvider(serverImpl, clientImpl);
+        
+        facade.setRoutingTableProvider(provider );
+        
+        broker.registerProvider(facade, bundleContext);
+        return facade;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModuleFactory.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModuleFactory.java
new file mode 100644 (file)
index 0000000..3cc3ac0
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+* Generated file
+
+* Generated from: yang module name: odl-sal-dom-rpc-remote-cfg  yang module local name: remote-zeromq-rpc-server
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Thu Dec 05 14:25:21 CET 2013
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.md.sal.remote.rpc;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
+import org.opendaylight.controller.config.spi.Module;
+import org.osgi.framework.BundleContext;
+
+/**
+*
+*/
+public class ZeroMQServerModuleFactory extends org.opendaylight.controller.config.yang.md.sal.remote.rpc.AbstractZeroMQServerModuleFactory
+{
+
+    @Override
+    public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+        ZeroMQServerModule module = (ZeroMQServerModule) super.createModule(instanceName, dependencyResolver, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+    
+    @Override
+    public Module createModule(String instanceName, DependencyResolver dependencyResolver,
+            DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception {
+        ZeroMQServerModule module = (ZeroMQServerModule) super.createModule(instanceName, dependencyResolver, old,bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/Client.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/Client.java
new file mode 100644 (file)
index 0000000..ef31623
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import com.google.common.base.Optional;
+
+import org.opendaylight.controller.sal.common.util.RpcErrors;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.MessageWrapper;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
+import org.opendaylight.controller.sal.connector.remoterpc.util.XmlUtils;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.*;
+
+import static com.google.common.base.Preconditions.*;
+
+/**
+ * An implementation of {@link RpcImplementation} that makes remote RPC calls
+ */
+public class Client implements RemoteRpcClient {
+
+    private final Logger _logger = LoggerFactory.getLogger(Client.class);
+
+    private final LinkedBlockingQueue<MessageWrapper> requestQueue = new LinkedBlockingQueue<MessageWrapper>(100);
+
+    private final ExecutorService pool = Executors.newSingleThreadExecutor();
+    private final long TIMEOUT = 5000; // in ms
+
+    private  RoutingTableProvider routingTableProvider;
+
+    public RoutingTableProvider getRoutingTableProvider() {
+        return routingTableProvider;
+    }
+
+    public void setRoutingTableProvider(RoutingTableProvider routingTableProvider) {
+        this.routingTableProvider = routingTableProvider;
+    }
+
+    public LinkedBlockingQueue<MessageWrapper> getRequestQueue() {
+        return requestQueue;
+    }
+
+    @Override
+    public Set<QName> getSupportedRpcs() {
+        // TODO: Find the entries from routing table
+        return Collections.emptySet();
+    }
+
+    public void start() {
+        pool.execute(new Sender(this));
+
+    }
+
+    public void stop() {
+
+        _logger.debug("Client stopping...");
+        Context.getInstance().getZmqContext().term();
+        _logger.debug("ZMQ context terminated");
+
+        pool.shutdown(); // intiate shutdown
+        try {
+            if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
+                pool.shutdownNow();
+                if (!pool.awaitTermination(10, TimeUnit.SECONDS))
+                    _logger.error("Client thread pool did not shut down");
+            }
+        } catch (InterruptedException e) {
+            // (Re-)Cancel if current thread also interrupted
+            pool.shutdownNow();
+            // Preserve interrupt status
+            Thread.currentThread().interrupt();
+        }
+        _logger.debug("Client stopped");
+    }
+
+    @Override
+    public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+
+        RouteIdentifierImpl routeId = new RouteIdentifierImpl();
+        routeId.setType(rpc);
+
+        String address = lookupRemoteAddress(routeId);
+
+        Message request = new Message.MessageBuilder().type(Message.MessageType.REQUEST)
+                .sender(Context.getInstance().getLocalUri()).recipient(address).route(routeId)
+                .payload(XmlUtils.compositeNodeToXml(input)).build();
+
+        List<RpcError> errors = new ArrayList<RpcError>();
+
+        try (SocketPair pair = new SocketPair()) {
+
+            MessageWrapper messageWrapper = new MessageWrapper(request, pair.getSender());
+            process(messageWrapper);
+            Message response = parseMessage(pair.getReceiver());
+
+            CompositeNode payload = XmlUtils.xmlToCompositeNode((String) response.getPayload());
+
+            return Rpcs.getRpcResult(true, payload, errors);
+
+        } catch (Exception e) {
+            collectErrors(e, errors);
+            return Rpcs.getRpcResult(false, null, errors);
+        }
+
+    }
+
+    public void process(MessageWrapper msg) throws TimeoutException, InterruptedException {
+        _logger.debug("Processing message [{}]", msg);
+
+        boolean success = requestQueue.offer(msg, TIMEOUT, TimeUnit.MILLISECONDS);
+        if (!success)
+            throw new TimeoutException("Queue is full");
+    }
+
+    /**
+     * Block on socket for reply
+     * 
+     * @param receiver
+     * @return
+     */
+    private Message parseMessage(ZMQ.Socket receiver) throws IOException, ClassNotFoundException {
+        return (Message) Message.deserialize(receiver.recv());
+    }
+
+    /**
+     * Find address for the given route identifier in routing table
+     * 
+     * @param routeId
+     *            route identifier
+     * @return remote network address
+     */
+    private String lookupRemoteAddress(RpcRouter.RouteIdentifier routeId) {
+        checkNotNull(routeId, "route must not be null");
+
+        Optional<RoutingTable<String, String>> routingTable = routingTableProvider.getRoutingTable();
+        checkNotNull(routingTable.isPresent(), "Routing table is null");
+
+        Set<String> addresses = routingTable.get().getRoutes(routeId.toString());
+        checkNotNull(addresses, "Address not found for route [%s]", routeId);
+        checkState(addresses.size() == 1, "Multiple remote addresses found for route [%s], \nonly 1 expected", routeId); // its
+                                                                                                                         // a
+                                                                                                                         // global
+                                                                                                                         // service.
+
+        String address = addresses.iterator().next();
+        checkNotNull(address, "Address not found for route [%s]", routeId);
+
+        return address;
+    }
+
+    private void collectErrors(Exception e, List<RpcError> errors) {
+        if (e == null)
+            return;
+        if (errors == null)
+            errors = new ArrayList<RpcError>();
+
+        errors.add(RpcErrors.getRpcError(null, null, null, null, e.getMessage(), null, e.getCause()));
+        for (Throwable t : e.getSuppressed()) {
+            errors.add(RpcErrors.getRpcError(null, null, null, null, t.getMessage(), null, t));
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        stop();
+    }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/Context.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/Context.java
new file mode 100644 (file)
index 0000000..f0bf12c
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.zeromq.ZMQ;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Enumeration;
+
+/**
+ * Provides a ZeroMQ Context object
+ */
+public class Context {
+  private ZMQ.Context zmqContext = ZMQ.context(1);
+  private String uri;
+
+  private static Context _instance = new Context();
+
+  private Context() {}
+
+  public static Context getInstance(){
+    return _instance;
+  }
+
+  public ZMQ.Context getZmqContext(){
+    return this.zmqContext;
+  }
+
+  public String getLocalUri(){
+    uri = (uri != null) ? uri
+            : new StringBuilder("tcp://").append(getIpAddress()).append(":")
+              .append(getRpcPort()).toString();
+
+    return uri;
+  }
+
+  public String getRpcPort(){
+    String rpcPort = (System.getProperty("rpc.port") != null)
+        ? System.getProperty("rpc.port")
+        : "5554";
+
+    return rpcPort;
+  }
+
+  private String getIpAddress(){
+    String ipAddress = (System.getProperty("local.ip") != null)
+        ? System.getProperty("local.ip")
+        : findIpAddress();
+
+    return ipAddress;
+  }
+
+  /**
+   * Finds IPv4 address of the local VM
+   * TODO: This method is non-deterministic. There may be more than one IPv4 address. Cant say which
+   * address will be returned. Read IP from a property file or enhance the code to make it deterministic.
+   * Should we use IP or hostname?
+   *
+   * @return
+   */
+  private String findIpAddress() {
+    String hostAddress = null;
+    Enumeration e = null;
+    try {
+      e = NetworkInterface.getNetworkInterfaces();
+    } catch (SocketException e1) {
+      e1.printStackTrace();
+    }
+    while (e.hasMoreElements()) {
+
+      NetworkInterface n = (NetworkInterface) e.nextElement();
+
+      Enumeration ee = n.getInetAddresses();
+      while (ee.hasMoreElements()) {
+        InetAddress i = (InetAddress) ee.nextElement();
+        if ((i instanceof Inet4Address) && (i.isSiteLocalAddress()))
+          hostAddress = i.getHostAddress();
+      }
+    }
+    return hostAddress;
+
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcClient.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcClient.java
new file mode 100644 (file)
index 0000000..6bd123b
--- /dev/null
@@ -0,0 +1,13 @@
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+
+public interface RemoteRpcClient extends RpcImplementation,AutoCloseable{
+
+
+    void setRoutingTableProvider(RoutingTableProvider provider);
+    
+    void stop();
+    
+    void start();
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProvider.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProvider.java
new file mode 100644 (file)
index 0000000..3c2e3b0
--- /dev/null
@@ -0,0 +1,95 @@
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+
+import org.opendaylight.controller.sal.connector.remoterpc.Client;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+public class RemoteRpcProvider implements 
+    RemoteRpcServer,
+    RemoteRpcClient,
+    Provider {
+
+    private final ServerImpl server;
+    private final Client client;
+    private RoutingTableProvider provider;
+
+    @Override
+    public void setRoutingTableProvider(RoutingTableProvider provider) {
+        this.provider = provider;
+        server.setRoutingTableProvider(provider);
+        client.setRoutingTableProvider(provider);
+    }
+    
+    @Override
+    public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+        return client.invokeRpc(rpc, input);
+    }
+    
+    @Override
+    public Set<QName> getSupportedRpcs() {
+        return client.getSupportedRpcs();
+    }
+    
+    
+    public RemoteRpcProvider(ServerImpl server, Client client) {
+        this.server = server;
+        this.client = client;
+    }
+    
+    public void setBrokerSession(ProviderSession session) {
+        server.setBrokerSession(session);
+    }
+    public void setServerPool(ExecutorService serverPool) {
+        server.setServerPool(serverPool);
+    }
+    public void start() {
+        client.setRoutingTableProvider(provider);
+        server.setRoutingTableProvider(provider);
+        server.start();
+        client.start();
+    }
+    public void onRouteUpdated(String key, Set values) {
+        server.onRouteUpdated(key, values);
+    }
+    public void onRouteDeleted(String key) {
+        server.onRouteDeleted(key);
+    }
+    
+    
+    @Override
+    public Collection<ProviderFunctionality> getProviderFunctionality() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+    
+    
+    @Override
+    public void onSessionInitiated(ProviderSession session) {
+        server.setBrokerSession(session);
+        start();
+    }
+    
+    
+    public void close() throws Exception {
+        server.close();
+        client.close();
+    }
+
+    
+    
+    
+    @Override
+    public void stop() {
+        server.stop();
+        client.stop();
+    }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcServer.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcServer.java
new file mode 100644 (file)
index 0000000..932600f
--- /dev/null
@@ -0,0 +1,6 @@
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+
+public interface RemoteRpcServer extends AutoCloseable {
+
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RoutingTableProvider.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RoutingTableProvider.java
new file mode 100644 (file)
index 0000000..cfdf986
--- /dev/null
@@ -0,0 +1,32 @@
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+import com.google.common.base.Optional;
+
+public class RoutingTableProvider implements AutoCloseable {
+
+    @SuppressWarnings("rawtypes")
+    final ServiceTracker<RoutingTable,RoutingTable> tracker;
+    
+    
+    public RoutingTableProvider(BundleContext ctx) {
+        @SuppressWarnings("rawtypes")
+        ServiceTracker<RoutingTable, RoutingTable> rawTracker = new ServiceTracker<>(ctx, RoutingTable.class, null);
+        tracker = rawTracker;
+        tracker.open();
+    }
+    
+    public Optional<RoutingTable<String, String>> getRoutingTable() {
+        @SuppressWarnings("unchecked")
+        RoutingTable<String,String> tracked = tracker.getService();
+        return Optional.fromNullable(tracked);
+    }
+
+    @Override
+    public void close() throws Exception {
+        tracker.close();
+    }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RpcSocket.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RpcSocket.java
new file mode 100644 (file)
index 0000000..7e8590a
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.MessageWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+
+import java.io.IOException;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A class encapsulating {@link ZMQ.Socket} of type {@link ZMQ.REQ}.
+ * It adds following capabilities:
+ * <li> Retry logic - Tries 3 times before giving up
+ * <li> Request times out after {@link TIMEOUT} property
+ * <li> The limitation of {@link ZMQ.REQ}/{@link ZMQ.REP} pair is that no 2 requests can be sent before
+ * the response for the 1st request is received. To overcome that, this socket queues all messages until
+ * the previous request has been responded.
+ */
+public class RpcSocket {
+
+  // Constants
+  public static final int TIMEOUT = 2000;
+  public static final int QUEUE_SIZE = 10;
+  public static final int NUM_RETRIES = 3;
+  private static final Logger log = LoggerFactory.getLogger(RpcSocket.class);
+
+  private ZMQ.Socket socket;
+  private ZMQ.Poller poller;
+  private String address;
+  private SocketState state;
+  private long sendTime;
+  private int retriesLeft;
+  private LinkedBlockingQueue<MessageWrapper> inQueue;
+
+
+  public RpcSocket(String address, ZMQ.Poller poller) {
+    this.socket = null;
+    this.state = new IdleSocketState();
+    this.sendTime = -1;
+    this.retriesLeft = NUM_RETRIES;
+    this.inQueue = new LinkedBlockingQueue<MessageWrapper>(QUEUE_SIZE);
+    this.address = address;
+    this.poller = poller;
+    createSocket();
+  }
+
+  public ZMQ.Socket getSocket() {
+    return socket;
+  }
+
+  public String getAddress() {
+    return address;
+  }
+
+  public int getRetriesLeft() {
+    return retriesLeft;
+  }
+
+  public void setRetriesLeft(int retriesLeft) {
+    this.retriesLeft = retriesLeft;
+  }
+
+  public SocketState getState() {
+    return state;
+  }
+
+  public void setState(SocketState state) {
+    this.state = state;
+  }
+
+  public int getQueueSize() {
+    return inQueue.size();
+  }
+
+  public MessageWrapper removeCurrentRequest() {
+    return inQueue.poll();
+  }
+
+  public boolean hasTimedOut() {
+    return (System.currentTimeMillis() - sendTime > RpcSocket.TIMEOUT);
+  }
+
+  public void send(MessageWrapper request) throws TimeoutException {
+    try {
+      boolean success = inQueue.offer(request, TIMEOUT, TimeUnit.MILLISECONDS);    
+      if (!success) {
+        throw new TimeoutException("send :: Queue is full");
+      }
+      process();
+    }
+    catch (InterruptedException e) {
+      log.error("send : Thread interrupted while attempting to add request to inQueue", e);
+    }
+  }
+  
+  public MessageWrapper receive() {
+    Message response = parseMessage();
+    MessageWrapper messageWrapper = inQueue.poll(); //remove the message from queue
+    MessageWrapper responseMessageWrapper = new MessageWrapper(response, messageWrapper.getReceiveSocket());
+
+    state = new IdleSocketState();
+    retriesLeft = NUM_RETRIES;
+    return responseMessageWrapper;
+  }
+  
+  public void process() {
+    if (getQueueSize() > 0) //process if there's message in the queue
+      state.process(this);
+  }
+
+  // Called by IdleSocketState & BusySocketState
+  public void sendMessage() {
+    //Get the message from queue without removing it. For retries
+    MessageWrapper messageWrapper = inQueue.peek();
+    if (messageWrapper != null) {
+      Message message = messageWrapper.getMessage();
+      try {
+        socket.send(Message.serialize(message));
+      }
+      catch (IOException e) {
+        log.debug("Message send failed [{}]", message);
+        log.debug("Exception [{}]", e);
+      }
+      sendTime = System.currentTimeMillis();
+    }
+  }
+  
+  public Message parseMessage() {
+    Message parsedMessage = null;
+    byte[] bytes = socket.recv();
+    log.debug("Received bytes:[{}]", bytes.length);
+    try {
+      parsedMessage = (Message)Message.deserialize(bytes);
+    }
+    catch (IOException|ClassNotFoundException e) {
+      log.debug("parseMessage : Deserializing received bytes failed", e);
+    }
+
+    return parsedMessage;
+  }
+
+  public void recycleSocket() {
+    close();
+  }
+
+  public void close() {
+    socket.setLinger(10);
+    socket.close();
+  }
+
+  private void createSocket() {
+    socket = Context.getInstance().getZmqContext().socket(ZMQ.REQ);
+    socket.connect(address);
+    poller.register(socket, ZMQ.Poller.POLLIN);
+    state = new IdleSocketState();
+  }
+
+
+  /**
+   * Represents the state of a {@link org.opendaylight.controller.sal.connector.remoterpc.RpcSocket}
+   */
+  public static interface SocketState {
+
+    /* The processing actions to be performed in this state
+     */
+    public void process(RpcSocket socket);
+  }
+
+  /**
+   * Represents the idle state of a {@link org.opendaylight.controller.sal.connector.remoterpc.RpcSocket}
+   */
+  public static class IdleSocketState implements SocketState {
+
+    @Override
+    public void process(RpcSocket socket) {
+      socket.sendMessage();
+      socket.setState(new BusySocketState());
+      socket.setRetriesLeft(socket.getRetriesLeft()-1);
+    }
+  }
+
+  /**
+   * Represents the busy state of a {@link org.opendaylight.controller.sal.connector.remoterpc.RpcSocket}
+   */
+  public static class BusySocketState implements SocketState {
+
+    private static Logger log = LoggerFactory.getLogger(BusySocketState.class);
+
+    @Override
+    public void process(RpcSocket socket) {
+      if (socket.hasTimedOut()) {
+        if (socket.getRetriesLeft() > 0) {
+          log.debug("process : Request timed out, retrying now...");
+          socket.sendMessage();
+          socket.setRetriesLeft(socket.getRetriesLeft() - 1);
+        }
+        else {
+          // No more retries for current request, so stop processing the current request
+          MessageWrapper message = socket.removeCurrentRequest();
+          if (message != null) {
+            log.error("Unable to process rpc request [{}]", message);
+            socket.setState(new IdleSocketState());
+            socket.setRetriesLeft(NUM_RETRIES);
+          }
+        }
+      }
+      // Else no timeout, so allow processing to continue
+    }
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/Sender.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/Sender.java
new file mode 100644 (file)
index 0000000..f53d5ad
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.MessageWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+
+import java.io.IOException;
+import java.util.concurrent.TimeoutException;
+
+import static com.google.common.base.Preconditions.*;
+
+/**
+ * Main server thread for sending requests.
+ */
+public class Sender implements Runnable{
+
+  private final static Logger _logger = LoggerFactory.getLogger(Sender.class);
+  private final Client client;
+
+
+  
+  
+  public Sender(Client client) {
+    super();
+    this.client = client;
+  }
+
+@Override
+  public void run() {
+    _logger.info("Starting...");
+
+    try (SocketManager socketManager = new SocketManager()){
+      while (!Thread.currentThread().isInterrupted()) {
+
+        //read incoming messages from blocking queue
+        MessageWrapper request = pollForRequest();
+
+        if (request != null) {
+          processRequest(socketManager, request);
+        }
+
+        flushSockets(socketManager);
+        pollForResponse(socketManager);
+        processResponse(socketManager);
+
+      }
+    } catch(Exception t){
+      _logger.error("Exception: [{}]", t);
+      _logger.error("Stopping...");
+    }
+  }
+
+  private void processResponse(SocketManager socketManager) {
+    for (int i = 0; i < socketManager.getPoller().getSize(); i++) {
+      // If any sockets get a response, process it
+      if (socketManager.getPoller().pollin(i)) {
+        Optional<RpcSocket> socket = socketManager.getManagedSocketFor(
+            socketManager.getPoller().getItem(i).getSocket());
+
+        checkState(socket.isPresent(), "Managed socket not found");
+
+        MessageWrapper response = socket.get().receive();
+        _logger.debug("Received rpc response [{}]", response.getMessage());
+
+        //TODO: handle exception and introduce timeout on receiver side
+        try {
+          response.getReceiveSocket().send(Message.serialize(response.getMessage()));
+        } catch (IOException e) {
+          e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+        }
+      }
+    }
+  }
+
+  private void processRequest(SocketManager socketManager, MessageWrapper request) throws TimeoutException {
+
+    if ((request.getMessage() == null) ||
+        (request.getMessage().getRecipient() == null)) {
+      //invalid message. log and drop
+      _logger.error("Invalid request [{}]", request);
+      return;
+    }
+
+    RpcSocket socket =
+        socketManager.getManagedSocket(request.getMessage().getRecipient());
+
+    socket.send(request);
+  }
+
+  private void flushSockets(SocketManager socketManager){
+    for (RpcSocket socket : socketManager.getManagedSockets()){
+      socket.process();
+    }
+  }
+
+  private MessageWrapper pollForRequest(){
+    return client.getRequestQueue().poll();
+  }
+
+  private void pollForResponse(SocketManager socketManager){
+    try{
+      socketManager.getPoller().poll(10); //poll every 10ms
+    }catch (Throwable t) { /*Ignore and continue*/ }
+  }
+}
+
+
+/*
+SCALA
+
+package org.opendaylight.controller.sal.connector.remoterpc
+
+  import org.slf4j.{LoggerFactory, Logger}
+  import scala.collection.JavaConverters._
+  import scala.Some
+  import org.opendaylight.controller.sal.connector.remoterpc.dto.{MessageWrapper, Message}
+*/
+/**
+ * Main server thread for sending requests. This does not maintain any state. If the
+ * thread dies, it will be restarted
+ */
+/*class Sender extends Runnable {
+  private val _logger: Logger = LoggerFactory.getLogger(Sender.this.getClass())
+
+  override def run = {
+    _logger.info("Sender starting...")
+    val socketManager = new SocketManager()
+
+    try {
+      while (!Thread.currentThread().isInterrupted) {
+        //read incoming messages from blocking queue
+        val request: MessageWrapper = Client.requestQueue.poll()
+
+        if (request != null) {
+          if ((request.message != null) &&
+            (request.message.getRecipient != null)) {
+
+            val socket = socketManager.getManagedSocket(request.message.getRecipient)
+            socket.send(request)
+          } else {
+            //invalid message. log and drop
+            _logger.error("Invalid request [{}]", request)
+          }
+        }
+
+        socketManager.getManagedSockets().asScala.map(s => s.process)
+
+        // Poll all sockets for responses every 1 sec
+        poll(socketManager)
+
+        // If any sockets get a response, process it
+        for (i <- 0 until socketManager.poller.getSize) {
+          if (socketManager.poller.pollin(i)) {
+            val socket = socketManager.getManagedSocketFor(socketManager.poller.getItem(i).getSocket)
+
+            socket match {
+              case None => //{
+                _logger.error("Could not find a managed socket for zmq socket")
+                throw new IllegalStateException("Could not find a managed socket for zmq socket")
+                //}
+              case Some(s) => {
+                val response = s.receive()
+                _logger.debug("Received rpc response [{}]", response.message)
+                response.receiveSocket.send(Message.serialize(response.message))
+              }
+            }
+          }
+        }
+
+      }
+    } catch{
+      case e:Exception => {
+        _logger.debug("Sender stopping due to exception")
+        e.printStackTrace()
+      }
+    } finally {
+      socketManager.stop
+    }
+  }
+
+  def poll(socketManager:SocketManager) = {
+    try{
+      socketManager.poller.poll(10)
+    }catch{
+      case t:Throwable => //ignore and continue
+    }
+  }
+}
+
+
+//    def newThread(r: Runnable): Thread = {
+//      val t = new RequestHandler()
+//      t.setUncaughtExceptionHandler(new RequestProcessorExceptionHandler)
+//      t
+//    }
+
+
+
+/**
+ * Restarts the request processing server in the event of unforeseen exceptions
+ */
+//private class RequestProcessorExceptionHandler extends UncaughtExceptionHandler {
+//  def uncaughtException(t: Thread, e: Throwable) = {
+//    _logger.error("Exception caught during request processing [{}]", e)
+//    _logger.info("Restarting request processor server...")
+//    RequestProcessor.start()
+//  }
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java
new file mode 100644 (file)
index 0000000..83b9385
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import com.google.common.base.Optional;
+
+import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message.MessageType;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
+import org.opendaylight.controller.sal.connector.remoterpc.util.XmlUtils;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+/**
+ * ZeroMq based implementation of RpcRouter TODO: 1. Make rpc request handling
+ * async and non-blocking. Note zmq socket is not thread safe 2. Read properties
+ * from config file using existing(?) ODL properties framework
+ */
+public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String, Set> {
+
+    private Logger _logger = LoggerFactory.getLogger(ServerImpl.class);
+
+    private ExecutorService serverPool;
+
+    // private RoutingTable<RpcRouter.RouteIdentifier, String> routingTable;
+    private RoutingTableProvider routingTable;
+    private Set<QName> remoteServices;
+    private ProviderSession brokerSession;
+    private ZMQ.Context context;
+    private ZMQ.Socket replySocket;
+
+    private final RpcListener listener = new RpcListener();
+
+    private final String localUri = Context.getInstance().getLocalUri();
+
+    private final int rpcPort;
+
+    private RpcImplementation client;
+
+    public RpcImplementation getClient() {
+        return client;
+    }
+
+    public void setClient(RpcImplementation client) {
+        this.client = client;
+    }
+
+    // Prevent instantiation
+    public ServerImpl(int rpcPort) {
+        this.rpcPort = rpcPort;
+    }
+
+    public void setBrokerSession(ProviderSession session) {
+        this.brokerSession = session;
+    }
+
+    public ExecutorService getServerPool() {
+        return serverPool;
+    }
+
+    public void setServerPool(ExecutorService serverPool) {
+        this.serverPool = serverPool;
+    }
+
+    public void start() {
+        context = ZMQ.context(1);
+        serverPool = Executors.newSingleThreadExecutor();
+        remoteServices = new HashSet<QName>();
+
+        // Start listening rpc requests
+        serverPool.execute(receive());
+
+        brokerSession.addRpcRegistrationListener(listener);
+        // routingTable.registerRouteChangeListener(routeChangeListener);
+
+        Set<QName> currentlySupported = brokerSession.getSupportedRpcs();
+        for (QName rpc : currentlySupported) {
+            listener.onRpcImplementationAdded(rpc);
+        }
+
+        _logger.debug("RPC Server started [{}]", localUri);
+    }
+
+    public void stop() {
+        // TODO: un-subscribe
+
+        // if (context != null)
+        // context.term();
+        //
+        // _logger.debug("ZMQ Context is terminated.");
+
+        if (serverPool != null)
+            serverPool.shutdown();
+
+        _logger.debug("Thread pool is closed.");
+    }
+
+    private Runnable receive() {
+        return new Runnable() {
+            public void run() {
+
+                // Bind to RPC reply socket
+                replySocket = context.socket(ZMQ.REP);
+                replySocket.bind("tcp://*:" + Context.getInstance().getRpcPort());
+
+                // Poller enables listening on multiple sockets using a single
+                // thread
+                ZMQ.Poller poller = new ZMQ.Poller(1);
+                poller.register(replySocket, ZMQ.Poller.POLLIN);
+                try {
+                    // TODO: Add code to restart the thread after exception
+                    while (!Thread.currentThread().isInterrupted()) {
+
+                        poller.poll();
+
+                        if (poller.pollin(0)) {
+                            handleRpcCall();
+                        }
+                    }
+                } catch (Exception e) {
+                    // log and continue
+                    _logger.error("Unhandled exception [{}]", e);
+                } finally {
+                    poller.unregister(replySocket);
+                    replySocket.close();
+                }
+
+            }
+        };
+    }
+
+    /**
+     * @throws InterruptedException
+     * @throws ExecutionException
+     */
+    private void handleRpcCall() {
+
+        Message request = parseMessage(replySocket);
+
+        _logger.debug("Received rpc request [{}]", request);
+
+        // Call broker to process the message then reply
+        Future<RpcResult<CompositeNode>> rpc = null;
+        RpcResult<CompositeNode> result = null;
+        try {
+            rpc = brokerSession.rpc((QName) request.getRoute().getType(),
+                    XmlUtils.xmlToCompositeNode((String) request.getPayload()));
+
+            result = (rpc != null) ? rpc.get() : null;
+
+        } catch (Exception e) {
+            _logger.debug("Broker threw  [{}]", e);
+        }
+
+        CompositeNode payload = (result != null) ? result.getResult() : null;
+
+        Message response = new Message.MessageBuilder().type(MessageType.RESPONSE).sender(localUri)
+                .route(request.getRoute()).payload(XmlUtils.compositeNodeToXml(payload)).build();
+
+        _logger.debug("Sending rpc response [{}]", response);
+
+        try {
+            replySocket.send(Message.serialize(response));
+        } catch (Exception e) {
+            _logger.debug("rpc response send failed for message [{}]", response);
+            _logger.debug("{}", e);
+        }
+
+    }
+
+    /**
+     * @param socket
+     * @return
+     */
+    private Message parseMessage(ZMQ.Socket socket) {
+
+        Message msg = null;
+        try {
+            byte[] bytes = socket.recv();
+            _logger.debug("Received bytes:[{}]", bytes.length);
+            msg = (Message) Message.deserialize(bytes);
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+        return msg;
+    }
+
+    @Override
+    public void onRouteUpdated(String key, Set values) {
+        RouteIdentifierImpl rId = new RouteIdentifierImpl();
+        try {
+            _logger.debug("Updating key/value {}-{}", key, values);
+            brokerSession.addRpcImplementation((QName) rId.fromString(key).getType(), client);
+
+        } catch (Exception e) {
+            _logger.info("Route update failed {}", e);
+        }
+    }
+
+    @Override
+    public void onRouteDeleted(String key) {
+        // TODO: Broker session needs to be updated to support this
+        throw new UnsupportedOperationException();
+    }
+    
+    /**
+     * Listener for rpc registrations
+     */
+    private class RpcListener implements RpcRegistrationListener {
+
+        
+
+        @Override
+        public void onRpcImplementationAdded(QName name) {
+
+            // if the service name exists in the set, this notice
+            // has bounced back from the broker. It should be ignored
+            if (remoteServices.contains(name))
+                return;
+
+            _logger.debug("Adding registration for [{}]", name);
+            RouteIdentifierImpl routeId = new RouteIdentifierImpl();
+            routeId.setType(name);
+
+            try {
+                routingTable.getRoutingTable().get().addGlobalRoute(routeId.toString(), localUri);
+                _logger.debug("Route added [{}-{}]", name, localUri);
+            } catch (RoutingTableException | SystemException e) {
+                // TODO: This can be thrown when route already exists in the
+                // table. Broker
+                // needs to handle this.
+                _logger.error("Unhandled exception while adding global route to routing table [{}]", e);
+
+            }
+        }
+
+        @Override
+        public void onRpcImplementationRemoved(QName name) {
+
+            _logger.debug("Removing registration for [{}]", name);
+            RouteIdentifierImpl routeId = new RouteIdentifierImpl();
+            routeId.setType(name);
+
+            try {
+                routingTable.getRoutingTable().get().removeGlobalRoute(routeId.toString());
+            } catch (RoutingTableException | SystemException e) {
+                _logger.error("Route delete failed {}", e);
+            }
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        stop();
+    }
+
+    public void setRoutingTableProvider(RoutingTableProvider provider) {
+        this.routingTable = provider;
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/SocketManager.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/SocketManager.java
new file mode 100644 (file)
index 0000000..588a299
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import com.google.common.base.Optional;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * Manages creation of {@link RpcSocket} and their registration with {@link ZMQ.Poller}
+ */
+public class SocketManager implements AutoCloseable{
+  private static final Logger log = LoggerFactory.getLogger(SocketManager.class);
+
+  /*
+   * RpcSockets mapped by network address its connected to
+   */
+  private ConcurrentHashMap<String, RpcSocket> managedSockets = new ConcurrentHashMap<String, RpcSocket>();
+
+  private ZMQ.Poller _poller = new ZMQ.Poller(2); //randomly selected size. Poller grows automatically
+
+  /**
+   * Returns a {@link RpcSocket} for the given address
+   * @param address network address with port eg: 10.199.199.20:5554
+   * @return
+   */
+  public RpcSocket getManagedSocket(String address) throws IllegalArgumentException {
+    //Precondition
+    if (!address.matches("(tcp://)(.*)(:)(\\d*)")) {
+      throw new IllegalArgumentException("Address must of format 'tcp://<ip address>:<port>' but is " + address);
+    }
+
+    if (!managedSockets.containsKey(address)) {
+      log.debug("{} Creating new socket for {}", Thread.currentThread().getName());
+      RpcSocket socket = new RpcSocket(address, _poller);
+      managedSockets.put(address, socket);
+    }
+
+    return managedSockets.get(address);
+  }
+
+  /**
+   * Returns a {@link RpcSocket} for the given {@link ZMQ.Socket}
+   * @param socket
+   * @return
+   */
+  public Optional<RpcSocket> getManagedSocketFor(ZMQ.Socket socket) {
+    for (RpcSocket rpcSocket : managedSockets.values()) {
+      if (rpcSocket.getSocket().equals(socket)) {
+        return Optional.of(rpcSocket);
+      }
+    }
+    return Optional.absent();
+  }
+
+  /**
+   * Return a collection of all managed sockets
+   * @return
+   */
+  public Collection<RpcSocket> getManagedSockets() {
+    return managedSockets.values();
+  }
+
+  /**
+   * Returns the {@link ZMQ.Poller}
+   * @return
+   */
+  public ZMQ.Poller getPoller() {
+    return _poller;
+  }
+
+  /**
+   * This should be called when stopping the server to close all the sockets
+   * @return
+   */
+  @Override
+  public void close() throws Exception {
+    log.debug("Stopping...");
+    for (RpcSocket socket : managedSockets.values()) {
+      socket.close();
+    }
+    managedSockets.clear();
+    log.debug("Stopped");
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/SocketPair.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/SocketPair.java
new file mode 100644 (file)
index 0000000..67b3a83
--- /dev/null
@@ -0,0 +1,41 @@
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.zeromq.ZMQ;
+
+import java.util.UUID;
+
+/**
+ *
+ */
+public class SocketPair implements AutoCloseable{
+  private ZMQ.Socket sender;
+  private ZMQ.Socket receiver;
+
+  private static final String INPROC_PREFIX = "inproc://";
+
+  public SocketPair(){
+    String address = new StringBuilder(INPROC_PREFIX)
+                         .append(UUID.randomUUID())
+                         .toString();
+
+    receiver = Context.getInstance().getZmqContext().socket(ZMQ.PAIR);
+    receiver.bind(address);
+
+    sender = Context.getInstance().getZmqContext().socket(ZMQ.PAIR);
+    sender.connect(address);
+  }
+
+  public ZMQ.Socket getSender(){
+    return this.sender;
+  }
+
+  public ZMQ.Socket getReceiver(){
+    return this.receiver;
+  }
+
+  @Override
+  public void close() throws Exception {
+    sender.close();
+    receiver.close();
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/CompositeNodeImpl.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/CompositeNodeImpl.java
new file mode 100644 (file)
index 0000000..073601a
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc.dto;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.*;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class CompositeNodeImpl implements CompositeNode, Serializable {
+
+  private QName key;
+  private List<Node<?>> children;
+
+  @Override
+  public List<Node<?>> getChildren() {
+    return children;
+  }
+
+  @Override
+  public List<CompositeNode> getCompositesByName(QName children) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public List<CompositeNode> getCompositesByName(String children) {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public List<SimpleNode<?>> getSimpleNodesByName(QName children) {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public List<SimpleNode<?>> getSimpleNodesByName(String children) {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public CompositeNode getFirstCompositeByName(QName container) {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public SimpleNode<?> getFirstSimpleByName(QName leaf) {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public MutableCompositeNode asMutable() {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public QName getKey() {
+    return key;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public List<Node<?>> setValue(List<Node<?>> value) {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public int size() {
+    return 0;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return false;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public boolean containsKey(Object key) {
+    return false;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public boolean containsValue(Object value) {
+    return false;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public List<Node<?>> get(Object key) {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public List<Node<?>> put(QName key, List<Node<?>> value) {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public List<Node<?>> remove(Object key) {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public void putAll(Map<? extends QName, ? extends List<Node<?>>> m) {
+    //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public void clear() {
+    //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public Set<QName> keySet() {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public Collection<List<Node<?>>> values() {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public Set<Entry<QName, List<Node<?>>>> entrySet() {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public QName getNodeType() {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public CompositeNode getParent() {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public List<Node<?>> getValue() {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public ModifyAction getModificationAction() {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+}
@@ -6,10 +6,8 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.sal.connector.remoterpc.router.zeromq;
+package org.opendaylight.controller.sal.connector.remoterpc.dto;
 
-
-import org.codehaus.jackson.map.ObjectMapper;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
 
 import java.io.*;
@@ -20,7 +18,8 @@ public class Message implements Serializable {
     ANNOUNCE((byte) 0),  //TODO: Remove announce, add rpc registration and deregistration
     HEARTBEAT((byte) 1),
     REQUEST((byte) 2),
-    RESPONSE((byte) 3);
+    RESPONSE((byte) 3),
+    ERROR((byte)4);
 
     private final byte type;
 
@@ -35,6 +34,7 @@ public class Message implements Serializable {
 
   private MessageType type;
   private String sender;
+  private String recipient;
   private RpcRouter.RouteIdentifier route;
   private Object payload;
 
@@ -70,11 +70,19 @@ public class Message implements Serializable {
     this.payload = payload;
   }
 
+  public String getRecipient() {
+    return recipient;
+  }
+
+  public void setRecipient(String recipient) {
+    this.recipient = recipient;
+  }
   @Override
   public String toString() {
     return "Message{" +
         "type=" + type +
         ", sender='" + sender + '\'' +
+        ", recipient='" + recipient + '\'' +
         ", route=" + route +
         ", payload=" + payload +
         '}';
@@ -108,17 +116,6 @@ public class Message implements Serializable {
     return o.readObject();
   }
 
-  public static byte[] toJsonBytes(Message m) throws IOException {
-    ObjectMapper o = new ObjectMapper();
-    return o.writeValueAsBytes(m);
-  }
-
-  public static Message fromJsonBytes(byte [] bytes) throws IOException {
-
-    ObjectMapper o = new ObjectMapper();
-    return o.readValue(bytes, Message.class);
-  }
-
   public static class Response extends Message implements RpcRouter.RpcReply {
     private ResponseCode code; // response code
 
@@ -163,6 +160,11 @@ public class Message implements Serializable {
       return this;
     }
 
+    public MessageBuilder recipient(String recipient){
+      message.setRecipient(recipient);
+      return this;
+    }
+
     public MessageBuilder route(RpcRouter.RouteIdentifier route){
       message.setRoute(route);
       return this;
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/MessageWrapper.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/MessageWrapper.java
new file mode 100644 (file)
index 0000000..8d2198c
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc.dto;
+
+import org.zeromq.ZMQ;
+
+/**
+ * A class encapsulating {@link Message} and the {@link ZMQ.Socket} over which it is transmitted
+ */
+public class MessageWrapper {
+
+  private Message _message;
+  private ZMQ.Socket _receiveSocket;
+  
+  public MessageWrapper(Message message, ZMQ.Socket receiveSocket) {
+    this._message = message;
+    this._receiveSocket = receiveSocket;
+  }
+
+  public Message getMessage() {
+    return _message;
+  }
+
+  public ZMQ.Socket getReceiveSocket() {
+    return _receiveSocket;
+  }
+}
@@ -5,19 +5,21 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.controller.sal.connector.remoterpc.router.zeromq;
+package org.opendaylight.controller.sal.connector.remoterpc.dto;
 
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.ObjectMapper;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
 import java.io.Serializable;
+import java.net.URI;
 
-/**
- * User: abhishk2
- */
 public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>,Serializable {
 
+  transient ObjectMapper mapper = new ObjectMapper();
+
   private QName context;
   private QName type;
   private InstanceIdentifier route;
@@ -51,10 +53,35 @@ public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier<QName, QNa
 
   @Override
   public String toString() {
-    return "RouteIdentifierImpl{" +
-        "context=" + context +
-        ", type=" + type +
-        ", route=" + route +
-        '}';
+    try {
+      return mapper.writeValueAsString(this);
+    } catch (Throwable e) {
+      //do nothing
+    }
+
+    return super.toString();
+  }
+
+  public RpcRouter.RouteIdentifier fromString(String input)
+      throws Exception {
+
+    JsonNode root = mapper.readTree(input);
+    this.context  = parseQName(root.get("context"));
+    this.type     = parseQName(root.get("type"));
+
+    return this;
+  }
+
+  private QName parseQName(JsonNode node){
+    if (node == null) return null;
+
+    String namespace = (node.get("namespace") != null) ?
+                       node.get("namespace").asText()  : "";
+
+    String localName = (node.get("localName") != null) ?
+                       node.get("localName").asText() : "";
+
+    URI uri = URI.create(namespace);
+    return new QName(uri, localName);
   }
 }
@@ -5,7 +5,7 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.controller.sal.connector.remoterpc.router.zeromq;
+package org.opendaylight.controller.sal.connector.remoterpc.dto;
 
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.yangtools.yang.common.QName;
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/util/XmlUtils.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/util/XmlUtils.java
new file mode 100644 (file)
index 0000000..7dab2e3
--- /dev/null
@@ -0,0 +1,63 @@
+package org.opendaylight.controller.sal.connector.remoterpc.util;
+
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.impl.NodeUtils;
+import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayInputStream;
+import java.io.StringWriter;
+
+public class XmlUtils {
+
+  private static final Logger _logger = LoggerFactory.getLogger(XmlUtils.class);
+
+  public static String compositeNodeToXml(CompositeNode cNode){
+    if (cNode == null) return new String();
+
+    Document domTree = NodeUtils.buildShadowDomTree(cNode);
+    StringWriter writer = new StringWriter();
+    try {
+      TransformerFactory tf = TransformerFactory.newInstance();
+      Transformer transformer = tf.newTransformer();
+      transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+      transformer.transform(new DOMSource(domTree), new StreamResult(writer));
+    } catch (TransformerException e) {
+      _logger.error("Error during translation of Document to OutputStream", e);
+    }
+
+    return writer.toString();
+  }
+
+  public static CompositeNode xmlToCompositeNode(String xml){
+    if (xml==null || xml.length()==0) return null;
+
+    Node<?> dataTree;
+    try {
+      dataTree = XmlTreeBuilder.buildDataTree(new ByteArrayInputStream(xml.getBytes()));
+    } catch (XMLStreamException e) {
+      _logger.error("Error during building data tree from XML", e);
+      return null;
+    }
+    if (dataTree == null) {
+      _logger.error("data tree is null");
+      return null;
+    }
+    if (dataTree instanceof SimpleNode) {
+      _logger.error("RPC XML was resolved as SimpleNode");
+      return null;
+    }
+    return (CompositeNode) dataTree;
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/scala/org/opendaylight/controller/sal/connector/remoterpc/Client.scala b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/scala/org/opendaylight/controller/sal/connector/remoterpc/Client.scala
new file mode 100644 (file)
index 0000000..63b6808
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc
+
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.yangtools.yang.common.{RpcError, RpcResult, QName}
+import org.opendaylight.controller.sal.core.api.RpcImplementation
+import java.util
+import java.util.{UUID, Collections}
+import org.zeromq.ZMQ
+import org.opendaylight.controller.sal.common.util.{RpcErrors, Rpcs}
+import org.slf4j.LoggerFactory
+import org.opendaylight.controller.sal.connector.remoterpc.dto.{MessageWrapper, RouteIdentifierImpl, Message}
+import Message.MessageType
+import java.util.concurrent._
+import java.lang.InterruptedException
+
+
+/**
+ * An implementation of {@link RpcImplementation} that makes
+ * remote RPC calls
+ */
+class Client extends RemoteRpcClient {
+
+  private val _logger = LoggerFactory.getLogger(this.getClass);
+
+  val requestQueue = new LinkedBlockingQueue[MessageWrapper](100)
+  val pool: ExecutorService = Executors.newSingleThreadExecutor()
+  private val TIMEOUT = 5000 //in ms
+  var routingTableProvider: RoutingTableProvider = null
+  
+  
+  def getInstance = this
+
+  
+  def setRoutingTableProvider(provider : RoutingTableProvider) = {
+    routingTableProvider = provider;
+  }
+  
+  def getSupportedRpcs: util.Set[QName] = {
+    Collections.emptySet()
+  }
+
+  def invokeRpc(rpc: QName, input: CompositeNode): RpcResult[CompositeNode] = {
+
+    val routeId = new RouteIdentifierImpl()
+    routeId.setType(rpc)
+
+    //lookup address for the rpc request
+    val routingTable = routingTableProvider.getRoutingTable()
+    require( routingTable != null, "Routing table not found. Exiting" )
+
+    val addresses:util.Set[String] = routingTable.getRoutes(routeId.toString)
+    require(addresses != null, "Address not found for rpc " + rpc);
+    require(addresses.size() == 1) //its a global service.
+
+    val address = addresses.iterator().next()
+    require(address != null, "Address is null")
+
+    //create in-process "pair" socket and pass it to sender thread
+    //Sender replies on this when result is available
+    val inProcAddress = "inproc://" + UUID.randomUUID()
+    val receiver = Context.zmqContext.socket(ZMQ.PAIR)
+    receiver.bind(inProcAddress);
+
+    val sender = Context.zmqContext.socket(ZMQ.PAIR)
+    sender.connect(inProcAddress)
+
+    val requestMessage = new Message.MessageBuilder()
+      .`type`(MessageType.REQUEST)
+      //.sender("tcp://localhost:8081")
+      .recipient(address)
+      .route(routeId)
+      .payload(input)
+      .build()
+
+    _logger.debug("Queuing up request and expecting response on [{}]", inProcAddress)
+
+    val messageWrapper = new MessageWrapper(requestMessage, sender)
+    val errors = new util.ArrayList[RpcError]
+
+    try {
+      process(messageWrapper)
+      val response = parseMessage(receiver)
+
+      return Rpcs.getRpcResult(
+        true, response.getPayload.asInstanceOf[CompositeNode], Collections.emptySet())
+
+    } catch {
+      case e: Exception => {
+        errors.add(RpcErrors.getRpcError(null,null,null,null,e.getMessage,null,e.getCause))
+        return Rpcs.getRpcResult(false, null, errors)
+      }
+    } finally {
+      receiver.close();
+      sender.close();
+    }
+
+  }
+
+  /**
+   * Block on socket for reply
+   * @param receiver
+   * @return
+   */
+  private def parseMessage(receiver:ZMQ.Socket): Message = {
+    val bytes = receiver.recv()
+    return  Message.deserialize(bytes).asInstanceOf[Message]
+  }
+
+  def start() = {
+    pool.execute(new Sender)
+  }
+
+  def process(msg: MessageWrapper) = {
+    _logger.debug("Processing message [{}]", msg)
+    val success = requestQueue.offer(msg, TIMEOUT, TimeUnit.MILLISECONDS)
+
+    if (!success) throw new TimeoutException("Queue is full");
+
+  }
+
+  def stop() = {
+    pool.shutdown() //intiate shutdown
+    _logger.debug("Client stopping...")
+    //    Context.zmqContext.term();
+    //    _logger.debug("ZMQ context terminated")
+
+    try {
+
+      if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
+        pool.shutdownNow();
+        if (!pool.awaitTermination(10, TimeUnit.SECONDS))
+          _logger.error("Client thread pool did not shut down");
+      }
+    } catch {
+      case ie:InterruptedException =>
+        // (Re-)Cancel if current thread also interrupted
+        pool.shutdownNow();
+        // Preserve interrupt status
+        Thread.currentThread().interrupt();
+    }
+    _logger.debug("Client stopped")
+  }
+  
+  def close() = {
+    stop();
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/yang/odl-sal-dom-rpc-remote-cfg.yang b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/yang/odl-sal-dom-rpc-remote-cfg.yang
new file mode 100644 (file)
index 0000000..d20efe5
--- /dev/null
@@ -0,0 +1,52 @@
+module odl-sal-dom-rpc-remote-cfg {
+       yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc";
+    prefix "rpc-cluster";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-dom {prefix dom;}
+    
+    description
+        "Service definition for Binding Aware MD-SAL.";
+    revision "2013-10-28" {
+        description
+            "Initial revision";
+    }
+
+    identity remote-rpc-server {
+        base config:service-type;
+        config:java-class "org.opendaylight.controller.sal.connector.remoterpc.RemoteRpcServer";
+    }
+
+    identity remote-rpc-client {
+        base config:service-type;
+        config:java-class "org.opendaylight.controller.sal.connector.remoterpc.RemoteRpcClient";
+    }
+
+    identity remote-zeromq-rpc-server {
+        base config:module-type;
+        config:provided-service remote-rpc-server;
+        config:provided-service remote-rpc-client;
+        config:java-name-prefix ZeroMQServer;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case remote-zeromq-rpc-server {
+            when "/config:modules/config:module/config:type = 'remote-zeromq-rpc-server'";
+            
+            container dom-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity dom:dom-broker-osgi-registry;
+                    }
+                }
+            }
+            
+            leaf port {
+                type uint16;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/ClientTest.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/ClientTest.java
new file mode 100644 (file)
index 0000000..2e77537
--- /dev/null
@@ -0,0 +1,56 @@
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import junit.framework.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.MessageWrapper;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+
+import java.util.concurrent.TimeoutException;
+
+public class ClientTest {
+
+    Client client;
+    
+  @Before
+  public void setup(){
+      client = new Client();
+      client.getRequestQueue().clear();
+  }
+
+  @Test
+  public void testStop() throws Exception {
+
+  }
+
+  @Test
+  public void testPool() throws Exception {
+
+  }
+
+  @Test
+  public void process_AddAMessage_ShouldAddToQueue() throws Exception {
+    client.process(getEmptyMessageWrapper());
+    Assert.assertEquals(1, client.getRequestQueue().size());
+  }
+
+  /**
+   * Queue size is 100. Adding 101 message should time out in 2 sec
+   * if server does not process it
+   * @throws Exception
+   */
+  @Test(expected = TimeoutException.class)
+  public void process_Add101Message_ShouldThrow() throws Exception {
+    for (int i=0;i<101;i++){
+      client.process(getEmptyMessageWrapper());
+    }
+  }
+
+  @Test
+  public void testStart() throws Exception {
+  }
+
+  private MessageWrapper getEmptyMessageWrapper(){
+    return new MessageWrapper(new Message(), null);
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RouteIdentifierImplTest.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RouteIdentifierImplTest.java
new file mode 100644 (file)
index 0000000..550d9ef
--- /dev/null
@@ -0,0 +1,50 @@
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.codehaus.jackson.JsonParseException;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+
+public class RouteIdentifierImplTest {
+
+  Logger _logger = LoggerFactory.getLogger(RouteIdentifierImplTest.class);
+
+  private final URI namespace = URI.create("http://cisco.com/example");
+  private final QName QNAME = new QName(namespace, "heartbeat");
+
+  @Test
+  public void testToString() throws Exception {
+    RouteIdentifierImpl rId = new RouteIdentifierImpl();
+    rId.setType(QNAME);
+
+    _logger.debug(rId.toString());
+
+    Assert.assertTrue(true);
+
+  }
+
+  @Test
+  public void testFromString() throws Exception {
+    RouteIdentifierImpl rId = new RouteIdentifierImpl();
+    rId.setType(QNAME);
+
+    _logger.debug("route: " + rId.fromString(rId.toString()));
+
+    Assert.assertTrue(true);
+  }
+
+  @Test(expected = JsonParseException.class)
+  public void testFromInvalidString() throws Exception {
+    String invalidInput = "aklhdgadfa;;;;;;;]]]]=]ag" ;
+    RouteIdentifierImpl rId = new RouteIdentifierImpl();
+    rId.fromString(invalidInput);
+
+    _logger.debug("" + rId);
+    Assert.assertTrue(true);
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RpcSocketTest.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RpcSocketTest.java
new file mode 100644 (file)
index 0000000..e23a3ca
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.MessageWrapper;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.zeromq.ZMQ;
+
+import java.util.concurrent.TimeoutException;
+
+import static org.mockito.Mockito.doNothing;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(RpcSocket.class)
+public class RpcSocketTest {
+  RpcSocket rpcSocket = new RpcSocket("tcp://localhost:5554", new ZMQ.Poller(1));
+  RpcSocket spy = PowerMockito.spy(rpcSocket);
+
+  @Test
+  public void testCreateSocket() throws Exception {
+    Assert.assertEquals("tcp://localhost:5554", spy.getAddress());
+    Assert.assertEquals(ZMQ.REQ, spy.getSocket().getType());
+  }
+
+  @Test(expected = TimeoutException.class)
+  public void send_WhenQueueGetsFull_ShouldThrow() throws Exception {
+
+    doNothing().when(spy).process();
+
+    //10 is queue size
+    for (int i=0;i<10;i++){
+      spy.send(getEmptyMessageWrapper());
+    }
+
+    //sending 11th message should throw
+    spy.send(getEmptyMessageWrapper());
+  }
+
+  @Test
+  public void testHasTimedOut() throws Exception {
+    spy.send(getEmptyMessageWrapper());
+    Assert.assertFalse(spy.hasTimedOut());
+    Thread.sleep(1000);
+    Assert.assertFalse(spy.hasTimedOut());
+    Thread.sleep(1000);
+    Assert.assertTrue(spy.hasTimedOut());
+  }
+
+  @Test
+  public void testProcess() throws Exception {
+    PowerMockito.doNothing().when(spy, "sendMessage");
+    spy.send(getEmptyMessageWrapper());
+
+    //Next message should get queued
+    spy.send(getEmptyMessageWrapper());
+
+    //queue size should be 2
+    Assert.assertEquals(2, spy.getQueueSize());
+
+
+    spy.process();
+    //sleep for 2 secs (timeout)
+    //message send would be retried
+    Thread.sleep(2000);
+    spy.process();
+    Thread.sleep(2000);
+    spy.process();
+    Thread.sleep(2000);
+    spy.process(); //retry fails, next message will get picked up
+    Assert.assertEquals(1, spy.getQueueSize());
+  }
+
+  @Test
+  public void testProcessStateTransitions() throws Exception {
+    PowerMockito.doNothing().when(spy, "sendMessage");
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+    spy.send(getEmptyMessageWrapper());
+    Assert.assertEquals(1, spy.getQueueSize());
+    Thread.sleep(200);
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+    Thread.sleep(1800);
+
+    //1st timeout, 2nd try
+    spy.process();
+    Thread.sleep(200);
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+    Thread.sleep(1800);
+
+    //2nd timeout, 3rd try
+    spy.process();
+    Thread.sleep(200);
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+    Thread.sleep(1800);
+
+    //3rd timeout, no more tries => remove
+    spy.process();
+    Thread.sleep(200);
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+    Assert.assertEquals(0, spy.getQueueSize());
+  }
+
+  @Test
+  public void testParseMessage() throws Exception {
+    // Write an integration test for parseMessage
+  }
+
+  @Test
+  public void testRecycleSocket() throws Exception {
+    // This will need to be updated in the future...for now, recycleSocket() calls close()
+    Assert.assertTrue(spy.getSocket().base().check_tag());
+    spy.close();
+    Assert.assertEquals(10, spy.getSocket().getLinger());
+    Assert.assertFalse(spy.getSocket().base().check_tag());
+  }
+
+  @Test
+  public void testClose() throws Exception {
+    Assert.assertTrue(spy.getSocket().base().check_tag());
+    spy.close();
+    Assert.assertEquals(10, spy.getSocket().getLinger());
+    Assert.assertFalse(spy.getSocket().base().check_tag());
+  }
+
+  @Test
+  public void testReceive() throws Exception {
+    PowerMockito.doReturn(null).when(spy, "parseMessage");
+    PowerMockito.doNothing().when(spy, "process");
+    spy.send(getEmptyMessageWrapper());
+
+    //There should be 1 message waiting in the queue
+    Assert.assertEquals(1, spy.getQueueSize());
+
+    spy.receive();
+    //This should complete message processing
+    //The message should be removed from the queue
+    Assert.assertEquals(0, spy.getQueueSize());
+    Assert.assertEquals(RpcSocket.NUM_RETRIES, spy.getRetriesLeft());
+
+  }
+
+  @Test
+  public void testReceiveStateTransitions() throws Exception {
+    PowerMockito.doReturn(null).when(spy, "parseMessage");
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+    spy.send(getEmptyMessageWrapper());
+
+    //There should be 1 message waiting in the queue
+    Assert.assertEquals(1, spy.getQueueSize());
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+
+    spy.receive();
+    //This should complete message processing
+    //The message should be removed from the queue
+    Assert.assertEquals(0, spy.getQueueSize());
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+  }
+
+  private MessageWrapper getEmptyMessageWrapper(){
+    return new MessageWrapper(new Message(), null);
+  }
+
+  @Test
+  public void testProcessReceiveSequence() throws Exception {
+    PowerMockito.doNothing().when(spy, "sendMessage");
+    PowerMockito.doReturn(null).when(spy, "parseMessage");
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+    spy.send(getEmptyMessageWrapper());
+    spy.send(getEmptyMessageWrapper());
+    Assert.assertEquals(2, spy.getQueueSize());
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+
+
+    Thread.sleep(2000);
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+    spy.receive();
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+    Assert.assertEquals(1, spy.getQueueSize());
+
+    spy.process();
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.BusySocketState);
+    spy.receive();
+    Assert.assertTrue(spy.getState() instanceof RpcSocket.IdleSocketState);
+    Assert.assertEquals(0, spy.getQueueSize());
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/SerilizationTest.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/SerilizationTest.java
new file mode 100644 (file)
index 0000000..36a4acd
--- /dev/null
@@ -0,0 +1,79 @@
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.impl.NodeUtils;
+import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.StringWriter;
+
+public class SerilizationTest {
+
+  private static final Logger _logger = LoggerFactory.getLogger(SerilizationTest.class);
+
+  public void fromXml() {
+  }
+
+  @Test
+  public void toXml() throws FileNotFoundException {
+
+    InputStream xmlStream = SerilizationTest.class.getResourceAsStream("/FourSimpleChildren.xml");
+    StringWriter writer = new StringWriter();
+
+    CompositeNode data = loadCompositeNode(xmlStream);
+    Document domTree = NodeUtils.buildShadowDomTree(data);
+    try {
+      TransformerFactory tf = TransformerFactory.newInstance();
+      Transformer transformer = tf.newTransformer();
+      transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+      //transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+      //transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+      //transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+      //transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+      transformer.transform(new DOMSource(domTree), new StreamResult(writer));
+    } catch (TransformerException e) {
+      _logger.error("Error during translation of Document to OutputStream", e);
+    }
+
+    _logger.info("Parsed xml [{}]", writer.toString());
+  }
+
+  //Note to self:  Stolen from TestUtils
+  ///Users/alefan/odl/controller4/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java
+  // Figure out how to include TestUtils through pom ...was getting errors
+  private CompositeNode loadCompositeNode(InputStream xmlInputStream) throws FileNotFoundException {
+    if (xmlInputStream == null) {
+      throw new IllegalArgumentException();
+    }
+    Node<?> dataTree;
+    try {
+      dataTree = XmlTreeBuilder.buildDataTree(xmlInputStream);
+    } catch (XMLStreamException e) {
+      _logger.error("Error during building data tree from XML", e);
+      return null;
+    }
+    if (dataTree == null) {
+      _logger.error("data tree is null");
+      return null;
+    }
+    if (dataTree instanceof SimpleNode) {
+      _logger.error("RPC XML was resolved as SimpleNode");
+      return null;
+    }
+    return (CompositeNode) dataTree;
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/SocketManagerTest.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/SocketManagerTest.java
new file mode 100644 (file)
index 0000000..130b30d
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import com.google.common.base.Optional;
+import junit.framework.Assert;
+import org.junit.After;
+import org.junit.Before;
+import org.zeromq.ZMQ;
+import org.opendaylight.controller.sal.connector.remoterpc.SocketManager;
+import org.opendaylight.controller.sal.connector.remoterpc.RpcSocket;
+import org.opendaylight.controller.sal.connector.remoterpc.Context;
+import org.junit.Test;
+
+public class SocketManagerTest {
+
+  SocketManager manager;
+
+  @Before
+  public void setup(){
+    manager = new SocketManager();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    manager.close();
+  }
+
+  @Test
+  public void getManagedSockets_When2NewAdded_ShouldContain2() throws Exception {
+
+    //Prepare data
+    manager.getManagedSocket("tcp://localhost:5554");
+    manager.getManagedSocket("tcp://localhost:5555");
+
+    Assert.assertTrue( 2 == manager.getManagedSockets().size());
+  }
+
+  @Test
+  public void getManagedSockets_When2NewAddedAnd1Existing_ShouldContain2() throws Exception {
+
+    //Prepare data
+    manager.getManagedSocket("tcp://localhost:5554");
+    manager.getManagedSocket("tcp://localhost:5555");
+    manager.getManagedSocket("tcp://localhost:5554"); //ask for the first one
+
+    Assert.assertTrue( 2 == manager.getManagedSockets().size());
+  }
+
+  @Test
+  public void getManagedSocket_WhenPassedAValidAddress_ShouldReturnARpcSocket() throws Exception {
+    String testAddress = "tcp://localhost:5554";
+    RpcSocket rpcSocket = manager.getManagedSocket(testAddress);
+    Assert.assertEquals(testAddress, rpcSocket.getAddress());
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void getManagedSocket_WhenPassedInvalidHostAddress_ShouldThrow() throws Exception {
+    String testAddress = "tcp://nonexistenthost:5554";
+    RpcSocket rpcSocket = manager.getManagedSocket(testAddress);
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void getManagedSocket_WhenPassedInvalidAddress_ShouldThrow() throws Exception {
+    String testAddress = "xxx";
+    RpcSocket rpcSocket = manager.getManagedSocket(testAddress);
+  }
+
+  @Test
+  public void getManagedSocket_WhenPassedAValidZmqSocket_ShouldReturnARpcSocket() throws Exception {
+    //Prepare data
+    String firstAddress = "tcp://localhost:5554";
+    RpcSocket firstRpcSocket = manager.getManagedSocket(firstAddress);
+    ZMQ.Socket firstZmqSocket = firstRpcSocket.getSocket();
+
+    String secondAddress = "tcp://localhost:5555";
+    RpcSocket secondRpcSocket = manager.getManagedSocket(secondAddress);
+    ZMQ.Socket secondZmqSocket = secondRpcSocket.getSocket();
+
+    Assert.assertEquals(firstRpcSocket, manager.getManagedSocketFor(firstZmqSocket).get());
+    Assert.assertEquals(secondRpcSocket, manager.getManagedSocketFor(secondZmqSocket).get());
+  }
+
+  @Test
+  public void getManagedSocket_WhenPassedNonManagedZmqSocket_ShouldReturnNone() throws Exception {
+    ZMQ.Socket nonManagedSocket = Context.getInstance().getZmqContext().socket(ZMQ.REQ);
+    nonManagedSocket.connect("tcp://localhost:5000");
+
+    //Prepare data
+    String firstAddress = "tcp://localhost:5554";
+    RpcSocket firstRpcSocket = manager.getManagedSocket(firstAddress);
+    ZMQ.Socket firstZmqSocket = firstRpcSocket.getSocket();
+
+    Assert.assertSame(Optional.<RpcSocket>absent(), manager.getManagedSocketFor(nonManagedSocket) );
+    Assert.assertSame(Optional.<RpcSocket>absent(), manager.getManagedSocketFor(null) );
+  }
+
+  @Test
+  public void stop_WhenCalled_ShouldEmptyManagedSockets() throws Exception {
+    manager.getManagedSocket("tcp://localhost:5554");
+    manager.getManagedSocket("tcp://localhost:5555");
+    Assert.assertTrue( 2 == manager.getManagedSockets().size());
+
+    manager.close();
+    Assert.assertTrue( 0 == manager.getManagedSockets().size());
+  }
+
+  @Test
+  public void poller_WhenCalled_ShouldReturnAnInstanceOfPoller() throws Exception {
+    Assert.assertTrue (manager.getPoller() instanceof ZMQ.Poller);
+  }
+
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/resources/FourSimpleChildren.xml b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/resources/FourSimpleChildren.xml
new file mode 100644 (file)
index 0000000..5ac991b
--- /dev/null
@@ -0,0 +1,6 @@
+<rpc>
+    <name>eth0</name>
+    <type>ethernetCsmacd</type>
+    <enabled>false</enabled>
+    <description>some interface</description>
+</rpc>
similarity index 87%
rename from opendaylight/md-sal/test/zeromq-test-consumer/pom.xml
rename to opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/pom.xml
index 7c6bc21b46f5cdfa08aa1ca294809cd6eb50468a..fa7b73be0e96a7b43e4c1a5952ec8d0b72e9fa77 100644 (file)
@@ -2,11 +2,11 @@
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
-        <artifactId>sal-test-parent</artifactId>
+        <artifactId>sal-remoterpc-connector-test-parent</artifactId>
         <groupId>org.opendaylight.controller.tests</groupId>
         <version>1.0-SNAPSHOT</version>
     </parent>
-    <artifactId>zeromq-test-consumer</artifactId>
+    <artifactId>sal-remoterpc-connector-test-consumer</artifactId>
     <packaging>bundle</packaging>
     <scm>
         <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
                 <configuration>
                     <instructions>
                         <Bundle-Activator>org.opendaylight.controller.sample.zeromq.consumer.ExampleConsumer</Bundle-Activator>
-                        <Import-Package>
-                            org.opendaylight.controller.sal.core.api,
-                            org.opendaylight.yangtools.yang.common;version="[0.5,1)",
-                            org.opendaylight.yangtools.yang.data.api,
-                        </Import-Package>
                     </instructions>
                 </configuration>
             </plugin>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-data-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-impl</artifactId>
+            <version>0.5.9-SNAPSHOT</version>
+        </dependency>
 
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java
new file mode 100644 (file)
index 0000000..87078ea
--- /dev/null
@@ -0,0 +1,122 @@
+package org.opendaylight.controller.sample.zeromq.consumer;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Hashtable;
+import java.util.concurrent.*;
+
+import org.opendaylight.controller.sal.core.api.AbstractConsumer;
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+
+import javax.xml.stream.XMLStreamException;
+
+public class ExampleConsumer extends AbstractConsumer {
+
+  private final URI namespace = URI.create("http://cisco.com/example");
+  private final QName QNAME = new QName(namespace, "heartbeat");
+
+  private ConsumerSession session;
+
+  private ServiceRegistration<ExampleConsumer> thisReg;
+  private Logger _logger = LoggerFactory.getLogger(ExampleConsumer.class);
+
+  @Override
+  public void onSessionInitiated(ConsumerSession session) {
+    this.session = session;
+  }
+
+  public RpcResult<CompositeNode> invokeRpc(QName qname, CompositeNode input) {
+    _logger.info("Invoking RPC:[{}] with Input:[{}]", qname.getLocalName(), input);
+    RpcResult<CompositeNode> result = null;
+    Future<RpcResult<CompositeNode>> future = ExampleConsumer.this.session.rpc(qname, input);
+    try {
+      result = future.get();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    _logger.info("Returning Result:[{}]", result);
+    return result;
+  }
+
+  @Override
+  protected void startImpl(BundleContext context){
+    thisReg = context.registerService(ExampleConsumer.class, this, new Hashtable<String,String>());
+  }
+  @Override
+  protected void stopImpl(BundleContext context) {
+    super.stopImpl(context);
+    thisReg.unregister();
+  }
+
+  public CompositeNode getValidCompositeNodeWithOneSimpleChild() throws FileNotFoundException {
+    InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/OneSimpleChild.xml");
+    return loadCompositeNode(xmlStream);
+  }
+
+  public CompositeNode getValidCompositeNodeWithTwoSimpleChildren() throws FileNotFoundException {
+    InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/TwoSimpleChildren.xml");
+    return loadCompositeNode(xmlStream);
+  }
+
+  public CompositeNode getValidCompositeNodeWithFourSimpleChildren() throws FileNotFoundException {
+    InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/FourSimpleChildren.xml");
+    return loadCompositeNode(xmlStream);
+  }
+
+  public CompositeNode getValidCompositeNodeWithOneSimpleOneCompositeChild() throws FileNotFoundException {
+    InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/OneSimpleOneCompositeChild.xml");
+    return loadCompositeNode(xmlStream);
+  }
+
+  public CompositeNode getValidCompositeNodeWithTwoCompositeChildren() throws FileNotFoundException {
+    InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/TwoCompositeChildren.xml");
+    return loadCompositeNode(xmlStream);
+  }
+
+  public CompositeNode getInvalidCompositeNodeSimpleChild() throws FileNotFoundException {
+    InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/InvalidSimpleChild.xml");
+    return loadCompositeNode(xmlStream);
+  }
+
+  public CompositeNode getInvalidCompositeNodeCompositeChild() throws FileNotFoundException {
+    InputStream xmlStream = ExampleConsumer.class.getResourceAsStream("/InvalidCompositeChild.xml");
+    return loadCompositeNode(xmlStream);
+  }
+
+  //Note to self:  Stolen from TestUtils
+  ///Users/alefan/odl/controller4/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java
+  // Figure out how to include TestUtils through pom ...was getting errors
+  private CompositeNode loadCompositeNode(InputStream xmlInputStream) throws FileNotFoundException {
+    if (xmlInputStream == null) {
+      throw new IllegalArgumentException();
+    }
+    Node<?> dataTree;
+    try {
+      dataTree = XmlTreeBuilder.buildDataTree(xmlInputStream);
+    } catch (XMLStreamException e) {
+      _logger.error("Error during building data tree from XML", e);
+      return null;
+    }
+    if (dataTree == null) {
+      _logger.error("data tree is null");
+      return null;
+    }
+    if (dataTree instanceof SimpleNode) {
+      _logger.error("RPC XML was resolved as SimpleNode");
+      return null;
+    }
+    return (CompositeNode) dataTree;
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/FourSimpleChildren.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/FourSimpleChildren.xml
new file mode 100644 (file)
index 0000000..5ac991b
--- /dev/null
@@ -0,0 +1,6 @@
+<rpc>
+    <name>eth0</name>
+    <type>ethernetCsmacd</type>
+    <enabled>false</enabled>
+    <description>some interface</description>
+</rpc>
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/InvalidCompositeChild.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/InvalidCompositeChild.xml
new file mode 100644 (file)
index 0000000..3979d02
--- /dev/null
@@ -0,0 +1,14 @@
+<rpc>
+    <innerinterface1>
+        <name>eth1</name>
+        <type>ethernet</type>
+        <enabled>false</enabled>
+        <description>some interface</description>
+    </innerinterface1>
+    <innerinterface2>
+        <name>error</name>
+        <type>ethernet</type>
+        <enabled>true</enabled>
+        <description>some interface</description>
+    </innerinterface2>
+</rpc>
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/InvalidSimpleChild.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/InvalidSimpleChild.xml
new file mode 100644 (file)
index 0000000..6082d72
--- /dev/null
@@ -0,0 +1,3 @@
+<rpc>
+    <name>error</name>
+</rpc>
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/OneSimpleChild.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/OneSimpleChild.xml
new file mode 100644 (file)
index 0000000..f431b04
--- /dev/null
@@ -0,0 +1,3 @@
+<rpc>
+    <name>eth0</name>
+</rpc>
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/OneSimpleOneCompositeChild.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/OneSimpleOneCompositeChild.xml
new file mode 100644 (file)
index 0000000..bca7682
--- /dev/null
@@ -0,0 +1,9 @@
+<rpc>
+    <name>eth0</name>
+    <innerinterface>
+        <name>eth1</name>
+        <type>ethernetCsmacd</type>
+        <enabled>false</enabled>
+        <description>some interface</description>
+    </innerinterface>
+</rpc>
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/TwoCompositeChildren.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/TwoCompositeChildren.xml
new file mode 100644 (file)
index 0000000..c49407e
--- /dev/null
@@ -0,0 +1,14 @@
+<rpc>
+    <innerinterface1>
+        <name>eth1</name>
+        <type>ethernet</type>
+        <enabled>false</enabled>
+        <description>some interface</description>
+    </innerinterface1>
+    <innerinterface2>
+        <name>eth2</name>
+        <type>ethernet</type>
+        <enabled>true</enabled>
+        <description>some interface</description>
+    </innerinterface2>
+</rpc>
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/TwoSimpleChildren.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/resources/TwoSimpleChildren.xml
new file mode 100644 (file)
index 0000000..5f4729c
--- /dev/null
@@ -0,0 +1,4 @@
+<rpc>
+    <name>eth0</name>
+    <type>ethernetCsmacd</type>
+</rpc>
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/pom.xml
new file mode 100644 (file)
index 0000000..5bfbcba
--- /dev/null
@@ -0,0 +1,26 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>sal-parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <relativePath>../..</relativePath>
+  </parent>
+  <packaging>pom</packaging>
+  <groupId>org.opendaylight.controller.tests</groupId>
+  <artifactId>sal-remoterpc-connector-test-parent</artifactId>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+  </scm>
+
+  <modules>
+    <module>consumer-service</module>
+    <module>provider-service</module>
+    <module>test-it</module>
+    <module>test-nb</module>
+  </modules>
+
+</project>
similarity index 89%
rename from opendaylight/md-sal/test/zeromq-test-provider/pom.xml
rename to opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/pom.xml
index 10e15aa9170c04e413086e1210b9cd5772d0803d..a13a5aeba08bfaa15f3ef8713ab0b93fdc411af6 100644 (file)
@@ -2,11 +2,11 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
-        <artifactId>sal-test-parent</artifactId>
+        <artifactId>sal-remoterpc-connector-test-parent</artifactId>
         <groupId>org.opendaylight.controller.tests</groupId>
         <version>1.0-SNAPSHOT</version>
   </parent>
-  <artifactId>zeromq-test-provider</artifactId>
+  <artifactId>sal-remoterpc-connector-test-provider</artifactId>
   <packaging>bundle</packaging>
   <scm>
     <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yang-data-api</artifactId>
     </dependency>
-
+        <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-impl</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-common-util</artifactId>
@@ -78,7 +81,7 @@
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
-      <artifactId>sal-zeromq-connector</artifactId>
+      <artifactId>sal-remoterpc-connector</artifactId>
       <version>1.0-SNAPSHOT</version>
     </dependency>
 
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java
new file mode 100644 (file)
index 0000000..6c294dd
--- /dev/null
@@ -0,0 +1,120 @@
+package org.opendaylight.controller.sample.zeromq.provider;
+
+import org.opendaylight.controller.sal.common.util.RpcErrors;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.CompositeNodeImpl;
+import org.opendaylight.controller.sal.core.api.AbstractProvider;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+import java.util.*;
+
+public class ExampleProvider extends AbstractProvider implements RpcImplementation {
+
+  private final URI namespace = URI.create("http://cisco.com/example");
+  private final QName QNAME = new QName(namespace, "heartbeat");
+  private RpcRegistration reg;
+
+  private ServiceRegistration thisReg;
+
+  private ProviderSession session;
+  private Logger _logger = LoggerFactory.getLogger(ExampleProvider.class);
+
+  @Override
+  public void onSessionInitiated(ProviderSession session) {
+    this.session = session;
+  }
+
+  @Override
+  public Set<QName> getSupportedRpcs() {
+    Set<QName> supportedRpcs = new HashSet<QName>();
+    supportedRpcs.add(QNAME);
+    return supportedRpcs;
+  }
+
+  @Override
+  public RpcResult<CompositeNode> invokeRpc(final QName rpc, CompositeNode input) {
+    boolean success = false;
+    CompositeNode output = null;
+    Collection<RpcError> errors = new ArrayList<>();
+
+    // Only handle supported RPC calls
+    if (getSupportedRpcs().contains(rpc))  {
+      if (input == null) {
+        errors.add(RpcErrors.getRpcError("app", "tag", "info", RpcError.ErrorSeverity.WARNING, "message:null input", RpcError.ErrorType.RPC, null));
+      }
+      else {
+        if (isErroneousInput(input)) {
+          errors.add(RpcErrors.getRpcError("app", "tag", "info", RpcError.ErrorSeverity.ERROR, "message:error", RpcError.ErrorType.RPC, null));
+        }
+        else {
+          success = true;
+          output = addSuccessNode(input);
+        }
+      }
+    }
+    return Rpcs.getRpcResult(success, output, errors);
+  }
+
+  // Examines input -- dives into CompositeNodes and finds any value equal to "error"
+  private boolean isErroneousInput(CompositeNode input) {
+    for (Node<?> n : input.getChildren()) {
+      if (n instanceof CompositeNode) {
+        if (isErroneousInput((CompositeNode)n)) {
+          return true;
+        }
+      }
+      else {  //SimpleNode
+        if ((input.getChildren().get(0).getValue()).equals("error")) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+  
+  // Adds a child SimpleNode containing the value "success" to the input CompositeNode
+  private CompositeNode addSuccessNode(CompositeNode input) {
+    List<Node<?>> list = new ArrayList<Node<?>>(input.getChildren());
+    SimpleNodeTOImpl<String> simpleNode = new SimpleNodeTOImpl<String>(QNAME, input, "success");
+    list.add(simpleNode);
+    return new CompositeNodeTOImpl(QNAME, null, list);
+  }
+
+  @Override
+  protected void startImpl(BundleContext context) {
+    thisReg = context.registerService(ExampleProvider.class, this, new Hashtable<String, String>());
+  }
+
+  @Override
+  protected void stopImpl(BundleContext context) {
+    if (reg != null) {
+      try {
+        reg.close();
+        thisReg.unregister();
+      } catch (Exception e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
+    }
+  }
+
+  public void announce(QName name) {
+    _logger.debug("Announcing [{}]\n\n\n", name);
+    reg = this.session.addRpcImplementation(name, this);
+  }
+
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/pom.xml
new file mode 100644 (file)
index 0000000..4305a28
--- /dev/null
@@ -0,0 +1,536 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>sal-remoterpc-connector-test-parent</artifactId>
+        <groupId>org.opendaylight.controller.tests</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>sal-remoterpc-connector-test-it</artifactId>
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+        <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+    </scm>
+
+    <properties>
+        <exam.version>3.0.0</exam.version>
+        <url.version>1.5.0</url.version>
+        <config.version>0.2.3-SNAPSHOT</config.version>
+        <netconf.version>0.2.3-SNAPSHOT</netconf.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>commons-codec</groupId>
+                <artifactId>commons-codec</artifactId>
+                <version>1.7</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.ops4j.pax.exam</groupId>
+                <artifactId>maven-paxexam-plugin</artifactId>
+                <version>1.2.4</version>
+                <executions>
+                    <execution>
+                        <id>generate-config</id>
+                        <goals>
+                            <goal>generate-depends-file</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <pluginManagement>
+            <plugins>
+                <!--This plugin's configuration is used to store Eclipse 
+                    m2e settings only. It has no influence on the Maven build itself. -->
+                <plugin>
+                    <groupId>org.eclipse.m2e</groupId>
+                    <artifactId>lifecycle-mapping</artifactId>
+                    <version>1.0.0</version>
+                    <configuration>
+                        <lifecycleMappingMetadata>
+                            <pluginExecutions>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>
+                                            org.ops4j.pax.exam
+                                        </groupId>
+                                        <artifactId>
+                                            maven-paxexam-plugin
+                                        </artifactId>
+                                        <versionRange>
+                                            [1.2.4,)
+                                        </versionRange>
+                                        <goals>
+                                            <goal>
+                                                generate-depends-file
+                                            </goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <ignore></ignore>
+                                    </action>
+                                </pluginExecution>
+                            </pluginExecutions>
+                        </lifecycleMappingMetadata>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+            <artifactId>xtend-lib-osgi</artifactId>
+            <version>2.4.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller.tests</groupId>
+            <artifactId>sal-remoterpc-connector-test-provider</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller.tests</groupId>
+            <artifactId>sal-remoterpc-connector-test-consumer</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-broker-impl</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-container-native</artifactId>
+            <version>${exam.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-junit4</artifactId>
+            <version>${exam.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-link-mvn</artifactId>
+            <version>${exam.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.url</groupId>
+            <artifactId>pax-url-aether</artifactId>
+            <version>1.5.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>equinoxSDK381</groupId>
+            <artifactId>org.eclipse.osgi</artifactId>
+            <version>3.8.1.v20120830-144521</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>log4j-over-slf4j</artifactId>
+            <version>1.7.2</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+            <version>1.0.9</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>1.0.9</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common-util</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-core-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-remoterpc-connector</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>containermanager</artifactId>
+            <version>0.5.1-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.osgi</groupId>
+                    <artifactId>org.osgi.compendium</artifactId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>commons-io</artifactId>
+                    <groupId>commons-io</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-binding</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-api</artifactId>
+        </dependency>
+        <!--dependency> <groupId>org.opendaylight.yangtools</groupId> <artifactId>yang-data-impl</artifactId> 
+            <version>0.5.9-SNAPSHOT</version> </dependency -->
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-parser-impl</artifactId>
+            <version>0.5.9-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common-util</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+            <artifactId>antlr4-runtime-osgi-nohead</artifactId>
+            <version>4.0</version>
+        </dependency>
+
+        <!-- routing table dependencies -->
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>zeromq-routingtable.implementation</artifactId>
+            <version>0.4.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>clustering.services</artifactId>
+            <version>0.4.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal</artifactId>
+            <version>0.5.1-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.osgi</groupId>
+                    <artifactId>org.osgi.compendium</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal.implementation</artifactId>
+            <version>0.4.0-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>commons-io</artifactId>
+                    <groupId>commons-io</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>containermanager</artifactId>
+            <version>0.5.0-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.osgi</groupId>
+                    <artifactId>org.osgi.compendium</artifactId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>commons-io</artifactId>
+                    <groupId>commons-io</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>containermanager.it.implementation</artifactId>
+            <version>0.5.0-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>commons-io</artifactId>
+                    <groupId>commons-io</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>clustering.stub</artifactId>
+            <version>0.4.0-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>commons-io</artifactId>
+                    <groupId>commons-io</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager.shell</artifactId>
+            <version>3.0.1</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.osgi</groupId>
+                    <artifactId>org.osgi.compendium</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>eclipselink</groupId>
+            <artifactId>javax.resource</artifactId>
+            <version>1.5.0.v200906010428</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal</artifactId>
+            <version>0.5.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>ietf-netconf-monitoring</artifactId>
+        <version>${netconf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-binding</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>yang-ext</artifactId>
+            <version>2013.09.07.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>opendaylight-l2-types</artifactId>
+            <version>2013.08.27.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-it</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-config</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-broker-impl</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-broker-impl</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.controller.model</groupId>
+            <artifactId>model-inventory</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-connector-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common-util</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>clustering.services</artifactId>
+            <version>0.4.1-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>equinoxSDK381</groupId>
+            <artifactId>org.eclipse.osgi</artifactId>
+            <version>3.8.1.v20120830-144521</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
+            <version>1.9.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-core-asl</artifactId>
+            <version>1.9.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.zeromq</groupId>
+            <artifactId>jeromq</artifactId>
+            <version>0.3.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+            <artifactId>xtend-lib-osgi</artifactId>
+            <version>2.4.3</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-broker-impl</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-container-native</artifactId>
+            <version>${exam.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-junit4</artifactId>
+            <version>${exam.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-netconf-connector</artifactId>
+            <version>${netconf.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>yang-store-impl</artifactId>
+            <version>${config.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>logback-config</artifactId>
+            <version>${config.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-persister-impl</artifactId>
+            <version>${config.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-persister-file-adapter</artifactId>
+            <version>${config.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>netconf-impl</artifactId>
+            <version>${netconf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>netconf-client</artifactId>
+            <version>${netconf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam</artifactId>
+            <version>${exam.version}</version>
+            <!-- Compile scope here is intentional, it is used in TestHelper 
+                class which could be downloaded via nexus and reused in other integration 
+                tests. -->
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-link-mvn</artifactId>
+            <version>${exam.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>equinoxSDK381</groupId>
+            <artifactId>org.eclipse.osgi</artifactId>
+            <version>3.8.1.v20120830-144521</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>log4j-over-slf4j</artifactId>
+            <version>1.7.2</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+            <version>1.0.9</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>1.0.9</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller.model</groupId>
+            <artifactId>model-flow-service</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-manager</artifactId>
+            <version>0.2.3-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>commons-io</artifactId>
+                    <groupId>commons-io</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller.model</groupId>
+            <artifactId>model-flow-management</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+            <artifactId>antlr4-runtime-osgi-nohead</artifactId>
+            <version>4.0</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/RouterTest.java b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/RouterTest.java
new file mode 100644 (file)
index 0000000..62c094d
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * 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.sample.zeromq.test.it;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.sal.connector.remoterpc.Client;
+import org.opendaylight.controller.sal.connector.remoterpc.RemoteRpcClient;
+import org.opendaylight.controller.sal.connector.remoterpc.RemoteRpcServer;
+import org.opendaylight.controller.sal.connector.remoterpc.ServerImpl;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sample.zeromq.provider.ExampleProvider;
+import org.opendaylight.controller.sample.zeromq.consumer.ExampleConsumer;
+import org.opendaylight.controller.test.sal.binding.it.TestHelper;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.util.Filter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+
+import javax.inject.Inject;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Hashtable;
+
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.baseModelBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.bindingAwareSalBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.configMinumumBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.mdSalCoreBundles;
+import static org.ops4j.pax.exam.CoreOptions.*;
+
+@RunWith(PaxExam.class)
+public class RouterTest {
+
+  private Logger _logger = LoggerFactory.getLogger(RouterTest.class);
+
+  public static final String ODL = "org.opendaylight.controller";
+  public static final String YANG = "org.opendaylight.yangtools";
+  public static final String SAMPLE = "org.opendaylight.controller.tests";
+  private final URI namespace = URI.create("http://cisco.com/example");
+  private final QName QNAME = new QName(namespace, "heartbeat");
+
+
+  @Inject
+  org.osgi.framework.BundleContext ctx;
+
+  @Inject
+  @Filter(timeout=60*1000)
+  Broker broker;
+  
+  private ZMQ.Context zmqCtx = ZMQ.context(1);
+  //private Server router;
+  //private ExampleProvider provider;
+
+  //@Test
+  public void testInvokeRpc() throws Exception{
+    //Thread.sleep(1000);
+    //Send announcement
+    ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+    Assert.assertNotNull(providerRef);
+
+    ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+    Assert.assertNotNull(provider);
+
+    ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+    Assert.assertNotNull(consumerRef);
+    ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+    Assert.assertNotNull(consumer);
+
+
+    _logger.debug("Provider sends announcement [{}]", "heartbeat");
+    provider.announce(QNAME);
+    ServiceReference routerRef = ctx.getServiceReference(Client.class);
+    Client router = (Client) ctx.getService(routerRef);
+    _logger.debug("Found router[{}]", router);
+    _logger.debug("Invoking RPC [{}]", QNAME);
+    for (int i = 0; i < 3; i++) {
+      RpcResult<CompositeNode> result = router.invokeRpc(QNAME, consumer.getValidCompositeNodeWithOneSimpleChild());
+      _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+      Assert.assertNotNull(result);
+    }
+  }
+
+  @Test
+  public void testInvokeRpcWithValidSimpleNode() throws Exception{
+    //Thread.sleep(1500);
+
+    ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+    Assert.assertNotNull(providerRef);
+    ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+    Assert.assertNotNull(provider);
+    ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+    Assert.assertNotNull(consumerRef);
+    ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+    Assert.assertNotNull(consumer);
+
+    // Provider sends announcement
+    _logger.debug("Provider sends announcement [{}]", "heartbeat");
+    provider.announce(QNAME);
+    // Consumer invokes RPC
+    _logger.debug("Invoking RPC [{}]", QNAME);
+    CompositeNode input = consumer.getValidCompositeNodeWithOneSimpleChild();
+    for (int i = 0; i < 3; i++) {
+      RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, input);
+      Assert.assertNotNull(result);
+      _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+      Assert.assertTrue(result.isSuccessful());
+      Assert.assertNotNull(result.getResult());
+      Assert.assertEquals(0, result.getErrors().size());
+      Assert.assertEquals(input.getChildren().size()+1, result.getResult().getChildren().size());
+    }
+  }
+
+  @Test
+  public void testInvokeRpcWithValidSimpleNodes() throws Exception{
+    //Thread.sleep(1500);
+
+    ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+    Assert.assertNotNull(providerRef);
+    ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+    Assert.assertNotNull(provider);
+    ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+    Assert.assertNotNull(consumerRef);
+    ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+    Assert.assertNotNull(consumer);
+
+    // Provider sends announcement
+    _logger.debug("Provider sends announcement [{}]", "heartbeat");
+    provider.announce(QNAME);
+    // Consumer invokes RPC
+    _logger.debug("Invoking RPC [{}]", QNAME);
+    CompositeNode input = consumer.getValidCompositeNodeWithFourSimpleChildren();
+    for (int i = 0; i < 3; i++) {
+      RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, input);
+      Assert.assertNotNull(result);
+      _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+      Assert.assertTrue(result.isSuccessful());
+      Assert.assertNotNull(result.getResult());
+      Assert.assertEquals(0, result.getErrors().size());
+      Assert.assertEquals(input.getChildren().size()+1, result.getResult().getChildren().size());
+    }
+  }
+
+  @Test
+  public void testInvokeRpcWithValidCompositeNode() throws Exception{
+    //Thread.sleep(1500);
+
+    ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+    Assert.assertNotNull(providerRef);
+    ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+    Assert.assertNotNull(provider);
+    ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+    Assert.assertNotNull(consumerRef);
+    ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+    Assert.assertNotNull(consumer);
+
+    // Provider sends announcement
+    _logger.debug("Provider sends announcement [{}]", "heartbeat");
+    provider.announce(QNAME);
+    // Consumer invokes RPC
+    _logger.debug("Invoking RPC [{}]", QNAME);
+    CompositeNode input = consumer.getValidCompositeNodeWithTwoCompositeChildren();
+    for (int i = 0; i < 3; i++) {
+      RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, input);
+      Assert.assertNotNull(result);
+      _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+      Assert.assertTrue(result.isSuccessful());
+      Assert.assertNotNull(result.getResult());
+      Assert.assertEquals(0, result.getErrors().size());
+      Assert.assertEquals(input.getChildren().size()+1, result.getResult().getChildren().size());
+    }
+  }
+
+  @Test
+  public void testInvokeRpcWithNullInput() throws Exception{
+    //Thread.sleep(1500);
+
+    ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+    Assert.assertNotNull(providerRef);
+    ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+    Assert.assertNotNull(provider);
+    ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+    Assert.assertNotNull(consumerRef);
+    ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+    Assert.assertNotNull(consumer);
+
+    // Provider sends announcement
+    _logger.debug("Provider sends announcement [{}]", QNAME.getLocalName());
+    provider.announce(QNAME);
+    // Consumer invokes RPC
+    _logger.debug("Invoking RPC [{}]", QNAME);
+    for (int i = 0; i < 3; i++) {
+      RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, null);
+      Assert.assertNotNull(result);
+      _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+      Assert.assertFalse(result.isSuccessful());
+      Assert.assertNull(result.getResult());
+      Assert.assertEquals(1, result.getErrors().size());
+      Assert.assertEquals(RpcError.ErrorSeverity.WARNING, ((RpcError)result.getErrors().toArray()[0]).getSeverity());
+    }
+  }
+
+  @Test
+  public void testInvokeRpcWithInvalidSimpleNode() throws Exception{
+    //Thread.sleep(1500);
+
+    ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+    Assert.assertNotNull(providerRef);
+    ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+    Assert.assertNotNull(provider);
+    ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+    Assert.assertNotNull(consumerRef);
+    ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+    Assert.assertNotNull(consumer);
+
+    // Provider sends announcement
+    _logger.debug("Provider sends announcement [{}]", QNAME.getLocalName());
+    provider.announce(QNAME);
+    // Consumer invokes RPC
+    _logger.debug("Invoking RPC [{}]", QNAME);
+    CompositeNode input = consumer.getInvalidCompositeNodeSimpleChild();
+    for (int i = 0; i < 3; i++) {
+      RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, input);
+      Assert.assertNotNull(result);
+      _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+      Assert.assertFalse(result.isSuccessful());
+      Assert.assertNull(result.getResult());
+      Assert.assertEquals(1, result.getErrors().size());
+      Assert.assertEquals(RpcError.ErrorSeverity.ERROR, ((RpcError)result.getErrors().toArray()[0]).getSeverity());
+    }
+  }
+
+  @Test
+  public void testInvokeRpcWithInvalidCompositeNode() throws Exception{
+    //Thread.sleep(1500);
+
+    ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+    Assert.assertNotNull(providerRef);
+    ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+    Assert.assertNotNull(provider);
+    ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+    Assert.assertNotNull(consumerRef);
+    ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+    Assert.assertNotNull(consumer);
+
+    // Provider sends announcement
+    _logger.debug("Provider sends announcement [{}]", QNAME.getLocalName());
+    provider.announce(QNAME);
+    // Consumer invokes RPC
+    _logger.debug("Invoking RPC [{}]", QNAME);
+    CompositeNode input = consumer.getInvalidCompositeNodeCompositeChild();
+    for (int i = 0; i < 3; i++) {
+      RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, input);
+      Assert.assertNotNull(result);
+      _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+      Assert.assertFalse(result.isSuccessful());
+      Assert.assertNull(result.getResult());
+      Assert.assertEquals(1, result.getErrors().size());
+      Assert.assertEquals(RpcError.ErrorSeverity.ERROR, ((RpcError)result.getErrors().toArray()[0]).getSeverity());
+    }
+  }
+
+  //@Test
+  // This method is UNTESTED -- need to get around the bundling issues before I know if this even work
+//  public void testInvokeRpcWithValidCompositeNode() throws Exception{
+//    Thread.sleep(10000);
+//    //Send announcement
+//    ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+//    Assert.assertNotNull(providerRef);
+//
+//    ExampleProvider provider = (ExampleProvider)ctx.getService(providerRef);
+//    Assert.assertNotNull(provider);
+//
+//    ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+//    Assert.assertNotNull(consumerRef);
+//
+//    ExampleConsumer consumer = (ExampleConsumer)ctx.getService(consumerRef);
+//    Assert.assertNotNull(consumer);
+//
+//    _logger.debug("Provider sends announcement [{}]", "heartbeat");
+//    provider.announce(QNAME);
+//    ServiceReference routerRef = ctx.getServiceReference(Client.class);
+//    Client router = (Client) ctx.getService(routerRef);
+//    _logger.debug("Found router[{}]", router);
+//    _logger.debug("Invoking RPC [{}]", QNAME);
+//    for (int i = 0; i < 3; i++) {
+//      RpcResult<CompositeNode> result = router.getInstance().invokeRpc(QNAME, consumer.getValidCompositeNodeWithOneSimpleChild());
+//      _logger.debug("{}-> Result is: Successful:[{}], Payload:[{}], Errors: [{}]", i, result.isSuccessful(), result.getResult(), result.getErrors());
+//      Assert.assertNotNull(result);
+//    }
+//  }
+
+  private Message send(Message msg) throws IOException {
+    ZMQ.Socket reqSocket = zmqCtx.socket(ZMQ.REQ);
+    reqSocket.connect("tcp://localhost:5555");
+    reqSocket.send(Message.serialize(msg));
+    Message response = parseMessage(reqSocket);
+
+    return response;
+  }
+
+  /**
+   * @param socket
+   * @return
+   */
+  private Message parseMessage(ZMQ.Socket socket) {
+
+    Message msg = null;
+    try {
+      byte[] bytes = socket.recv();
+      _logger.debug("Received bytes:[{}]", bytes.length);
+      msg = (Message) Message.deserialize(bytes);
+    } catch (Throwable t) {
+      t.printStackTrace();
+    }
+    return msg;
+  }
+
+  
+  private void printState(){
+    Bundle[] b = ctx.getBundles();
+    _logger.debug("\n\nNumber of bundles [{}]\n\n]", b.length);
+    for (int i=0;i<b.length;i++){
+      _logger.debug("Bundle States {}-{} ",b[i].getSymbolicName(), stateToString(b[i].getState()));
+
+      if ( Bundle.INSTALLED == b[i].getState() || (Bundle.RESOLVED == b[i].getState())){
+        try {
+          b[i].start();
+        } catch (BundleException e) {
+          e.printStackTrace();
+        }
+      }
+    }
+  }
+  private String stateToString(int state) {
+    switch (state) {
+      case Bundle.ACTIVE:
+        return "ACTIVE";
+      case Bundle.INSTALLED:
+        return "INSTALLED";
+      case Bundle.RESOLVED:
+        return "RESOLVED";
+      case Bundle.UNINSTALLED:
+        return "UNINSTALLED";
+      default:
+        return "Not CONVERTED";
+    }
+  }
+
+  @Configuration
+  public Option[] config() {
+    return options(systemProperty("osgi.console").value("2401"),
+        systemProperty("rpc.port").value("5555"),
+        mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), //
+        mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
+        mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
+        mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
+
+        //mavenBundle(ODL, "sal-binding-broker-impl").versionAsInProject().update(), //
+        mavenBundle(ODL, "sal-common").versionAsInProject(), //
+        mavenBundle(ODL, "sal-common-api").versionAsInProject(),//
+        mavenBundle(ODL, "sal-common-impl").versionAsInProject(), //
+        mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
+        mavenBundle(ODL, "sal-core-api").versionAsInProject().update(), //
+        mavenBundle(ODL, "sal-broker-impl").versionAsInProject(), //
+        mavenBundle(ODL, "sal-core-spi").versionAsInProject().update(), //
+        mavenBundle(ODL, "sal-connector-api").versionAsInProject(), //
+
+
+        
+        baseModelBundles(),
+        bindingAwareSalBundles(),
+        TestHelper.bindingIndependentSalBundles(),
+        TestHelper.configMinumumBundles(),
+        TestHelper.mdSalCoreBundles(),
+        
+      //Added the consumer
+        mavenBundle(SAMPLE, "sal-remoterpc-connector-test-consumer").versionAsInProject(), //
+      //**** These two bundles below are NOT successfully resolved -- some of their dependencies must be missing
+      //**** This causes the "Message" error to occur, the class cannot be found
+        mavenBundle(SAMPLE, "sal-remoterpc-connector-test-provider").versionAsInProject(), //
+        mavenBundle(ODL, "sal-remoterpc-connector").versionAsInProject(), //
+
+        mavenBundle(ODL, "zeromq-routingtable.implementation").versionAsInProject(),
+        mavenBundle(YANG, "concepts").versionAsInProject(),
+        mavenBundle(YANG, "yang-binding").versionAsInProject(), //
+        mavenBundle(YANG, "yang-common").versionAsInProject(), //
+        mavenBundle(YANG, "yang-data-api").versionAsInProject(), //
+        mavenBundle(YANG, "yang-data-impl").versionAsInProject(), //
+        mavenBundle(YANG, "yang-model-api").versionAsInProject(), //
+        mavenBundle(YANG, "yang-parser-api").versionAsInProject(), //
+        mavenBundle(YANG, "yang-parser-impl").versionAsInProject(), //
+        mavenBundle(YANG, "yang-model-util").versionAsInProject(), //
+        mavenBundle(YANG + ".thirdparty", "xtend-lib-osgi").versionAsInProject(), //
+        mavenBundle(YANG + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), //
+        mavenBundle("com.google.guava", "guava").versionAsInProject(), //
+        mavenBundle("org.zeromq", "jeromq").versionAsInProject(),
+        mavenBundle("org.codehaus.jackson", "jackson-mapper-asl").versionAsInProject(),
+        mavenBundle("org.codehaus.jackson", "jackson-core-asl").versionAsInProject(),
+        //routingtable dependencies
+        systemPackages("sun.reflect", "sun.reflect.misc", "sun.misc"),
+        // List framework bundles
+        mavenBundle("equinoxSDK381", "org.eclipse.equinox.console").versionAsInProject(),
+        mavenBundle("equinoxSDK381", "org.eclipse.equinox.util").versionAsInProject(),
+        mavenBundle("equinoxSDK381", "org.eclipse.osgi.services").versionAsInProject(),
+        mavenBundle("equinoxSDK381", "org.eclipse.equinox.ds").versionAsInProject(),
+        mavenBundle("equinoxSDK381", "org.apache.felix.gogo.command").versionAsInProject(),
+        mavenBundle("equinoxSDK381", "org.apache.felix.gogo.runtime").versionAsInProject(),
+        mavenBundle("equinoxSDK381", "org.apache.felix.gogo.shell").versionAsInProject(),
+        // List logger bundles
+
+        mavenBundle("org.opendaylight.controller", "clustering.services")
+            .versionAsInProject(),
+        mavenBundle("org.opendaylight.controller", "clustering.stub")
+            .versionAsInProject(),
+
+
+        // List all the bundles on which the test case depends
+        mavenBundle("org.opendaylight.controller", "sal")
+            .versionAsInProject(),
+        mavenBundle("org.opendaylight.controller", "sal.implementation")
+            .versionAsInProject(),
+        mavenBundle("org.jboss.spec.javax.transaction",
+            "jboss-transaction-api_1.1_spec").versionAsInProject(),
+        mavenBundle("org.apache.commons", "commons-lang3")
+            .versionAsInProject(),
+        mavenBundle("org.apache.felix",
+            "org.apache.felix.dependencymanager")
+            .versionAsInProject(),
+
+        junitBundles()
+    );
+  }
+
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/resources/controller.config b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/resources/controller.config
new file mode 100644 (file)
index 0000000..0d9cd6a
--- /dev/null
@@ -0,0 +1,123 @@
+//START OF CONFIG-LAST
+<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+       <module>
+               <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
+               <name>yang-schema-service</name>
+       </module>
+       <module>
+               <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
+               <name>hash-map-data-store</name>
+       </module>
+       <module>
+               <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+               <name>dom-broker</name>
+               <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                       <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+                       <name>ref_hash-map-data-store</name>
+               </data-store>
+       </module>
+       <module>
+               <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
+               <name>binding-broker-impl</name>
+               <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                       <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+                       <name>ref_binding-notification-broker</name>
+               </notification-service>
+               <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                       <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+                       <name>ref_binding-data-broker</name>
+               </data-broker>
+       </module>
+       <module>
+               <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+               <name>runtime-mapping-singleton</name>
+       </module>
+       <module>
+               <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+               <name>binding-notification-broker</name>
+       </module>
+       <module>
+               <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
+               <name>binding-data-broker</name>
+               <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                       <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                       <name>ref_dom-broker</name>
+               </dom-broker>
+               <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+               <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+               <name>ref_runtime-mapping-singleton</name>
+               </mapping-service>
+       </module>
+       <module>
+               <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc">prefix:remote-zeromq-rpc-server</type>
+               <name>remoter</name>
+               <port xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc">5666</port>
+               <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc">
+                       <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
+                       <name>ref_dom-broker</name>
+               </dom-broker>
+       </module>
+</modules>
+<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+       <service>
+       <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+               <instance>
+               <name>ref_yang-schema-service</name>
+               <provider>/config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']</provider>
+               </instance>
+       </service>
+       <service>
+               <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+               <instance>
+                       <name>ref_binding-notification-broker</name>
+                       <provider>/config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']</provider>
+               </instance>
+       </service>
+       <service>
+               <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+               <instance>
+                       <name>ref_hash-map-data-store</name>
+                       <provider>/config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']</provider>
+               </instance>
+       </service>
+       <service>
+               <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+               <instance>
+                       <name>ref_binding-broker-impl</name>
+                       <provider>/config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']</provider>
+               </instance>
+       </service>
+       <service>
+               <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
+               <instance>
+                       <name>ref_runtime-mapping-singleton</name>
+                       <provider>/config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']</provider>
+               </instance>
+       </service>
+       <service>
+       <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+               <instance>
+                       <name>ref_dom-broker</name>
+                       <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']</provider>
+               </instance>
+       </service>
+       <service>
+               <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+               <instance>
+               <name>ref_binding-data-broker</name>
+               <provider>/config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']</provider>
+       </instance>
+       </service>
+</services>
+</data>
+
+
+//END OF SNAPSHOT
+urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc?module=odl-sal-dom-rpc-remote-cfg&revision=2013-10-28
+//END OF CONFIG
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/resources/logback.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/resources/logback.xml
new file mode 100644 (file)
index 0000000..1d17796
--- /dev/null
@@ -0,0 +1,16 @@
+<configuration scan="true">
+
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <encoder>
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+      </pattern>
+    </encoder>
+  </appender>
+
+
+  <logger name="org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort" level="ERROR"/>
+
+  <root level="info">
+    <appender-ref ref="STDOUT" />
+  </root>
+</configuration>
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml
new file mode 100644 (file)
index 0000000..dd7e36c
--- /dev/null
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>sal-remoterpc-connector-test-parent</artifactId>
+    <groupId>org.opendaylight.controller.tests</groupId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>sal-remoterpc-connector-test-nb</artifactId>
+  <packaging>bundle</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>${bundle.plugin.version}</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+            </Export-Package>
+            <Import-Package>
+              com.sun.jersey.spi.container.servlet,
+              org.codehaus.jackson.annotate,
+              javax.ws.rs,
+              javax.ws.rs.core,
+              javax.xml.bind,
+              javax.xml.bind.annotation,
+              org.slf4j,
+              org.apache.catalina.filters,
+              org.codehaus.jackson.jaxrs,
+              org.opendaylight.controller.sample.zeromq.provider,
+              org.opendaylight.controller.sample.zeromq.consumer,
+              org.opendaylight.controller.sal.utils,
+              org.opendaylight.yangtools.yang.common,
+              org.opendaylight.controller.sal.connector.api,
+              org.opendaylight.controller.sal.connector.remoterpc.api;version="[0.4,1)",
+              org.opendaylight.controller.sal.connector.remoterpc.impl;version="[0.4,1)",
+              org.opendaylight.controller.sal.connector.remoterpc.dto,
+              org.opendaylight.controller.sal.connector.remoterpc.util,
+              org.osgi.framework,
+              com.google.common.base,
+              org.opendaylight.yangtools.yang.data.api,
+              !org.codehaus.enunciate.jaxrs
+
+            </Import-Package>
+            <Web-ContextPath>/controller/nb/v2/zmqnb</Web-ContextPath>
+            <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
+          </instructions>
+          <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>containermanager</artifactId>
+      <version>0.5.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>commons.northbound</artifactId>
+      <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.5.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.tests</groupId>
+      <artifactId>sal-remoterpc-connector-test-provider</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.tests</groupId>
+      <artifactId>sal-remoterpc-connector-test-consumer</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-remoterpc-connector</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <version>5.0.0</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>zeromq-routingtable.implementation</artifactId>
+          <version>0.4.1-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>com.google.guava</groupId>
+          <artifactId>guava</artifactId>
+      </dependency>
+  </dependencies>
+
+ </project>
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqrouter/rest/Router.java b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqrouter/rest/Router.java
new file mode 100644 (file)
index 0000000..6c9ec4e
--- /dev/null
@@ -0,0 +1,246 @@
+package org.opendaylight.controller.tests.zmqrouter.rest;
+
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.CompositeNodeImpl;
+import org.opendaylight.controller.sal.connector.remoterpc.impl.RoutingTableImpl;
+import org.opendaylight.controller.sal.connector.remoterpc.util.XmlUtils;
+import org.opendaylight.controller.sample.zeromq.consumer.ExampleConsumer;
+import org.opendaylight.controller.sample.zeromq.provider.ExampleProvider;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.osgi.framework.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Set;
+
+@Path("router")
+public class Router {
+  private Logger _logger = LoggerFactory.getLogger(Router.class);
+  private final URI namespace = URI.create("http://cisco.com/example");
+  private final QName QNAME = new QName(namespace, "heartbeat");
+
+
+  @GET
+  @Path("/hello")
+  @Produces(MediaType.TEXT_PLAIN)
+  public String hello() {
+    return "Hello";
+  }
+
+  @GET
+  @Path("/announce")
+  @Produces(MediaType.TEXT_PLAIN)
+  public String announce() {
+    _logger.info("Announce request received");
+
+    BundleContext ctx = getBundleContext();
+    ServiceReference providerRef = ctx.getServiceReference(ExampleProvider.class);
+    if (providerRef == null) {
+      _logger.debug("Could not get provider reference");
+      return "Could not get provider reference";
+    }
+
+    ExampleProvider provider = (ExampleProvider) ctx.getService(providerRef);
+    if (provider == null) {
+      _logger.info("Could not get provider service");
+      return "Could not get provider service";
+    }
+
+    provider.announce(QNAME);
+    return "Announcement sent ";
+
+  }
+
+  @GET
+  @Path("/rpc")
+  @Produces(MediaType.TEXT_PLAIN)
+  public String invokeRpc() throws Exception {
+    _logger.info("Invoking RPC");
+
+    ExampleConsumer consumer = getConsumer();
+    RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, new CompositeNodeImpl());
+    _logger.info("Result [{}]", result.isSuccessful());
+
+    return stringify(result);
+  }
+
+  @GET
+  @Path("/rpc-success")
+  @Produces(MediaType.TEXT_PLAIN)
+  public String invokeRpcSuccess() throws Exception {
+    ExampleConsumer consumer = getConsumer();
+    RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, consumer.getValidCompositeNodeWithFourSimpleChildren()); //TODO: Change this
+    _logger.info("Result [{}]", result.isSuccessful());
+
+    return stringify(result);
+  }
+
+  @GET
+  @Path("/rpc-failure")
+  @Produces(MediaType.TEXT_PLAIN)
+  public String invokeRpcFailure() throws Exception {
+    ExampleConsumer consumer = getConsumer();
+    //RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, consumer.getInvalidCompositeNodeCompositeChild()); //TODO: Change this
+    RpcResult<CompositeNode> result = consumer.invokeRpc(QNAME, null); //TODO: Change this
+    _logger.info("Result [{}]", result.isSuccessful());
+
+    return stringify(result);
+  }
+
+  @GET
+  @Path("/routingtable")
+  @Produces(MediaType.TEXT_PLAIN)
+  public String invokeRoutingTable() {
+    _logger.info("Invoking adding an entry in routing table");
+
+    BundleContext ctx = getBundleContext();
+    ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class);
+    if (routingTableServiceReference == null) {
+      _logger.debug("Could not get routing table impl reference");
+      return "Could not get routingtable referen ";
+    }
+    RoutingTable routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference);
+    if (routingTable == null) {
+      _logger.info("Could not get routing table service");
+      return "Could not get routing table service";
+    }
+
+
+    RoutingIdentifierImpl rii = new RoutingIdentifierImpl();
+    try {
+      routingTable.addGlobalRoute(rii.toString(), "172.27.12.1:5000");
+    } catch (RoutingTableException e) {
+      _logger.error("error in adding routing identifier" + e.getMessage());
+
+    } catch (SystemException e) {
+      _logger.error("error in adding routing identifier" + e.getMessage());
+    }
+
+    Set<String> routes = routingTable.getRoutes(rii.toString());
+
+    StringBuilder stringBuilder = new StringBuilder();
+    for (String route : routes) {
+      stringBuilder.append(route);
+    }
+
+    _logger.info("Result [{}] routes added for route" + rii + stringBuilder.toString());
+
+    return stringBuilder.toString();
+  }
+
+  @GET
+  @Path("/routingtabledelete")
+  @Produces(MediaType.TEXT_PLAIN)
+  public String invokeDeleteRoutingTable() {
+    _logger.info("Invoking adding an entry in routing table");
+
+    BundleContext ctx = getBundleContext();
+    ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class);
+    if (routingTableServiceReference == null) {
+      _logger.debug("Could not get routing table impl reference");
+      return "Could not get routingtable referen ";
+    }
+    RoutingTable routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference);
+    if (routingTable == null) {
+      _logger.info("Could not get routing table service");
+      return "Could not get routing table service";
+    }
+
+
+    RoutingIdentifierImpl rii = new RoutingIdentifierImpl();
+    try {
+      routingTable.removeGlobalRoute(rii.toString());
+    } catch (RoutingTableException e) {
+      _logger.error("error in adding routing identifier" + e.getMessage());
+
+    } catch (SystemException e) {
+      _logger.error("error in adding routing identifier" + e.getMessage());
+    }
+
+    Set<String> routes = routingTable.getRoutes(rii.toString());
+
+    StringBuilder stringBuilder = new StringBuilder();
+    if (routes != null) {
+      for (String route : routes) {
+        stringBuilder.append(route);
+      }
+    } else {
+      stringBuilder.append(" successfully");
+    }
+
+    _logger.info("Result [{}] routes removed for route" + rii + stringBuilder.toString());
+
+    return stringBuilder.toString();
+  }
+
+  private String stringify(RpcResult<CompositeNode> result) {
+    CompositeNode node = result.getResult();
+    StringBuilder builder = new StringBuilder("result:").append(XmlUtils.compositeNodeToXml(node)).append("\n")
+        .append("error:").append(result.getErrors()).append("\n");
+
+    return builder.toString();
+  }
+
+  private BundleContext getBundleContext() {
+    ClassLoader tlcl = Thread.currentThread().getContextClassLoader();
+    Bundle bundle = null;
+
+    if (tlcl instanceof BundleReference) {
+      bundle = ((BundleReference) tlcl).getBundle();
+    } else {
+      _logger.info("Unable to determine the bundle context based on " +
+          "thread context classloader.");
+      bundle = FrameworkUtil.getBundle(this.getClass());
+    }
+    return (bundle == null ? null : bundle.getBundleContext());
+  }
+
+  private ExampleConsumer getConsumer() {
+    BundleContext ctx = getBundleContext();
+    ServiceReference consumerRef = ctx.getServiceReference(ExampleConsumer.class);
+    if (consumerRef == null) {
+      _logger.debug("Could not get consumer reference");
+      throw new NullPointerException("Could not get consumer reference");
+    }
+    ExampleConsumer consumer = (ExampleConsumer) ctx.getService(consumerRef);
+    if (consumer == null) {
+      _logger.info("Could not get consumer service");
+      throw new NullPointerException("Could not get consumer service");
+    }
+    return consumer;
+  }
+
+  class RoutingIdentifierImpl implements RpcRouter.RouteIdentifier, Serializable {
+
+    private final URI namespace = URI.create("http://cisco.com/example");
+    private final QName QNAME = new QName(namespace, "global");
+    private final QName instance = new QName(URI.create("127.0.0.1"), "local");
+
+    @Override
+    public QName getContext() {
+      return QNAME;
+    }
+
+    @Override
+    public QName getType() {
+      return QNAME;
+    }
+
+    @Override
+    public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier getRoute() {
+      return InstanceIdentifier.of(instance);
+    }
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/src/main/resources/WEB-INF/web.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/src/main/resources/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..5bd2139
--- /dev/null
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+        version="3.0">
+  <servlet>
+    <servlet-name>JAXRSZmq</servlet-name>
+    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+    <init-param>
+      <param-name>javax.ws.rs.Application</param-name>
+      <param-value>org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
+    </init-param>
+    <load-on-startup>1</load-on-startup>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>JAXRSZmq</servlet-name>
+    <url-pattern>/*</url-pattern>
+  </servlet-mapping>
+
+
+
+        <security-constraint>
+          <web-resource-collection>
+            <web-resource-name>NB api</web-resource-name>
+            <url-pattern>/*</url-pattern>
+            <http-method>POST</http-method>
+            <http-method>GET</http-method>
+            <http-method>PUT</http-method>
+            <http-method>PATCH</http-method>
+            <http-method>DELETE</http-method>
+            <http-method>HEAD</http-method>
+          </web-resource-collection>
+          <auth-constraint>
+            <role-name>System-Admin</role-name>
+            <role-name>Network-Admin</role-name>
+            <role-name>Network-Operator</role-name>
+            <role-name>Container-User</role-name>
+          </auth-constraint>
+        </security-constraint>
+
+        <security-role>
+                <role-name>System-Admin</role-name>
+        </security-role>
+        <security-role>
+                <role-name>Network-Admin</role-name>
+        </security-role>
+        <security-role>
+                <role-name>Network-Operator</role-name>
+        </security-role>
+        <security-role>
+                <role-name>Container-User</role-name>
+        </security-role>
+
+        <login-config>
+                <auth-method>BASIC</auth-method>
+                <realm-name>opendaylight</realm-name>
+        </login-config>
+</web-app>
index 7022db2bc9bba631b2b21f50f2bb2a20d395d7d5..04114fa0edd3d536cb9eb408663ab3404789d3a3 100644 (file)
@@ -17,6 +17,7 @@ import javax.ws.rs.ext.Provider;
 import org.opendaylight.controller.sal.rest.api.Draft01;
 import org.opendaylight.controller.sal.rest.api.Draft02;
 import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.controller.sal.restconf.impl.ResponseException;
 import org.opendaylight.controller.sal.restconf.impl.StructuredData;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
@@ -45,7 +46,7 @@ public enum StructuredDataToJsonProvider implements MessageBodyWriter<Structured
             throws IOException, WebApplicationException {
         CompositeNode data = t.getData();
         if (data == null) {
-            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
+            throw new ResponseException(Response.Status.NOT_FOUND, "No data exists.");
         }
 
         JsonWriter writer = new JsonWriter(new OutputStreamWriter(entityStream, "UTF-8"));
index c0de0d80a8c0f04fbb5a322c822acf4ca5e91661..4a077e663f187f6d23e05a771d4ec988290c8c90 100644 (file)
@@ -59,7 +59,6 @@ public class XmlMapper {
             throws UnsupportedDataTypeException {
         QName dataType = data.getNodeType();
         Element itemEl = doc.createElementNS(dataType.getNamespace().toString(), dataType.getLocalName());
-
         if (data instanceof SimpleNode<?>) {
             if (schema instanceof LeafListSchemaNode) {
                 writeValueOfNodeByType(itemEl, (SimpleNode<?>) data, ((LeafListSchemaNode) schema).getType());
@@ -73,11 +72,14 @@ public class XmlMapper {
             }
         } else { // CompositeNode
             for (Node<?> child : ((CompositeNode) data).getChildren()) {
-                DataSchemaNode childSchema = findFirstSchemaForNode(child, ((DataNodeContainer) schema).getChildNodes());
-                if (logger.isDebugEnabled()) {
-                    if (childSchema == null) {
-                        logger.debug("Probably the data node \"" + ((child == null) ? "" : child.getNodeType().getLocalName())
-                                + "\" is not conform to schema");
+                DataSchemaNode childSchema = null;
+                if(schema != null){
+                    childSchema = findFirstSchemaForNode(child, ((DataNodeContainer) schema).getChildNodes());
+                    if (logger.isDebugEnabled()) {
+                        if (childSchema == null) {
+                            logger.debug("Probably the data node \"" + ((child == null) ? "" : child.getNodeType().getLocalName())
+                                    + "\" is not conform to schema");
+                        }
                     }
                 }
                 itemEl.appendChild(translateToXmlAndReturnRootElement(doc, child, childSchema));
index 1b0fda41ca723d67f640de2418ebd6e33e153751..df6b58c8971331b74c89418a6e1ee039e1fcdf10 100644 (file)
@@ -9,9 +9,12 @@ import org.opendaylight.yangtools.yang.common.QName
 import org.opendaylight.yangtools.yang.common.RpcResult
 import org.opendaylight.yangtools.yang.data.api.CompositeNode
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.slf4j.LoggerFactory
 
 class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
 
+
+    val static LOG = LoggerFactory.getLogger(BrokerFacade)
     val static BrokerFacade INSTANCE = new BrokerFacade
 
     @Property
@@ -38,11 +41,13 @@ class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
 
     override readConfigurationData(InstanceIdentifier path) {
         checkPreconditions
+        LOG.info("Read Configuration via Restconf: {}",path)
         return dataService.readConfigurationData(path);
     }
 
     override readOperationalData(InstanceIdentifier path) {
         checkPreconditions
+        LOG.info("Read Operational via Restconf: {}",path)
         return dataService.readOperationalData(path);
     }
 
index 602e8b92425ea9d1ab26bd784893f7ff3a3a9ba1..fed56fe297a8ed9cc929437329701799ce06ccfb 100644 (file)
@@ -33,6 +33,7 @@ import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
 
 import static com.google.common.base.Preconditions.*
 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
 
 class ControllerContext implements SchemaServiceListener {
 
@@ -291,7 +292,16 @@ class ControllerContext implements SchemaServiceListener {
         checkArgument(node instanceof LeafSchemaNode);
         val urlDecoded = URLDecoder.decode(uriValue);
         val typedef = (node as LeafSchemaNode).type;
-        val decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
+        var decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
+        if(decoded == null) {
+            var baseType = typedef
+            while (baseType.baseType != null) {
+                baseType = baseType.baseType;
+            }
+            if(baseType instanceof IdentityrefTypeDefinition) {
+                decoded = toQName(urlDecoded)
+            }
+        }
         map.put(node.QName, decoded);
     }
 
index 35352e0819c9720d4bc23e80f30437b542351633..94a7756da65cefd02adbe3a00eecb69efe9a8dab 100644 (file)
@@ -18,9 +18,10 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
 import org.opendaylight.yangtools.yang.common.QName
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
+import static javax.ws.rs.core.Response.Status.*
 
 class RestconfImpl implements RestconfService {
-    
+
     val static RestconfImpl INSTANCE = new RestconfImpl
 
     @Property
@@ -28,13 +29,13 @@ class RestconfImpl implements RestconfService {
 
     @Property
     extension ControllerContext controllerContext
-    
+
     private new() {
         if (INSTANCE !== null) {
             throw new IllegalStateException("Already instantiated");
         }
     }
-    
+
     static def getInstance() {
         return INSTANCE
     }
@@ -61,141 +62,148 @@ class RestconfImpl implements RestconfService {
     override createConfigurationData(String identifier, CompositeNode payload) {
         val identifierWithSchemaNode = identifier.resolveInstanceIdentifier
         val value = normalizeNode(payload, identifierWithSchemaNode.schemaNode)
-        val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
+        val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier, value).get();
         switch status.result {
-            case TransactionStatus.COMMITED: Response.status(Response.Status.OK).build
-            default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build
+            case TransactionStatus.COMMITED: Response.status(NO_CONTENT).build
+            default: Response.status(INTERNAL_SERVER_ERROR).build
         }
     }
 
     override updateConfigurationData(String identifier, CompositeNode payload) {
         val identifierWithSchemaNode = identifier.resolveInstanceIdentifier
         val value = normalizeNode(payload, identifierWithSchemaNode.schemaNode)
-        val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
+        val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier, value).get();
         switch status.result {
-            case TransactionStatus.COMMITED: Response.status(Response.Status.NO_CONTENT).build
-            default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build
+            case TransactionStatus.COMMITED: Response.status(OK).build
+            default: Response.status(INTERNAL_SERVER_ERROR).build
         }
     }
 
     override invokeRpc(String identifier, CompositeNode payload) {
         val rpc = identifier.rpcDefinition
         if (rpc === null) {
-            throw new ResponseException(Response.Status.NOT_FOUND, "RPC does not exist.");
+            throw new ResponseException(NOT_FOUND, "RPC does not exist.");
         }
         val value = normalizeNode(payload, rpc.input)
         val List<Node<?>> input = new ArrayList
         input.add(value)
         val rpcRequest = NodeFactory.createMutableCompositeNode(rpc.QName, null, input, null, null)
         val rpcResult = broker.invokeRpc(rpc.QName, rpcRequest);
-        return new StructuredData(rpcResult.result, rpc.output);
+        if (!rpcResult.successful) {
+            throw new ResponseException(INTERNAL_SERVER_ERROR, "Operation failed")
+        }
+        if (rpcResult.result === null) {
+            return null
+        }
+        return new StructuredData(rpcResult.result, rpc.output)
     }
-    
+
     override readConfigurationData(String identifier) {
         val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier
         val data = broker.readConfigurationData(instanceIdentifierWithSchemaNode.getInstanceIdentifier);
         return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode)
     }
-    
+
     override readOperationalData(String identifier) {
         val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier
         val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier);
         return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode)
     }
-    
+
     override updateConfigurationDataLegacy(String identifier, CompositeNode payload) {
-        updateConfigurationData(identifier,payload);
+        updateConfigurationData(identifier, payload);
     }
-    
+
     override createConfigurationDataLegacy(String identifier, CompositeNode payload) {
-        createConfigurationData(identifier,payload);
+        createConfigurationData(identifier, payload);
     }
-    
+
     private def InstanceIdWithSchemaNode resolveInstanceIdentifier(String identifier) {
         val identifierWithSchemaNode = identifier.toInstanceIdentifier
         if (identifierWithSchemaNode === null) {
-            throw new ResponseException(Response.Status.BAD_REQUEST, "URI has bad format");
+            throw new ResponseException(BAD_REQUEST, "URI has bad format");
         }
         return identifierWithSchemaNode
     }
-    
+
     private def CompositeNode normalizeNode(CompositeNode node, DataSchemaNode schema) {
         if (node instanceof CompositeNodeWrapper) {
-            normalizeNode(node as CompositeNodeWrapper, schema,null)
+            normalizeNode(node as CompositeNodeWrapper, schema, null)
             return (node as CompositeNodeWrapper).unwrap()
         }
         return node
     }
 
-    private def void normalizeNode(NodeWrapper<?> nodeBuilder, DataSchemaNode schema,QName previousAugment) {
+    private def void normalizeNode(NodeWrapper<?> nodeBuilder, DataSchemaNode schema, QName previousAugment) {
         if (schema === null) {
-            throw new ResponseException(Response.Status.BAD_REQUEST,
+            throw new ResponseException(BAD_REQUEST,
                 "Data has bad format\n" + nodeBuilder.localName + " does not exist in yang schema.");
         }
         var validQName = schema.QName
         var currentAugment = previousAugment;
-        if(schema.augmenting) {
+        if (schema.augmenting) {
             currentAugment = schema.QName
-        } else if(previousAugment !== null && schema.QName.namespace !== previousAugment.namespace) {
-            validQName = QName.create(currentAugment,schema.QName.localName);
+        } else if (previousAugment !== null && schema.QName.namespace !== previousAugment.namespace) {
+            validQName = QName.create(currentAugment, schema.QName.localName);
         }
         val moduleName = controllerContext.findModuleByNamespace(validQName.namespace);
         if (nodeBuilder.namespace === null || nodeBuilder.namespace == validQName.namespace ||
             nodeBuilder.namespace.path == moduleName) {
             nodeBuilder.qname = validQName
         } else {
-            throw new ResponseException(Response.Status.BAD_REQUEST,
+            throw new ResponseException(BAD_REQUEST,
                 "Data has bad format\nIf data is in XML format then namespace for " + nodeBuilder.localName +
                     " should be " + schema.QName.namespace + ".\n If data is in Json format then module name for " +
                     nodeBuilder.localName + " should be " + moduleName + ".");
         }
-        
+
         if (nodeBuilder instanceof CompositeNodeWrapper) {
             val List<NodeWrapper<?>> children = (nodeBuilder as CompositeNodeWrapper).getValues
             for (child : children) {
                 normalizeNode(child,
-                    findFirstSchemaByLocalName(child.localName, (schema as DataNodeContainer).childNodes),currentAugment)
+                    findFirstSchemaByLocalName(child.localName, (schema as DataNodeContainer).childNodes),
+                    currentAugment)
             }
         } else if (nodeBuilder instanceof SimpleNodeWrapper) {
             val simpleNode = (nodeBuilder as SimpleNodeWrapper)
             val stringValue = simpleNode.value as String;
-            
+
             val objectValue = TypeDefinitionAwareCodec.from(schema.typeDefinition)?.deserialize(stringValue);
             simpleNode.setValue(objectValue)
         } else if (nodeBuilder instanceof EmptyNodeWrapper) {
             val emptyNodeBuilder = nodeBuilder as EmptyNodeWrapper
-            if(schema instanceof LeafSchemaNode) {
+            if (schema instanceof LeafSchemaNode) {
                 emptyNodeBuilder.setComposite(false);
-            } else if(schema instanceof ContainerSchemaNode) {
+            } else if (schema instanceof ContainerSchemaNode) {
+
                 // FIXME: Add presence check
                 emptyNodeBuilder.setComposite(true);
             }
         }
     }
-    
+
     private def dispatch TypeDefinition<?> typeDefinition(LeafSchemaNode node) {
         node.type
     }
-    
+
     private def dispatch TypeDefinition<?> typeDefinition(LeafListSchemaNode node) {
         node.type
     }
-    
-    
+
     private def DataSchemaNode findFirstSchemaByLocalName(String localName, Set<DataSchemaNode> schemas) {
         for (schema : schemas) {
             if (schema instanceof ChoiceNode) {
                 for (caze : (schema as ChoiceNode).cases) {
-                    val result =  findFirstSchemaByLocalName(localName, caze.childNodes)
+                    val result = findFirstSchemaByLocalName(localName, caze.childNodes)
                     if (result !== null) {
                         return result
                     }
                 }
             } else {
                 val result = schemas.findFirst[n|n.QName.localName.equals(localName)]
-                if(result !== null) {
+                if (result !== null) {
                     return result;
-                
+
                 }
             }
         }
index 103c9ed3cdbe04f3f192180da77d6fd8fc14945e..d58b7e9dab0cecac48f4d5641dd2b6ff9bc8ba3a 100644 (file)
@@ -27,7 +27,7 @@ public class InvokeRpcMethodTest {
         @Override
         public RpcResult<CompositeNode> answer(InvocationOnMock invocation) throws Throwable {
             CompositeNode compNode = (CompositeNode) invocation.getArguments()[1];
-            return new DummyRpcResult.Builder<CompositeNode>().result(compNode).build();
+            return new DummyRpcResult.Builder<CompositeNode>().result(compNode).isSuccessful(true).build();
         }
     }
 
index 5b0eea32126e5f85dc5c95d2c7b0ef52624c9a9d..ec7dba67b9a35392845e93588862411f45362b49 100644 (file)
@@ -133,21 +133,21 @@ public class XmlProvidersTest extends JerseyTest {
 
         String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0");
         Response response = target(uri).request(MEDIA_TYPE_DRAFT02).put(entity);
-        assertEquals(204, response.getStatus());
-        response = target(uri).request(MEDIA_TYPE_DRAFT02).post(entity);
         assertEquals(200, response.getStatus());
+        response = target(uri).request(MEDIA_TYPE_DRAFT02).post(entity);
+        assertEquals(204, response.getStatus());
 
         uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0");
         response = target(uri).request(MEDIA_TYPE_DRAFT02).put(entity);
-        assertEquals(204, response.getStatus());
-        response = target(uri).request(MEDIA_TYPE_DRAFT02).post(entity);
         assertEquals(200, response.getStatus());
+        response = target(uri).request(MEDIA_TYPE_DRAFT02).post(entity);
+        assertEquals(204, response.getStatus());
 
         uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0");
         response = target(uri).request(MEDIA_TYPE).put(entity);
-        assertEquals(204, response.getStatus());
-        response = target(uri).request(MEDIA_TYPE).post(entity);
         assertEquals(200, response.getStatus());
+        response = target(uri).request(MEDIA_TYPE).post(entity);
+        assertEquals(204, response.getStatus());
     }
 
     @Test
diff --git a/opendaylight/md-sal/sal-zeromq-connector/pom.xml b/opendaylight/md-sal/sal-zeromq-connector/pom.xml
deleted file mode 100644 (file)
index 7859908..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <parent>
-    <groupId>org.opendaylight.controller</groupId>
-    <artifactId>sal-parent</artifactId>
-    <version>1.0-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>sal-zeromq-connector</artifactId>
-  <packaging>bundle</packaging>
-
-  <properties>
-    <scala.version>2.10.3</scala.version>
-  </properties>
-
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Import-Package>
-              org.opendaylight.controller.sal.connector.api,
-              org.opendaylight.controller.sal.core.api,
-              org.opendaylight.yangtools.concepts;version="[0.1,1)",
-              org.opendaylight.yangtools.yang.common;version="[0.5,1)",
-              org.opendaylight.yangtools.yang.data.api;version="[0.5,1)",
-              org.zeromq;version="[0.3,1)"
-            </Import-Package>
-            <Bundle-Activator>org.opendaylight.controller.sal.connector.remoterpc.router.zeromq.Activator</Bundle-Activator>
-          </instructions>
-        </configuration>
-      </plugin>
-
-      <plugin>
-        <groupId>net.alchim31.maven</groupId>
-        <artifactId>scala-maven-plugin</artifactId>
-        <version>3.1.6</version>
-        <configuration>
-          <recompileMode>incremental</recompileMode>
-          <args>
-            <arg>-target:jvm-1.7</arg>
-          </args>
-          <javacArgs>
-            <javacArg>-source</javacArg><javacArg>1.7</javacArg>
-            <javacArg>-target</javacArg><javacArg>1.7</javacArg>
-          </javacArgs>
-        </configuration>
-        <executions>
-          <execution>
-            <id>scala-compile</id>
-            <goals>
-              <goal>compile</goal>
-            </goals>
-          </execution>
-          <execution>
-            <id>scala-test-compile</id>
-            <goals>
-              <goal>testCompile</goal>
-            </goals>
-          </execution>
-        </executions>
-
-      </plugin>
-      <plugin>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>default-compile</id>
-            <phase>none</phase>
-          </execution>
-          <execution>
-            <id>default-testCompile</id>
-            <phase>none</phase>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-
-  <dependencies>
-    <dependency>
-      <groupId>org.scala-lang</groupId>
-      <artifactId>scala-library</artifactId>
-      <version>${scala.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>containermanager</artifactId>
-      <version>0.5.1-SNAPSHOT</version>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>commons.northbound</artifactId>
-      <version>0.4.1-SNAPSHOT</version>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>sal</artifactId>
-      <version>0.5.1-SNAPSHOT</version>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
-      <artifactId>yang-binding</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
-      <artifactId>yang-common</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>sal-connector-api</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>sal-common-util</artifactId>
-      <version>1.0-SNAPSHOT</version>
-    </dependency>
-
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.jeromq</groupId>
-      <artifactId>jeromq</artifactId>
-      <version>0.3.0-SNAPSHOT</version>
-    </dependency>
-
-  </dependencies>
-  <repositories>
-    <repository>
-      <id>sonatype-nexus-snapshots</id>
-      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
-      <releases>
-        <enabled>false</enabled>
-      </releases>
-      <snapshots>
-        <enabled>true</enabled>
-      </snapshots>
-    </repository>
-  </repositories>
-
-</project>
diff --git a/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChange.java b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChange.java
deleted file mode 100644 (file)
index ba90f37..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.connector.remoterpc.api;
-
-import java.util.Map;
-import java.util.Set;
-
-public interface RouteChange<I, R> {
-
-  Map<I, Set<R>> getRemovals();
-  Map<I, Set<R>> getAnnouncements();
-}
diff --git a/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/router/zeromq/Activator.java b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/router/zeromq/Activator.java
deleted file mode 100644 (file)
index 5b927a5..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.connector.remoterpc.router.zeromq;
-
-import org.opendaylight.controller.sal.core.api.AbstractProvider;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-import org.osgi.framework.BundleContext;
-
-public class Activator extends AbstractProvider {
-
-  ZeroMqRpcRouter router;
-
-  @Override
-  public void onSessionInitiated(ProviderSession session) {
-    router = ZeroMqRpcRouter.getInstance();
-    router.setBrokerSession(session);
-    router.start();
-  }
-
-  @Override
-  protected void stopImpl(BundleContext context) {
-    router.stop();
-  }
-
-}
diff --git a/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/router/zeromq/ZeroMqRpcRouter.java b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/router/zeromq/ZeroMqRpcRouter.java
deleted file mode 100644 (file)
index af94804..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.connector.remoterpc.router.zeromq;
-
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
-import org.opendaylight.controller.sal.connector.api.RpcRouter;
-import org.opendaylight.controller.sal.connector.remoterpc.router.zeromq.Message.MessageType;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcError;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.zeromq.ZMQ;
-
-/**
- * ZeroMq based implementation of RpcRouter
- * TODO:
- *    1. Make it multi VM aware
- *    2. Make rpc request handling async and non-blocking. Note zmq socket is not thread safe
- *    3. sendRpc() should use connection pooling
- *    4. Read properties from config file using existing(?) ODL properties framework
- */
-public class ZeroMqRpcRouter implements RpcRouter<QName, QName, InstanceIdentifier, Object> {
-
-  private ExecutorService serverPool;
-  private static ExecutorService handlersPool;
-
-  private Map<RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>, String> routingTable;
-
-  private ProviderSession brokerSession;
-
-  private ZMQ.Context context;
-  private ZMQ.Socket publisher;
-  private ZMQ.Socket subscriber;
-  private ZMQ.Socket replySocket;
-
-  private static ZeroMqRpcRouter _instance = new ZeroMqRpcRouter();
-
-  private final RpcFacade facade = new RpcFacade();
-  private final RpcListener listener = new RpcListener();
-
-  private final String localIp = getLocalIpAddress();
-
-  private String pubPort = System.getProperty("pub.port");// port on which announcements are sent
-  private String subPort = System.getProperty("sub.port");// other controller's pub port
-  private String pubIp = System.getProperty("pub.ip"); // other controller's ip
-  private String rpcPort = System.getProperty("rpc.port");// port on which RPC messages are received
-
-  private Logger _logger = LoggerFactory.getLogger(ZeroMqRpcRouter.class);
-
-  //Prevent instantiation
-  private ZeroMqRpcRouter() {
-  }
-
-  public static ZeroMqRpcRouter getInstance() {
-    return _instance;
-  }
-
-  public void start() {
-    context = ZMQ.context(2);
-    publisher = context.socket(ZMQ.PUB);
-    int ret = publisher.bind("tcp://*:" + pubPort);
-    // serverPool = Executors.newSingleThreadExecutor();
-    serverPool = Executors.newCachedThreadPool();
-    handlersPool = Executors.newCachedThreadPool();
-    routingTable = new ConcurrentHashMap<RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>, String>();
-
-    // Start listening for announce and rpc messages
-    serverPool.execute(receive());
-
-    brokerSession.addRpcRegistrationListener(listener);
-
-    Set<QName> currentlySupported = brokerSession.getSupportedRpcs();
-    for (QName rpc : currentlySupported) {
-      listener.onRpcImplementationAdded(rpc);
-    }
-
-  }
-
-  public void stop() {
-    if (handlersPool != null)
-      handlersPool.shutdown();
-    if (serverPool != null)
-      serverPool.shutdown();
-    if (publisher != null) {
-      publisher.setLinger(0);
-      publisher.close();
-    }
-    if (replySocket != null) {
-      replySocket.setLinger(0);
-      replySocket.close();
-    }
-    if (subscriber != null) {
-      subscriber.setLinger(0);
-      subscriber.close();
-    }
-    if (context != null)
-      context.term();
-
-  }
-
-  private Runnable receive() {
-    return new Runnable() {
-      public void run() {
-        try {
-          // Bind to RPC reply socket
-          replySocket = context.socket(ZMQ.REP);
-          replySocket.bind("tcp://*:" + rpcPort);
-
-          // Bind to publishing controller
-          subscriber = context.socket(ZMQ.SUB);
-          String pubAddress = "tcp://" + pubIp + ":" + subPort;
-          subscriber.connect(pubAddress);
-          _logger.debug("{} Subscribing at[{}]", Thread.currentThread().getName(), pubAddress);
-
-          //subscribe for announcements
-          //TODO: Message type would be changed. Update this
-          subscriber.subscribe(Message.serialize(Message.MessageType.ANNOUNCE));
-
-          // Poller enables listening on multiple sockets using a single thread
-          ZMQ.Poller poller = new ZMQ.Poller(2);
-          poller.register(replySocket, ZMQ.Poller.POLLIN);
-          poller.register(subscriber, ZMQ.Poller.POLLIN);
-
-          //TODO: Add code to restart the thread after exception
-          while (!Thread.currentThread().isInterrupted()) {
-
-            poller.poll();
-
-            if (poller.pollin(0)) {
-              handleRpcCall();
-            }
-            if (poller.pollin(1)) {
-              handleAnnouncement();
-            }
-          }
-        } catch (Exception e) {
-          e.printStackTrace();
-        }
-        replySocket.setLinger(0);
-        replySocket.close();
-        subscriber.setLinger(0);
-        subscriber.close();
-      }
-    };
-  }
-
-  /**
-   * @throws IOException
-   * @throws ClassNotFoundException
-   */
-  private void handleAnnouncement() throws IOException, ClassNotFoundException {
-
-    _logger.info("Announcement received");
-    Message.MessageType topic = (MessageType) Message.deserialize(subscriber.recv());
-
-    if (subscriber.hasReceiveMore()) {
-      try {
-        Message m = (Message) Message.deserialize(subscriber.recv());
-        _logger.debug("Announcement message [{}]", m);
-
-        // TODO: check on msg type or topic. Both
-        // should be same. Need to normalize.
-        if (Message.MessageType.ANNOUNCE == m.getType())
-          updateRoutingTable(m);
-      } catch (IOException | ClassNotFoundException e) {
-        e.printStackTrace();
-      }
-    }
-
-  }
-
-  /**
-   * @throws InterruptedException
-   * @throws ExecutionException
-   */
-  private void handleRpcCall() throws InterruptedException, ExecutionException {
-    try {
-      Message request = parseMessage(replySocket);
-
-      _logger.debug("Received rpc request [{}]", request);
-
-      // Call broker to process the message then reply
-      Future<RpcResult<CompositeNode>> rpc = brokerSession.rpc(
-          (QName) request.getRoute().getType(), (CompositeNode) request.getPayload());
-
-      RpcResult<CompositeNode> result = rpc.get();
-
-      Message response = new Message.MessageBuilder()
-          .type(MessageType.RESPONSE)
-          .sender(localIp + ":" + rpcPort)
-          .route(request.getRoute())
-          //.payload(result)    TODO: enable and test
-          .build();
-
-      replySocket.send(Message.serialize(response));
-
-      _logger.debug("Sent rpc response [{}]", response);
-
-    } catch (IOException ex) {
-      //TODO: handle exception and send error codes to caller
-      ex.printStackTrace();
-    }
-  }
-
-
-  @Override
-  public Future<RpcReply<Object>> sendRpc(
-      final RpcRequest<QName, QName, InstanceIdentifier, Object> input) {
-
-    return handlersPool.submit(new Callable<RpcReply<Object>>() {
-
-      @Override
-      public RpcReply<Object> call() {
-        ZMQ.Socket requestSocket = context.socket(ZMQ.REQ);
-
-        // TODO pick the ip and port from routing table based on routing identifier
-        requestSocket.connect("tcp://" + pubIp + ":5554");
-
-        Message requestMessage = new Message.MessageBuilder()
-            .type(MessageType.REQUEST)
-            .sender(localIp + ":" + rpcPort)
-            .route(input.getRoutingInformation())
-            .payload(input.getPayload())
-            .build();
-
-        _logger.debug("Sending rpc request [{}]", requestMessage);
-
-        RpcReply<Object> reply = null;
-
-        try {
-
-          requestSocket.send(Message.serialize(requestMessage));
-          final Message response = parseMessage(requestSocket);
-
-          _logger.debug("Received response [{}]", response);
-
-          reply = new RpcReply<Object>() {
-
-            @Override
-            public Object getPayload() {
-              return response.getPayload();
-            }
-          };
-        } catch (IOException ex) {
-          // TODO: Pass exception back to the caller
-          ex.printStackTrace();
-        }
-
-        return reply;
-      }
-    });
-  }
-
-  /**
-   * TODO: Remove this implementation and use RoutingTable implementation to send announcements
-   * Publishes a notice to other controllers in the cluster
-   *
-   * @param notice
-   */
-  public void publish(final Message notice) {
-    Runnable task = new Runnable() {
-      public void run() {
-
-        try {
-
-          publisher.sendMore(Message.serialize(Message.MessageType.ANNOUNCE));
-          publisher.send(Message.serialize(notice));
-          _logger.debug("Announcement sent [{}]", notice);
-        } catch (IOException ex) {
-          _logger.error("Error in sending announcement [{}]", notice);
-          ex.printStackTrace();
-        }
-      }
-    };
-    handlersPool.execute(task);
-  }
-
-  /**
-   * Finds IPv4 address of the local VM
-   * TODO: This method is non-deterministic. There may be more than one IPv4 address. Cant say which
-   * address will be returned. Read IP from a property file or enhance the code to make it deterministic.
-   * Should we use IP or hostname?
-   *
-   * @return
-   */
-  private String getLocalIpAddress() {
-    String hostAddress = null;
-    Enumeration e = null;
-    try {
-      e = NetworkInterface.getNetworkInterfaces();
-    } catch (SocketException e1) {
-      e1.printStackTrace();
-    }
-    while (e.hasMoreElements()) {
-
-      NetworkInterface n = (NetworkInterface) e.nextElement();
-
-      Enumeration ee = n.getInetAddresses();
-      while (ee.hasMoreElements()) {
-        InetAddress i = (InetAddress) ee.nextElement();
-        if ((i instanceof Inet4Address) && (i.isSiteLocalAddress()))
-          hostAddress = i.getHostAddress();
-      }
-    }
-    return hostAddress;
-
-  }
-
-  /**
-   * TODO: Change to use external routing table implementation
-   *
-   * @param msg
-   */
-  private void updateRoutingTable(Message msg) {
-    routingTable.put(msg.getRoute(), msg.getSender());
-    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> route = msg.getRoute();
-
-    // Currently only registers rpc implementation.
-    // TODO: do registration for instance based routing
-    QName rpcType = route.getType();
-    RpcRegistration registration = brokerSession.addRpcImplementation(rpcType, facade);
-    _logger.debug("Routing table updated");
-  }
-
-  /**
-   * @param socket
-   * @return
-   */
-  private Message parseMessage(ZMQ.Socket socket) {
-
-    Message msg = null;
-    try {
-      byte[] bytes = socket.recv();
-      _logger.debug("Received bytes:[{}]", bytes.length);
-      msg = (Message) Message.deserialize(bytes);
-    } catch (Throwable t) {
-      t.printStackTrace();
-    }
-    return msg;
-  }
-
-  private class RpcFacade implements RpcImplementation {
-
-    @Override
-    public Set<QName> getSupportedRpcs() {
-      return Collections.emptySet();
-    }
-
-    @Override
-    public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
-
-      RouteIdentifierImpl routeId = new RouteIdentifierImpl();
-      routeId.setType(rpc);
-
-      RpcRequestImpl request = new RpcRequestImpl();
-      request.setRouteIdentifier(routeId);
-      request.setPayload(input);
-
-      final Future<RpcReply<Object>> ret = sendRpc(request);
-
-      //TODO: Review result handling
-      RpcResult<CompositeNode> result = new RpcResult<CompositeNode>() {
-        @Override
-        public boolean isSuccessful() {
-          try {
-            ret.get();
-          } catch (InterruptedException | ExecutionException e) {
-            e.printStackTrace();
-            return false;
-          }
-          return true;
-        }
-
-        @Override
-        public CompositeNode getResult() {
-          return null;
-        }
-
-        @Override
-        public Collection<RpcError> getErrors() {
-          return Collections.EMPTY_LIST;
-        }
-      };
-      return result;
-    }
-  }
-
-  /**
-   * Listener for rpc registrations
-   */
-  private class RpcListener implements RpcRegistrationListener {
-
-    @Override
-    public void onRpcImplementationAdded(QName name) {
-
-      _logger.debug("Announcing registration for [{}]", name);
-      RouteIdentifierImpl routeId = new RouteIdentifierImpl();
-      routeId.setType(name);
-
-      //TODO: Make notice immutable and change message type
-      Message notice = new Message.MessageBuilder()
-          .type(MessageType.ANNOUNCE)
-          .sender("tcp://" + localIp + ":" + rpcPort)
-          .route(routeId)
-          .build();
-
-      publish(notice);
-    }
-
-    @Override
-    public void onRpcImplementationRemoved(QName name) {
-      // TODO: send a rpc-deregistrtation notice
-
-    }
-  }
-
-  public void setBrokerSession(ProviderSession session) {
-    this.brokerSession = session;
-
-  }
-
-}
diff --git a/opendaylight/md-sal/test/pom.xml b/opendaylight/md-sal/test/pom.xml
deleted file mode 100644 (file)
index f9e500e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-       <modelVersion>4.0.0</modelVersion>
-       <parent>
-               <artifactId>sal-parent</artifactId>
-               <version>1.0-SNAPSHOT</version>
-               <groupId>org.opendaylight.controller</groupId>
-       </parent>
-       <packaging>pom</packaging>
-       <groupId>org.opendaylight.controller.tests</groupId>
-       <artifactId>sal-test-parent</artifactId>
-    <scm>
-      <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
-      <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
-      <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
-    </scm>
-
-       <modules>
-               <module>zeromq-test-consumer</module>
-        <module>zeromq-test-it</module>
-        <module>zeromq-test-provider</module>
-       </modules>
-       
-</project>
diff --git a/opendaylight/md-sal/test/zeromq-test-consumer/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java b/opendaylight/md-sal/test/zeromq-test-consumer/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java
deleted file mode 100644 (file)
index a56a7de..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.opendaylight.controller.sample.zeromq.consumer;
-
-import java.net.URI;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import org.opendaylight.controller.sal.core.api.AbstractConsumer;
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.osgi.framework.BundleContext;
-
-public class ExampleConsumer extends AbstractConsumer {
-
-    private final URI namespace = URI.create("http://cisco.com/example");
-    private final QName QNAME = new QName(namespace,"heartbeat");
-    
-    ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
-    private ConsumerSession session;
-    
-    
-    @Override
-    public void onSessionInitiated(ConsumerSession session) {
-        this.session = session;
-        executor.scheduleAtFixedRate(new Runnable() {
-            
-            @Override
-            public void run() {
-                int count = 0;
-                try {
-                    Future<RpcResult<CompositeNode>> future = ExampleConsumer.this.session.rpc(QNAME, null);
-                    RpcResult<CompositeNode> result = future.get();
-                    System.out.println("Result received. Status is :" + result.isSuccessful());
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-                
-            }
-        }, 0, 10, TimeUnit.SECONDS);
-    }
-    
-    @Override
-    protected void stopImpl(BundleContext context) {
-        // TODO Auto-generated method stub
-        super.stopImpl(context);
-        executor.shutdown();
-    }
-}
diff --git a/opendaylight/md-sal/test/zeromq-test-it/pom.xml b/opendaylight/md-sal/test/zeromq-test-it/pom.xml
deleted file mode 100644 (file)
index 56945d1..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <artifactId>sal-test-parent</artifactId>
-        <groupId>org.opendaylight.controller.tests</groupId>
-        <version>1.0-SNAPSHOT</version>
-    </parent>
-    <artifactId>zeromq-test-it</artifactId>
-    <scm>
-        <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
-        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
-        <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
-    </scm>
-
-    <properties>
-        <exam.version>3.0.0</exam.version>
-        <url.version>1.5.0</url.version>
-    </properties>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.ops4j.pax.exam</groupId>
-                <artifactId>maven-paxexam-plugin</artifactId>
-                <version>1.2.4</version>
-                <executions>
-                    <execution>
-                        <id>generate-config</id>
-                        <goals>
-                            <goal>generate-depends-file</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-        <pluginManagement>
-            <plugins>
-                <!--This plugin's configuration is used to store Eclipse m2e settings 
-                    only. It has no influence on the Maven build itself. -->
-                <plugin>
-                    <groupId>org.eclipse.m2e</groupId>
-                    <artifactId>lifecycle-mapping</artifactId>
-                    <version>1.0.0</version>
-                    <configuration>
-                        <lifecycleMappingMetadata>
-                            <pluginExecutions>
-                                <pluginExecution>
-                                    <pluginExecutionFilter>
-                                        <groupId>
-                                            org.ops4j.pax.exam
-                                        </groupId>
-                                        <artifactId>
-                                            maven-paxexam-plugin
-                                        </artifactId>
-                                        <versionRange>
-                                            [1.2.4,)
-                                        </versionRange>
-                                        <goals>
-                                            <goal>
-                                                generate-depends-file
-                                            </goal>
-                                        </goals>
-                                    </pluginExecutionFilter>
-                                    <action>
-                                        <ignore></ignore>
-                                    </action>
-                                </pluginExecution>
-                            </pluginExecutions>
-                        </lifecycleMappingMetadata>
-                    </configuration>
-                </plugin>
-            </plugins>
-        </pluginManagement>
-    </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.opendaylight.yangtools.thirdparty</groupId>
-            <artifactId>xtend-lib-osgi</artifactId>
-            <version>2.4.3</version>
-        </dependency>
-        <dependency>
-            <groupId>org.opendaylight.controller.tests</groupId>
-            <artifactId>zeromq-test-provider</artifactId>
-            <version>1.0-SNAPSHOT</version>
-        </dependency>
-        <dependency>
-            <groupId>org.opendaylight.controller.tests</groupId>
-            <artifactId>zeromq-test-consumer</artifactId>
-            <version>1.0-SNAPSHOT</version>
-        </dependency>
-        <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal-broker-impl</artifactId>
-            <version>1.0-SNAPSHOT</version>
-        </dependency>
-        <dependency>
-            <groupId>org.ops4j.pax.exam</groupId>
-            <artifactId>pax-exam-container-native</artifactId>
-            <version>${exam.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.ops4j.pax.exam</groupId>
-            <artifactId>pax-exam-junit4</artifactId>
-            <version>${exam.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.ops4j.pax.exam</groupId>
-            <artifactId>pax-exam-link-mvn</artifactId>
-            <version>${exam.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>equinoxSDK381</groupId>
-            <artifactId>org.eclipse.osgi</artifactId>
-            <version>3.8.1.v20120830-144521</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>log4j-over-slf4j</artifactId>
-            <version>1.7.2</version>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-core</artifactId>
-            <version>1.0.9</version>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-classic</artifactId>
-            <version>1.0.9</version>
-        </dependency>
-      <dependency>
-        <groupId>org.opendaylight.controller</groupId>
-        <artifactId>sal-binding-api</artifactId>
-        <version>1.0-SNAPSHOT</version>
-      </dependency>
-      <dependency>
-        <groupId>org.opendaylight.controller</groupId>
-        <artifactId>sal-common-util</artifactId>
-        <version>1.0-SNAPSHOT</version>
-      </dependency>
-      <dependency>
-        <groupId>org.opendaylight.controller</groupId>
-        <artifactId>sal-core-api</artifactId>
-        <version>1.0-SNAPSHOT</version>
-      </dependency>
-
-
-      <dependency>
-        <groupId>org.opendaylight.controller</groupId>
-        <artifactId>containermanager</artifactId>
-        <version>0.5.1-SNAPSHOT</version>
-      </dependency>
-
-      <dependency>
-        <groupId>org.opendaylight.controller</groupId>
-        <artifactId>sal</artifactId>
-        <version>0.5.1-SNAPSHOT</version>
-      </dependency>
-      <dependency>
-        <groupId>org.opendaylight.yangtools</groupId>
-        <artifactId>yang-binding</artifactId>
-      </dependency>
-      <dependency>
-        <groupId>org.opendaylight.yangtools</groupId>
-        <artifactId>yang-common</artifactId>
-      </dependency>
-      <dependency>
-        <groupId>org.opendaylight.yangtools</groupId>
-        <artifactId>yang-data-api</artifactId>
-      </dependency>
-
-      <dependency>
-        <groupId>org.opendaylight.controller</groupId>
-        <artifactId>sal-common-util</artifactId>
-        <version>1.0-SNAPSHOT</version>
-      </dependency>
-    </dependencies>
-</project>
diff --git a/opendaylight/md-sal/test/zeromq-test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/ServiceConsumerController.java b/opendaylight/md-sal/test/zeromq-test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/ServiceConsumerController.java
deleted file mode 100644 (file)
index c17b143..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.opendaylight.controller.sample.zeromq.test.it;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.osgi.framework.BundleContext;
-
-import javax.inject.Inject;
-
-import static org.junit.Assert.assertTrue;
-import static org.ops4j.pax.exam.CoreOptions.*;
-
-@RunWith(PaxExam.class)
-public class ServiceConsumerController {
-
-    public static final String ODL = "org.opendaylight.controller";
-    public static final String YANG = "org.opendaylight.yangtools";
-    public static final String SAMPLE = "org.opendaylight.controller.samples";
-
-    @Test
-    public void properInitialized() throws Exception {
-
-        Thread.sleep(30000); // Waiting for services to get wired.
-        assertTrue(true);
-        //assertTrue(consumer.createToast(WhiteBread.class, 5));
-
-    }
-
-//    @Inject
-//    BindingAwareBroker broker;
-
-//    @Inject
-//    ToastConsumer consumer;
-
-    @Inject
-    BundleContext ctx;
-
-    @Configuration
-    public Option[] config() {
-        return options(systemProperty("osgi.console").value("2401"),
-                systemProperty("pub.port").value("5557"),
-                systemProperty("sub.port").value("5556"),
-                systemProperty("rpc.port").value("5555"),
-                systemProperty("pub.ip").value("localhost"),
-                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), //
-                mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
-                mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
-                mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
-               
-                //mavenBundle(ODL, "sal-binding-broker-impl").versionAsInProject().update(), //
-                mavenBundle(ODL, "sal-common").versionAsInProject(), //
-                mavenBundle(ODL, "sal-common-api").versionAsInProject(),//
-                mavenBundle(ODL, "sal-common-impl").versionAsInProject(), //
-                mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
-                mavenBundle(ODL, "sal-core-api").versionAsInProject().update(), //
-                mavenBundle(ODL, "sal-broker-impl").versionAsInProject(), //
-                mavenBundle(ODL, "sal-core-spi").versionAsInProject().update(), //
-                mavenBundle(ODL, "sal-connector-api").versionAsInProject(), //
-                mavenBundle(SAMPLE, "zeromq-test-consumer").versionAsInProject(), //
-                mavenBundle(ODL, "sal-zeromq-connector").versionAsInProject(), //
-                mavenBundle(YANG, "concepts").versionAsInProject(),
-                mavenBundle(YANG, "yang-binding").versionAsInProject(), //
-                mavenBundle(YANG, "yang-common").versionAsInProject(), //
-                mavenBundle(YANG, "yang-data-api").versionAsInProject(), //
-                mavenBundle(YANG, "yang-model-api").versionAsInProject(), //
-                mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(), //
-                mavenBundle("com.google.guava", "guava").versionAsInProject(), //
-                mavenBundle("org.jeromq", "jeromq").versionAsInProject(),
-                junitBundles()
-                );
-    }
-
-}
diff --git a/opendaylight/md-sal/test/zeromq-test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/ServiceProviderController.java b/opendaylight/md-sal/test/zeromq-test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/ServiceProviderController.java
deleted file mode 100644 (file)
index 2d28b0b..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.opendaylight.controller.sample.zeromq.test.it;
-
-import static org.junit.Assert.*;
-import static org.ops4j.pax.exam.CoreOptions.junitBundles;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemPackages;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-import static org.ops4j.pax.exam.CoreOptions.maven;
-
-import java.util.Collection;
-
-import javax.inject.Inject;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.CoreOptions;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-
-@RunWith(PaxExam.class)
-public class ServiceProviderController {
-
-    public static final String ODL = "org.opendaylight.controller";
-    public static final String YANG = "org.opendaylight.yangtools";
-    public static final String SAMPLE = "org.opendaylight.controller.samples";
-
-    @Test
-    public void properInitialized() throws Exception {
-
-        Thread.sleep(30000); // Waiting for services to get wired.
-        assertTrue(true);
-        //assertTrue(consumer.createToast(WhiteBread.class, 5));
-
-    }
-
-//    @Inject
-//    BindingAwareBroker broker;
-
-//    @Inject
-//    ToastConsumer consumer;
-
-    @Inject
-    BundleContext ctx;
-
-    @Configuration
-    public Option[] config() {
-        return options(systemProperty("osgi.console").value("2401"),
-                systemProperty("pub.port").value("5556"),
-                systemProperty("sub.port").value("5557"),
-                systemProperty("rpc.port").value("5554"),
-                systemProperty("pub.ip").value("localhost"),
-                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), //
-                mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
-                mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
-                mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
-               
-                //mavenBundle(ODL, "sal-binding-broker-impl").versionAsInProject().update(), //
-                mavenBundle(ODL, "sal-common").versionAsInProject(), //
-                mavenBundle(ODL, "sal-common-api").versionAsInProject(),//
-                mavenBundle(ODL, "sal-common-impl").versionAsInProject(), //
-                mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
-                mavenBundle(ODL, "sal-core-api").versionAsInProject().update(), //
-                mavenBundle(ODL, "sal-broker-impl").versionAsInProject(), //
-                mavenBundle(ODL, "sal-core-spi").versionAsInProject().update(), //
-                mavenBundle(ODL, "sal-connector-api").versionAsInProject(), //
-                mavenBundle(SAMPLE, "zeromq-test-provider").versionAsInProject(), //
-                mavenBundle(ODL, "sal-zeromq-connector").versionAsInProject(), //
-                mavenBundle(YANG, "concepts").versionAsInProject(),
-                mavenBundle(YANG, "yang-binding").versionAsInProject(), //
-                mavenBundle(YANG, "yang-common").versionAsInProject(), //
-                mavenBundle(YANG, "yang-data-api").versionAsInProject(), //
-                mavenBundle(YANG, "yang-model-api").versionAsInProject(), //
-                mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(), //
-                mavenBundle("com.google.guava", "guava").versionAsInProject(), //
-                mavenBundle("org.jeromq", "jeromq").versionAsInProject(),
-                junitBundles()
-                );
-    }
-
-}
diff --git a/opendaylight/md-sal/test/zeromq-test-provider/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java b/opendaylight/md-sal/test/zeromq-test-provider/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java
deleted file mode 100644 (file)
index ec7d7a8..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-package org.opendaylight.controller.sample.zeromq.provider;
-
-import java.net.URI;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-
-import org.opendaylight.controller.sal.common.util.Rpcs;
-import org.opendaylight.controller.sal.core.api.AbstractProvider;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcError;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.osgi.framework.BundleContext;
-
-public class ExampleProvider extends AbstractProvider implements RpcImplementation  {
-
-    private final URI namespace = URI.create("http://cisco.com/example");
-    private final QName QNAME = new QName(namespace,"heartbeat");
-    private RpcRegistration reg;
-    
-    
-    @Override
-    public void onSessionInitiated(ProviderSession session) {
-      //Adding heartbeat 10 times just to make sure subscriber get it
-      for (int i=0;i<10;i++){
-        System.out.println("ExampleProvider: Adding " + QNAME + " " + i);
-        reg = session.addRpcImplementation(QNAME, this);
-        try {
-          Thread.sleep(1000);
-        } catch (InterruptedException e) {
-          e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
-        }
-      }
-    }
-    
-    @Override
-    public Set<QName> getSupportedRpcs() {
-        return Collections.singleton(QNAME);
-    }
-    
-    @Override
-    public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
-        if(QNAME.equals(rpc)) {
-            RpcResult<CompositeNode> output = Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
-            return output;
-        }
-        RpcResult<CompositeNode> output = Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
-        return output;
-    }
-    
-    @Override
-    protected void stopImpl(BundleContext context) {
-     if(reg != null) {
-         try {
-            reg.close();
-        } catch (Exception e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-     }
-    }
-
-}
index 37c973e864958c92f25956d63b52b782c4c7c24d..2926786849f82999903565f3388e49481b4ab637 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.opendaylight.controller</groupId>
                 <extensions>true</extensions>
                 <configuration>
                     <instructions>
-
+                        <Export-Package>
+                            org.opendaylight.controller.sal.connector.remoterpc.api,
+                            org.opendaylight.controller.sal.connector.remoterpc.impl
+                        </Export-Package>
                         <Import-Package>
                             javax.xml.bind.annotation,
                             org.opendaylight.controller.sal.core,
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal</artifactId>
-            <version>0.5.1-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.osgi</groupId>
+                    <artifactId>org.osgi.compendium</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
index d855f1554125764c16170b84c26457bd0976fa04..888f13c8fee1750bdd402b5e104a5798ea5730b1 100644 (file)
                             org.osgi.framework,
                             org.osgi.util.tracker,
                             org.slf4j,
-                            org.w3c.dom
+                            org.w3c.dom,
+                            com.google.common.io,
+                            org.opendaylight.yangtools.yang.model.api.type
                         </Import-Package>
                         <Export-Package>
                         </Export-Package>
index 4b6dcfd46528b3068fe2a7c41dc9b9224f205b9c..697b811d51c90c9b7cab4f05f266292d25d2a260 100644 (file)
@@ -12,7 +12,9 @@ import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIf
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
+import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
 
 import javax.management.openmbean.ArrayType;
 import javax.management.openmbean.CompositeType;
@@ -29,7 +31,10 @@ public abstract class AttributeIfcSwitchStatement<T> {
 
         if (attributeIfc instanceof JavaAttribute) {
             try {
-                return caseJavaAttribute(attributeIfc.getOpenType());
+                if(((JavaAttribute)attributeIfc).getTypeDefinition() instanceof BinaryTypeDefinition) {
+                    return caseJavaBinaryAttribute(attributeIfc.getOpenType());
+                } else
+                    return caseJavaAttribute(attributeIfc.getOpenType());
             } catch (UnknownOpenTypeException e) {
                 throw getIllegalArgumentException(attributeIfc);
             }
@@ -37,7 +42,9 @@ public abstract class AttributeIfcSwitchStatement<T> {
         } else if (attributeIfc instanceof DependencyAttribute) {
             return caseDependencyAttribute(((DependencyAttribute) attributeIfc).getOpenType());
         } else if (attributeIfc instanceof ListAttribute) {
-            return caseListAttribute(((ListAttribute) attributeIfc).getOpenType());
+            return caseListAttribute((ArrayType<?>) attributeIfc.getOpenType());
+        } else if (attributeIfc instanceof ListDependenciesAttribute) {
+            return caseListDependeciesAttribute((ArrayType<?>) attributeIfc.getOpenType());
         } else if (attributeIfc instanceof TOAttribute) {
             return caseTOAttribute(((TOAttribute) attributeIfc).getOpenType());
         }
@@ -45,6 +52,10 @@ public abstract class AttributeIfcSwitchStatement<T> {
         throw getIllegalArgumentException(attributeIfc);
     }
 
+    protected T caseJavaBinaryAttribute(OpenType<?> openType) {
+        return caseJavaAttribute(openType);
+    }
+
     private IllegalArgumentException getIllegalArgumentException(AttributeIfc attributeIfc) {
         return new IllegalArgumentException("Unknown attribute type " + attributeIfc.getClass() + ", " + attributeIfc
                 + " with open type:" + attributeIfc.getOpenType());
@@ -74,6 +85,7 @@ public abstract class AttributeIfcSwitchStatement<T> {
 
     protected abstract T caseListAttribute(ArrayType<?> openType);
 
+    protected abstract T caseListDependeciesAttribute(ArrayType<?> openType);
 
     private static class UnknownOpenTypeException extends RuntimeException {
         public UnknownOpenTypeException(String message) {
index 867d94e0b70f628a1454cde825f44d6c27233528..793911262810f826f332f84c75bb642bb1d7fe6e 100644 (file)
@@ -27,11 +27,14 @@ public abstract class AbstractAttributeReadingStrategy implements AttributeReadi
     @Override
     public AttributeConfigElement readElement(List<XmlElement> configNodes) {
         if (configNodes.size() == 0)
-            return AttributeConfigElement.createNullValue(nullableDefault);
+            return AttributeConfigElement.createNullValue(postprocessNullableDefault(nullableDefault));
 
         return readElementHook(configNodes);
     }
 
     abstract AttributeConfigElement readElementHook(List<XmlElement> configNodes);
 
+    protected Object postprocessNullableDefault(String nullableDefault) {
+        return nullableDefault;
+    }
 }
index 598935a0bc4f15ddcc61039723e313d55c0d9860..a1f46dde54ff078596b709e12e0eeeb8914e7056 100644 (file)
@@ -9,7 +9,6 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
 
 import com.google.common.base.Optional;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.AttributeResolvingStrategy;
 
 import javax.management.openmbean.OpenType;
@@ -47,24 +46,14 @@ public class AttributeConfigElement {
 
     }
 
-    public static AttributeConfigElement create(AttributeIfc attributeIfc, Object value) {
-        String nullableDefault = attributeIfc.getNullableDefault();
-        return create(nullableDefault, value);
-    }
-
-    public static AttributeConfigElement create(String nullableDefault, Object value) {
+    public static AttributeConfigElement create(Object nullableDefault, Object value) {
         return new AttributeConfigElement(nullableDefault, value);
     }
 
-    public static AttributeConfigElement createNullValue(AttributeIfc attributeIfc) {
-        return new AttributeConfigElement(attributeIfc.getNullableDefault(), null);
-    }
-
-    public static AttributeConfigElement createNullValue(String nullableDefault) {
+    public static AttributeConfigElement createNullValue(Object nullableDefault) {
         return new AttributeConfigElement(nullableDefault, null);
     }
 
-
     public Object getValue() {
         return value;
     }
index bc3c74a88f218aa01ad82a97976ee704df8d1f86..a2691f241cfa9a6c273c95c653c2fa9720d03cb9 100644 (file)
@@ -12,11 +12,13 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
 
 import javax.management.openmbean.ArrayType;
 import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
 import javax.management.openmbean.SimpleType;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -40,6 +42,11 @@ public class ObjectXmlReader extends AttributeIfcSwitchStatement<AttributeReadin
         return switchAttribute(attributeIfc);
     }
 
+    @Override
+    protected AttributeReadingStrategy caseJavaBinaryAttribute(OpenType<?> openType) {
+        return new SimpleBinaryAttributeReadingStrategy(lastAttribute.getNullableDefault());
+    }
+
     @Override
     public AttributeReadingStrategy caseJavaSimpleAttribute(SimpleType<?> openType) {
         return new SimpleAttributeReadingStrategy(lastAttribute.getNullableDefault());
@@ -86,4 +93,11 @@ public class ObjectXmlReader extends AttributeIfcSwitchStatement<AttributeReadin
         return new ArrayAttributeReadingStrategy(lastAttribute.getNullableDefault(), innerStrategy);
     }
 
+    @Override
+    protected AttributeReadingStrategy caseListDependeciesAttribute(ArrayType<?> openType) {
+        Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
+        AttributeReadingStrategy innerStrategy = caseDependencyAttribute(SimpleType.OBJECTNAME);
+        return new ArrayAttributeReadingStrategy(lastAttribute.getNullableDefault(), innerStrategy);
+    }
+
 }
index be86a2ab6f58181894700e95e1f5bee413bc8a21..a8605243af3f77f587563d453ea69d51401f2aa4 100644 (file)
@@ -28,7 +28,13 @@ public class SimpleAttributeReadingStrategy extends AbstractAttributeReadingStra
         String textContent = xmlElement.getTextContent();
 
         Preconditions.checkNotNull(textContent, "This element should contain text %s", xmlElement);
-        return AttributeConfigElement.create(getNullableDefault(), postprocessParsedValue(textContent));
+        return AttributeConfigElement.create(postprocessNullableDefault(getNullableDefault()),
+                postprocessParsedValue(textContent));
+    }
+
+    @Override
+    protected Object postprocessNullableDefault(String nullableDefault) {
+        return nullableDefault;
     }
 
     protected Object postprocessParsedValue(String textContent) {
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleBinaryAttributeReadingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleBinaryAttributeReadingStrategy.java
new file mode 100644 (file)
index 0000000..2cac902
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.fromxml;
+
+import com.google.common.collect.Lists;
+import com.google.common.io.BaseEncoding;
+
+import java.util.List;
+
+public class SimpleBinaryAttributeReadingStrategy extends SimpleAttributeReadingStrategy {
+
+    public SimpleBinaryAttributeReadingStrategy(String nullableDefault) {
+        super(nullableDefault);
+    }
+
+    protected Object postprocessParsedValue(String textContent) {
+        BaseEncoding en = BaseEncoding.base64();
+        byte[] decode = en.decode(textContent);
+        List<String> parsed = Lists.newArrayListWithCapacity(decode.length);
+        for (byte b : decode) {
+            parsed.add(Byte.toString(b));
+        }
+        return parsed;
+    }
+
+    @Override
+    protected Object postprocessNullableDefault(String nullableDefault) {
+        return nullableDefault == null ? null : postprocessParsedValue(nullableDefault);
+    }
+}
index 9249ac9fa82b4a8cd03cfb8ce394c58b207f0dc2..22c9e015a94d4bb2a72e800927f7af1da2ca2363 100644 (file)
@@ -14,7 +14,6 @@ import java.util.HashMap;
 
 public class SimpleCompositeAttributeReadingStrategy extends SimpleAttributeReadingStrategy {
 
-
     private final String key;
 
     public SimpleCompositeAttributeReadingStrategy(String nullableDefault, String key) {
@@ -28,4 +27,8 @@ public class SimpleCompositeAttributeReadingStrategy extends SimpleAttributeRead
         return map;
     }
 
+    @Override
+    protected Object postprocessNullableDefault(String nullableDefault) {
+        return nullableDefault == null ? null : postprocessParsedValue(nullableDefault);
+    }
 }
index 853197c0b089b7ca1dd32bdf09486a5b8b72f849..6e5bd0d3fe8229597ab6984f37150f1833cd3525 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
@@ -121,4 +122,10 @@ public class ObjectMapper extends AttributeIfcSwitchStatement<AttributeMappingSt
                 prepareStrategy(((ListAttribute) lastAttribute).getInnerAttribute()));
     }
 
+    @Override
+    protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseListDependeciesAttribute(ArrayType<?> openType) {
+        Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
+        return new ArrayAttributeMappingStrategy(openType, caseDependencyAttribute(SimpleType.OBJECTNAME));
+    }
+
 }
index a85f3064cf742b3ec0782f213a5bf3cd8e173468..c477821051b08d03288d129fc29c1aaddd32eef6 100644 (file)
@@ -70,7 +70,7 @@ final class CompositeAttributeResolvingStrategy extends
                     parsedInnerValue.isPresent() ? parsedInnerValue.get() : null);
         }
 
-        CompositeDataSupport parsedValue = null;
+        CompositeDataSupport parsedValue;
         try {
             parsedValue = new CompositeDataSupport(getOpenType(), items);
         } catch (OpenDataException e) {
index c321164cf6b29c02548d9239787de2686d26e521..f5a25112602ac6b92c6d08faa46b311dbd11533c 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
@@ -109,4 +110,10 @@ public class ObjectResolver extends AttributeIfcSwitchStatement<AttributeResolvi
         return new ArrayAttributeResolvingStrategy(prepareStrategy(innerAttribute), openType);
     }
 
+    @Override
+    protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseListDependeciesAttribute(ArrayType<?> openType) {
+        Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
+        return new ArrayAttributeResolvingStrategy(caseDependencyAttribute(SimpleType.OBJECTNAME), openType);
+    }
+
 }
index 99e969970ccbd9ec27926979a5d597ab2b1f8881..a174e9a25160e8aa3d52ab66891c9d1314e58185 100644 (file)
@@ -12,12 +12,14 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
 import org.w3c.dom.Document;
 
 import javax.management.openmbean.ArrayType;
 import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
 import javax.management.openmbean.SimpleType;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -50,6 +52,11 @@ public class ObjectXmlWriter extends AttributeIfcSwitchStatement<AttributeWritin
         return switchAttribute(expectedAttr);
     }
 
+    @Override
+    protected AttributeWritingStrategy caseJavaBinaryAttribute(OpenType<?> openType) {
+        return new SimpleBinaryAttributeWritingStrategy(document, key);
+    }
+
     @Override
     protected AttributeWritingStrategy caseJavaSimpleAttribute(SimpleType<?> openType) {
         return new SimpleAttributeWritingStrategy(document, key);
@@ -96,4 +103,11 @@ public class ObjectXmlWriter extends AttributeIfcSwitchStatement<AttributeWritin
         return new ArrayAttributeWritingStrategy(innerStrategy);
     }
 
+    @Override
+    protected AttributeWritingStrategy caseListDependeciesAttribute(ArrayType<?> openType) {
+        Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
+        AttributeWritingStrategy innerStrategy = caseDependencyAttribute(SimpleType.OBJECTNAME);
+        return new ArrayAttributeWritingStrategy(innerStrategy);
+    }
+
 }
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleBinaryAttributeWritingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleBinaryAttributeWritingStrategy.java
new file mode 100644 (file)
index 0000000..c159e46
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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.netconf.confignetconfconnector.mapping.attributes.toxml;
+
+import com.google.common.base.Preconditions;
+import com.google.common.io.BaseEncoding;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.w3c.dom.Document;
+
+import java.util.List;
+
+public class SimpleBinaryAttributeWritingStrategy extends SimpleAttributeWritingStrategy {
+
+    /**
+     * @param document
+     * @param key
+     */
+    public SimpleBinaryAttributeWritingStrategy(Document document, String key) {
+        super(document, key);
+    }
+
+    protected Object preprocess(Object value) {
+        Util.checkType(value, List.class);
+        BaseEncoding en = BaseEncoding.base64();
+
+        List<?> list = (List<?>) value;
+        byte[] decoded = new byte[list.size()];
+        int i = 0;
+        for (Object bAsStr : list) {
+            Preconditions.checkArgument(bAsStr instanceof String, "Unexpected inner value for %s, expected string", value);
+            byte b = Byte.parseByte((String) bAsStr);
+            decoded[i++] = b;
+        }
+
+        return en.encode(decoded);
+    }
+
+}
index e4fa6f504b7b86799c1276875c2471a5719f5892..f522668733497333b7b2ac2052fe5949985f8f51 100644 (file)
@@ -284,8 +284,13 @@ public final class Services {
         public static ServiceInstance fromString(String instanceId) {
             instanceId = instanceId.trim();
             Matcher matcher = p.matcher(instanceId);
+            if(matcher.matches() == false) {
+                matcher = pDeprecated.matcher(instanceId);
+            }
+
             Preconditions.checkArgument(matcher.matches(), "Unexpected format for provider, expected " + p.toString()
-                    + " but was " + instanceId);
+                    + " or " + pDeprecated.toString() + " but was " + instanceId);
+
             String factoryName = matcher.group(1);
             String instanceName = matcher.group(2);
             return new ServiceInstance(factoryName, instanceName);
@@ -310,16 +315,25 @@ public final class Services {
             return instanceName;
         }
 
-        private static final String blueprint = "/" + XmlNetconfConstants.CONFIG_KEY + "/"
+        private static final String blueprint = "/"
                 + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "["
-                + XmlNetconfConstants.NAME_KEY + "='%s']/" + XmlNetconfConstants.INSTANCE_KEY + "["
+                + XmlNetconfConstants.TYPE_KEY + "='%s']["
                 + XmlNetconfConstants.NAME_KEY + "='%s']";
 
-        private static final String blueprintR = "/" + XmlNetconfConstants.CONFIG_KEY + "/"
+        // TODO unify with xpath in RuntimeRpc
+
+        // Previous version of xpath, needs to be supported for backwards compatibility (persisted configs by config-persister)
+        private static final String blueprintRDeprecated = "/" + XmlNetconfConstants.CONFIG_KEY + "/"
                 + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "\\["
                 + XmlNetconfConstants.NAME_KEY + "='%s'\\]/" + XmlNetconfConstants.INSTANCE_KEY + "\\["
                 + XmlNetconfConstants.NAME_KEY + "='%s'\\]";
 
+        private static final String blueprintR = "/"
+                + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "\\["
+                + XmlNetconfConstants.TYPE_KEY + "='%s'\\]\\["
+                + XmlNetconfConstants.NAME_KEY + "='%s'\\]";
+
+        private static final Pattern pDeprecated = Pattern.compile(String.format(blueprintRDeprecated, "(.+)", "(.+)"));
         private static final Pattern p = Pattern.compile(String.format(blueprintR, "(.+)", "(.+)"));
 
         @Override
index d91e38db33bf9206c96c18ba178dbfaa2ef115d7..f8916ecac2244943b55abe0dd036e0e52204f3f3 100644 (file)
@@ -55,7 +55,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
 import javax.management.InstanceAlreadyExistsException;
@@ -125,6 +124,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
         edit("netconfMessages/editConfig.xml");
         checkBinaryLeafEdited(getConfigCandidate());
 
+
         // default-operation:none, should not affect binary leaf
         edit("netconfMessages/editConfig_none.xml");
         checkBinaryLeafEdited(getConfigCandidate());
@@ -136,6 +136,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
         checkBinaryLeafEdited(response);
         checkTypeConfigAttribute(response);
         checkTypedefs(response);
+        checkTestingDeps(response);
         checkEnum(response);
         checkBigDecimal(response);
 
@@ -164,8 +165,12 @@ public class NetconfMappingTest extends AbstractConfigTest {
     }
 
     private void checkBigDecimal(Element response) {
-        int size = response.getElementsByTagName("sleep-factor").getLength();
-        assertEquals(1, size);
+        String responseTrimmed = XmlUtil.toString(response).replaceAll("\\s", "");
+
+        assertContainsString(responseTrimmed, "<sleep-factorxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">2.58</sleep-factor>");
+        // Default
+        assertContainsString(responseTrimmed, "<sleep-factorxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">2.00</sleep-factor>");
+
     }
 
     private void closeSession() throws NetconfDocumentedException, ParserConfigurationException, SAXException,
@@ -235,14 +240,9 @@ public class NetconfMappingTest extends AbstractConfigTest {
             edit("netconfMessages/namespaces/editConfig_sameAttrDifferentNamespaces.xml");
         } catch (NetconfDocumentedException e) {
             String message = e.getMessage();
-            assertThat(message,
-                    JUnitMatchers
-                            .containsString("Element simple-long-2 present multiple times with different namespaces"));
-            assertThat(message,
-                    JUnitMatchers.containsString("urn:opendaylight:params:xml:ns:yang:controller:test:impl"));
-            assertThat(message,
-                    JUnitMatchers
-                            .containsString(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
+            assertContainsString(message, "Element simple-long-2 present multiple times with different namespaces");
+            assertContainsString(message, "urn:opendaylight:params:xml:ns:yang:controller:test:impl");
+            assertContainsString(message, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
             throw e;
         }
     }
@@ -253,9 +253,9 @@ public class NetconfMappingTest extends AbstractConfigTest {
             edit("netconfMessages/namespaces/editConfig_differentNamespaceTO.xml");
         } catch (NetconfDocumentedException e) {
             String message = e.getMessage();
-            assertThat(message, JUnitMatchers.containsString("Unrecognised elements"));
-            assertThat(message, JUnitMatchers.containsString("simple-int2"));
-            assertThat(message, JUnitMatchers.containsString("dto_d"));
+            assertContainsString(message, "Unrecognised elements");
+            assertContainsString(message, "simple-int2");
+            assertContainsString(message, "dto_d");
             throw e;
         }
     }
@@ -266,13 +266,9 @@ public class NetconfMappingTest extends AbstractConfigTest {
             edit("netconfMessages/namespaces/editConfig_sameAttrDifferentNamespacesList.xml");
         } catch (NetconfDocumentedException e) {
             String message = e.getMessage();
-            assertThat(message,
-                    JUnitMatchers.containsString("Element binaryLeaf present multiple times with different namespaces"));
-            assertThat(message,
-                    JUnitMatchers.containsString("urn:opendaylight:params:xml:ns:yang:controller:test:impl"));
-            assertThat(message,
-                    JUnitMatchers
-                            .containsString(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
+            assertContainsString(message, "Element binaryLeaf present multiple times with different namespaces");
+            assertContainsString(message, "urn:opendaylight:params:xml:ns:yang:controller:test:impl");
+            assertContainsString(message, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
             throw e;
         }
     }
@@ -309,8 +305,8 @@ public class NetconfMappingTest extends AbstractConfigTest {
             try {
                 edit(file);
             } catch (NetconfDocumentedException e) {
-                assertThat(e.getMessage(), JUnitMatchers.containsString("Unrecognised elements"));
-                assertThat(e.getMessage(), JUnitMatchers.containsString("unknownAttribute"));
+                assertContainsString(e.getMessage(), "Unrecognised elements");
+                assertContainsString(e.getMessage(), "unknownAttribute");
                 continue;
             }
             fail("Unrecognised test should throw exception " + file);
@@ -356,22 +352,37 @@ public class NetconfMappingTest extends AbstractConfigTest {
     }
 
     private void checkBinaryLeafEdited(final Element response) {
-        final NodeList children = response.getElementsByTagName("binaryLeaf");
-        assertEquals(3, children.getLength());
-        final StringBuffer buf = new StringBuffer();
-        for (int i = 0; i < 3; i++) {
-            final Element e = (Element) children.item(i);
-            buf.append(XmlElement.fromDomElement(e).getTextContent());
-        }
-        assertEquals("810", buf.toString());
+        String responseTrimmed = XmlUtil.toString(response).replaceAll("\\s", "");
+        String substring = "<binaryLeafxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">YmluYXJ5</binaryLeaf>";
+        assertContainsString(responseTrimmed, substring);
+        substring = "<binaryLeafxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">ZGVmYXVsdEJpbg==</binaryLeaf>";
+        assertContainsString(responseTrimmed, substring);
     }
 
     private void checkTypedefs(final Element response) {
-        NodeList children = response.getElementsByTagName("extended");
-        assertEquals(1, children.getLength());
+        String responseTrimmed = XmlUtil.toString(response).replaceAll("\\s", "");
+
+        String substring = "<extendedxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">10</extended>";
+        assertContainsString(responseTrimmed, substring);
+        // Default
+        assertContainsString(responseTrimmed,
+                "<extendedxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">1</extended>");
 
-        children = response.getElementsByTagName("extended-twice");
-        assertEquals(1, children.getLength());
+        assertContainsString(responseTrimmed,
+                "<extended-twicexmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">20</extended-twice>");
+        // Default
+        assertContainsString(responseTrimmed,
+                "<extended-twicexmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">2</extended-twice>");
+
+        assertContainsString(responseTrimmed,
+                "<extended-enumxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">TWO</extended-enum>");
+        // Default
+        assertContainsString(responseTrimmed,
+                "<extended-enumxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">ONE</extended-enum>");
+    }
+
+    private void assertContainsString(String string, String substring) {
+        assertThat(string, JUnitMatchers.containsString(substring));
     }
 
     private void checkEnum(final Element response) {
@@ -394,6 +405,11 @@ public class NetconfMappingTest extends AbstractConfigTest {
         fail("Enum attribute " + enumName + ":" + enumContent + " not present in " + XmlUtil.toString(response));
     }
 
+    private void checkTestingDeps(Element response) {
+        int testingDepsSize = response.getElementsByTagName("testing-deps").getLength();
+        assertEquals(2, testingDepsSize);
+    }
+
     private void checkTypeConfigAttribute(Element response) {
 
         XmlElement modulesElement = XmlElement.fromDomElement(response).getOnlyChildElement("data")
@@ -450,17 +466,17 @@ public class NetconfMappingTest extends AbstractConfigTest {
         RuntimeRpc netconf = new RuntimeRpc(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
 
         response = executeOp(netconf, "netconfMessages/rpc.xml");
-        assertThat(XmlUtil.toString(response), JUnitMatchers.containsString("testarg1".toUpperCase()));
+        assertContainsString(XmlUtil.toString(response), "testarg1".toUpperCase());
 
         response = executeOp(netconf, "netconfMessages/rpcInner.xml");
-        assertThat(XmlUtil.toString(response), JUnitMatchers.containsString("ok"));
+        assertContainsString(XmlUtil.toString(response), "ok");
 
         response = executeOp(netconf, "netconfMessages/rpcInnerInner.xml");
-        assertThat(XmlUtil.toString(response), JUnitMatchers.containsString("true"));
+        assertContainsString(XmlUtil.toString(response), "true");
 
         response = executeOp(netconf, "netconfMessages/rpcInnerInner_complex_output.xml");
-        assertThat(XmlUtil.toString(response), JUnitMatchers.containsString("1"));
-        assertThat(XmlUtil.toString(response), JUnitMatchers.containsString("2"));
+        assertContainsString(XmlUtil.toString(response), "1");
+        assertContainsString(XmlUtil.toString(response), "2");
     }
 
     private Element get() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
index 99b7ee60a2c51c8033c44e1195f78a93328b63c9..1c3ac7a455c4f80eb8a1607f1e942bb2c91f3977 100644 (file)
@@ -8,45 +8,22 @@
 
 package org.opendaylight.controller.netconf.persist.impl;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Pattern;
-import javax.annotation.concurrent.ThreadSafe;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanServerConnection;
-import javax.management.Notification;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
 import org.opendaylight.controller.netconf.api.jmx.DefaultCommitOperationMXBean;
 import org.opendaylight.controller.netconf.api.jmx.NetconfJMXNotification;
 import org.opendaylight.controller.netconf.client.NetconfClient;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
-import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 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.annotation.concurrent.ThreadSafe;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServerConnection;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.regex.Pattern;
 
 /**
  * Responsible for listening for notifications from netconf containing latest
@@ -57,163 +34,27 @@ import org.xml.sax.SAXException;
 public class ConfigPersisterNotificationHandler implements NotificationListener, Closeable {
 
     private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
-    private static final int NETCONF_SEND_ATTEMPT_MS_DELAY = 1000;
-    private static final int NETCONF_SEND_ATTEMPTS = 20;
-
-    private final InetSocketAddress address;
-    private final EventLoopGroup nettyThreadgroup;
-
-    private NetconfClientDispatcher netconfClientDispatcher;
-    private NetconfClient netconfClient;
-
-    private final Persister persister;
-    private final MBeanServerConnection mbeanServer;
-
-
-    private final ObjectName on = DefaultCommitOperationMXBean.objectName;
-
-    public static final long DEFAULT_TIMEOUT = 120000L;// 120 seconds until netconf must be stable
-    private final long timeout;
+    private final MBeanServerConnection mBeanServerConnection;
+    private final NetconfClient netconfClient;
+    private final PersisterAggregator persisterAggregator;
     private final Pattern ignoredMissingCapabilityRegex;
 
-    public ConfigPersisterNotificationHandler(Persister persister, InetSocketAddress address,
-            MBeanServerConnection mbeanServer, Pattern ignoredMissingCapabilityRegex) {
-        this(persister, address, mbeanServer, DEFAULT_TIMEOUT, ignoredMissingCapabilityRegex);
-
-    }
-
-    public ConfigPersisterNotificationHandler(Persister persister, InetSocketAddress address,
-            MBeanServerConnection mbeanServer, long timeout, Pattern ignoredMissingCapabilityRegex) {
-        this.persister = persister;
-        this.address = address;
-        this.mbeanServer = mbeanServer;
-        this.timeout = timeout;
-
-        this.nettyThreadgroup = new NioEventLoopGroup();
+    public ConfigPersisterNotificationHandler(MBeanServerConnection mBeanServerConnection, NetconfClient netconfClient,
+                                              PersisterAggregator persisterAggregator, Pattern ignoredMissingCapabilityRegex) {
+        this.mBeanServerConnection = mBeanServerConnection;
+        this.netconfClient = netconfClient;
+        this.persisterAggregator = persisterAggregator;
         this.ignoredMissingCapabilityRegex = ignoredMissingCapabilityRegex;
     }
 
-    public void init() throws InterruptedException {
-        Optional<ConfigSnapshotHolder> maybeConfig = loadLastConfig();
-
-        if (maybeConfig.isPresent()) {
-            logger.debug("Last config found {}", persister);
-            ConflictingVersionException lastException = null;
-            pushLastConfigWithRetries(maybeConfig, lastException);
-
-        } else {
-            // this ensures that netconf is initialized, this is first
-            // connection
-            // this means we can register as listener for commit
-            registerToNetconf(Collections.<String>emptySet());
-
-            logger.info("No last config provided by backend storage {}", persister);
-        }
+    public void init() {
         registerAsJMXListener();
     }
 
-    private void pushLastConfigWithRetries(Optional<ConfigSnapshotHolder> maybeConfig, ConflictingVersionException lastException) throws InterruptedException {
-        int maxAttempts = 30;
-        for(int i = 0 ; i < maxAttempts; i++) {
-            registerToNetconf(maybeConfig.get().getCapabilities());
-
-            final String configSnapshot = maybeConfig.get().getConfigSnapshot();
-            logger.trace("Pushing following xml to netconf {}", configSnapshot);
-            try {
-                pushLastConfig(XmlUtil.readXmlToElement(configSnapshot));
-                return;
-            } catch(ConflictingVersionException e) {
-                closeClientAndDispatcher(netconfClient, netconfClientDispatcher);
-                lastException = e;
-                Thread.sleep(1000);
-            } catch (SAXException | IOException e) {
-                throw new IllegalStateException("Unable to load last config", e);
-            }
-        }
-        throw new IllegalStateException("Failed to push configuration, maximum attempt count has been reached: "
-                + maxAttempts, lastException);
-    }
-
-    private synchronized long registerToNetconf(Set<String> expectedCaps) throws InterruptedException {
-
-        Set<String> currentCapabilities = Sets.newHashSet();
-
-        // TODO think about moving capability subset check to netconf client
-        // could be utilized by integration tests
-
-        long pollingStart = System.currentTimeMillis();
-        int delay = 5000;
-
-        int attempt = 0;
-
-        long deadline = pollingStart + timeout;
-        while (System.currentTimeMillis() < deadline) {
-            attempt++;
-            netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup);
-            try {
-                netconfClient = new NetconfClient(this.toString(), address, delay, netconfClientDispatcher);
-            } catch (IllegalStateException e) {
-                logger.debug("Netconf {} was not initialized or is not stable, attempt {}", address, attempt, e);
-                netconfClientDispatcher.close();
-                Thread.sleep(delay);
-                continue;
-            }
-            currentCapabilities = netconfClient.getCapabilities();
-
-            if (isSubset(currentCapabilities, expectedCaps)) {
-                logger.debug("Hello from netconf stable with {} capabilities", currentCapabilities);
-                long currentSessionId = netconfClient.getSessionId();
-                logger.info("Session id received from netconf server: {}", currentSessionId);
-                return currentSessionId;
-            }
-
-
-
-            logger.debug("Polling hello from netconf, attempt {}, capabilities {}", attempt, currentCapabilities);
-
-            closeClientAndDispatcher(netconfClient, netconfClientDispatcher);
-
-            Thread.sleep(delay);
-        }
-        Set<String> allNotFound = new HashSet<>(expectedCaps);
-        allNotFound.removeAll(currentCapabilities);
-        logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}",
-                allNotFound, expectedCaps ,currentCapabilities);
-        throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound);
-
-    }
-
-    private static void closeClientAndDispatcher(Closeable client, Closeable dispatcher) {
-        Exception fromClient = null;
-        try {
-            client.close();
-        } catch (Exception e) {
-            fromClient = e;
-        } finally {
-            try {
-                dispatcher.close();
-            } catch (Exception e) {
-                if (fromClient != null) {
-                    e.addSuppressed(fromClient);
-                }
-
-                throw new RuntimeException("Error closing temporary client ", e);
-            }
-        }
-    }
-
-    private boolean isSubset(Set<String> currentCapabilities, Set<String> expectedCaps) {
-        for (String exCap : expectedCaps) {
-            if (currentCapabilities.contains(exCap) == false)
-                return false;
-        }
-        return true;
-    }
-
     private void registerAsJMXListener() {
         logger.trace("Called registerAsJMXListener");
         try {
-            mbeanServer.addNotificationListener(on, this, null, null);
+            mBeanServerConnection.addNotificationListener(DefaultCommitOperationMXBean.objectName, this, null, null);
         } catch (InstanceNotFoundException | IOException e) {
             throw new RuntimeException("Cannot register as JMX listener to netconf", e);
         }
@@ -242,7 +83,7 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
 
     private void handleAfterCommitNotification(final CommitJMXNotification notification) {
         try {
-            persister.persistConfig(new CapabilityStrippingConfigSnapshotHolder(notification.getConfigSnapshot(),
+            persisterAggregator.persistConfig(new CapabilityStrippingConfigSnapshotHolder(notification.getConfigSnapshot(),
                     notification.getCapabilities(), ignoredMissingCapabilityRegex));
             logger.info("Configuration persisted successfully");
         } catch (IOException e) {
@@ -250,137 +91,21 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
         }
     }
 
-    private Optional<ConfigSnapshotHolder> loadLastConfig() {
-        Optional<ConfigSnapshotHolder> maybeConfigElement;
-        try {
-            maybeConfigElement = persister.loadLastConfig();
-        } catch (IOException e) {
-            throw new RuntimeException("Unable to load configuration", e);
-        }
-        return maybeConfigElement;
-    }
-
-    private synchronized void pushLastConfig(Element xmlToBePersisted) throws ConflictingVersionException {
-        logger.info("Pushing last configuration to netconf");
-        StringBuilder response = new StringBuilder("editConfig response = {");
-
-
-        NetconfMessage message = createEditConfigMessage(xmlToBePersisted, "/netconfOp/editConfig.xml");
-
-        // sending message to netconf
-        NetconfMessage responseMessage = netconfClient.sendMessage(message, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
-
-        XmlElement element = XmlElement.fromDomDocument(responseMessage.getDocument());
-        Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
-        element = element.getOnlyChildElement();
-
-        checkIsOk(element, responseMessage);
-        response.append(XmlUtil.toString(responseMessage.getDocument()));
-        response.append("}");
-        responseMessage = netconfClient.sendMessage(getNetconfMessageFromResource("/netconfOp/commit.xml"), NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
-
-        element = XmlElement.fromDomDocument(responseMessage.getDocument());
-        Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
-        element = element.getOnlyChildElement();
-
-        checkIsOk(element, responseMessage);
-        response.append("commit response = {");
-        response.append(XmlUtil.toString(responseMessage.getDocument()));
-        response.append("}");
-        logger.info("Last configuration loaded successfully");
-        logger.trace("Detailed message {}", response);
-    }
-
-    static void checkIsOk(XmlElement element, NetconfMessage responseMessage) throws ConflictingVersionException {
-        if (element.getName().equals(XmlNetconfConstants.OK)) {
-            return;
-        }
-
-        if (element.getName().equals(XmlNetconfConstants.RPC_ERROR)) {
-            logger.warn("Can not load last configuration, operation failed");
-            // is it ConflictingVersionException ?
-            XPathExpression xPathExpression = XMLNetconfUtil.compileXPath("/netconf:rpc-reply/netconf:rpc-error/netconf:error-info/netconf:error");
-            String error = (String) XmlUtil.evaluateXPath(xPathExpression, element.getDomElement(), XPathConstants.STRING);
-            if (error!=null && error.contains(ConflictingVersionException.class.getCanonicalName())) {
-                throw new ConflictingVersionException(error);
-            }
-            throw new IllegalStateException("Can not load last configuration, operation failed: "
-                    + XmlUtil.toString(responseMessage.getDocument()));
-        }
-
-        logger.warn("Can not load last configuration. Operation failed.");
-        throw new IllegalStateException("Can not load last configuration. Operation failed: "
-                + XmlUtil.toString(responseMessage.getDocument()));
-    }
-
-    private static NetconfMessage createEditConfigMessage(Element dataElement, String editConfigResourcename) {
-        try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcename)) {
-            Preconditions.checkNotNull(stream, "Unable to load resource " + editConfigResourcename);
-
-            Document doc = XmlUtil.readXmlToDocument(stream);
-
-            doc.getDocumentElement();
-            XmlElement editConfigElement = XmlElement.fromDomDocument(doc).getOnlyChildElement();
-            XmlElement configWrapper = editConfigElement.getOnlyChildElement(XmlNetconfConstants.CONFIG_KEY);
-            editConfigElement.getDomElement().removeChild(configWrapper.getDomElement());
-            for (XmlElement el : XmlElement.fromDomElement(dataElement).getChildElements()) {
-                configWrapper.appendChild((Element) doc.importNode(el.getDomElement(), true));
-            }
-            editConfigElement.appendChild(configWrapper.getDomElement());
-            return new NetconfMessage(doc);
-        } catch (IOException | SAXException e) {
-            throw new RuntimeException("Unable to parse message from resources " + editConfigResourcename, e);
-        }
-    }
-
-    private NetconfMessage getNetconfMessageFromResource(String resource) {
-        try (InputStream stream = getClass().getResourceAsStream(resource)) {
-            Preconditions.checkNotNull(stream, "Unable to load resource " + resource);
-            return new NetconfMessage(XmlUtil.readXmlToDocument(stream));
-        } catch (SAXException | IOException e) {
-            throw new RuntimeException("Unable to parse message from resources " + resource, e);
-        }
-    }
-
     @Override
     public synchronized void close() {
-        // TODO persister is received from constructor, should not be closed
-        // here
-        try {
-            persister.close();
-        } catch (Exception e) {
-            logger.warn("Unable to close config persister {}", persister, e);
-        }
-
-        if (netconfClient != null) {
-            try {
-                netconfClient.close();
-            } catch (Exception e) {
-                logger.warn("Unable to close connection to netconf {}", netconfClient, e);
-            }
-        }
-
-        if (netconfClientDispatcher != null) {
-            try {
-                netconfClientDispatcher.close();
-            } catch (Exception e) {
-                logger.warn("Unable to close connection to netconf {}", netconfClientDispatcher, e);
-            }
-        }
-
-        try {
-            nettyThreadgroup.shutdownGracefully();
-        } catch (Exception e) {
-            logger.warn("Unable to close netconf client thread group {}", netconfClientDispatcher, e);
-        }
-
         // unregister from JMX
+        ObjectName on = DefaultCommitOperationMXBean.objectName;
         try {
-            if (mbeanServer.isRegistered(on)) {
-                mbeanServer.removeNotificationListener(on, this);
+            if (mBeanServerConnection.isRegistered(on)) {
+                mBeanServerConnection.removeNotificationListener(on, this);
             }
         } catch (Exception e) {
             logger.warn("Unable to unregister {} as listener for {}", this, on, e);
         }
     }
+
+    public NetconfClient getNetconfClient() {
+        return netconfClient;
+    }
+
 }
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java
new file mode 100644 (file)
index 0000000..044346e
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * 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.netconf.persist.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import io.netty.channel.EventLoopGroup;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.NetconfClient;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+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.annotation.concurrent.Immutable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Immutable
+public class ConfigPusher {
+    private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
+    private static final int NETCONF_SEND_ATTEMPT_MS_DELAY = 1000;
+    private static final int NETCONF_SEND_ATTEMPTS = 20;
+
+    private final InetSocketAddress address;
+    private final EventLoopGroup nettyThreadgroup;
+
+
+    public static final long DEFAULT_TIMEOUT = 120000L;// 120 seconds until netconf must be stable
+    private final long timeout;
+
+    public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadgroup) {
+        this(address, DEFAULT_TIMEOUT, nettyThreadgroup);
+
+    }
+
+    public ConfigPusher(InetSocketAddress address, long timeout, EventLoopGroup nettyThreadgroup) {
+        this.address = address;
+        this.timeout = timeout;
+
+        this.nettyThreadgroup = nettyThreadgroup;
+    }
+
+    public synchronized NetconfClient init(List<ConfigSnapshotHolder> configs) throws InterruptedException {
+        logger.debug("Last config snapshots to be pushed to netconf: {}", configs);
+        return pushAllConfigs(configs);
+    }
+
+    private synchronized NetconfClient pushAllConfigs(List<ConfigSnapshotHolder> configs) throws InterruptedException {
+        NetconfClient netconfClient = makeNetconfConnection(Collections.<String>emptySet(), Optional.<NetconfClient>absent());
+        for (ConfigSnapshotHolder configSnapshotHolder: configs){
+            netconfClient = pushSnapshotWithRetries(configSnapshotHolder, Optional.of(netconfClient));
+        }
+        return netconfClient;
+    }
+
+    private synchronized NetconfClient pushSnapshotWithRetries(ConfigSnapshotHolder configSnapshotHolder,
+                                                               Optional<NetconfClient> oldClientForPossibleReuse)
+            throws InterruptedException {
+
+        ConflictingVersionException lastException = null;
+        int maxAttempts = 30;
+        for(int i = 0 ; i < maxAttempts; i++) {
+            NetconfClient netconfClient = makeNetconfConnection(configSnapshotHolder.getCapabilities(), oldClientForPossibleReuse);
+            final String configSnapshot = configSnapshotHolder.getConfigSnapshot();
+            logger.trace("Pushing following xml to netconf {}", configSnapshot);
+            try {
+                pushLastConfig(configSnapshotHolder, netconfClient);
+                return netconfClient;
+            } catch(ConflictingVersionException e) {
+                Util.closeClientAndDispatcher(netconfClient);
+                lastException = e;
+                Thread.sleep(1000);
+            } catch (SAXException | IOException e) {
+                throw new IllegalStateException("Unable to load last config", e);
+            }
+        }
+        throw new IllegalStateException("Failed to push configuration, maximum attempt count has been reached: "
+                + maxAttempts, lastException);
+    }
+
+    /**
+     * @param expectedCaps capabilities that server hello must contain. Will retry until all are found or throws RuntimeException.
+     *                     If empty set is provided, will only make sure netconf client successfuly connected to the server.
+     * @param oldClientForPossibleReuse if present, try to get expected capabilities from it before closing it and retrying with
+     *                                  new client connection.
+     * @return NetconfClient that has all required capabilities from server.
+     */
+    private synchronized NetconfClient makeNetconfConnection(Set<String> expectedCaps,
+                                                             Optional<NetconfClient> oldClientForPossibleReuse)
+            throws InterruptedException {
+
+        if (oldClientForPossibleReuse.isPresent()) {
+            NetconfClient oldClient = oldClientForPossibleReuse.get();
+            if (Util.isSubset(oldClient, expectedCaps)) {
+                return oldClient;
+            } else {
+                Util.closeClientAndDispatcher(oldClient);
+            }
+        }
+
+        // TODO think about moving capability subset check to netconf client
+        // could be utilized by integration tests
+
+        long pollingStart = System.currentTimeMillis();
+        int delay = 5000;
+
+        int attempt = 0;
+
+        long deadline = pollingStart + timeout;
+
+        Set<String> latestCapabilities = new HashSet<>();
+        while (System.currentTimeMillis() < deadline) {
+            attempt++;
+            NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup);
+            NetconfClient netconfClient;
+            try {
+                netconfClient = new NetconfClient(this.toString(), address, delay, netconfClientDispatcher);
+            } catch (IllegalStateException e) {
+                logger.debug("Netconf {} was not initialized or is not stable, attempt {}", address, attempt, e);
+                netconfClientDispatcher.close();
+                Thread.sleep(delay);
+                continue;
+            }
+            latestCapabilities = netconfClient.getCapabilities();
+            if (Util.isSubset(netconfClient, expectedCaps)) {
+                logger.debug("Hello from netconf stable with {} capabilities", latestCapabilities);
+                logger.info("Session id received from netconf server: {}", netconfClient.getClientSession());
+                return netconfClient;
+            }
+            logger.debug("Polling hello from netconf, attempt {}, capabilities {}", attempt, latestCapabilities);
+            Util.closeClientAndDispatcher(netconfClient);
+            Thread.sleep(delay);
+        }
+        Set<String> allNotFound = new HashSet<>(expectedCaps);
+        allNotFound.removeAll(latestCapabilities);
+        logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}",
+                allNotFound, expectedCaps, latestCapabilities);
+        throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound);
+    }
+
+
+    private synchronized void pushLastConfig(ConfigSnapshotHolder configSnapshotHolder, NetconfClient netconfClient)
+            throws ConflictingVersionException, IOException, SAXException {
+
+        Element xmlToBePersisted = XmlUtil.readXmlToElement(configSnapshotHolder.getConfigSnapshot());
+        logger.info("Pushing last configuration to netconf: {}", configSnapshotHolder);
+        StringBuilder response = new StringBuilder("editConfig response = {");
+
+
+        NetconfMessage message = createEditConfigMessage(xmlToBePersisted, "/netconfOp/editConfig.xml");
+
+        // sending message to netconf
+        NetconfMessage responseMessage = netconfClient.sendMessage(message, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+
+        XmlElement element = XmlElement.fromDomDocument(responseMessage.getDocument());
+        Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
+        element = element.getOnlyChildElement();
+
+        Util.checkIsOk(element, responseMessage);
+        response.append(XmlUtil.toString(responseMessage.getDocument()));
+        response.append("}");
+        responseMessage = netconfClient.sendMessage(getNetconfMessageFromResource("/netconfOp/commit.xml"), NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+
+        element = XmlElement.fromDomDocument(responseMessage.getDocument());
+        Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
+        element = element.getOnlyChildElement();
+
+        Util.checkIsOk(element, responseMessage);
+        response.append("commit response = {");
+        response.append(XmlUtil.toString(responseMessage.getDocument()));
+        response.append("}");
+        logger.info("Last configuration loaded successfully");
+        logger.trace("Detailed message {}", response);
+    }
+
+    private static NetconfMessage createEditConfigMessage(Element dataElement, String editConfigResourcename) {
+        try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcename)) {
+            Preconditions.checkNotNull(stream, "Unable to load resource " + editConfigResourcename);
+
+            Document doc = XmlUtil.readXmlToDocument(stream);
+
+            doc.getDocumentElement();
+            XmlElement editConfigElement = XmlElement.fromDomDocument(doc).getOnlyChildElement();
+            XmlElement configWrapper = editConfigElement.getOnlyChildElement(XmlNetconfConstants.CONFIG_KEY);
+            editConfigElement.getDomElement().removeChild(configWrapper.getDomElement());
+            for (XmlElement el : XmlElement.fromDomElement(dataElement).getChildElements()) {
+                configWrapper.appendChild((Element) doc.importNode(el.getDomElement(), true));
+            }
+            editConfigElement.appendChild(configWrapper.getDomElement());
+            return new NetconfMessage(doc);
+        } catch (IOException | SAXException e) {
+            throw new RuntimeException("Unable to parse message from resources " + editConfigResourcename, e);
+        }
+    }
+
+    private static NetconfMessage getNetconfMessageFromResource(String resource) {
+        try (InputStream stream = ConfigPusher.class.getResourceAsStream(resource)) {
+            Preconditions.checkNotNull(stream, "Unable to load resource " + resource);
+            return new NetconfMessage(XmlUtil.readXmlToDocument(stream));
+        } catch (SAXException | IOException e) {
+            throw new RuntimeException("Unable to parse message from resources " + resource, e);
+        }
+    }
+}
index b37c1457c330ee73467e48950144bf3ee237ccbc..27f930990dd22149e17fb8092a2ae30bbaa93a6e 100644 (file)
@@ -8,7 +8,6 @@
 
 package org.opendaylight.controller.netconf.persist.impl;
 
-import com.google.common.base.Optional;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.api.PropertiesProvider;
@@ -17,6 +16,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
 
 public class NoOpStorageAdapter implements StorageAdapter, Persister {
     private static final Logger logger = LoggerFactory.getLogger(NoOpStorageAdapter.class);
@@ -33,9 +34,9 @@ public class NoOpStorageAdapter implements StorageAdapter, Persister {
     }
 
     @Override
-    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
         logger.debug("loadLastConfig called");
-        return Optional.absent();
+        return Collections.emptyList();
     }
 
     @Override
index e109ebec887b8e3c2a1579e5e2292fc970b25f1e..7e9dce67bd78586459b8d8d2c40e248b392ecf01 100644 (file)
@@ -9,7 +9,6 @@
 package org.opendaylight.controller.netconf.persist.impl;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.api.StorageAdapter;
@@ -20,6 +19,7 @@ import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.ListIterator;
 
@@ -48,7 +48,7 @@ import java.util.ListIterator;
  </pre>
  * During server startup {@link ConfigPersisterNotificationHandler} requests last snapshot from underlying storages.
  * Each storage can respond by giving snapshot or absent response.
- * The {@link #loadLastConfig()} will search for first non-absent response from storages ordered backwards as user
+ * The {@link #loadLastConfigs()} will search for first non-absent response from storages ordered backwards as user
  * specified (first '3', then '2').
  *
  * When a commit notification is received, '2' will be omitted because readonly flag is set to true, so
@@ -154,19 +154,29 @@ public final class PersisterAggregator implements Persister {
         }
     }
 
+    /**
+     * @return last non-empty result from input persisters
+     */
     @Override
-    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+    public List<ConfigSnapshotHolder> loadLastConfigs()  {
         // iterate in reverse order
         ListIterator<PersisterWithConfiguration> li = persisterWithConfigurations.listIterator(persisterWithConfigurations.size());
         while(li.hasPrevious()) {
             PersisterWithConfiguration persisterWithConfiguration = li.previous();
-            Optional<ConfigSnapshotHolder> configSnapshotHolderOptional = persisterWithConfiguration.storage.loadLastConfig();
-            if (configSnapshotHolderOptional.isPresent()) {
-                return configSnapshotHolderOptional;
+            List<ConfigSnapshotHolder> configs = null;
+            try {
+                configs = persisterWithConfiguration.storage.loadLastConfigs();
+            } catch (IOException e) {
+                throw new RuntimeException("Error while calling loadLastConfig on " +  persisterWithConfiguration, e);
+            }
+            if (configs.isEmpty() == false) {
+                logger.debug("Found non empty configs using {}:{}", persisterWithConfiguration, configs);
+                return configs;
             }
         }
         // no storage had an answer
-        return Optional.absent();
+        logger.debug("No non-empty list of configuration snapshots found");
+        return Collections.emptyList();
     }
 
     @VisibleForTesting
index b17309123c8081ce081b178539d66ea68bfdb116..811ba38c10068d470492a93073a656f6b0c42f79 100644 (file)
@@ -8,24 +8,79 @@
 
 package org.opendaylight.controller.netconf.persist.impl;
 
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadFactory;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.NetconfClient;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import java.util.Set;
 
 public final class Util {
+    private static final Logger logger = LoggerFactory.getLogger(Util.class);
+
+
+    public static boolean isSubset(NetconfClient netconfClient, Set<String> expectedCaps) {
+        return isSubset(netconfClient.getCapabilities(), expectedCaps);
+
+    }
+
+    private static boolean isSubset(Set<String> currentCapabilities, Set<String> expectedCaps) {
+        for (String exCap : expectedCaps) {
+            if (currentCapabilities.contains(exCap) == false)
+                return false;
+        }
+        return true;
+    }
+
+
+    // TODO: check if closing in correct order
+    public static void closeClientAndDispatcher(NetconfClient client) {
+        NetconfClientDispatcher dispatcher = client.getNetconfClientDispatcher();
+        Exception fromClient = null;
+        try {
+            client.close();
+        } catch (Exception e) {
+            fromClient = e;
+        } finally {
+            try {
+                dispatcher.close();
+            } catch (Exception e) {
+                if (fromClient != null) {
+                    e.addSuppressed(fromClient);
+                }
+                throw new RuntimeException("Error closing temporary client ", e);
+            }
+        }
+    }
 
-    public static ScheduledExecutorService getExecutorServiceWithThreadName(final String threadNamePrefix,
-            int threadCount) {
-        return Executors.newScheduledThreadPool(threadCount, new ThreadFactory() {
 
-            private int i = 1;
+    public static void checkIsOk(XmlElement element, NetconfMessage responseMessage) throws ConflictingVersionException {
+        if (element.getName().equals(XmlNetconfConstants.OK)) {
+            return;
+        }
 
-            @Override
-            public Thread newThread(Runnable r) {
-                Thread thread = new Thread(r);
-                thread.setName(threadNamePrefix + ":" + i++);
-                return thread;
+        if (element.getName().equals(XmlNetconfConstants.RPC_ERROR)) {
+            logger.warn("Can not load last configuration, operation failed");
+            // is it ConflictingVersionException ?
+            XPathExpression xPathExpression = XMLNetconfUtil.compileXPath("/netconf:rpc-reply/netconf:rpc-error/netconf:error-info/netconf:error");
+            String error = (String) XmlUtil.evaluateXPath(xPathExpression, element.getDomElement(), XPathConstants.STRING);
+            if (error!=null && error.contains(ConflictingVersionException.class.getCanonicalName())) {
+                throw new ConflictingVersionException(error);
             }
-        });
+            throw new IllegalStateException("Can not load last configuration, operation failed: "
+                    + XmlUtil.toString(responseMessage.getDocument()));
+        }
+
+        logger.warn("Can not load last configuration. Operation failed.");
+        throw new IllegalStateException("Can not load last configuration. Operation failed: "
+                + XmlUtil.toString(responseMessage.getDocument()));
     }
 }
index e7916c2d5f3d041ee315e03335586d533c76206e..656091115c8907aa5de61394e1a6a6f9da516317 100644 (file)
@@ -8,8 +8,13 @@
 
 package org.opendaylight.controller.netconf.persist.impl.osgi;
 
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import org.opendaylight.controller.netconf.client.NetconfClient;
 import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
+import org.opendaylight.controller.netconf.persist.impl.ConfigPusher;
 import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator;
+import org.opendaylight.controller.netconf.persist.impl.Util;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
@@ -28,14 +33,19 @@ public class ConfigPersisterActivator implements BundleActivator {
     private final static MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
     private static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex";
 
-    private ConfigPersisterNotificationHandler configPersisterNotificationHandler;
+    public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
 
-    private Thread initializationThread;
+    public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX = "storageAdapterClass";
 
-    public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
-    public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX =  "storageAdapterClass";
     public static final String DEFAULT_IGNORED_REGEX = "^urn:ietf:params:xml:ns:netconf:base:1.0";
 
+
+    private volatile ConfigPersisterNotificationHandler jmxNotificationHandler;
+    private volatile NetconfClient netconfClient;
+    private Thread initializationThread;
+    private EventLoopGroup nettyThreadgroup;
+    private PersisterAggregator persisterAggregator;
+
     @Override
     public void start(final BundleContext context) throws Exception {
         logger.debug("ConfigPersister starting");
@@ -49,20 +59,24 @@ public class ConfigPersisterActivator implements BundleActivator {
         } else {
             regex = DEFAULT_IGNORED_REGEX;
         }
-        Pattern ignoredMissingCapabilityRegex = Pattern.compile(regex);
-        PersisterAggregator persister = PersisterAggregator.createFromProperties(propertiesProvider);
+        final Pattern ignoredMissingCapabilityRegex = Pattern.compile(regex);
+        nettyThreadgroup = new NioEventLoopGroup();
+
+        persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
+        final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context, "Netconf is not configured, persister is not operational", true);
+        final ConfigPusher configPusher = new ConfigPusher(address, nettyThreadgroup);
 
-        InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
-                "Netconf is not configured, persister is not operational",true);
-        configPersisterNotificationHandler = new ConfigPersisterNotificationHandler(persister, address,
-                platformMBeanServer, ignoredMissingCapabilityRegex);
 
         // offload initialization to another thread in order to stop blocking activator
         Runnable initializationRunnable = new Runnable() {
             @Override
             public void run() {
                 try {
-                    configPersisterNotificationHandler.init();
+                    netconfClient = configPusher.init(persisterAggregator.loadLastConfigs());
+                    jmxNotificationHandler = new ConfigPersisterNotificationHandler(
+                            platformMBeanServer, netconfClient, persisterAggregator,
+                            ignoredMissingCapabilityRegex);
+                    jmxNotificationHandler.init();
                 } catch (InterruptedException e) {
                     logger.info("Interrupted while waiting for netconf connection");
                 }
@@ -75,6 +89,18 @@ public class ConfigPersisterActivator implements BundleActivator {
     @Override
     public void stop(BundleContext context) throws Exception {
         initializationThread.interrupt();
-        configPersisterNotificationHandler.close();
+        if (jmxNotificationHandler != null) {
+            jmxNotificationHandler.close();
+        }
+        if (netconfClient != null) {
+            netconfClient = jmxNotificationHandler.getNetconfClient();
+            try {
+                Util.closeClientAndDispatcher(netconfClient);
+            } catch (Exception e) {
+                logger.warn("Unable to close connection to netconf {}", netconfClient, e);
+            }
+        }
+        nettyThreadgroup.shutdownGracefully();
+        persisterAggregator.close();
     }
 }
index 6c45c9c0119073fd4ff8d64869ed6a7068181090..a124d85b91c7deea3a027d1726fddba01d74258c 100644 (file)
@@ -24,7 +24,7 @@ public class ConfigPersisterNotificationHandlerTest {
     public void testConflictingVersionDetection() throws Exception {
         Document document = XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/conflictingVersionResponse.xml"));
         try{
-            ConfigPersisterNotificationHandler.checkIsOk(XmlElement.fromDomDocument(document).getOnlyChildElement(), new NetconfMessage(document));
+            Util.checkIsOk(XmlElement.fromDomDocument(document).getOnlyChildElement(), new NetconfMessage(document));
             fail();
         }catch(ConflictingVersionException e){
             assertThat(e.getMessage(), containsString("Optimistic lock failed. Expected parent version 21, was 18"));
index 7a11b9cd6fa092709239cccca223c55d69d533d4..e824b588324e25a232ff03f6faef2f54be7f3839 100644 (file)
@@ -7,13 +7,14 @@
  */
 package org.opendaylight.controller.netconf.persist.impl;
 
-import com.google.common.base.Optional;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.api.PropertiesProvider;
 import org.opendaylight.controller.config.persist.api.StorageAdapter;
 
 import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
 
 public class DummyAdapter implements StorageAdapter, Persister {
 
@@ -27,9 +28,9 @@ public class DummyAdapter implements StorageAdapter, Persister {
     static int load = 0;
 
     @Override
-    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
         load++;
-        return Optional.absent();
+        return Collections.emptyList();
     }
 
     static int props = 0;
index d9fa7ba4d82dbfa931106d93389d83837f105daf..227018bf5b8761e82b88760cdd3dc8a4a6e23705 100644 (file)
@@ -8,7 +8,6 @@
 
 package org.opendaylight.controller.netconf.persist.impl;
 
-import com.google.common.base.Optional;
 import org.junit.Test;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
@@ -18,14 +17,14 @@ import org.opendaylight.controller.netconf.persist.impl.osgi.PropertiesProviderB
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Properties;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 import static org.junit.matchers.JUnitMatchers.containsString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -79,9 +78,9 @@ public class PersisterAggregatorTest {
         assertFalse(persister.isReadOnly());
 
         persisterAggregator.persistConfig(null);
-        persisterAggregator.loadLastConfig();
+        persisterAggregator.loadLastConfigs();
         persisterAggregator.persistConfig(null);
-        persisterAggregator.loadLastConfig();
+        persisterAggregator.loadLastConfigs();
 
         assertEquals(2, DummyAdapter.persist);
         assertEquals(2, DummyAdapter.load);
@@ -110,29 +109,41 @@ public class PersisterAggregatorTest {
         }
     }
 
+    private ConfigSnapshotHolder mockHolder(String name){
+        ConfigSnapshotHolder result = mock(ConfigSnapshotHolder.class);
+        doReturn("mock:" + name).when(result).toString();
+        return result;
+    }
+
+    private Persister mockPersister(String name){
+        Persister result = mock(Persister.class);
+        doReturn("mock:" + name).when(result).toString();
+        return result;
+    }
+
     @Test
     public void loadLastConfig() throws Exception {
         List<PersisterWithConfiguration> persisterWithConfigurations = new ArrayList<>();
         PersisterWithConfiguration first = new PersisterWithConfiguration(mock(Persister.class), false);
 
-        ConfigSnapshotHolder ignored = mock(ConfigSnapshotHolder.class);
-        doReturn(Optional.of(ignored)).when(first.getStorage()).loadLastConfig(); // should be ignored
+        ConfigSnapshotHolder ignored = mockHolder("ignored");
+        doReturn(Arrays.asList(ignored)).when(first.getStorage()).loadLastConfigs(); // should be ignored
 
-        ConfigSnapshotHolder used = mock(ConfigSnapshotHolder.class);
-        PersisterWithConfiguration second = new PersisterWithConfiguration(mock(Persister.class), false);
-        doReturn(Optional.of(used)).when(second.getStorage()).loadLastConfig(); // should be used
 
-        PersisterWithConfiguration third = new PersisterWithConfiguration(mock(Persister.class), false);
-        doReturn(Optional.absent()).when(third.getStorage()).loadLastConfig();
+        ConfigSnapshotHolder used = mockHolder("used");
+        PersisterWithConfiguration second = new PersisterWithConfiguration(mockPersister("p1"), false);
+        doReturn(Arrays.asList(used)).when(second.getStorage()).loadLastConfigs(); // should be used
+
+        PersisterWithConfiguration third = new PersisterWithConfiguration(mockPersister("p2"), false);
+        doReturn(Arrays.asList()).when(third.getStorage()).loadLastConfigs();
 
         persisterWithConfigurations.add(first);
         persisterWithConfigurations.add(second);
         persisterWithConfigurations.add(third);
 
         PersisterAggregator persisterAggregator = new PersisterAggregator(persisterWithConfigurations);
-        Optional<ConfigSnapshotHolder> configSnapshotHolderOptional = persisterAggregator.loadLastConfig();
-        assertTrue(configSnapshotHolderOptional.isPresent());
-        assertEquals(used, configSnapshotHolderOptional.get());
+        List<ConfigSnapshotHolder> configSnapshotHolderOptional = persisterAggregator.loadLastConfigs();
+        assertEquals(1, configSnapshotHolderOptional.size());
+        assertEquals(used, configSnapshotHolderOptional.get(0));
     }
-
 }
index 1e14bfdba285ec0e8f68f3b0b363abe2e370c66b..eb7235f04490eaaef675e7f993da23455223222f 100644 (file)
@@ -58,7 +58,7 @@ public abstract class NetconfSession extends AbstractProtocolSession<NetconfMess
 
     @Override
     protected void handleMessage(NetconfMessage netconfMessage) {
-        logger.debug("handlign incomming message");
+        logger.debug("handling incoming message");
         sessionListener.onMessage(this, netconfMessage);
     }
 
index d95977492a9206fb0ff05d4e6229810b08dcda9a..95f526b2ecb535787570fd60fe97e96094421420 100644 (file)
@@ -67,6 +67,10 @@ public class NetconfClient implements Closeable {
         }
     }
 
+    public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
+        return new NetconfClient(clientLabelForLogging,address,strat,netconfClientDispatcher);
+    }
+
     public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs,
             NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
         this(clientLabelForLogging, address,
@@ -100,6 +104,10 @@ public class NetconfClient implements Closeable {
         clientSession.close();
     }
 
+    public NetconfClientDispatcher getNetconfClientDispatcher() {
+        return dispatch;
+    }
+
     private static ReconnectStrategy getReconnectStrategy(int connectionAttempts, int attemptMsTimeout) {
         return new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, attemptMsTimeout, 1000, 1.0, null,
                 Long.valueOf(connectionAttempts), null);
index 221953e56e51053af95bc32bd866f2d51b99f05a..520627a09899c826f7a7254610cf8e9f7f776b65 100644 (file)
@@ -1,6 +1,7 @@
 <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <capabilities>
         <capability>urn:ietf:params:netconf:base:1.0</capability>
+        <capability>urn:ietf:params:netconf:base:1.1</capability>
         <capability>urn:ietf:params:netconf:capability:exi:1.0</capability>
     </capabilities>
 </hello>
\ No newline at end of file
index ccc7c85eb39e38d345d710e50a42aed2d485df0b..c61dab7f643ebd119544cb12d76c0b420435d6af 100644 (file)
@@ -8,23 +8,41 @@
 
 package org.opendaylight.controller.netconf.it;
 
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-import com.google.common.base.Optional;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import static java.util.Collections.emptyList;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.ObjectName;
+import javax.xml.parsers.ParserConfigurationException;
+
 import junit.framework.Assert;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
-import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
 import org.opendaylight.controller.config.yang.store.api.YangStoreException;
@@ -49,8 +67,6 @@ import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFact
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
-import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
 import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.controller.netconf.util.xml.ExiParameters;
@@ -64,28 +80,11 @@ import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.xml.sax.SAXException;
 
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Pattern;
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
 
-import static java.util.Collections.emptyList;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 
 public class NetconfITTest extends AbstractConfigTest {
 
@@ -220,14 +219,18 @@ public class NetconfITTest extends AbstractConfigTest {
         }
     }
 
+
+    //TODO: test persister actually
+    @Ignore
     @Test(timeout = 10000)
     public void testPersister() throws Exception {
-        Persister persister = mock(Persister.class);
-        doReturn("mockPersister").when(persister).toString();
-        doReturn(Optional.absent()).when(persister).loadLastConfig();
-        ConfigPersisterNotificationHandler h =
-                new ConfigPersisterNotificationHandler(persister, tcpAddress, ManagementFactory.getPlatformMBeanServer(), Pattern.compile(ConfigPersisterActivator.DEFAULT_IGNORED_REGEX));
-        h.init();
+//        Persister persister = mock(Persister.class);
+//        doReturn("mockPersister").when(persister).toString();
+//        doReturn(Collections.emptyList()).when(persister).loadLastConfigs();
+//        ConfigPersisterNotificationHandler h =
+//                new ConfigPersisterNotificationHandler(persister, tcpAddress, ManagementFactory.getPlatformMBeanServer(),
+//                        Pattern.compile(ConfigPersisterActivator.DEFAULT_IGNORED_REGEX));
+//        h.init();
     }
 
     @Ignore
index 4e34591284e78e23e4b84f0553aea90c53792295..46f6f76412e01b8b09c45f209021fff8ec0d270d 100644 (file)
@@ -1,5 +1,6 @@
 <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <capabilities>
         <capability>urn:ietf:params:netconf:base:1.0</capability>
+        <capability>urn:ietf:params:netconf:base:1.1</capability>
     </capabilities>
 </hello>
index caa0094c4b2b31a1259df17b536ebdb84d89a8b6..94b73f4b100754e17918b9d5d75bed8542130f46 100644 (file)
                     <name>test1</name>
 
                     <sleep-factor>
-                        2.00
+                        2.58
                     </sleep-factor>
 
                     <extended>
-                            1
+                            10
                     </extended>
 
                     <extended-twice>
-                            1
+                            20
                     </extended-twice>
 
                     <extended-enum>
@@ -48,9 +48,8 @@
                     </extended-enum>
 
                     <simple-long-2>44</simple-long-2>
-                    <binaryLeaf>8</binaryLeaf>
-                    <binaryLeaf>1</binaryLeaf>
-                    <binaryLeaf>0</binaryLeaf>
+                    <binaryLeaf>YmluYXJ5</binaryLeaf>
+
                     <type xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">configAttributeType</type>
                     <dto_d xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
                         <simple-int1>444</simple-int1>
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                         <name>ref_dep</name>
                     </testing-dep>
+
+                    <testing-deps>
+                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+                        <name>ref_dep</name>
+                    </testing-deps>
+                    <testing-deps>
+                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+                        <name>ref_dep_2</name>
+                    </testing-deps>
                 </module>
 
                 <module>
 
                     <testing-dep>
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep</name>
+                        <name>ref_dep_2</name>
                     </testing-dep>
                 </module>
             </modules>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index c825536b7b320e511d0ad3e96335cf692dd6258b..b48730d3f71e74a86fde37131c38602d3f1169c1 100644 (file)
@@ -27,9 +27,7 @@
                     </type>
                     <name>test1</name>
                     <simple-long-2>44</simple-long-2>
-                    <binaryLeaf>8</binaryLeaf>
-                    <binaryLeaf>7</binaryLeaf>
-                    <binaryLeaf>9</binaryLeaf>
+                    <binaryLeaf>8ad1</binaryLeaf>
                     <dto_d>
                         <simple-int1>444</simple-int1>
                         <simple-int2>4444</simple-int2>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 82c218dd73620a3c4d5f45b6330a8ce74daef8f0..df2a5e845257c6b8308ad03eac43a91feb687772 100644 (file)
@@ -32,9 +32,7 @@
                     <name>test1</name>
 
                     <simple-long-2>44</simple-long-2>
-                    <binaryLeaf>8</binaryLeaf>
-                    <binaryLeaf>1</binaryLeaf>
-                    <binaryLeaf>0</binaryLeaf>
+                    <binaryLeaf>8545649856</binaryLeaf>
                     <type xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">configAttributeType</type>
                     <dto_d>
                         <simple-int1>444</simple-int1>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 7c19b9f7b3b9005fda4f339704ad6f887dcc82a8..c399c196d37174a9df5bba448f44d4b7fbdd441d 100644 (file)
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 84ae57555952c30f8bfa8500841405958743d69d..47b82c6114f6048fa4a42fd4a8482ac8665162b0 100644 (file)
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 2d9e9edb2c4a00d92fe77b5a444052f112427c48..02aca8d787863a2683db402b0c3a9a82ed6ff699 100644 (file)
@@ -32,9 +32,7 @@
                     <name>test1</name>
 
                     <simple-long-2>44</simple-long-2>
-                    <binaryLeaf>8</binaryLeaf>
-                    <binaryLeaf>1</binaryLeaf>
-                    <binaryLeaf>0</binaryLeaf>
+                    <binaryLeaf>8545649856</binaryLeaf>
                     <dto_d xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
                         <simple-int1>444</simple-int1>
                         <simple-int2>4444</simple-int2>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 9407dd0c7539d7269e19ed2d96ded86b1d9d4d41..bc05d6393181bc379659b33580bbdda0c22f8e7b 100644 (file)
@@ -27,7 +27,7 @@
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                 </service>
index 233ad23286fa12d4d003400c945d2001215ac7fe..f20d9ff9fa16ea1cb93725d3e81463fb4b03a2bb 100644 (file)
@@ -28,7 +28,7 @@
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                 </service>
index 4593887f49ccae613b92666cbef245d54e2249c1..ff0bd9feb5dc31ab7e19ce14132a9af6d1df3611 100644 (file)
@@ -29,7 +29,7 @@
 
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                 </service>
index 81c4137d4e88c8a0b8414d7d2396a746d02c9c48..906367b7a6257277ae4d391dd7fe3b8301fd343e 100644 (file)
@@ -29,7 +29,7 @@
                     <instance>
                         <name>ref_dep</name>
                         <unknownAttribute>error</unknownAttribute>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                 </service>
index 528d5b06fcc63f0e7f3a50427687a0056881633b..b05046db4b15b18294c3b8f314d39fbf9e2d34d9 100644 (file)
@@ -26,7 +26,7 @@
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                 </service>
index a1e304b374686390c17eb5a4360aad631f41a166..825be6d19fff18b2d8ccb0c078e6266e4e89c3f1 100644 (file)
@@ -32,9 +32,7 @@
                     <name>test1</name>
 
                     <simple-long-2>44</simple-long-2>
-                    <binaryLeaf>8</binaryLeaf>
-                    <binaryLeaf>1</binaryLeaf>
-                    <binaryLeaf>0</binaryLeaf>
+                    <binaryLeaf>8545649856</binaryLeaf>
                     <dto_d>
                         <unknownAttribute>error</unknownAttribute>
                         <simple-int1>444</simple-int1>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 812882a2a97da77bed74c9ec8e4421874ee6969d..9ef2bed7d70dfb7654df642480cacc3df354baae 100644 (file)
@@ -32,9 +32,7 @@
                     <name>test1</name>
 
                     <simple-long-2>44</simple-long-2>
-                    <binaryLeaf>8</binaryLeaf>
-                    <binaryLeaf>1</binaryLeaf>
-                    <binaryLeaf>0</binaryLeaf>
+                    <binaryLeaf>8545649856</binaryLeaf>
                     <dto_d>
                         <simple-int1>444</simple-int1>
                         <simple-int2>4444</simple-int2>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 8a7c3983d1cae6e7c2260c00dbdeb8d1263065f2..259ffde4b447e1d5d8c916ff96a26ee38198b3bf 100644 (file)
@@ -142,17 +142,17 @@ public class Flows implements IDaylightWeb {
         }
 
         Map<String, Object> nodes = new HashMap<String, Object>();
-        Map<Short, String> port;
+        Map<String, String> port;
 
         for (Switch node : switchManager.getNetworkDevices()) {
-            port = new HashMap<Short, String>(); // new port
+            port = new HashMap<String, String>(); // new port
             Set<NodeConnector> nodeConnectorSet = node.getNodeConnectors();
 
             if (nodeConnectorSet != null) {
                 for (NodeConnector nodeConnector : nodeConnectorSet) {
                     String nodeConnectorName = ((Name) switchManager.getNodeConnectorProp(nodeConnector,
                             Name.NamePropName)).getValue();
-                    port.put((Short) nodeConnector.getID(),
+                    port.put( nodeConnector.getID().toString(),
                             nodeConnectorName + "(" + nodeConnector.getNodeConnectorIDString() + ")");
                 }
             }