Merge changes I1474351f,I2ddc5ffa
authorGiovanni Meo <gmeo@cisco.com>
Tue, 17 Dec 2013 13:46:06 +0000 (13:46 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 17 Dec 2013 13:46:06 +0000 (13:46 +0000)
* changes:
  FRM to properly handle timed flows in case of switch down/up
  Adding password salting

238 files changed:
opendaylight/commons/integrationtest/pom.xml
opendaylight/commons/opendaylight/pom.xml
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigRegistry.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigTransactionController.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/LookupRegistry.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceReadableRegistry.java [new file with mode: 0644]
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceWritableRegistry.java [new file with mode: 0644]
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/annotations/ServiceInterfaceAnnotation.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/ModuleFactory.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java [new file with mode: 0644]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java [new file with mode: 0644]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionJMXRegistrator.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelper.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java [new file with mode: 0644]
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigWithJolokiaTest.java [deleted file]
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ClassBasedModuleFactory.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImplLookupTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionManagerImplTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPConfigMXBean.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModuleFactory.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/AbstractParallelAPSPTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/DependentWiringTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/scheduledthreadpool/TestingScheduledThreadPoolModuleFactory.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/ModifiableThreadPoolServiceInterface.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/TestingScheduledThreadPoolServiceInterface.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/TestingThreadPoolServiceInterface.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java [new file with mode: 0644]
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/TestingFixedThreadPoolModuleFactory.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java
opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java
opendaylight/config/config-persister-directory-xml-adapter/pom.xml [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/oneFile/controller.config.xml [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config1.xml [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/pom.xml [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/SnapshotHandler.java [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java [new file with mode: 0644]
opendaylight/config/config-util/pom.xml
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ConfigRegistryJolokiaClient.java [deleted file]
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ConfigTransactionJolokiaClient.java [deleted file]
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ListableJolokiaClient.java [deleted file]
opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java
opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigTransactionClientsTest.java
opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/JolokiaHelper.java [deleted file]
opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/LookupTest.java
opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigRegistry.java
opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java
opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/jolokia/ListableJolokiaClientTest.java [deleted file]
opendaylight/config/pom.xml
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.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/Annotation.java
opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/factory_abs_template.ftl
opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java
opendaylight/config/yang-jmx-generator/pom.xml
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/ModuleUtil.java [new file with mode: 0644]
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.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/JavaAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java
opendaylight/config/yang-test/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/controller/config/test/types/rev131127/UnionTestBuilder.java [new file with mode: 0644]
opendaylight/config/yang-test/src/main/yang/config-test-impl.yang
opendaylight/config/yang-test/src/main/yang/types/test-types.yang
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.conf
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java
opendaylight/md-sal/model/model-flow-base/src/main/yang/match-types.yang
opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-action-types.yang
opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-flow-types.yang
opendaylight/md-sal/model/model-flow-base/src/main/yang/port-types.yang
opendaylight/md-sal/model/model-flow-base/src/main/yang/queue-types.yang
opendaylight/md-sal/model/model-flow-base/src/main/yang/table-types.yang
opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang
opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-statistics.yang
opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-table-statistics.yang [new file with mode: 0644]
opendaylight/md-sal/model/model-flow-statistics/src/main/yang/port-statistics.yang [new file with mode: 0644]
opendaylight/md-sal/model/model-flow-statistics/src/main/yang/queue-statistics.yang [new file with mode: 0644]
opendaylight/md-sal/model/model-flow-statistics/src/main/yang/statistics-types.yang
opendaylight/md-sal/pom.xml
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend [deleted file]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend [deleted file]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/JavassistUtils.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/BindingAwareBrokerImpl.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java [moved from opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java with 58% similarity]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java
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/DOMCodecBug02Test.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/pom.xml
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/yangtools/yang/util/YangSchemaUtils.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ReadConfAndOperDataTest.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatistics.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java
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/AttributesConstants.java [new file with mode: 0644]
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/SimpleUnionAttributeReadingStrategy.java [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/CompositeAttributeMappingStrategy.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/mapping/ObjectNameAttributeMappingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/UnionCompositeAttributeMappingStrategy.java [new file with mode: 0644]
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/ObjectNameAttributeResolvingStrategy.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/resolving/UnionCompositeAttributeResolvingStrategy.java [new file with mode: 0644]
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/SimpleUnionAttributeWritingStrategy.java [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/AbstractEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/DeleteEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/NoneEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/RemoveEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationProvider.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImpl.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/util/Util.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImplTest.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/pom.xml
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.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/PropertiesProviderAdapterImpl.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java
opendaylight/netconf/config-persister-impl/src/test/resources/test2.properties
opendaylight/netconf/config-persister-impl/src/test/resources/test3.properties
opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml [new file with mode: 0644]
opendaylight/netconf/ietf-netconf-monitoring-extension/src/main/yang/ietf-netconf-monitoring-extension.yang [new file with mode: 0644]
opendaylight/netconf/ietf-netconf-monitoring/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/netconf/monitoring/rev101004/netconf/state/schemas/LocationBuilder.java [new file with mode: 0644]
opendaylight/netconf/netconf-api/pom.xml
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java
opendaylight/netconf/netconf-impl/pom.xml
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfMonitoringITTest.java
opendaylight/netconf/netconf-monitoring/pom.xml
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java
opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageAdditionalHeader.java [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_addServiceName.xml [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_threadfactory.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_remove.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_setUnions.xml [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml
opendaylight/netconf/pom.xml
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDP.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDPTLV.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeConnectorCreator.java
opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/Subnet.java
opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java
opendaylight/topologymanager/integrationtest/pom.xml

index 5e101ebd2856e8706e4a0b4d422c1d146a2f35e7..fe5aa473a69c18090552f5e7c7fdf94971b30b34 100644 (file)
       <artifactId>junit</artifactId>
     </dependency>
     <!-- Add Pax Exam -->
-    <dependency>
-      <groupId>org.ops4j.pax.exam</groupId>
-      <artifactId>pax-exam-container-native</artifactId>
-      <scope>test</scope>
-    </dependency>
     <dependency>
       <groupId>org.ops4j.pax.exam</groupId>
       <artifactId>pax-exam-junit4</artifactId>
index dd73815b34475757d6950662bcbcfc0dd165a51f..5183165752446b8e38507d7dd3cc239394051cdb 100644 (file)
           <includeTestSourceDirectory>true</includeTestSourceDirectory>
           <sourceDirectory>${project.basedir}</sourceDirectory>
           <includes>**\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat</includes>
-          <excludes>**\/target\/,**\/bin\/</excludes>
+          <excludes>**\/target\/,**\/bin\/,**\/target-ide\/</excludes>
         </configuration>
       </plugin>
       <plugin>
index 5f23c90bbed10ef8a6068d30317d8448132b59b0..d81c48a6020b6854cc75603a0513a27f8c41da9b 100644 (file)
@@ -19,7 +19,7 @@ import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConsta
  * Provides functionality for working with configuration registry - mainly
  * creating and committing config transactions.
  */
-public interface ConfigRegistry extends LookupRegistry {
+public interface ConfigRegistry extends LookupRegistry, ServiceReferenceReadableRegistry {
 
     /**
      * Only well-known ObjectName in configuration system, under which
@@ -62,8 +62,13 @@ public interface ConfigRegistry extends LookupRegistry {
      */
     boolean isHealthy();
 
+    /**
+     * @return module factory names available in the system
+     */
     Set<String> getAvailableModuleNames();
 
+
+
     /**
      * Find all runtime beans
      *
index 7e8ee64daa089fec089d8d0d57b31cba364f25c9..c257e55dc088b7b7d80bb99fea333e5aacc33c6e 100644 (file)
@@ -16,7 +16,7 @@ import javax.management.ObjectName;
 /**
  * Represents functionality provided by configuration transaction.
  */
-public interface ConfigTransactionController extends LookupRegistry {
+public interface ConfigTransactionController extends LookupRegistry, ServiceReferenceReadableRegistry, ServiceReferenceWritableRegistry {
 
     /**
      * Create new configuration bean.
@@ -64,6 +64,9 @@ public interface ConfigTransactionController extends LookupRegistry {
      */
     String getTransactionName();
 
+    /**
+     * @return all known module factory names as reported by {@link org.opendaylight.controller.config.spi.ModuleFactory#getImplementationName()}
+     */
     Set<String> getAvailableModuleNames();
 
 }
index 7a3c4bf82d4dec0dbc5e3b43462fa57e29f17ddb..772617e97d8492898d2e587ba804798cfbd9d643 100644 (file)
@@ -7,10 +7,9 @@
  */
 package org.opendaylight.controller.config.api;
 
-import java.util.Set;
-
 import javax.management.InstanceNotFoundException;
 import javax.management.ObjectName;
+import java.util.Set;
 
 public interface LookupRegistry {
 
@@ -58,4 +57,17 @@ public interface LookupRegistry {
     ObjectName lookupConfigBean(String moduleName, String instanceName)
             throws InstanceNotFoundException;
 
+    /**
+     * Check that object name corresponds with existing module.
+     *
+     * @throws InstanceNotFoundException
+     *             if search did not find exactly one instance
+     */
+    void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException;
+
+    /**
+     * @return qnames of all ModuleFactory instances in the system
+     */
+    Set<String> getAvailableModuleFactoryQNames();
+
 }
diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceReadableRegistry.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceReadableRegistry.java
new file mode 100644 (file)
index 0000000..f84fcd4
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.api;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+import java.util.Set;
+
+public interface ServiceReferenceReadableRegistry {
+
+    /**
+     * Lookup object name by fully qualified service interface name and service reference name.
+     * @param serviceInterfaceName service interface name
+     * @param refName service reference name supplied in
+     * {@link org.opendaylight.controller.config.api.ConfigTransactionController#saveServiceReference(String, String, javax.management.ObjectName)}
+     * @throws java.lang.IllegalArgumentException if module not found
+     */
+    ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName);
+
+    /**
+     * Get mapping of services to reference names and module object names.
+     */
+    Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> getServiceMapping();
+
+    /**
+     * Get current mapping between reference names and module object names for given service interface name.
+     * @param serviceInterfaceName service interface name
+     * @throws IllegalArgumentException if there is a mismatch between serviceInterfaceName and objectName
+     */
+    Map<String /* refName */, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName);
+
+    /**
+     * Find all available service interface names of a module.
+     * @param objectName module object name
+     * @throws InstanceNotFoundException if search did not find exactly one instance
+     */
+    Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException;
+
+    /**
+     * @param namespace service interface namespace
+     * @param localName service interface local name
+     * @return fully qualified name needed by all other service reference mapping methods.
+     * @throws java.lang.IllegalArgumentException if namespace or localName is not found
+     */
+    String getServiceInterfaceName(String namespace, String localName);
+
+}
diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceWritableRegistry.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceWritableRegistry.java
new file mode 100644 (file)
index 0000000..f3d6d16
--- /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.api;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+
+public interface ServiceReferenceWritableRegistry extends ServiceReferenceReadableRegistry {
+    /**
+     * Create or update reference name to objectName. Reference name is unique per service interface name.
+     * @throws IllegalArgumentException if there is a mismatch between serviceInterfaceName and objectName
+     * @throws InstanceNotFoundException if search did not find exactly one instance
+     */
+    void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException;
+
+    /**
+     * Remove service reference.
+     * @return true iif removed
+     * @throws IllegalArgumentException if service interface name is not advertised by any module
+     */
+    boolean removeServiceReference(String serviceInterfaceName, String refName);
+
+    /**
+     * Remove all service references.
+     */
+    void removeAllServiceReferences();
+
+    /**
+     * Remove all service references attached to given module.
+     * @return true iif at least one reference was removed
+     */
+    boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException;
+}
index a81d992d81ae1cbae4d711e9a18be194524eba71..e66de46520a11741e42c4cf72049ff6d18d2b0df 100644 (file)
@@ -23,8 +23,9 @@ import java.lang.annotation.Target;
 public @interface ServiceInterfaceAnnotation {
 
     /**
-     * Specifies human readable name of this service. Each service name should
-     * be globally unique. Should not contain spaces.
+     * Fully qualified name of a service that must be globally unique.
+     * When generating service interfaces from yang, this will be QName of
+     * identity extending service-type.
      */
     String value();
 
@@ -34,4 +35,19 @@ public @interface ServiceInterfaceAnnotation {
      * is called.
      */
     Class<?> osgiRegistrationType();
+
+    /**
+     * Get namespace of {@link #value()}
+     */
+    String namespace();
+
+    /**
+     * Get revision of {@link #value()}
+     */
+    String revision();
+
+    /**
+     * Get local name of {@link #value()}
+     */
+    String localName();
 }
index 8111690c72bb9b65df66b1afe83f7fc79cc2e3d3..cc1d89761c2ef8784b6f79019101fa76a21361c1 100644 (file)
@@ -7,6 +7,11 @@
  */
 package org.opendaylight.controller.config.api.jmx;
 
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants;
+
+import javax.annotation.concurrent.ThreadSafe;
+import javax.management.ObjectName;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -15,12 +20,6 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
-import javax.annotation.concurrent.ThreadSafe;
-import javax.management.ObjectName;
-
-import org.opendaylight.controller.config.api.ModuleIdentifier;
-import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants;
-
 /**
  * Provides ObjectName creation. Each created ObjectName consists of domain that
  * is defined as {@link #ON_DOMAIN} and at least one key-value pair. The only
@@ -129,18 +128,31 @@ public class ObjectNameUtil {
         return objectName.getKeyProperty(TRANSACTION_NAME_KEY);
     }
 
-    public static ObjectName withoutTransactionName(ObjectName on) {
-        if (getTransactionName(on) == null) {
+    /**
+     * Sanitize on: keep only mandatory attributes of module + metadata.
+     */
+    public static ObjectName withoutTransactionName(ObjectName inputON) {
+        if (getTransactionName(inputON) == null) {
             throw new IllegalArgumentException(
-                    "Expected ObjectName with transaction:" + on);
+                    "Expected ObjectName with transaction:" + inputON);
         }
-        if (ON_DOMAIN.equals(on.getDomain()) == false) {
+        if (ON_DOMAIN.equals(inputON.getDomain()) == false) {
             throw new IllegalArgumentException("Expected different domain: "
-                    + on);
+                    + inputON);
+        }
+        String moduleName = getFactoryName(inputON);
+        String instanceName = getInstanceName(inputON);
+
+
+        Map<String, String> allProperties = getAdditionalProperties(inputON);
+        Map<String, String> outputProperties = new HashMap<>(createModuleON(moduleName, instanceName));
+
+        for(Entry<String, String> entry: allProperties.entrySet()) {
+            if (entry.getKey().startsWith("X-")) {
+                outputProperties.put(entry.getKey(), entry.getValue());
+            }
         }
-        String moduleName = getFactoryName(on);
-        String instanceName = getInstanceName(on);
-        return createReadOnlyModuleON(moduleName, instanceName);
+        return createON(ON_DOMAIN, outputProperties);
     }
 
     private static void assertDoesNotContain(
index 7b8f7c164efd716f6c1f38e6029636a9bc9e2522..c86b38149377733fdc59d3281f97a49d31dcd3d6 100644 (file)
@@ -97,6 +97,8 @@ public interface ModuleFactory {
     boolean isModuleImplementingServiceInterface(
             Class<? extends AbstractServiceInterface> serviceInterface);
 
+    Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces();
+
     /**
      * Called when ModuleFactory is registered to config manager.
      * Useful for populating the registry with pre-existing state. Since
index 1b695a9bda2fe42a2fcdd042636e9bff4b0a511d..e3311c747f872f601b0448e01d7e864163a15a75 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.controller.config.manager.impl;
 import org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.CommitStatus;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
@@ -23,6 +25,7 @@ import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistr
 import org.opendaylight.controller.config.manager.impl.osgi.BeanToOsgiServiceManager;
 import org.opendaylight.controller.config.manager.impl.osgi.BeanToOsgiServiceManager.OsgiRegistration;
 import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil;
+import org.opendaylight.controller.config.manager.impl.util.ModuleQNameUtil;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.osgi.framework.BundleContext;
@@ -59,9 +62,6 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
     private final ModuleFactoriesResolver resolver;
     private final MBeanServer configMBeanServer;
 
-    @GuardedBy("this")
-    private final BundleContext bundleContext;
-
     @GuardedBy("this")
     private long version = 0;
     @GuardedBy("this")
@@ -99,23 +99,26 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
     // internal jmx server shared by all transactions
     private final MBeanServer transactionsMBeanServer;
 
+    // Used for finding new factory instances for default module functionality
     @GuardedBy("this")
     private List<ModuleFactory> lastListOfFactories = Collections.emptyList();
 
+    @GuardedBy("this") // switched in every 2ndPC
+    private ServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry();
+
     // constructor
     public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
-            BundleContext bundleContext, MBeanServer configMBeanServer) {
-        this(resolver, bundleContext, configMBeanServer,
+            MBeanServer configMBeanServer) {
+        this(resolver, configMBeanServer,
                 new BaseJMXRegistrator(configMBeanServer));
     }
 
     // constructor
     public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
-            BundleContext bundleContext, MBeanServer configMBeanServer,
+            MBeanServer configMBeanServer,
             BaseJMXRegistrator baseJMXRegistrator) {
         this.resolver = resolver;
         this.beanToOsgiServiceManager = new BeanToOsgiServiceManager();
-        this.bundleContext = bundleContext;
         this.configMBeanServer = configMBeanServer;
         this.baseJMXRegistrator = baseJMXRegistrator;
         this.registryMBeanServer = MBeanServerFactory
@@ -142,21 +145,32 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
 
     private synchronized ConfigTransactionControllerInternal beginConfigInternal(boolean blankTransaction) {
         versionCounter++;
-        String transactionName = "ConfigTransaction-" + version + "-" + versionCounter;
-        TransactionJMXRegistrator transactionRegistrator = baseJMXRegistrator
-                .createTransactionJMXRegistrator(transactionName);
-        Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories = Collections.unmodifiableMap(resolver.getAllFactories());
+        final String transactionName = "ConfigTransaction-" + version + "-" + versionCounter;
+
+        TransactionJMXRegistratorFactory factory = new TransactionJMXRegistratorFactory() {
+            @Override
+            public TransactionJMXRegistrator create() {
+                return baseJMXRegistrator.createTransactionJMXRegistrator(transactionName);
+            }
+        };
+
+        Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories = Collections.unmodifiableMap(
+                resolver.getAllFactories());
+        ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier(
+                transactionName), factory, allCurrentFactories);
+        ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry(
+                readableSRRegistry, txLookupRegistry, allCurrentFactories);
+
         ConfigTransactionControllerInternal transactionController = new ConfigTransactionControllerImpl(
-                transactionName, transactionRegistrator, version,
-                versionCounter, allCurrentFactories, transactionsMBeanServer, configMBeanServer, blankTransaction);
+                txLookupRegistry, version,
+                versionCounter, allCurrentFactories, transactionsMBeanServer,
+                configMBeanServer, blankTransaction, writableRegistry);
         try {
-            transactionRegistrator.registerMBean(transactionController, transactionController.getControllerObjectName());
+            txLookupRegistry.registerMBean(transactionController, transactionController.getControllerObjectName());
         } catch (InstanceAlreadyExistsException e) {
             throw new IllegalStateException(e);
         }
-
         transactionController.copyExistingModulesAndProcessFactoryDiff(currentConfig.getEntries(), lastListOfFactories);
-
         transactionsHolder.add(transactionName, transactionController);
         return transactionController;
     }
@@ -352,6 +366,10 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
 
         // update version
         version = configTransactionController.getVersion();
+
+        // switch readable Service Reference Registry
+        this.readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(configTransactionController.getWritableRegistry(), this);
+
         return new CommitStatus(newInstances, reusedInstances,
                 recreatedInstances);
     }
@@ -493,6 +511,49 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         return baseJMXRegistrator.queryNames(namePattern, null);
     }
 
+    @Override
+    public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+        ObjectNameUtil.checkDomain(objectName);
+        ObjectNameUtil.checkType(objectName, ObjectNameUtil.TYPE_MODULE);
+        String transactionName = ObjectNameUtil.getTransactionName(objectName);
+        if (transactionName != null) {
+            throw new IllegalArgumentException("Transaction attribute not supported in registry, wrong ObjectName: " + objectName);
+        }
+        // make sure exactly one match is found:
+        LookupBeansUtil.lookupConfigBean(this, ObjectNameUtil.getFactoryName(objectName), ObjectNameUtil.getInstanceName(objectName));
+    }
+
+    // service reference functionality:
+    @Override
+    public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+        return readableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName);
+    }
+
+    @Override
+    public synchronized Map<String, Map<String, ObjectName>> getServiceMapping() {
+        return readableSRRegistry.getServiceMapping();
+    }
+
+    @Override
+    public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+        return readableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName);
+    }
+
+    @Override
+    public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+        return readableSRRegistry.lookupServiceInterfaceNames(objectName);
+    }
+
+    @Override
+    public synchronized String getServiceInterfaceName(String namespace, String localName) {
+        return readableSRRegistry.getServiceInterfaceName(namespace, localName);
+    }
+
+    @Override
+    public Set<String> getAvailableModuleFactoryQNames() {
+        return ModuleQNameUtil.getQNames(resolver.getAllFactories());
+    }
+
 }
 
 /**
@@ -550,6 +611,8 @@ class ConfigHolder {
         Collections.sort(result);
         return result;
     }
+
+
 }
 
 /**
index 3e53a7a217e1855dedb596a2b5f1dedcd707ca85..17ce0781546e231a5f81b2a8ca1b276f5a046d74 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.config.manager.impl;
 
 import org.opendaylight.controller.config.api.DependencyResolver;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.config.manager.impl.dependencyresolver.DependencyResolverManager;
@@ -16,10 +17,8 @@ import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicWrita
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean.ReadOnlyAtomicBooleanImpl;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder;
-import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator;
 import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator;
 import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
-import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.yangtools.concepts.Identifiable;
@@ -34,20 +33,20 @@ import javax.management.InstanceAlreadyExistsException;
 import javax.management.InstanceNotFoundException;
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import static java.lang.String.format;
 
 /**
  * This is a JMX bean representing current transaction. It contains
- * {@link #transactionIdentifier}, unique version and parent version for
+ * transaction identifier, unique version and parent version for
  * optimistic locking.
  */
 class ConfigTransactionControllerImpl implements
@@ -56,10 +55,9 @@ class ConfigTransactionControllerImpl implements
         Identifiable<TransactionIdentifier>{
     private static final Logger logger = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class);
 
-    private final TransactionIdentifier transactionIdentifier;
+    private final ConfigTransactionLookupRegistry txLookupRegistry;
     private final ObjectName controllerON;
-    private final TransactionJMXRegistrator transactionRegistrator;
-    private final TransactionModuleJMXRegistrator txModuleJMXRegistrator;
+
     private final long parentVersion, currentVersion;
     private final HierarchicalConfigMBeanFactoriesHolder factoriesHolder;
     private final DependencyResolverManager dependencyResolverManager;
@@ -80,19 +78,18 @@ class ConfigTransactionControllerImpl implements
 
     private final boolean blankTransaction;
 
-    public ConfigTransactionControllerImpl(String transactionName,
-                                           TransactionJMXRegistrator transactionRegistrator,
+    @GuardedBy("this")
+    private final ServiceReferenceWritableRegistry writableSRRegistry;
+
+    public ConfigTransactionControllerImpl(ConfigTransactionLookupRegistry txLookupRegistry,
                                            long parentVersion, long currentVersion,
                                            Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories,
                                            MBeanServer transactionsMBeanServer, MBeanServer configMBeanServer,
-                                           boolean blankTransaction) {
-
-        this.transactionIdentifier = new TransactionIdentifier(transactionName);
-        this.controllerON = ObjectNameUtil
-                .createTransactionControllerON(transactionName);
-        this.transactionRegistrator = transactionRegistrator;
-        txModuleJMXRegistrator = transactionRegistrator
-                .createTransactionModuleJMXRegistrator();
+                                           boolean blankTransaction, ServiceReferenceWritableRegistry writableSRRegistry) {
+
+        this.txLookupRegistry = txLookupRegistry;
+        String transactionName = txLookupRegistry.getTransactionIdentifier().getName();
+        this.controllerON = ObjectNameUtil.createTransactionControllerON(transactionName);
         this.parentVersion = parentVersion;
         this.currentVersion = currentVersion;
         this.currentlyRegisteredFactories = currentlyRegisteredFactories;
@@ -102,6 +99,7 @@ class ConfigTransactionControllerImpl implements
         this.transactionsMBeanServer = transactionsMBeanServer;
         this.configMBeanServer = configMBeanServer;
         this.blankTransaction = blankTransaction;
+        this.writableSRRegistry = writableSRRegistry;
     }
 
     @Override
@@ -225,14 +223,14 @@ class ConfigTransactionControllerImpl implements
                     + moduleIdentifier + ", got " + dependencyResolver.getIdentifier());
         }
         DynamicMBean writableDynamicWrapper = new DynamicWritableWrapper(
-                module, moduleIdentifier, transactionIdentifier,
+                module, moduleIdentifier, getTransactionIdentifier(),
                 readOnlyAtomicBoolean, transactionsMBeanServer,
                 configMBeanServer);
 
         ObjectName writableON = ObjectNameUtil.createTransactionModuleON(
-                transactionIdentifier.getName(), moduleIdentifier);
+                getTransactionIdentifier().getName(), moduleIdentifier);
         // put wrapper to jmx
-        TransactionModuleJMXRegistration transactionModuleJMXRegistration = txModuleJMXRegistrator
+        TransactionModuleJMXRegistration transactionModuleJMXRegistration = getTxModuleJMXRegistrator()
                 .registerMBean(writableDynamicWrapper, writableON);
         ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
                 moduleIdentifier, module, moduleFactory,
@@ -243,18 +241,21 @@ class ConfigTransactionControllerImpl implements
     }
 
     @Override
-    public synchronized void destroyModule(ObjectName objectName)
-            throws InstanceNotFoundException {
+    public synchronized void destroyModule(ObjectName objectName) throws InstanceNotFoundException {
+        checkTransactionName(objectName);
+        ObjectNameUtil.checkDomain(objectName);
+        ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(objectName,
+                ObjectNameUtil.TYPE_MODULE);
+        destroyModule(moduleIdentifier);
+    }
+
+    private void checkTransactionName(ObjectName objectName) {
         String foundTransactionName = ObjectNameUtil
                 .getTransactionName(objectName);
-        if (transactionIdentifier.getName().equals(foundTransactionName) == false) {
+        if (getTransactionIdentifier().getName().equals(foundTransactionName) == false) {
             throw new IllegalArgumentException("Wrong transaction name "
                     + objectName);
         }
-        ObjectNameUtil.checkDomain(objectName);
-        ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(objectName,
-                ObjectNameUtil.TYPE_MODULE);
-        destroyModule(moduleIdentifier);
     }
 
     private synchronized void destroyModule(ModuleIdentifier moduleIdentifier) {
@@ -268,6 +269,15 @@ class ConfigTransactionControllerImpl implements
                 logger.warn("Warning: removing default bean. This will be forbidden in next version of config-subsystem");
             }
         }
+        // first remove refNames, it checks for objectname existence
+        try {
+            writableSRRegistry.removeServiceReferences(
+                    ObjectNameUtil.createTransactionModuleON(getTransactionName(),moduleIdentifier));
+        } catch (InstanceNotFoundException e) {
+            logger.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry);
+            throw new IllegalStateException("Possible code error: cannot find " + moduleIdentifier, e);
+        }
+
         ModuleInternalTransactionalInfo removedTInfo = dependencyResolverManager.destroyModule(moduleIdentifier);
         // remove from jmx
         removedTInfo.getTransactionModuleJMXRegistration().close();
@@ -297,7 +307,7 @@ class ConfigTransactionControllerImpl implements
 
     private void validate_noLocks() throws ValidationException {
         transactionStatus.checkNotAborted();
-        logger.info("Validating transaction {}", transactionIdentifier);
+        logger.info("Validating transaction {}", getTransactionIdentifier());
         // call validate()
         List<ValidationException> collectedExceptions = new ArrayList<>();
         for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
@@ -317,7 +327,7 @@ class ConfigTransactionControllerImpl implements
             throw ValidationException
                     .createFromCollectedValidationExceptions(collectedExceptions);
         }
-        logger.info("Validated transaction {}", transactionIdentifier);
+        logger.info("Validated transaction {}", getTransactionIdentifier());
     }
 
     /**
@@ -359,7 +369,7 @@ class ConfigTransactionControllerImpl implements
                             + "to obtain a lock");
         }
 
-        logger.info("Committing transaction {}", transactionIdentifier);
+        logger.info("Committing transaction {}", getTransactionIdentifier());
 
         // call getInstance()
         for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
@@ -368,21 +378,21 @@ class ConfigTransactionControllerImpl implements
             ModuleIdentifier name = entry.getKey();
             try {
                 logger.debug("About to commit {} in transaction {}",
-                        name, transactionIdentifier);
+                        name, getTransactionIdentifier());
                 module.getInstance();
             } catch (Exception e) {
                 logger.error("Commit failed on {} in transaction {}", name,
-                        transactionIdentifier, e);
+                        getTransactionIdentifier(), e);
                 internalAbort();
                 throw new RuntimeException(
                         format("Error - getInstance() failed for %s in transaction %s",
-                                name, transactionIdentifier), e);
+                                name, getTransactionIdentifier()), e);
             }
         }
 
         // count dependency order
 
-        logger.info("Committed configuration {}", transactionIdentifier);
+        logger.info("Committed configuration {}", getTransactionIdentifier());
         transactionStatus.setCommitted();
         // unregister this and all modules from jmx
         close();
@@ -403,7 +413,8 @@ class ConfigTransactionControllerImpl implements
     }
 
     private void close() {
-        transactionRegistrator.close();
+        //FIXME: should not close object that was retrieved in constructor, a wrapper object should do that perhaps
+        txLookupRegistry.close();
     }
 
     @Override
@@ -413,7 +424,7 @@ class ConfigTransactionControllerImpl implements
 
     @Override
     public String getTransactionName() {
-        return transactionIdentifier.getName();
+        return getTransactionIdentifier().getName();
     }
 
     /**
@@ -421,7 +432,7 @@ class ConfigTransactionControllerImpl implements
      */
     @Override
     public Set<ObjectName> lookupConfigBeans() {
-        return lookupConfigBeans("*", "*");
+        return txLookupRegistry.lookupConfigBeans();
     }
 
     /**
@@ -429,7 +440,7 @@ class ConfigTransactionControllerImpl implements
      */
     @Override
     public Set<ObjectName> lookupConfigBeans(String moduleName) {
-        return lookupConfigBeans(moduleName, "*");
+        return txLookupRegistry.lookupConfigBeans(moduleName);
     }
 
     /**
@@ -438,20 +449,29 @@ class ConfigTransactionControllerImpl implements
     @Override
     public ObjectName lookupConfigBean(String moduleName, String instanceName)
             throws InstanceNotFoundException {
-        return LookupBeansUtil.lookupConfigBean(this, moduleName, instanceName);
+        return txLookupRegistry.lookupConfigBean(moduleName, instanceName);
     }
 
     /**
      * {@inheritDoc}
      */
     @Override
-    public Set<ObjectName> lookupConfigBeans(String moduleName,
-            String instanceName) {
-        ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName,
-                instanceName, transactionIdentifier.getName());
-        return txModuleJMXRegistrator.queryNames(namePattern, null);
+    public Set<ObjectName> lookupConfigBeans(String moduleName, String instanceName) {
+        return txLookupRegistry.lookupConfigBeans(moduleName, instanceName);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+        txLookupRegistry.checkConfigBeanExists(objectName);
+    }
+    // --
+
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Set<String> getAvailableModuleNames() {
         return factoriesHolder.getModuleNames();
@@ -473,11 +493,11 @@ class ConfigTransactionControllerImpl implements
     // @VisibleForTesting
 
     TransactionModuleJMXRegistrator getTxModuleJMXRegistrator() {
-        return txModuleJMXRegistrator;
+        return txLookupRegistry.getTxModuleJMXRegistrator();
     }
 
     public TransactionIdentifier getName() {
-        return transactionIdentifier;
+        return getTransactionIdentifier();
     }
 
     @Override
@@ -487,7 +507,7 @@ class ConfigTransactionControllerImpl implements
 
     @Override
     public TransactionIdentifier getIdentifier() {
-        return transactionIdentifier;
+        return getTransactionIdentifier();
     }
 
     @Override
@@ -498,4 +518,67 @@ class ConfigTransactionControllerImpl implements
         }
         return factoryBundleContextEntry.getValue();
     }
+
+    // service reference functionality:
+
+
+    @Override
+    public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+        return writableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName);
+    }
+
+    @Override
+    public synchronized Map<String, Map<String, ObjectName>> getServiceMapping() {
+        return writableSRRegistry.getServiceMapping();
+    }
+
+    @Override
+    public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+        return writableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName);
+    }
+
+    @Override
+    public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+        return writableSRRegistry.lookupServiceInterfaceNames(objectName);
+    }
+
+    @Override
+    public synchronized String getServiceInterfaceName(String namespace, String localName) {
+        return writableSRRegistry.getServiceInterfaceName(namespace, localName);
+    }
+
+    @Override
+    public synchronized void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException {
+        writableSRRegistry.saveServiceReference(serviceInterfaceName, refName, objectName);
+    }
+
+    @Override
+    public synchronized boolean removeServiceReference(String serviceInterfaceName, String refName) {
+        return writableSRRegistry.removeServiceReference(serviceInterfaceName, refName);
+    }
+
+    @Override
+    public synchronized void removeAllServiceReferences() {
+        writableSRRegistry.removeAllServiceReferences();
+    }
+
+    @Override
+    public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
+        return writableSRRegistry.removeServiceReferences(objectName);
+    }
+
+    @Override
+    public ServiceReferenceWritableRegistry getWritableRegistry() {
+        return writableSRRegistry;
+    }
+
+    public TransactionIdentifier getTransactionIdentifier() {
+        return txLookupRegistry.getTransactionIdentifier();
+    }
+
+    @Override
+    public Set<String> getAvailableModuleFactoryQNames() {
+        return txLookupRegistry.getAvailableModuleFactoryQNames();
+    }
+
 }
index 4dc877c62b339bebad0a55848c6debc25b96300a..82bae44a01b60148b9105e4e8ef98cc1530daf9f 100644 (file)
@@ -13,6 +13,7 @@ import java.util.List;
 import javax.management.ObjectName;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.osgi.framework.BundleContext;
@@ -71,4 +72,7 @@ interface ConfigTransactionControllerInternal extends
     List<ModuleFactory> getCurrentlyRegisteredFactories();
 
     BundleContext getModuleFactoryBundleContext(String factoryName);
+
+    ServiceReferenceWritableRegistry getWritableRegistry();
+
 }
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java
new file mode 100644 (file)
index 0000000..12db6c8
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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.manager.impl;
+
+import org.opendaylight.controller.config.api.LookupRegistry;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator;
+import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil;
+import org.opendaylight.controller.config.manager.impl.util.ModuleQNameUtil;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.BundleContext;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.io.Closeable;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Responsible for creating TransactionJMXRegistrator, registering transaction and all its beans,
+ * lookup of beans, closing of TransactionJMXRegistrator.
+ */
+class ConfigTransactionLookupRegistry  implements LookupRegistry, Closeable {
+    private final TransactionJMXRegistrator transactionJMXRegistrator;
+    private final TransactionIdentifier transactionIdentifier;
+    private final TransactionModuleJMXRegistrator txModuleJMXRegistrator;
+    private final Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories;
+
+    ConfigTransactionLookupRegistry(TransactionIdentifier transactionIdentifier,
+                                    TransactionJMXRegistratorFactory factory, Map<String, Entry<ModuleFactory, BundleContext>> allCurrentFactories) {
+        this.transactionIdentifier = transactionIdentifier;
+        this.transactionJMXRegistrator = factory.create();
+        this.txModuleJMXRegistrator = transactionJMXRegistrator.createTransactionModuleJMXRegistrator();
+        this.allCurrentFactories = allCurrentFactories;
+    }
+
+    private void checkTransactionName(ObjectName objectName) {
+        String foundTransactionName = ObjectNameUtil
+                .getTransactionName(objectName);
+        if (transactionIdentifier.getName().equals(foundTransactionName) == false) {
+            throw new IllegalArgumentException("Wrong transaction name "
+                    + objectName);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Set<ObjectName> lookupConfigBeans() {
+        return lookupConfigBeans("*", "*");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Set<ObjectName> lookupConfigBeans(String moduleName) {
+        return lookupConfigBeans(moduleName, "*");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ObjectName lookupConfigBean(String moduleName, String instanceName)
+            throws InstanceNotFoundException {
+        return LookupBeansUtil.lookupConfigBean(this, moduleName, instanceName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Set<ObjectName> lookupConfigBeans(String moduleName,
+                                             String instanceName) {
+        ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName,
+                instanceName, transactionIdentifier.getName());
+        return txModuleJMXRegistrator.queryNames(namePattern, null);
+    }
+
+    @Override
+    public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+        ObjectNameUtil.checkDomain(objectName);
+        ObjectNameUtil.checkType(objectName, ObjectNameUtil.TYPE_MODULE);
+        checkTransactionName(objectName);
+        // make sure exactly one match is found:
+        LookupBeansUtil.lookupConfigBean(this, ObjectNameUtil.getFactoryName(objectName), ObjectNameUtil.getInstanceName(objectName));
+    }
+
+    TransactionIdentifier getTransactionIdentifier() {
+        return transactionIdentifier;
+    }
+
+    TransactionModuleJMXRegistrator getTxModuleJMXRegistrator() {
+        return txModuleJMXRegistrator;
+    }
+
+    public void close() {
+        transactionJMXRegistrator.close();
+    }
+
+    public void registerMBean(ConfigTransactionControllerInternal transactionController, ObjectName controllerObjectName) throws InstanceAlreadyExistsException {
+        transactionJMXRegistrator.registerMBean(transactionController, controllerObjectName);
+    }
+
+    @Override
+    public Set<String> getAvailableModuleFactoryQNames() {
+        return ModuleQNameUtil.getQNames(allCurrentFactories);
+    }
+
+}
+
+interface TransactionJMXRegistratorFactory {
+    TransactionJMXRegistrator create();
+}
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java
new file mode 100644 (file)
index 0000000..7fedcdf
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * 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.manager.impl;
+
+import org.opendaylight.controller.config.api.LookupRegistry;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
+import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableRegistry, ServiceReferenceWritableRegistry {
+    private static final Logger logger = LoggerFactory.getLogger(ServiceReferenceRegistryImpl.class);
+
+    private final Map<String, ModuleFactory> factories;
+    private final Map<String, Set<String>> factoryNamesToQNames;
+    // validator of incoming ObjectNames - throws InstanceNotFoundException if not found either in registry or transaction
+    private final LookupRegistry lookupRegistry;
+    // helper method for getting QName of SI from namespace + local name
+    private final Map<String /* namespace */, Map<String /* local name */, ServiceInterfaceAnnotation>> namespacesToAnnotations;
+    // all Service Interface qNames for sanity checking
+    private final Set<String /* qName */> allQNames;
+
+    // actual reference database
+    private final Map<String /* qName */, Map<String /* refName */, ModuleIdentifier>> refNames;
+
+    /**
+     * Static constructor for config registry. Since only transaction can write to this registry, it will
+     * return blank state.
+     */
+    public static ServiceReferenceReadableRegistry createInitialSRLookupRegistry() {
+        // since this is initial state, just throw exception:
+        LookupRegistry lookupRegistry = new LookupRegistry() {
+            @Override
+            public Set<ObjectName> lookupConfigBeans() {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public Set<ObjectName> lookupConfigBeans(String moduleName) {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public Set<ObjectName> lookupConfigBeans(String moduleName, String instanceName) {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public ObjectName lookupConfigBean(String moduleName, String instanceName) throws InstanceNotFoundException {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+                throw new InstanceNotFoundException("Cannot find " + objectName);
+            }
+
+            @Override
+            public Set<String> getAvailableModuleFactoryQNames() {
+                throw new UnsupportedOperationException();
+            }
+        };
+        return new ServiceReferenceRegistryImpl(Collections.<String, ModuleFactory>emptyMap(), lookupRegistry,
+                Collections.<String /* qName */, Map<String /* refName */, ModuleIdentifier>>emptyMap());
+    }
+
+    /**
+     * Static constructor for transaction controller. Take current state as seen by config registry, allow writing new data.
+     */
+    public static ServiceReferenceWritableRegistry createSRWritableRegistry(ServiceReferenceReadableRegistry oldReadableRegistry,
+            LookupRegistry lookupRegistry, Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories) {
+
+        ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldReadableRegistry;
+        Map<String, ModuleFactory> factories = extractFactoriesMap(currentlyRegisteredFactories);
+        return new ServiceReferenceRegistryImpl(factories, lookupRegistry, Collections.unmodifiableMap(old.refNames));
+    }
+
+    /**
+     * Copy back state to config registry after commit.
+     */
+    public static ServiceReferenceReadableRegistry createSRReadableRegistry(ServiceReferenceWritableRegistry oldWritableRegistry, LookupRegistry lookupRegistry) {
+        ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldWritableRegistry;
+        // even if factories do change, nothing in the mapping can change between transactions
+        return new ServiceReferenceRegistryImpl(old.factories, lookupRegistry, Collections.unmodifiableMap(old.refNames));
+    }
+
+    private static Map<String, ModuleFactory> extractFactoriesMap(Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories) {
+        Map<String, ModuleFactory> result = new HashMap<>();
+        for (Entry<String, Entry<ModuleFactory, BundleContext>> entry : currentlyRegisteredFactories.entrySet()) {
+            result.put(entry.getKey(), entry.getValue().getKey());
+        }
+        return result;
+    }
+
+    private ServiceReferenceRegistryImpl(Map<String, ModuleFactory> factories, LookupRegistry lookupRegistry,
+                                         Map<String /* qName */, Map<String /* refName */, ModuleIdentifier>> refNamesToCopy) {
+        this.factories = factories;
+        this.lookupRegistry = lookupRegistry;
+        Map<String, Set<String /* QName */>> factoryNamesToQNames = new HashMap<>();
+        Set<ServiceInterfaceAnnotation> allAnnotations = new HashSet<>();
+        Set<String /* qName */> allQNames = new HashSet<>();
+        for (Entry<String, ModuleFactory> entry : factories.entrySet()) {
+            if (entry.getKey().equals(entry.getValue().getImplementationName()) == false) {
+                logger.error("Possible error in code: Mismatch between supplied and actual name of {}", entry);
+                throw new IllegalArgumentException("Possible error in code: Mismatch between supplied and actual name of " + entry);
+            }
+            Set<ServiceInterfaceAnnotation> siAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(entry.getValue());
+            Set<String> qNames = new HashSet<>();
+            for (ServiceInterfaceAnnotation sia: siAnnotations) {
+                qNames.add(sia.value());
+            }
+            allAnnotations.addAll(siAnnotations);
+            allQNames.addAll(qNames);
+            factoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames));
+        }
+        this.factoryNamesToQNames = Collections.unmodifiableMap(factoryNamesToQNames);
+        this.allQNames = Collections.unmodifiableSet(allQNames);
+        // fill namespacesToAnnotations
+        Map<String /* namespace */, Map<String /* localName */, ServiceInterfaceAnnotation>> namespacesToAnnotations =
+                new HashMap<>();
+        for (ServiceInterfaceAnnotation sia : allAnnotations) {
+            Map<String, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(sia.namespace());
+            if (ofNamespace == null) {
+                ofNamespace = new HashMap<>();
+                namespacesToAnnotations.put(sia.namespace(), ofNamespace);
+            }
+            if (ofNamespace.containsKey(sia.localName())) {
+                logger.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}",
+                        sia.namespace(), sia.localName(), namespacesToAnnotations);
+                throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName());
+            }
+            ofNamespace.put(sia.localName(), sia);
+        }
+        this.namespacesToAnnotations = Collections.unmodifiableMap(namespacesToAnnotations);
+        // copy refNames
+        Map<String /* qName */, Map<String /* refName */, ModuleIdentifier>> deepCopy = new HashMap<>();
+        for (Entry<String, Map<String, ModuleIdentifier>> outerROEntry: refNamesToCopy.entrySet()) {
+            Map<String /* refName */, ModuleIdentifier> innerWritableMap = new HashMap<>();
+            deepCopy.put(outerROEntry.getKey(), innerWritableMap);
+            for (Entry<String, ModuleIdentifier> innerROEntry:  outerROEntry.getValue().entrySet()) {
+                innerWritableMap.put(innerROEntry.getKey(), innerROEntry.getValue());
+            }
+        }
+        this.refNames = deepCopy;
+        logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames);
+        logger.trace("refNames:{}", refNames);
+    }
+
+
+    @Override
+    public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+        lookupRegistry.checkConfigBeanExists(objectName);
+
+        String factoryName = ObjectNameUtil.getFactoryName(objectName);
+        Set<String> serviceInterfaceAnnotations = factoryNamesToQNames.get(factoryName);
+        if (serviceInterfaceAnnotations == null) {
+            logger.error("Possible error in code: cannot find factory annotations of '{}' extracted from ON {} in {}",
+                    factoryName, objectName, factoryNamesToQNames);
+            throw new IllegalArgumentException("Cannot find factory with name " + factoryName);
+        }
+        return serviceInterfaceAnnotations;
+    }
+
+    @Override
+    public String getServiceInterfaceName(String namespace, String localName) {
+        Map<String /* localName */, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(namespace);
+        if (ofNamespace == null) {
+            logger.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations);
+            throw new IllegalArgumentException("Cannot find namespace " + namespace);
+        }
+        ServiceInterfaceAnnotation sia = ofNamespace.get(localName);
+        if (sia == null) {
+            logger.error("Cannot find local name {} in namespace {}, found only {}", localName, namespace, ofNamespace);
+            throw new IllegalArgumentException("Cannot find local name " + localName + " in namespace " + namespace);
+        }
+        return sia.value();
+    }
+
+
+
+    // reading:
+
+    @Override
+    public Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> getServiceMapping() {
+        Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> result = new HashMap<>();
+        for (Entry<String /* qName */, Map<String, ModuleIdentifier>> outerEntry: refNames.entrySet()) {
+            String qName = outerEntry.getKey();
+            Map<String /* refName */, ObjectName> innerMap = new HashMap<>();
+            result.put(qName, innerMap);
+            for (Entry<String /* refName */, ModuleIdentifier> innerEntry: outerEntry.getValue().entrySet()) {
+                ModuleIdentifier moduleIdentifier = innerEntry.getValue();
+                ObjectName on;
+                on = getObjectName(moduleIdentifier);
+                innerMap.put(innerEntry.getKey(), on);
+            }
+        }
+        return result;
+    }
+
+    private ObjectName getObjectName(ModuleIdentifier moduleIdentifier) {
+        ObjectName on;
+        try {
+            on = lookupRegistry.lookupConfigBean(moduleIdentifier.getFactoryName(), moduleIdentifier.getInstanceName());
+        } catch (InstanceNotFoundException e) {
+            logger.error("Cannot find instance {}", moduleIdentifier);
+            throw new IllegalStateException("Cannot find instance " + moduleIdentifier, e);
+        }
+        return on;
+    }
+
+    @Override
+    public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+        Map<String, ModuleIdentifier> innerMap = refNames.get(serviceInterfaceName);
+        if (innerMap == null) {
+            logger.error("Cannot find qname {} in {}", serviceInterfaceName, refName);
+            throw new IllegalArgumentException("Cannot find " + serviceInterfaceName);
+        }
+        ModuleIdentifier moduleIdentifier = innerMap.get(refName);
+        if (moduleIdentifier == null) {
+            logger.error("Cannot find refName {} in {}, using qname {}", refName, innerMap, serviceInterfaceName);
+            throw new IllegalArgumentException("Cannot find module based on service reference " + refName);
+        }
+        return getObjectName(moduleIdentifier);
+    }
+
+    @Override
+    public  Map<String /* refName */, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+        Map<String, ModuleIdentifier> innerMap = refNames.get(serviceInterfaceName);
+        if (innerMap == null) {
+            logger.error("Cannot find qname {} in {}", serviceInterfaceName, refNames);
+            throw new IllegalArgumentException("Cannot find " + serviceInterfaceName);
+        }
+        Map<String /* refName */, ObjectName> result = new HashMap<>();
+        for (Entry<String/* refName */, ModuleIdentifier> entry: innerMap.entrySet()) {
+            ObjectName on = getObjectName(entry.getValue());
+            result.put(entry.getKey(), on);
+        }
+        return result;
+    }
+
+    // writing:
+
+    @Override
+    public void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName)  throws InstanceNotFoundException {
+        // make sure it is found
+        lookupRegistry.checkConfigBeanExists(objectName);
+        String factoryName = ObjectNameUtil.getFactoryName(objectName);
+        // check that service interface name exist
+        Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(factoryName);
+        if (serviceInterfaceQNames == null) {
+            logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, objectName);
+            throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName);
+        }
+        // supplied serviceInterfaceName must exist in this collection
+        if (serviceInterfaceQNames.contains(serviceInterfaceName) == false) {
+            logger.error("Cannot find qname {} with factory name {}, found {}", serviceInterfaceName, factoryName, serviceInterfaceQNames);
+            throw new IllegalArgumentException("Cannot find service interface " + serviceInterfaceName + " within factory " + factoryName );
+        }
+        String instanceName = ObjectNameUtil.getInstanceName(objectName);
+        ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
+        Map<String /* refName */, ModuleIdentifier> ofQName = refNames.get(serviceInterfaceName);
+        // might be null
+        if (ofQName == null) {
+            ofQName = new HashMap<>();
+            refNames.put(serviceInterfaceName, ofQName);
+        }
+        ofQName.put(refName, moduleIdentifier);
+    }
+
+    @Override
+    public boolean removeServiceReference(String serviceInterfaceName, String refName) {
+        // is the qname known?
+        if (allQNames.contains(serviceInterfaceName) == false) {
+            logger.error("Cannot find qname {} in {}", serviceInterfaceName, allQNames);
+            throw new IllegalArgumentException("Cannot find service interface " + serviceInterfaceName);
+        }
+        Map<String, ModuleIdentifier> ofQName = refNames.get(serviceInterfaceName);
+        if (ofQName == null) {
+            return false;
+        }
+        return ofQName.remove(refName) != null;
+    }
+
+    @Override
+    public void removeAllServiceReferences() {
+        refNames.clear();
+    }
+
+    @Override
+    public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
+        lookupRegistry.checkConfigBeanExists(objectName);
+        String factoryName = ObjectNameUtil.getFactoryName(objectName);
+        // check that service interface name exist
+        Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(factoryName);
+        if (serviceInterfaceQNames == null) {
+            logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, objectName);
+            throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName);
+        }
+        String instanceName = ObjectNameUtil.getInstanceName(objectName);
+        ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
+        boolean found = false;
+        for(String qName: serviceInterfaceQNames){
+            Map<String, ModuleIdentifier> ofQName = refNames.get(qName);
+            if (ofQName != null) {
+                for(Iterator<Entry<String, ModuleIdentifier>> it = ofQName.entrySet ().iterator(); it.hasNext();){
+                    Entry<String, ModuleIdentifier> next = it.next();
+                    if (next.getValue().equals(moduleIdentifier)) {
+                        found = true;
+                        it.remove();
+                    }
+                }
+            }
+        }
+        return found;
+    }
+
+    @Override
+    public String toString() {
+        return "ServiceReferenceRegistryImpl{" +
+                "refNames=" + refNames +
+                ", factoryNamesToQNames=" + factoryNamesToQNames +
+                '}';
+    }
+}
index 065a0f843f501cdb7e2a4230c9cc0b72caf31f3c..760fe50e28f533021684f1d1a0bb25685272fac8 100644 (file)
@@ -48,6 +48,7 @@ final class DependencyResolverImpl implements DependencyResolver,
     /**
      * {@inheritDoc}
      */
+    //TODO: check for cycles
     @Override
     public void validateDependency(
             Class<? extends AbstractServiceInterface> expectedServiceInterface,
@@ -101,6 +102,7 @@ final class DependencyResolverImpl implements DependencyResolver,
     /**
      * {@inheritDoc}
      */
+    //TODO: check for cycles
     @Override
     public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentON,
             JmxAttribute jmxAttribute) {
index f82a7295aaeaa47e4e7169e86dd5452666a7fd16..16f7cf024a40958118467641736eae6ebecfcd98 100644 (file)
@@ -13,6 +13,7 @@ import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.List;
 import java.util.Map;
@@ -76,4 +77,7 @@ public class HierarchicalConfigMBeanFactoriesHolder {
         return moduleFactories;
     }
 
+    public Map<String, Entry<ModuleFactory, BundleContext>> getModuleNamesToConfigBeanFactories() {
+        return moduleNamesToConfigBeanFactories;
+    }
 }
index 523cbc5b013c48724a68a5c5518003afdb435b61..b371c3f1709c3160bc2c2a372f0d7647dec24253 100644 (file)
@@ -65,7 +65,7 @@ public class TransactionJMXRegistrator implements Closeable {
     }
 
     @Override
-    public void close() {
+    public void close() { // closes also all child TransactionModuleJMXRegistrator instances
         childJMXRegistrator.close();
     }
 }
index ab81143170b91d3c4565049539b16bc410469abe..1ee6cca7e22f86b1eb634b3c94c71ee503cd1a84 100644 (file)
@@ -36,8 +36,7 @@ public class ConfigManagerActivator implements BundleActivator {
                 new BundleContextBackedModuleFactoriesResolver(context);
         MBeanServer configMBeanServer = ManagementFactory.getPlatformMBeanServer();
         configRegistry = new ConfigRegistryImpl(
-                bundleContextBackedModuleFactoriesResolver, context,
-                configMBeanServer);
+                bundleContextBackedModuleFactoriesResolver, configMBeanServer);
 
         // register config registry to OSGi
         configRegistryServiceRegistration = context.registerService(ConfigRegistryImpl.class, configRegistry, null);
index 76cb64cf9349ae62cc99d7f66eb12e7f66a0ed74..033f7222fcc7fd64103e25336a3b81f669d14adc 100644 (file)
@@ -7,17 +7,18 @@
  */
 package org.opendaylight.controller.config.manager.impl.util;
 
+import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
+import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+
+import javax.management.JMX;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
 
-import javax.management.JMX;
-
-import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
-import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
-import org.opendaylight.controller.config.spi.Module;
-
 public class InterfacesHelper {
 
     public static Set<Class<?>> getAllInterfaces(Class<?> clazz) {
@@ -32,16 +33,25 @@ public class InterfacesHelper {
             // get parent class
             clazz = clazz.getSuperclass();
         }
+        return getAllSuperInterfaces(toBeInspected);
+
+    }
+
+    private static Set<Class<?>> getAllSuperInterfaces(Set<Class<?>> ifcs) {
+        ifcs = new HashSet<>(ifcs); // create copy to modify
         // each interface can extend other interfaces
-        Set<Class<?>> inspected = new HashSet<>();
-        while (toBeInspected.size() > 0) {
-            Iterator<Class<?>> iterator = toBeInspected.iterator();
+        Set<Class<?>> result = new HashSet<>();
+        while (ifcs.size() > 0) {
+            Iterator<Class<?>> iterator = ifcs.iterator();
             Class<?> ifc = iterator.next();
             iterator.remove();
-            toBeInspected.addAll(Arrays.asList(ifc.getInterfaces()));
-            inspected.add(ifc);
+            if (ifc.isInterface() == false)  {
+                throw new IllegalArgumentException(ifc + " should be an interface");
+            }
+            ifcs.addAll(Arrays.asList(ifc.getInterfaces()));
+            result.add(ifc);
         }
-        return inspected;
+        return result;
     }
 
     /**
@@ -80,6 +90,18 @@ public class InterfacesHelper {
         return result;
     }
 
+    public static Set<Class<? extends AbstractServiceInterface>> getAllAbstractServiceClasses(Class<? extends Module> configBeanClass) {
+
+        Set<Class<? extends AbstractServiceInterface>> foundGeneratedSIClasses = new HashSet<>();
+        for (Class<?> clazz : getAllInterfaces(configBeanClass)) {
+            if (AbstractServiceInterface.class.isAssignableFrom(clazz) && AbstractServiceInterface.class.equals(clazz) == false) {
+                foundGeneratedSIClasses.add((Class<? extends AbstractServiceInterface>) clazz);
+            }
+        }
+        return getAllAbstractServiceInterfaceClasses(foundGeneratedSIClasses);
+    }
+
+
     /**
      * Get OSGi registration types under which config bean instance should be
      * registered. This is specified in
@@ -98,4 +120,37 @@ public class InterfacesHelper {
         return result;
     }
 
+
+    public static Set<ServiceInterfaceAnnotation> getServiceInterfaceAnnotations(ModuleFactory factory) {
+        Set<Class<? extends AbstractServiceInterface>> implementedServiceIntefaces = Collections.unmodifiableSet(factory.getImplementedServiceIntefaces());
+        return getServiceInterfaceAnnotations(implementedServiceIntefaces);
+    }
+
+    private static Set<ServiceInterfaceAnnotation> getServiceInterfaceAnnotations(Set<Class<? extends AbstractServiceInterface>> implementedServiceIntefaces) {
+        Set<Class<? extends AbstractServiceInterface>> inspected = getAllAbstractServiceInterfaceClasses(implementedServiceIntefaces);
+        Set<ServiceInterfaceAnnotation> result = new HashSet<>();
+        // SIs can form hierarchies, inspect superclass until it does not extend AbstractSI
+        for (Class<?> clazz : inspected) {
+            ServiceInterfaceAnnotation annotation = clazz.getAnnotation(ServiceInterfaceAnnotation.class);
+            if (annotation != null) {
+                result.add(annotation);
+            }
+        }
+        return result;
+    }
+
+    static Set<Class<? extends AbstractServiceInterface>> getAllAbstractServiceInterfaceClasses(
+            Set<Class<? extends AbstractServiceInterface>> directlyImplementedAbstractSIs) {
+
+        Set<Class<?>> allInterfaces = getAllSuperInterfaces((Set) directlyImplementedAbstractSIs);
+        Set<Class<? extends AbstractServiceInterface>> result = new HashSet<>();
+        for(Class<?> ifc: allInterfaces){
+            if (AbstractServiceInterface.class.isAssignableFrom(ifc) &&
+                    ifc.equals(AbstractServiceInterface.class) == false) {
+                result.add((Class<? extends AbstractServiceInterface>) ifc);
+            }
+
+        }
+        return result;
+    }
 }
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java
new file mode 100644 (file)
index 0000000..e843377
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.manager.impl.util;
+
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class ModuleQNameUtil {
+
+    public static Set<String> getQNames(Map<String, Entry<ModuleFactory, BundleContext>> resolved) {
+        Set<String> result = new HashSet<>();
+        for (Entry<ModuleFactory, BundleContext> entry : resolved.values()) {
+            Class<?> inspected = entry.getKey().getClass();
+            if (inspected.isInterface()) {
+                throw new IllegalArgumentException("Unexpected interface " + inspected);
+            }
+            ModuleQName annotation = null;
+            while(annotation == null && inspected != null) {
+                annotation = inspected.getAnnotation(ModuleQName.class);
+                inspected = inspected.getSuperclass();
+            }
+            if (annotation != null) {
+                // FIXME
+                String qName = "(" + annotation.namespace() + "?revision=" + annotation.revision() + ")" + annotation.name();
+                result.add(qName);
+            }
+        }
+        return result;
+    }
+
+}
index ccb67d371e5e63b9abac0be0a6baeba85f9a352b..e6b07bab645fff3e4e0fe2e781dbafad457e964f 100644 (file)
@@ -40,7 +40,7 @@ public class ConfigRegistryImplTest extends
                     factory, factory);
 
             configRegistry = new ConfigRegistryImpl(resolver,
-                    context, ManagementFactory.getPlatformMBeanServer());
+                    ManagementFactory.getPlatformMBeanServer());
 
             configRegistry.beginConfig();
             fail();
index 5ed56bd2bf6f81081be3369a9fa7ffc848c33ace..a7e3fa6c6fa29343f62bffb163fb35719aadae88 100644 (file)
@@ -70,7 +70,7 @@ public abstract class AbstractConfigTest extends
         internalJmxRegistrator = new InternalJMXRegistrator(platformMBeanServer);
         baseJmxRegistrator = new BaseJMXRegistrator(internalJmxRegistrator);
 
-        configRegistry = new ConfigRegistryImpl(resolver, mockedContext,
+        configRegistry = new ConfigRegistryImpl(resolver,
                 platformMBeanServer, baseJmxRegistrator);
         try {
             configRegistryJMXRegistrator.registerToJMX(configRegistry);
diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigWithJolokiaTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigWithJolokiaTest.java
deleted file mode 100644 (file)
index de26220..0000000
+++ /dev/null
@@ -1,38 +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.config.manager.impl;
-
-import org.junit.After;
-import org.junit.Before;
-import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver;
-import org.opendaylight.controller.config.util.JolokiaHelper;
-import org.opendaylight.controller.config.util.jolokia.ConfigRegistryJolokiaClient;
-
-public class AbstractConfigWithJolokiaTest extends AbstractConfigTest {
-    protected String jolokiaURL;
-    protected ConfigRegistryJolokiaClient configRegistryJolokiaClient;
-
-    @Before
-    public void initJolokia() {
-        jolokiaURL = JolokiaHelper.startTestingJolokia();
-    }
-
-    // this method should be called in @Before
-    @Override
-    protected void initConfigTransactionManagerImpl(
-            ModuleFactoriesResolver resolver) {
-        super.initConfigTransactionManagerImpl(resolver);
-        configRegistryJolokiaClient = new ConfigRegistryJolokiaClient(
-                jolokiaURL);
-    }
-
-    @After
-    public void cleanUpJolokia() {
-        JolokiaHelper.stopJolokia();
-    }
-}
index d23b5ca1282739935e73a27278fab6a7d2fcb904..672f15091430f26532a20cf3636cbad0e6eee477 100644 (file)
@@ -13,6 +13,7 @@ import org.opendaylight.controller.config.api.DependencyResolverFactory;
 import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.osgi.framework.BundleContext;
@@ -107,4 +108,9 @@ public class ClassBasedModuleFactory implements ModuleFactory {
     public Set<Module> getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) {
         return new HashSet<Module>();
     }
+
+    @Override
+    public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+        return InterfacesHelper.getAllAbstractServiceClasses(configBeanClass);
+    }
 }
index 6dddc62f67914c989f22e2cace7e4df08918dadc..a522356a276fe1bb39f1289b9bb8c65915d81039 100644 (file)
@@ -66,7 +66,7 @@ public class ConfigRegistryImplLookupTest extends
 
     @Before
     public void setUp() throws Exception {
-        configRegistryImpl = new ConfigRegistryImpl(null, null,
+        configRegistryImpl = new ConfigRegistryImpl(null,
                 ManagementFactory.getPlatformMBeanServer());
         Field field = configRegistryImpl.getClass().getDeclaredField(
                 "baseJMXRegistrator");
index 22a959060cfaca6d598e8e84a41225352bd00eb1..50f5742149176ef0052235593651392d57f72541 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.collect.Sets;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator;
 import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator;
@@ -61,13 +62,22 @@ public class ConfigTransactionControllerImplTest extends
                 ManagementFactory.getPlatformMBeanServer());
         transactionsMBeanServer = MBeanServerFactory.createMBeanServer();
         Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories = new HashMap<>();
-        TransactionJMXRegistrator jmxRegistrator123 = baseJMXRegistrator
-                .createTransactionJMXRegistrator(transactionName123);
+
+        ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier(transactionName123), new TransactionJMXRegistratorFactory() {
+            @Override
+            public TransactionJMXRegistrator create() {
+                return baseJMXRegistrator.createTransactionJMXRegistrator(transactionName123);
+            }
+        }, currentlyRegisteredFactories);
+
+        ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry(
+                ServiceReferenceRegistryImpl.createInitialSRLookupRegistry(), txLookupRegistry, currentlyRegisteredFactories);
+
 
         testedTxController = new ConfigTransactionControllerImpl(
-                transactionName123, jmxRegistrator123, 1, 1,
+                txLookupRegistry, 1, 1,
                 currentlyRegisteredFactories, transactionsMBeanServer,
-                ManagementFactory.getPlatformMBeanServer(), false);
+                ManagementFactory.getPlatformMBeanServer(), false, writableRegistry);
         TransactionModuleJMXRegistrator transactionModuleJMXRegistrator123 = testedTxController
                 .getTxModuleJMXRegistrator();
         transactionModuleJMXRegistrator123.registerMBean(
index eaaee5eb5be5aa5d54d1525b11e101e6fa49ff92..bbb3784b33b02e49be8929d39e983e2c4cb7d33a 100644 (file)
@@ -7,23 +7,19 @@
  */
 package org.opendaylight.controller.config.manager.impl;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-import javax.management.InstanceAlreadyExistsException;
-
 import org.junit.Before;
 import org.junit.Test;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
+
+import javax.management.InstanceAlreadyExistsException;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
 
 public class ConfigTransactionManagerImplTest extends
-        AbstractConfigWithJolokiaTest {
+        AbstractConfigTest {
 
     @Before
     public void setUp() {
@@ -55,23 +51,4 @@ public class ConfigTransactionManagerImplTest extends
         transaction.commit();
     }
 
-    @Test
-    public void testRemoteCallsUsingJolokia() throws Exception {
-
-        ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient
-                .createTransaction();
-
-        assertEquals("ConfigTransaction-0-1",
-                ObjectNameUtil.getTransactionName(transactionClient
-                        .getTransactionON()));
-
-        assertEquals(
-                ConfigRegistryConstants.ON_DOMAIN
-                        + ":TransactionName=ConfigTransaction-0-1,type=ConfigTransaction",
-                transactionClient.getTransactionON().getCanonicalName());
-
-        // commit
-        transactionClient.commit();
-
-    }
 }
index cf6ed18c6cd96b4483ac8f1f9064a84ae2ea1db2..75b0414711095d70b3e98f7964c84ff422a3ec75 100644 (file)
@@ -97,7 +97,8 @@ public class AnnotationsTest {
     static final String SIMPLE = "simple";
     static final String SUBCLASS2 = "subclass2";
 
-    @ServiceInterfaceAnnotation(value = SIMPLE, osgiRegistrationType = Executor.class)
+    @ServiceInterfaceAnnotation(value = SIMPLE, osgiRegistrationType = Executor.class,
+    namespace = "ns", revision = "rev", localName = SIMPLE)
     static interface SimpleSI extends AbstractServiceInterface {
 
     }
@@ -161,7 +162,9 @@ public class AnnotationsTest {
 
     }
 
-    @ServiceInterfaceAnnotation(value = SUBCLASS2, osgiRegistrationType = ExecutorService.class)
+    @ServiceInterfaceAnnotation(value = SUBCLASS2, osgiRegistrationType = ExecutorService.class,
+    namespace = "ns", revision = "rev", localName = SUBCLASS2)
+
     static interface SubSI2 extends SubSI {
 
     }
index 9a5452aa6caa237cc702d1b81b8b388d4520cfd0..22ea528030931b5350cd79c0facc30d1c4ed73a5 100644 (file)
@@ -9,11 +9,15 @@ package org.opendaylight.controller.config.manager.impl.util;
 
 import static org.junit.Assert.assertEquals;
 
+import java.util.HashSet;
 import java.util.Set;
 
 import javax.management.MXBean;
 
 import org.junit.Test;
+import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingScheduledThreadPoolServiceInterface;
+import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.yangtools.concepts.Identifiable;
 
@@ -60,4 +64,17 @@ public class InterfacesHelperTest {
         assertEquals(expected, InterfacesHelper.getMXInterfaces(SubClass.class));
     }
 
+    @Test
+    public void testGetAllAbstractServiceInterfaceClasses(){
+        Class<? extends AbstractServiceInterface> clazz = TestingScheduledThreadPoolServiceInterface.class;
+        Set<Class<? extends AbstractServiceInterface>> input = new HashSet<>();
+        input.add(clazz);
+        Set<Class<? extends AbstractServiceInterface>> result = InterfacesHelper.getAllAbstractServiceInterfaceClasses(input);
+
+        Set<Class<?>> expected = Sets.newHashSet((Class<?>) TestingScheduledThreadPoolServiceInterface.class,
+                TestingThreadPoolServiceInterface.class
+                );
+        assertEquals(expected, result);
+    }
+
 }
index 4fd2f5f1b5a08676458d211b37cfb1d6f2d2ad7f..9674a110ce18fd742f8534915fa8713a2ce4b550 100644 (file)
@@ -11,7 +11,8 @@ import javax.management.ObjectName;
 
 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
 
-@ServiceInterfaceAnnotation(value = TestingParallelAPSPConfigMXBean.NAME, osgiRegistrationType = TestingAPSP.class)
+@ServiceInterfaceAnnotation(value = TestingParallelAPSPConfigMXBean.NAME, osgiRegistrationType = TestingAPSP.class,
+namespace = "namespace", revision = "rev", localName = TestingParallelAPSPConfigMXBean.NAME)
 public interface TestingParallelAPSPConfigMXBean {
 
     static final String NAME = "apsp";
index 3adf11484e6506299468c17e42f33976567f988d..50a58792e14b700b0bd43ddcccbb9517c9c3a0ab 100644 (file)
@@ -18,6 +18,7 @@ import org.osgi.framework.BundleContext;
 
 import javax.annotation.concurrent.ThreadSafe;
 import javax.management.ObjectName;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -69,4 +70,9 @@ public class TestingParallelAPSPModuleFactory implements ModuleFactory {
     public Set<Module> getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext context) {
         return new HashSet<Module>();
     }
+
+    @Override
+    public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+        return Collections.emptySet();
+    }
 }
index 7deb1efb55c5ae68c2016a7c1816eba27b8b2de4..3d9d5245ef2886be3eaa937312c247541e50557e 100644 (file)
@@ -7,16 +7,16 @@
  */
 package org.opendaylight.controller.config.manager.testingservices.parallelapsp.test;
 
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-
-import org.opendaylight.controller.config.manager.impl.AbstractConfigWithJolokiaTest;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
 import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPConfigMXBean;
 import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPModuleFactory;
 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
 
-abstract class AbstractParallelAPSPTest extends AbstractConfigWithJolokiaTest {
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.ObjectName;
+
+abstract class AbstractParallelAPSPTest extends AbstractConfigTest {
     protected final String fixed1 = "fixed1";
     protected final String apsp1 = "apsp-parallel";
 
index 5b1a6f6e8184f69805ec5245e2d4b99089467e5d..f9a11301e1aaf09b98d8af43bd965f1f8902e153 100644 (file)
@@ -7,17 +7,6 @@
  */
 package org.opendaylight.controller.config.manager.testingservices.parallelapsp.test;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.internal.matchers.StringContains.containsString;
-
-import java.util.Map;
-
-import javax.management.ObjectName;
-
-import org.json.simple.JSONObject;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -32,7 +21,15 @@ import org.opendaylight.controller.config.manager.testingservices.threadpool.Tes
 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
+
+import javax.management.ObjectName;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.internal.matchers.StringContains.containsString;
 
 public class DependentWiringTest extends AbstractParallelAPSPTest {
     private final String fixed1 = "fixed1";
@@ -135,44 +132,4 @@ public class DependentWiringTest extends AbstractParallelAPSPTest {
                 parallelAPSPRuntimeProxy.getMaxNumberOfThreads());
 
     }
-
-    @Test
-    public void testUsingJolokia() throws Exception {
-
-        ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient
-                .createTransaction();
-        // fixed1
-        ObjectName fixed1ON = transactionClient.createModule(
-                getThreadPoolImplementationName(), fixed1);
-        transactionClient.setAttribute(fixed1ON, "ThreadCount",
-                TestingParallelAPSPImpl.MINIMAL_NUMBER_OF_THREADS);
-
-        // apsp-parallel with syntetic attrib
-        String threadPoolString = "ThreadPool";
-        ObjectName apsp1ON = transactionClient.createModule(
-                TestingParallelAPSPModuleFactory.NAME, apsp1);
-        transactionClient.setAttribute(apsp1ON, threadPoolString, fixed1ON);
-        // check
-        assertEquals(ObjectNameUtil.withoutTransactionName(fixed1ON),
-                transactionClient.getAttributeON(apsp1ON, threadPoolString));
-        transactionClient.setAttribute(apsp1ON, "SomeParam", "ahoj");
-
-        // commit
-        transactionClient.commit();
-        // check thread pool
-        assertEquals(1, TestingFixedThreadPool.allExecutors.size());
-        // check platform MBeanServer
-        ObjectName apspReadOnlyON = ObjectNameUtil
-                .withoutTransactionName(apsp1ON);
-        JSONObject threadPoolONJson = (JSONObject) configRegistryJolokiaClient
-                .getAttribute(apspReadOnlyON, threadPoolString);
-        ObjectName fixed1ReadOnlyON = ObjectNameUtil
-                .withoutTransactionName(fixed1ON);
-        assertEquals(fixed1ReadOnlyON, ObjectNameUtil.createON(threadPoolONJson
-                .get("objectName").toString()));
-        assertEquals(fixed1ReadOnlyON,
-                configRegistryJolokiaClient.getAttributeON(apspReadOnlyON,
-                        threadPoolString));
-
-    }
 }
index 2e1047849e6773c02e3b6d4fe6f7b1f94ba9198a..e5306a4fa60272e23adac53af8f83f5454876b86 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool;
 
+import com.google.common.collect.Sets;
 import org.opendaylight.controller.config.api.DependencyResolver;
 import org.opendaylight.controller.config.api.DependencyResolverFactory;
 import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
@@ -18,16 +19,16 @@ import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.osgi.framework.BundleContext;
 
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
 public class TestingScheduledThreadPoolModuleFactory implements ModuleFactory {
     public static final String NAME = "scheduled";
 
-    private static List<Class<? extends TestingThreadPoolServiceInterface>> ifc = Arrays
-            .asList(TestingScheduledThreadPoolServiceInterface.class, TestingThreadPoolServiceInterface.class);
+    private static Set<Class<? extends AbstractServiceInterface>> ifc = Collections.unmodifiableSet(Sets.newHashSet(
+            (Class<? extends AbstractServiceInterface>) TestingScheduledThreadPoolServiceInterface.class,
+                    TestingThreadPoolServiceInterface.class));
 
     @Override
     public boolean isModuleImplementingServiceInterface(
@@ -70,4 +71,11 @@ public class TestingScheduledThreadPoolModuleFactory implements ModuleFactory {
     public Set<Module> getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) {
         return new HashSet<Module>();
     }
+
+    @Override
+    public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+        return ifc;
+    }
+
+
 }
index ab1b6bd2184d4f9d4114ea067e0dbf4f9ce090cd..5c30d1e977fafbed51ba19c87e4027ec67d87bd1 100644 (file)
@@ -10,7 +10,8 @@ package org.opendaylight.controller.config.manager.testingservices.seviceinterfa
 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingModifiableThreadPoolIfc;
 
-@ServiceInterfaceAnnotation(value = "modifiable-threadpool", osgiRegistrationType = TestingModifiableThreadPoolIfc.class)
+@ServiceInterfaceAnnotation(value = "fqn:modifiable-threadpool", osgiRegistrationType = TestingModifiableThreadPoolIfc.class,
+        namespace = "foo",  revision = "bar", localName = "modifiable-threadpool")
 public interface ModifiableThreadPoolServiceInterface extends
         TestingThreadPoolServiceInterface {
 }
index e4e388c610e6ac5459ea4581a4be9a061501986d..5ddc1892e3b4139320eaee85c865b5437ae09895 100644 (file)
@@ -10,7 +10,8 @@ package org.opendaylight.controller.config.manager.testingservices.seviceinterfa
 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
 import org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool.TestingScheduledThreadPoolIfc;
 
-@ServiceInterfaceAnnotation(value = "threadpool-scheduled", osgiRegistrationType = TestingScheduledThreadPoolIfc.class)
+@ServiceInterfaceAnnotation(value = "threadpool-scheduled", osgiRegistrationType = TestingScheduledThreadPoolIfc.class,
+    namespace = "ns", revision = "rev", localName = "threadpool-scheduled")
 public interface TestingScheduledThreadPoolServiceInterface extends
         TestingThreadPoolServiceInterface {
 }
index fd5ab1780d7afe7feae4f4e4d4d68ee595f381eb..91a4cff415ac3200366deee7c4324a9755423a89 100644 (file)
@@ -11,7 +11,8 @@ import org.opendaylight.controller.config.api.annotations.AbstractServiceInterfa
 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingThreadPoolIfc;
 
-@ServiceInterfaceAnnotation(value = "testing-threadpool", osgiRegistrationType = TestingThreadPoolIfc.class)
+@ServiceInterfaceAnnotation(value = "testing-threadpool", osgiRegistrationType = TestingThreadPoolIfc.class,
+    namespace = "ns", revision = "foo", localName = "bar")
 public interface TestingThreadPoolServiceInterface extends
         AbstractServiceInterface {
 }
diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java
new file mode 100644 (file)
index 0000000..0286400
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * 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.manager.testingservices.threadpool;
+
+import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName;
+
+@ModuleQName(namespace = "namespace", revision = "revision", name = "name")
+public abstract class AbstractTestingFixedThreadPoolModuleFactory {
+}
index cf05e445306b30eb16ac8740bb30ec83a7452649..bec28685576aba673422c32222acafc6aca34a23 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.config.manager.testingservices.threadpool;
 
+import com.google.common.collect.Sets;
 import org.opendaylight.controller.config.api.DependencyResolver;
 import org.opendaylight.controller.config.api.DependencyResolverFactory;
 import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
@@ -18,15 +19,16 @@ import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.osgi.framework.BundleContext;
 
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
-public class TestingFixedThreadPoolModuleFactory implements ModuleFactory {
+public class TestingFixedThreadPoolModuleFactory extends AbstractTestingFixedThreadPoolModuleFactory implements ModuleFactory {
     public static final String NAME = "fixed";
-    private static List<Class<? extends TestingThreadPoolServiceInterface>> ifc = Arrays
-            .asList(ModifiableThreadPoolServiceInterface.class, TestingThreadPoolServiceInterface.class);
+
+    private static Set<Class<? extends AbstractServiceInterface>> ifc = Collections.unmodifiableSet(Sets.newHashSet(
+            (Class<? extends AbstractServiceInterface>) ModifiableThreadPoolServiceInterface.class,
+            TestingThreadPoolServiceInterface.class));
 
     @Override
     public String getImplementationName() {
@@ -71,4 +73,9 @@ public class TestingFixedThreadPoolModuleFactory implements ModuleFactory {
     public Set<Module> getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) {
         return new HashSet<Module>();
     }
+
+    @Override
+    public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+        return ifc;
+    }
 }
index c2f2558a5d202d5c0279eaef157c913bc2ff7889..441de36db07655558a3f882e7ebbb9ba929e964f 100644 (file)
@@ -7,28 +7,7 @@
  */
 package org.opendaylight.controller.config.manager.testingservices.threadpool.test;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.matchers.JUnitMatchers.containsString;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ThreadPoolExecutor;
-
-import javax.management.DynamicMBean;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanException;
-import javax.management.ObjectName;
-import javax.management.ReflectionException;
-import javax.management.RuntimeMBeanException;
-
+import com.google.common.collect.Sets;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -37,14 +16,33 @@ import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
 import org.opendaylight.controller.config.api.jmx.CommitStatus;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.manager.impl.AbstractConfigWithJolokiaTest;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool;
 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
+
+import javax.management.DynamicMBean;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.RuntimeMBeanException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 /**
  * Tests basic functionality of configuration registry:
@@ -58,7 +56,7 @@ import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaC
  * Only one bean is being configured - {@link TestingThreadPoolIfc} which has no
  * dependencies.
  */
-public class SimpleConfigurationTest extends AbstractConfigWithJolokiaTest {
+public class SimpleConfigurationTest extends AbstractConfigTest {
     private final int numberOfThreads = 5;
     private final int numberOfThreads2 = 10;
     private static final String fixed1 = "fixed1";
@@ -134,12 +132,6 @@ public class SimpleConfigurationTest extends AbstractConfigWithJolokiaTest {
         testValidation(transaction);
     }
 
-    @Test
-    public void testValidationUsingJolokiaClient() throws Exception {
-        ConfigTransactionClient transaction = configRegistryJolokiaClient
-                .createTransaction();
-        testValidation(transaction);
-    }
 
     private void testValidation(ConfigTransactionClient transaction)
             throws InstanceAlreadyExistsException, ReflectionException,
@@ -393,68 +385,12 @@ public class SimpleConfigurationTest extends AbstractConfigWithJolokiaTest {
         }
     }
 
-    @Test
-    public void testOptimisticLock_ConfigTransactionJolokiaClient()
-            throws Exception {
-        ConfigTransactionJolokiaClient transaction1 = configRegistryJolokiaClient
-                .createTransaction();
-        ConfigTransactionJolokiaClient transaction2 = configRegistryJolokiaClient
-                .createTransaction();
-        transaction2.assertVersion(0, 2);
-        transaction2.commit();
-        try {
-            transaction1.commit();
-            fail();
-        } catch (ConflictingVersionException e) {
-            assertEquals(
-                    "Optimistic lock failed. Expected parent version 2, was 0",
-                    e.getMessage());
-        }
-    }
 
     @Test
-    public void testOptimisticLock_ConfigRegistryJolokiaClient()
-            throws Exception {
-        ConfigTransactionJolokiaClient transaction1 = configRegistryJolokiaClient
-                .createTransaction();
-        ConfigTransactionJolokiaClient transaction2 = configRegistryJolokiaClient
-                .createTransaction();
-        transaction2.assertVersion(0, 2);
-        transaction2.commit();
-        try {
-            configRegistryJolokiaClient.commitConfig(transaction1
-                    .getObjectName());
-            fail();
-        } catch (ConflictingVersionException e) {
-            assertEquals(
-                    "Optimistic lock failed. Expected parent version 2, was 0",
-                    e.getMessage());
-        }
-    }
-
-    @Test
-    public void testUsingJolokia() throws Exception {
-        ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient
-                .createTransaction();
-
-        ObjectName name = transactionClient.createModule(
-                TestingFixedThreadPoolModuleFactory.NAME, fixed1);
-
-        try {
-            transactionClient.validateConfig();
-            fail();
-        } catch (ValidationException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("Parameter 'threadCount' must be greater than 0"));
-        }
-
-        transactionClient.setAttribute(name, "ThreadCount", numberOfThreads);
-        // commit
-        CommitStatus commitStatus = transactionClient.commit();
-        CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil
-                .withoutTransactionName(name)), emptyONs, emptyONs);
-        assertEquals(expected, commitStatus);
+    public void testQNames() {
+        Set<String> availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames();
+        String expected = "(namespace?revision=revision)name";
+        assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames);
     }
 
 }
index 39595edb0b728de43917e32d9d7a71283499f293..a123eb981ed9ca81d50baf0a6fa582b7ab6e3048 100644 (file)
@@ -139,7 +139,7 @@ class MyLineProcessor implements com.google.common.io.LineProcessor<String> {
     }
 
     private void checkFileConsistency(){
-        checkState(inCapabilities, "File {} is missing delimiters in this order: {}", fileNameForReporting,
+        checkState(inCapabilities, "File %s is missing delimiters in this order: %s", fileNameForReporting,
                 Arrays.asList(DirectoryPersister.MODULES_START,
                         DirectoryPersister.SERVICES_START,
                         DirectoryPersister.CAPABILITIES_START));
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/pom.xml b/opendaylight/config/config-persister-directory-xml-adapter/pom.xml
new file mode 100644 (file)
index 0000000..b2ea632
--- /dev/null
@@ -0,0 +1,115 @@
+<?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>config-subsystem</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.2.3-SNAPSHOT</version>
+        <relativePath>..</relativePath>
+    </parent>
+    <artifactId>config-persister-directory-xml-adapter</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <!-- compile dependencies -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>config-persister-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-persister-file-xml-adapter</artifactId>
+            <version>${config.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.persistence</groupId>
+            <artifactId>org.eclipse.persistence.moxy</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.persistence</groupId>
+            <artifactId>org.eclipse.persistence.core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+
+        <!-- test dependencies -->
+        <dependency>
+            <groupId>org.opendaylight.bgpcep</groupId>
+            <artifactId>mockito-configuration</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <!-- workaround for creating version according to OSGi specification (major.minor.micro[.qualifier] -->
+            <plugin>
+                <groupId>org.codehaus.groovy.maven</groupId>
+                <artifactId>gmaven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <configuration>
+                            <source>
+                                System.setProperty("osgiversion", "${project.version}".replace('-', '.'))
+                            </source>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Fragment-Host>${project.groupId}.config-persister-impl;bundle-version=${osgiversion}
+                        </Fragment-Host>
+                        <Provide-Capability>org.opendaylight.controller.config.persister.storage.adapter
+                        </Provide-Capability>
+                        <Import-Package>
+                            com.google.common.base,
+                            com.google.common.io,
+                            org.apache.commons.io,
+                            org.opendaylight.controller.config.persist.api,
+                            org.slf4j,
+                            com.google.common.collect,
+                            javax.xml.bind,
+                            javax.xml.bind.annotation,
+                            javax.xml.transform,
+                            javax.xml.transform.stream,
+                            org.eclipse.persistence.jaxb,
+                            org.apache.commons.lang3
+                        </Import-Package>
+                        <Private-Package>
+                            org.opendaylight.controller.config.persist.storage.file.xml.model,
+                        </Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java
new file mode 100644 (file)
index 0000000..f6f6de9
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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.persist.storage.directory.xml;
+
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedSet;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class XmlDirectoryPersister implements Persister {
+    private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryPersister.class);
+
+    private final File storage;
+
+    public XmlDirectoryPersister(File storage) {
+        checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage);
+        this.storage = storage;
+    }
+
+    @Override
+    public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
+        throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass());
+    }
+
+    @Override
+    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
+        File[] filesArray = storage.listFiles();
+        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);
+
+        List<ConfigSnapshotHolder> result = new ArrayList<>();
+        for (File file : sortedFiles) {
+            logger.trace("Adding file '{}' to combined result", file);
+            ConfigSnapshotHolder h = fromXmlSnapshot(file);
+            result.add(h);
+        }
+        return result;
+    }
+
+    private ConfigSnapshotHolder fromXmlSnapshot(File file) {
+        try {
+            JAXBContext jaxbContext = JAXBContext.newInstance(ConfigSnapshot.class);
+            Unmarshaller um = jaxbContext.createUnmarshaller();
+
+            return asHolder((ConfigSnapshot) um.unmarshal(file));
+        } catch (JAXBException e) {
+            logger.warn("Unable to restore configuration snapshot from {}", file, e);
+            throw new IllegalStateException("Unable to restore configuration snapshot from " + file, e);
+        }
+    }
+
+    private ConfigSnapshotHolder asHolder(final ConfigSnapshot unmarshalled) {
+        return new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return unmarshalled.getConfigSnapshot();
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return unmarshalled.getCapabilities();
+            }
+
+            @Override
+            public String toString() {
+                return unmarshalled.toString();
+            }
+        };
+    }
+
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer sb = new StringBuffer("XmlDirectoryPersister{");
+        sb.append("storage=").append(storage);
+        sb.append('}');
+        return sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java
new file mode 100644 (file)
index 0000000..ab6fb15
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.persist.storage.directory.xml;
+
+import com.google.common.base.Preconditions;
+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 java.io.File;
+
+/**
+ * StorageAdapter that retrieves initial configuration from a directory. If multiple files are present, snapshot and
+ * required capabilities will be merged together. Writing to this persister is not supported.
+ */
+public class XmlDirectoryStorageAdapter implements StorageAdapter {
+    private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryStorageAdapter.class);
+
+    public static final String DIRECTORY_STORAGE_PROP = "directoryStorage";
+
+
+    @Override
+    public Persister instantiate(PropertiesProvider propertiesProvider) {
+        String fileStorageProperty = propertiesProvider.getProperty(DIRECTORY_STORAGE_PROP);
+        Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(DIRECTORY_STORAGE_PROP));
+        File storage  = new File(fileStorageProperty);
+        logger.debug("Using {}", storage);
+        return new XmlDirectoryPersister(storage);
+    }
+
+}
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java b/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java
new file mode 100644 (file)
index 0000000..73061f8
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.persist.storage.directory.xml;
+
+import org.junit.Test;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedSet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class DirectoryStorageAdapterTest {
+    XmlDirectoryPersister tested;
+
+    @Test
+    public void testEmptyDirectory() throws Exception {
+        File folder = new File("target/emptyFolder");
+        folder.mkdir();
+        tested = new XmlDirectoryPersister((folder));
+        assertEquals(Collections.<ConfigSnapshotHolder>emptyList(), tested.loadLastConfigs());
+
+        try {
+            tested.persistConfig(new ConfigSnapshotHolder() {
+                @Override
+                public String getConfigSnapshot() {
+                    throw new RuntimeException();
+                }
+
+                @Override
+                public SortedSet<String> getCapabilities() {
+                    throw new RuntimeException();
+                }
+            });
+            fail();
+        } catch (UnsupportedOperationException e) {
+
+        }
+    }
+
+    private File getFolder(String folderName) {
+        File result = new File(("src/test/resources/" +
+                folderName).replace("/", File.separator));
+        assertTrue(result + " is not a directory", result.isDirectory());
+        return result;
+    }
+
+    @Test
+    public void testOneFile() throws Exception {
+        File folder = getFolder("oneFile");
+        tested = new XmlDirectoryPersister((folder));
+        List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+        assertEquals(1, results.size());
+        ConfigSnapshotHolder result = results.get(0);
+        assertResult(result, "<config>1</config>", "cap1&rev", "cap2", "capa a");
+    }
+
+    private void assertResult(ConfigSnapshotHolder result, String s, String... caps) {
+        assertEquals(s, result.getConfigSnapshot().replaceAll("\\s", ""));
+        int i = 0;
+        for (String capFromSnapshot : result.getCapabilities()) {
+            assertEquals(capFromSnapshot, caps[i++]);
+        }
+    }
+
+    @Test
+    public void testTwoFiles() throws Exception {
+        File folder = getFolder("twoFiles");
+        tested = new XmlDirectoryPersister((folder));
+        List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+        assertEquals(2, results.size());
+
+        assertResult(results.get(0), "<config>1</config>", "cap1-a", "cap2-a", "capa a-a");
+        assertResult(results.get(1), "<config>2</config>", "cap1-b", "cap2-b", "capa a-b");
+
+    }
+
+}
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/oneFile/controller.config.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/oneFile/controller.config.xml
new file mode 100644 (file)
index 0000000..aa8b14c
--- /dev/null
@@ -0,0 +1,10 @@
+<snapshot>
+    <required-capabilities>
+        <capability>cap1&amp;rev</capability>
+        <capability>cap2</capability>
+        <capability>capa a</capability>
+    </required-capabilities>
+    <configuration>
+        <config>1</config>
+    </configuration>
+</snapshot>
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config1.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config1.xml
new file mode 100644 (file)
index 0000000..28f112e
--- /dev/null
@@ -0,0 +1,10 @@
+<snapshot>
+    <required-capabilities>
+        <capability>cap1-a</capability>
+        <capability>cap2-a</capability>
+        <capability>capa a-a</capability>
+    </required-capabilities>
+    <configuration>
+        <config>1</config>
+    </configuration>
+</snapshot>
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml
new file mode 100644 (file)
index 0000000..8fed29d
--- /dev/null
@@ -0,0 +1,10 @@
+<snapshot>
+    <required-capabilities>
+        <capability>cap1-b</capability>
+        <capability>cap2-b</capability>
+        <capability>capa a-b</capability>
+    </required-capabilities>
+    <configuration>
+        <config>2</config>
+    </configuration>
+</snapshot>
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-file-xml-adapter/pom.xml b/opendaylight/config/config-persister-file-xml-adapter/pom.xml
new file mode 100644 (file)
index 0000000..abbec38
--- /dev/null
@@ -0,0 +1,87 @@
+<?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>config-subsystem</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.2.3-SNAPSHOT</version>
+        <relativePath>..</relativePath>
+    </parent>
+    <artifactId>config-persister-file-xml-adapter</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <!-- compile dependencies -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>config-persister-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.persistence</groupId>
+            <artifactId>org.eclipse.persistence.moxy</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.persistence</groupId>
+            <artifactId>org.eclipse.persistence.core</artifactId>
+        </dependency>
+
+        <!-- test dependencies -->
+        <dependency>
+            <groupId>org.opendaylight.bgpcep</groupId>
+            <artifactId>mockito-configuration</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <!-- workaround for creating version according to OSGi specification (major.minor.micro[.qualifier] -->
+            <plugin>
+                <groupId>org.codehaus.groovy.maven</groupId>
+                <artifactId>gmaven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <configuration>
+                            <source>
+                                System.setProperty("osgiversion", "${project.version}".replace('-', '.'))
+                            </source>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Fragment-Host>${project.groupId}.config-persister-impl;bundle-version=${osgiversion}
+                        </Fragment-Host>
+                        <Provide-Capability>org.opendaylight.controller.config.persister.storage.adapter
+                        </Provide-Capability>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java
new file mode 100644 (file)
index 0000000..e75c62b
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * 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.persist.storage.file.xml;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+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 org.opendaylight.controller.config.persist.storage.file.xml.model.Config;
+import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * StorageAdapter that stores configuration in an xml file.
+ */
+public class XmlFileStorageAdapter implements StorageAdapter, Persister {
+    private static final Logger logger = LoggerFactory.getLogger(XmlFileStorageAdapter.class);
+
+    public static final String FILE_STORAGE_PROP = "fileStorage";
+    public static final String NUMBER_OF_BACKUPS = "numberOfBackups";
+
+    private static Integer numberOfStoredBackups;
+    private File storage;
+
+    @Override
+    public Persister instantiate(PropertiesProvider propertiesProvider) {
+        File storage = extractStorageFileFromProperties(propertiesProvider);
+        logger.debug("Using file {}", storage.getAbsolutePath());
+        // Create file if it does not exist
+        File parentFile = storage.getAbsoluteFile().getParentFile();
+        if (parentFile.exists() == false) {
+            logger.debug("Creating parent folders {}", parentFile);
+            parentFile.mkdirs();
+        }
+        if (storage.exists() == false) {
+            logger.debug("Storage file does not exist, creating empty file");
+            try {
+                boolean result = storage.createNewFile();
+                if (result == false)
+                    throw new RuntimeException("Unable to create storage file " + storage);
+            } catch (IOException e) {
+                throw new RuntimeException("Unable to create storage file " + storage, e);
+            }
+        }
+        if (numberOfStoredBackups == 0) {
+            throw new RuntimeException(NUMBER_OF_BACKUPS
+                    + " property should be either set to positive value, or ommited. Can not be set to 0.");
+        }
+        setFileStorage(storage);
+        return this;
+    }
+
+    @VisibleForTesting
+    public void setFileStorage(File storage) {
+        this.storage = storage;
+    }
+
+    @VisibleForTesting
+    public void setNumberOfBackups(Integer numberOfBackups) {
+        numberOfStoredBackups = numberOfBackups;
+    }
+
+    private static File extractStorageFileFromProperties(PropertiesProvider propertiesProvider) {
+        String fileStorageProperty = propertiesProvider.getProperty(FILE_STORAGE_PROP);
+        Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(FILE_STORAGE_PROP));
+        File result = new File(fileStorageProperty);
+        String numberOfBackupsAsString = propertiesProvider.getProperty(NUMBER_OF_BACKUPS);
+        if (numberOfBackupsAsString != null) {
+            numberOfStoredBackups = Integer.valueOf(numberOfBackupsAsString);
+        } else {
+            numberOfStoredBackups = Integer.MAX_VALUE;
+        }
+        logger.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups);
+        return result;
+    }
+
+    @Override
+    public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
+        Preconditions.checkNotNull(storage, "Storage file is null");
+
+        Config cfg = Config.fromXml(storage);
+        cfg.addConfigSnapshot(ConfigSnapshot.fromConfigSnapshot(holder), numberOfStoredBackups);
+        cfg.toXml(storage);
+    }
+
+    @Override
+    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
+        Preconditions.checkNotNull(storage, "Storage file is null");
+
+        if (!storage.exists()) {
+            return Collections.emptyList();
+        }
+
+        Optional<ConfigSnapshot> lastSnapshot = Config.fromXml(storage).getLastSnapshot();
+
+        if (lastSnapshot.isPresent())
+            return Lists.newArrayList(toConfigSnapshot(lastSnapshot.get()));
+        else
+            return Collections.emptyList();
+    }
+
+
+    public ConfigSnapshotHolder toConfigSnapshot(final ConfigSnapshot configSnapshot) {
+        return new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return configSnapshot.getConfigSnapshot();
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return configSnapshot.getCapabilities();
+            }
+
+            @Override
+            public String toString() {
+                return configSnapshot.toString();
+            }
+        };
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String toString() {
+        return "XmlFileStorageAdapter [storage=" + storage + "]";
+    }
+
+}
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java
new file mode 100644 (file)
index 0000000..d384df6
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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.persist.storage.file.xml.model;
+
+import javax.xml.bind.ValidationEventHandler;
+import javax.xml.bind.annotation.DomHandler;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+class CapabilityHandler implements DomHandler<String, StreamResult> {
+
+    private static final String START_TAG = "<capability>";
+    private static final String END_TAG = "</capability>";
+
+    private StringWriter xmlWriter = new StringWriter();
+
+    public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) {
+        xmlWriter.getBuffer().setLength(0);
+        return new StreamResult(xmlWriter);
+    }
+
+    public String getElement(StreamResult rt) {
+        String xml = rt.getWriter().toString();
+        int beginIndex = xml.indexOf(START_TAG) + START_TAG.length();
+        int endIndex = xml.indexOf(END_TAG);
+        return xml.substring(beginIndex, endIndex);
+    }
+
+    public Source marshal(String n, ValidationEventHandler errorHandler) {
+        try {
+            String xml = START_TAG + n.trim() + END_TAG;
+            StringReader xmlReader = new StringReader(xml);
+            return new StreamSource(xmlReader);
+        } catch(Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java
new file mode 100644 (file)
index 0000000..fb84651
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.persist.storage.file.xml.model;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+@XmlRootElement(name = "persisted-snapshots")
+public final class Config {
+
+    private List<ConfigSnapshot> snapshots;
+
+    Config(List<ConfigSnapshot> snapshots) {
+        this.snapshots = snapshots;
+    }
+
+    public Config() {
+        this.snapshots = Lists.newArrayList();
+    }
+
+    @XmlElement(name = "snapshot")
+    @XmlElementWrapper(name = "snapshots")
+    public List<ConfigSnapshot> getSnapshots() {
+        return snapshots;
+    }
+
+    public void setSnapshots(List<ConfigSnapshot> snapshots) {
+        this.snapshots = snapshots;
+    }
+
+    public void toXml(File to) {
+        try {
+
+            // TODO Moxy has to be used instead of default jaxb impl due to a bug
+            // default implementation has a bug that prevents from serializing xml in a string
+            JAXBContext jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(new Class[]{Config.class}, null);
+
+            Marshaller marshaller = jaxbContext.createMarshaller();
+
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+
+            marshaller.marshal(this, to);
+        } catch (JAXBException e) {
+            throw new PersistException("Unable to persist configuration", e);
+        }
+    }
+
+    public static Config fromXml(File from) {
+        if(isEmpty(from))
+            return new Config();
+
+        try {
+            JAXBContext jaxbContext = JAXBContext.newInstance(Config.class);
+            Unmarshaller um = jaxbContext.createUnmarshaller();
+
+            return (Config) um.unmarshal(from);
+        } catch (JAXBException e) {
+            throw new PersistException("Unable to restore configuration", e);
+        }
+    }
+
+    private static boolean isEmpty(File from) {
+        return from.length() == 0 || isBlank(from);
+    }
+
+    private static boolean isBlank(File from) {
+        try {
+            return StringUtils.isBlank(Files.toString(from, Charsets.UTF_8));
+        } catch (IOException e) {
+            throw new IllegalStateException("Unexpected error reading file" + from, e);
+        }
+    }
+
+    public Optional<ConfigSnapshot> getLastSnapshot() {
+        ConfigSnapshot last = Iterables.getLast(snapshots, null);
+        return last == null ? Optional.<ConfigSnapshot>absent() : Optional.of(last);
+    }
+
+    public void addConfigSnapshot(ConfigSnapshot snap, int numberOfStoredBackups) {
+        if(shouldReplaceLast(numberOfStoredBackups) && snapshots.isEmpty() == false) {
+            snapshots.remove(0);
+        }
+        snapshots.add(snap);
+    }
+
+    private boolean shouldReplaceLast(int numberOfStoredBackups) {
+        return numberOfStoredBackups == snapshots.size();
+    }
+}
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java
new file mode 100644 (file)
index 0000000..4197600
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.persist.storage.file.xml.model;
+
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+
+import javax.xml.bind.annotation.XmlAnyElement;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.SortedSet;
+
+@XmlRootElement(name = "snapshot")
+public class ConfigSnapshot {
+
+    private String configSnapshot;
+    private SortedSet<String> capabilities;
+
+    ConfigSnapshot(String configXml, SortedSet<String> capabilities) {
+        this.configSnapshot = configXml;
+        this.capabilities = capabilities;
+    }
+
+    public ConfigSnapshot() {
+    }
+
+    public static ConfigSnapshot fromConfigSnapshot(ConfigSnapshotHolder cfg) {
+        return new ConfigSnapshot(cfg.getConfigSnapshot(), cfg.getCapabilities());
+    }
+
+    @XmlAnyElement(SnapshotHandler.class)
+    public String getConfigSnapshot() {
+        return configSnapshot;
+    }
+
+    public void setConfigSnapshot(String configSnapshot) {
+        this.configSnapshot = configSnapshot;
+    }
+
+    @XmlElement(name = "capability")
+    @XmlElementWrapper(name = "required-capabilities")
+    public SortedSet<String> getCapabilities() {
+        return capabilities;
+    }
+
+    public void setCapabilities(SortedSet<String> capabilities) {
+        this.capabilities = capabilities;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer sb = new StringBuffer("ConfigSnapshot{");
+        sb.append("configSnapshot='").append(configSnapshot).append('\'');
+        sb.append(", capabilities=").append(capabilities);
+        sb.append('}');
+        return sb.toString();
+    }
+}
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java
new file mode 100644 (file)
index 0000000..29d6232
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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.persist.storage.file.xml.model;
+
+final class PersistException extends RuntimeException {
+
+    public PersistException(String s, Exception e) {
+        super(s, e);
+    }
+}
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/SnapshotHandler.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/SnapshotHandler.java
new file mode 100644 (file)
index 0000000..dd39410
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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.persist.storage.file.xml.model;
+
+import javax.xml.bind.ValidationEventHandler;
+import javax.xml.bind.annotation.DomHandler;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+class SnapshotHandler implements DomHandler<String, StreamResult> {
+
+    private static final String START_TAG = "<configuration>";
+    private static final String END_TAG = "</configuration>";
+
+    private StringWriter xmlWriter = new StringWriter();
+
+    public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) {
+        xmlWriter.getBuffer().setLength(0);
+        return new StreamResult(xmlWriter);
+    }
+
+    public String getElement(StreamResult rt) {
+        String xml = rt.getWriter().toString();
+        int beginIndex = xml.indexOf(START_TAG) + START_TAG.length();
+        int endIndex = xml.indexOf(END_TAG);
+        return xml.substring(beginIndex, endIndex);
+    }
+
+    public Source marshal(String n, ValidationEventHandler errorHandler) {
+        try {
+            String xml = START_TAG + n.trim() + END_TAG;
+            StringReader xmlReader = new StringReader(xml);
+            return new StreamSource(xmlReader);
+        } catch(Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java b/opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java
new file mode 100644 (file)
index 0000000..d6bbeb3
--- /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.config.persist.storage.file.xml;
+
+import com.google.common.base.Charsets;
+import junit.framework.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import static junit.framework.Assert.assertFalse;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class FileStorageAdapterTest {
+
+    private static int i;
+    private File file;
+
+    @Before
+    public void setUp() throws Exception {
+        file = Files.createTempFile("testFilePersist", ".txt").toFile();
+        if (!file.exists())
+            return;
+        com.google.common.io.Files.write("", file, Charsets.UTF_8);
+        i = 1;
+    }
+
+    @Test
+    public void testFileAdapter() throws Exception {
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        storage.setFileStorage(file);
+        storage.setNumberOfBackups(Integer.MAX_VALUE);
+        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return createConfig();
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return createCaps();
+            }
+        };
+        storage.persistConfig(holder);
+
+        storage.persistConfig(holder);
+
+        assertEquals(27, com.google.common.io.Files.readLines(file, Charsets.UTF_8).size());
+        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+        assertEquals(1, lastConf.size());
+        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
+        assertEquals("<config>2</config>",
+                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
+        assertEquals(createCaps(), configSnapshotHolder.getCapabilities());
+
+        storage = new XmlFileStorageAdapter();
+        storage.setFileStorage(file);
+        storage.setNumberOfBackups(Integer.MAX_VALUE);
+
+        List<ConfigSnapshotHolder> last = storage.loadLastConfigs();
+        Assert.assertEquals(createCaps(), last.get(0).getCapabilities());
+    }
+
+    private SortedSet<String> createCaps() {
+        SortedSet<String> caps = new TreeSet<>();
+
+        caps.add("cap1" + i);
+        caps.add("cap2" + i);
+        caps.add("urn:opendaylight:params:xml:ns:yang:controller:netty?module=netty&revision=2013-11-19" + i);
+        caps.add("capaaaa as dasfasdf s2" + i);
+        return caps;
+    }
+
+    @Test
+    public void testFileAdapterOneBackup() throws Exception {
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        storage.setFileStorage(file);
+        storage.setNumberOfBackups(1);
+        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return createConfig();
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return createCaps();
+            }
+        };
+        storage.persistConfig(holder);
+
+        storage.persistConfig(holder);
+
+        assertEquals(16, com.google.common.io.Files.readLines(file, Charsets.UTF_8).size());
+
+        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+        assertEquals(1, lastConf.size());
+        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
+        assertEquals("<config>2</config>",
+                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
+    }
+
+    @Test
+    public void testFileAdapterOnlyTwoBackups() throws Exception {
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        storage.setFileStorage(file);
+        storage.setNumberOfBackups(2);
+        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return createConfig();
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return createCaps();
+            }
+        };
+        storage.persistConfig(holder);
+
+        storage.persistConfig(holder);
+        storage.persistConfig(holder);
+
+        List<String> readLines = com.google.common.io.Files.readLines(file, Charsets.UTF_8);
+        assertEquals(27, readLines.size());
+
+        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+        assertEquals(1, lastConf.size());
+        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
+        assertEquals("<config>3</config>",
+                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
+        assertFalse(readLines.contains(holder.getConfigSnapshot()));
+    }
+
+    @Test
+    public void testNoLastConfig() throws Exception {
+        File file = Files.createTempFile("testFilePersist", ".txt").toFile();
+        if (!file.exists())
+            return;
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        storage.setFileStorage(file);
+
+        List<ConfigSnapshotHolder> elementOptional = storage.loadLastConfigs();
+        assertThat(elementOptional.size(), is(0));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNoProperties() throws Exception {
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        storage.loadLastConfigs();
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNoProperties2() throws Exception {
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        storage.persistConfig(new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return Mockito.mock(String.class);
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return new TreeSet<>();
+            }
+        } );
+    }
+
+    static String createConfig() {
+        return "<config>" + i++ + "</config>";
+    }
+
+}
index 206184ccce0b6f2f3209fa0a2c4a728f986eefa0..23603ae626554714da53e1f14897f285e2418b14 100644 (file)
             <groupId>${project.groupId}</groupId>
             <artifactId>config-api</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.jolokia</groupId>
-            <artifactId>jolokia-client-java</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.jolokia</groupId>
-            <artifactId>jolokia-jvm</artifactId>
-            <classifier>agent</classifier>
-        </dependency>
-
         <!-- test dependencies -->
         <dependency>
             <groupId>com.google.guava</groupId>
index 3a1efaeaaf1992163e794f950f1f48b743c64204..8badb75f05c26f0082f00b627eedd91836bd28d5 100644 (file)
@@ -7,9 +7,11 @@
  */
 package org.opendaylight.controller.config.util;
 
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.api.jmx.CommitStatus;
+import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 
 import javax.management.AttributeNotFoundException;
 import javax.management.InstanceNotFoundException;
@@ -20,15 +22,13 @@ import javax.management.MBeanServer;
 import javax.management.ObjectInstance;
 import javax.management.ObjectName;
 import javax.management.ReflectionException;
-
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.jmx.CommitStatus;
-import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 public class ConfigRegistryJMXClient implements ConfigRegistryClient {
-    private final ConfigRegistryMXBean configRegistryProxy;
+    private final ConfigRegistryMXBean configRegistryMXBeanProxy;
     private final ObjectName configRegistryON;
     private final MBeanServer configMBeanServer;
 
@@ -40,7 +40,7 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient {
         if (!(searchResult.size() == 1)) {
             throw new IllegalStateException("Config registry not found");
         }
-        configRegistryProxy = JMX.newMXBeanProxy(configMBeanServer, configRegistryON, ConfigRegistryMXBean.class,
+        configRegistryMXBeanProxy = JMX.newMXBeanProxy(configMBeanServer, configRegistryON, ConfigRegistryMXBean.class,
                 false);
     }
 
@@ -61,7 +61,7 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient {
     @Override
     public ConfigTransactionJMXClient getConfigTransactionClient(
             ObjectName objectName) {
-        return new ConfigTransactionJMXClient(configRegistryProxy, objectName,
+        return new ConfigTransactionJMXClient(configRegistryMXBeanProxy, objectName,
                 configMBeanServer);
     }
 
@@ -75,18 +75,18 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient {
 
     @Override
     public ObjectName beginConfig() {
-        return configRegistryProxy.beginConfig();
+        return configRegistryMXBeanProxy.beginConfig();
     }
 
     @Override
     public CommitStatus commitConfig(ObjectName transactionControllerON)
             throws ConflictingVersionException, ValidationException {
-        return configRegistryProxy.commitConfig(transactionControllerON);
+        return configRegistryMXBeanProxy.commitConfig(transactionControllerON);
     }
 
     @Override
     public List<ObjectName> getOpenConfigs() {
-        return configRegistryProxy.getOpenConfigs();
+        return configRegistryMXBeanProxy.getOpenConfigs();
     }
 
     @Override
@@ -101,45 +101,75 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient {
 
     @Override
     public Set<String> getAvailableModuleNames() {
-        return configRegistryProxy.getAvailableModuleNames();
+        return configRegistryMXBeanProxy.getAvailableModuleNames();
     }
 
     @Override
     public boolean isHealthy() {
-        return configRegistryProxy.isHealthy();
+        return configRegistryMXBeanProxy.isHealthy();
     }
 
     @Override
     public Set<ObjectName> lookupConfigBeans() {
-        return configRegistryProxy.lookupConfigBeans();
+        return configRegistryMXBeanProxy.lookupConfigBeans();
     }
 
     @Override
     public Set<ObjectName> lookupConfigBeans(String moduleName) {
-        return configRegistryProxy.lookupConfigBeans(moduleName);
+        return configRegistryMXBeanProxy.lookupConfigBeans(moduleName);
     }
 
     @Override
     public Set<ObjectName> lookupConfigBeans(String moduleName,
             String instanceName) {
-        return configRegistryProxy.lookupConfigBeans(moduleName, instanceName);
+        return configRegistryMXBeanProxy.lookupConfigBeans(moduleName, instanceName);
     }
 
     @Override
     public ObjectName lookupConfigBean(String moduleName, String instanceName)
             throws InstanceNotFoundException {
-        return configRegistryProxy.lookupConfigBean(moduleName, instanceName);
+        return configRegistryMXBeanProxy.lookupConfigBean(moduleName, instanceName);
     }
 
     @Override
     public Set<ObjectName> lookupRuntimeBeans() {
-        return configRegistryProxy.lookupRuntimeBeans();
+        return configRegistryMXBeanProxy.lookupRuntimeBeans();
     }
 
     @Override
     public Set<ObjectName> lookupRuntimeBeans(String ifcName,
             String instanceName) {
-        return configRegistryProxy.lookupRuntimeBeans(ifcName, instanceName);
+        return configRegistryMXBeanProxy.lookupRuntimeBeans(ifcName, instanceName);
+    }
+
+    @Override
+    public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+        configRegistryMXBeanProxy.checkConfigBeanExists(objectName);
+    }
+
+    @Override
+    public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+        return configRegistryMXBeanProxy.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName);
+    }
+
+    @Override
+    public Map<String, Map<String, ObjectName>> getServiceMapping() {
+        return configRegistryMXBeanProxy.getServiceMapping();
+    }
+
+    @Override
+    public Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+        return configRegistryMXBeanProxy.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName);
+    }
+
+    @Override
+    public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+        return configRegistryMXBeanProxy.lookupServiceInterfaceNames(objectName);
+    }
+
+    @Override
+    public String getServiceInterfaceName(String namespace, String localName) {
+        return configRegistryMXBeanProxy.getServiceInterfaceName(namespace, localName);
     }
 
     @Override
@@ -167,4 +197,8 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient {
         }
     }
 
+    @Override
+    public Set<String> getAvailableModuleFactoryQNames() {
+        return configRegistryMXBeanProxy.getAvailableModuleFactoryQNames();
+    }
 }
index 548c0e9ea4f6eedc7c317cabc7cbc820cda03f62..0db1e5b8224761bc8dbb091f22c1513cf6d5216a 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.config.util;
 
+import java.util.Map;
 import java.util.Set;
 
 import javax.management.Attribute;
@@ -26,19 +27,19 @@ import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXB
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 
 public class ConfigTransactionJMXClient implements ConfigTransactionClient {
-    private final ConfigRegistryMXBean configTransactionManagerProxy;
+    private final ConfigRegistryMXBean configRegistryMXBeanProxy;
     private final ObjectName configTransactionControllerON;
-    private final ConfigTransactionControllerMXBean configControllerProxy;
+    private final ConfigTransactionControllerMXBean configTransactionControllerMXBeanProxy;
     private final MBeanServer configMBeanServer;
 
     public ConfigTransactionJMXClient(
-            ConfigRegistryMXBean configTransactionManagerProxy,
+            ConfigRegistryMXBean configRegistryMXBeanProxy,
             ObjectName configTransactionControllerON,
             MBeanServer configMBeanServer) {
         this.configMBeanServer = configMBeanServer;
-        this.configTransactionManagerProxy = configTransactionManagerProxy;
+        this.configRegistryMXBeanProxy = configRegistryMXBeanProxy;
         this.configTransactionControllerON = configTransactionControllerON;
-        this.configControllerProxy = JMX.newMXBeanProxy(configMBeanServer,
+        this.configTransactionControllerMXBeanProxy = JMX.newMXBeanProxy(configMBeanServer,
                 configTransactionControllerON,
                 ConfigTransactionControllerMXBean.class);
     }
@@ -54,7 +55,7 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
     @Override
     public CommitStatus commit() throws ConflictingVersionException,
             ValidationException {
-        return configTransactionManagerProxy
+        return configRegistryMXBeanProxy
                 .commitConfig(configTransactionControllerON);
     }
 
@@ -73,13 +74,13 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
     @Override
     public ObjectName createModule(String moduleName, String instanceName)
             throws InstanceAlreadyExistsException {
-        return configControllerProxy.createModule(moduleName, instanceName);
+        return configTransactionControllerMXBeanProxy.createModule(moduleName, instanceName);
     }
 
     @Override
     public void destroyModule(ObjectName objectName)
             throws InstanceNotFoundException {
-        configControllerProxy.destroyModule(objectName);
+        configTransactionControllerMXBeanProxy.destroyModule(objectName);
     }
 
     @Override
@@ -91,12 +92,12 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
 
     @Override
     public void abortConfig() {
-        configControllerProxy.abortConfig();
+        configTransactionControllerMXBeanProxy.abortConfig();
     }
 
     @Override
     public void validateConfig() throws ValidationException {
-        configControllerProxy.validateConfig();
+        configTransactionControllerMXBeanProxy.validateConfig();
     }
 
     @Override
@@ -121,12 +122,12 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
 
     @Override
     public String getTransactionName() {
-        return configControllerProxy.getTransactionName();
+        return configTransactionControllerMXBeanProxy.getTransactionName();
     }
 
     @Override
     public Set<String> getAvailableModuleNames() {
-        return configControllerProxy.getAvailableModuleNames();
+        return configTransactionControllerMXBeanProxy.getAvailableModuleNames();
     }
 
     @Override
@@ -136,27 +137,77 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
 
     @Override
     public Set<ObjectName> lookupConfigBeans() {
-        return configControllerProxy.lookupConfigBeans();
+        return configTransactionControllerMXBeanProxy.lookupConfigBeans();
     }
 
     @Override
     public Set<ObjectName> lookupConfigBeans(String moduleName) {
-        return configControllerProxy.lookupConfigBeans(moduleName);
+        return configTransactionControllerMXBeanProxy.lookupConfigBeans(moduleName);
     }
 
     @Override
     public ObjectName lookupConfigBean(String moduleName, String instanceName)
             throws InstanceNotFoundException {
-        return configControllerProxy.lookupConfigBean(moduleName, instanceName);
+        return configTransactionControllerMXBeanProxy.lookupConfigBean(moduleName, instanceName);
     }
 
     @Override
     public Set<ObjectName> lookupConfigBeans(String moduleName,
             String instanceName) {
-        return configControllerProxy
+        return configTransactionControllerMXBeanProxy
                 .lookupConfigBeans(moduleName, instanceName);
     }
 
+    @Override
+    public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+        configTransactionControllerMXBeanProxy.checkConfigBeanExists(objectName);
+    }
+
+    @Override
+    public void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException {
+        configTransactionControllerMXBeanProxy.saveServiceReference(serviceInterfaceName,refName,objectName);
+    }
+
+    @Override
+    public boolean removeServiceReference(String serviceInterfaceName, String refName) {
+        return configTransactionControllerMXBeanProxy.removeServiceReference(serviceInterfaceName, refName);
+    }
+
+    @Override
+    public void removeAllServiceReferences() {
+        configTransactionControllerMXBeanProxy.removeAllServiceReferences();
+    }
+
+    @Override
+    public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+        return configTransactionControllerMXBeanProxy.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName);
+    }
+
+    @Override
+    public Map<String, Map<String, ObjectName>> getServiceMapping() {
+        return configTransactionControllerMXBeanProxy.getServiceMapping();
+    }
+
+    @Override
+    public Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+        return configTransactionControllerMXBeanProxy.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName);
+    }
+
+    @Override
+    public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+        return configTransactionControllerMXBeanProxy.lookupServiceInterfaceNames(objectName);
+    }
+
+    @Override
+    public String getServiceInterfaceName(String namespace, String localName) {
+        return configTransactionControllerMXBeanProxy.getServiceInterfaceName(namespace, localName);
+    }
+
+    @Override
+    public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
+        return configTransactionControllerMXBeanProxy.removeServiceReferences(objectName);
+    }
+
     @Override
     public void validateBean(ObjectName configBeanON)
             throws ValidationException {
@@ -182,4 +233,9 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
                     + attrName + " for " + on, e);
         }
     }
+
+    @Override
+    public Set<String> getAvailableModuleFactoryQNames() {
+        return configTransactionControllerMXBeanProxy.getAvailableModuleFactoryQNames();
+    }
 }
diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ConfigRegistryJolokiaClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ConfigRegistryJolokiaClient.java
deleted file mode 100644 (file)
index f29f0e0..0000000
+++ /dev/null
@@ -1,139 +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.config.util.jolokia;
-
-import java.util.List;
-import java.util.Set;
-
-import javax.management.ObjectName;
-
-import org.jolokia.client.request.J4pExecRequest;
-import org.jolokia.client.request.J4pReadRequest;
-import org.jolokia.client.request.J4pResponse;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.jmx.CommitStatus;
-import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-
-public class ConfigRegistryJolokiaClient extends ListableJolokiaClient
-        implements ConfigRegistryClient {
-
-    public ConfigRegistryJolokiaClient(String url) {
-        super(url, ConfigRegistryMXBean.OBJECT_NAME);
-    }
-
-    @Override
-    public ConfigTransactionJolokiaClient createTransaction() {
-        // create transaction
-        J4pExecRequest execReq = new J4pExecRequest(objectName, "beginConfig");
-        J4pResponse<J4pExecRequest> resp = execute(execReq);
-        ObjectName transactionControllerON = extractObjectName(resp);
-        return getConfigTransactionClient(transactionControllerON);
-    }
-
-    @Override
-    public ConfigTransactionJolokiaClient getConfigTransactionClient(
-            String transactionName) {
-        ObjectName objectName = ObjectNameUtil
-                .createTransactionControllerON(transactionName);
-        return getConfigTransactionClient(objectName);
-    }
-
-    @Override
-    public ConfigTransactionJolokiaClient getConfigTransactionClient(
-            ObjectName objectName) {
-        return new ConfigTransactionJolokiaClient(url, objectName, this);
-    }
-
-    @Override
-    public CommitStatus commitConfig(ObjectName transactionControllerON)
-            throws ConflictingVersionException, ValidationException {
-        J4pExecRequest execReq = new J4pExecRequest(objectName, "commitConfig",
-                transactionControllerON);
-        JSONObject jsonObject;
-        jsonObject = execute(execReq).getValue();
-        JSONArray newInstancesArray = (JSONArray) jsonObject
-                .get("newInstances");
-        List<ObjectName> newInstances = jsonArrayToObjectNames(newInstancesArray);
-        JSONArray reusedInstancesArray = (JSONArray) jsonObject
-                .get("reusedInstances");
-        List<ObjectName> reusedInstances = jsonArrayToObjectNames(reusedInstancesArray);
-        JSONArray recreatedInstancesArray = (JSONArray) jsonObject
-                .get("recreatedInstances");
-        List<ObjectName> recreatedInstances = jsonArrayToObjectNames(recreatedInstancesArray);
-        return new CommitStatus(newInstances, reusedInstances,
-                recreatedInstances);
-    }
-
-    public Object getAttribute(ObjectName configBeanTransactionON, String key) {
-        J4pReadRequest req = new J4pReadRequest(configBeanTransactionON, key);
-        return execute(req).getValue();
-    }
-
-    public ObjectName getAttributeON(ObjectName configBeanTransactionON,
-            String key) {
-        JSONObject jsonAttrib = (JSONObject) getAttribute(
-                configBeanTransactionON, key);
-        return extractObjectName(jsonAttrib);
-    }
-
-    // proxy around ConfigTransactionManagerMXBean
-
-    @Override
-    public ObjectName beginConfig() {
-        ConfigTransactionJolokiaClient result = createTransaction();
-        return result.getTransactionON();
-    }
-
-    @Override
-    public List<ObjectName> getOpenConfigs() {
-        J4pReadRequest req = new J4pReadRequest(objectName, "OpenConfigs");
-        JSONArray jsonArray = execute(req).getValue();
-        return jsonArrayToObjectNames(jsonArray);
-    }
-
-    @Override
-    public long getVersion() {
-        J4pReadRequest req = new J4pReadRequest(objectName, "Version");
-        return (Long) execute(req).getValue();
-    }
-
-    @Override
-    public boolean isHealthy() {
-        J4pReadRequest req = new J4pReadRequest(objectName, "Healthy");
-        return (Boolean) execute(req).getValue();
-    }
-
-    @Override
-    public Set<ObjectName> lookupRuntimeBeans() {
-        return lookupSomething("lookupRuntimeBeans()", new Object[0]);
-    }
-
-    @Override
-    public Set<ObjectName> lookupRuntimeBeans(String moduleName,
-            String instanceName) {
-        return lookupSomething(
-                "lookupRuntimeBeans(java.lang.String,java.lang.String)",
-                new Object[] { moduleName, instanceName });
-    }
-
-    @Override
-    public Object invokeMethod(ObjectName on, String name, Object[] params,
-            String[] signature) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Object getAttributeCurrentValue(ObjectName on, String attributeName) {
-        throw new UnsupportedOperationException();
-    }
-}
diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ConfigTransactionJolokiaClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ConfigTransactionJolokiaClient.java
deleted file mode 100644 (file)
index f4824cd..0000000
+++ /dev/null
@@ -1,165 +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.config.util.jolokia;
-
-import java.util.Map;
-
-import javax.management.Attribute;
-import javax.management.AttributeNotFoundException;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-
-import org.jolokia.client.request.J4pExecRequest;
-import org.jolokia.client.request.J4pReadRequest;
-import org.jolokia.client.request.J4pWriteRequest;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.jmx.CommitStatus;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.AttributeEntry;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-
-public class ConfigTransactionJolokiaClient extends ListableJolokiaClient
-        implements ConfigTransactionClient {
-
-    private final ConfigRegistryJolokiaClient configRegistryJolokiaClient;
-
-    public ConfigTransactionJolokiaClient(String url,
-            ObjectName transactionControllerON,
-            ConfigRegistryJolokiaClient configRegistryJolokiaClient) {
-        super(url, transactionControllerON);
-        this.configRegistryJolokiaClient = configRegistryJolokiaClient;
-    }
-
-    public ObjectName getTransactionON() {
-        return objectName;
-    }
-
-    @Override
-    public CommitStatus commit() throws ConflictingVersionException,
-            ValidationException {
-        return configRegistryJolokiaClient.commitConfig(objectName);
-    }
-
-    @Override
-    public ObjectName createModule(String moduleName, String instanceName)
-            throws InstanceAlreadyExistsException {
-        J4pExecRequest execReq = new J4pExecRequest(objectName, "createModule",
-                moduleName, instanceName);
-        try {
-            return extractObjectName(execute(execReq));
-        } catch (RuntimeException e) {
-            if (e.getMessage() != null
-                    && e.getMessage().startsWith(
-                            InstanceAlreadyExistsException.class.getName()))
-                throw new InstanceAlreadyExistsException();
-            throw e;
-        }
-    }
-
-    @Override
-    public void destroyModule(ObjectName configBeanON) {
-        J4pExecRequest execReq = new J4pExecRequest(objectName,
-                "destroyModule(javax.management.ObjectName)", configBeanON);
-        execute(execReq);
-    }
-
-    @Override
-    public void destroyConfigBean(String moduleName, String instanceName)
-            throws InstanceNotFoundException {
-        destroyModule(ObjectNameUtil.createTransactionModuleON(
-                getTransactionName(), moduleName, instanceName));
-    }
-
-    @Override
-    public void abortConfig() {
-        J4pExecRequest execReq = new J4pExecRequest(objectName, "abortConfig");
-        execute(execReq);
-    }
-
-    @Override
-    public void validateConfig() throws ValidationException {
-        J4pExecRequest execReq = new J4pExecRequest(objectName,
-                "validateConfig");
-        execute(execReq);
-    }
-
-    @Override
-    public long getParentVersion() {
-        J4pReadRequest req = new J4pReadRequest(objectName, "ParentVersion");
-        return (Long) execute(req).getValue();
-    }
-
-    @Override
-    public long getVersion() {
-        J4pReadRequest req = new J4pReadRequest(objectName, "Version");
-        return (Long) execute(req).getValue();
-    }
-
-    public void setAttribute(ObjectName configBeanTransactionON, String key,
-            Object value) {
-        J4pWriteRequest req = new J4pWriteRequest(configBeanTransactionON, key,
-                value);
-        try {
-            execute(req);
-        } catch (RuntimeException e) {
-            if (e.getMessage() != null
-                    && e.getMessage().startsWith(
-                            AttributeNotFoundException.class.getName())) {
-                // try to fix wrong case
-                Map<String, AttributeEntry> allAttributes = getAttributes(configBeanTransactionON);
-                for (AttributeEntry attrib : allAttributes.values()) {
-                    if (attrib.getKey().equalsIgnoreCase(key)) {
-                        req = new J4pWriteRequest(configBeanTransactionON,
-                                attrib.getKey(), value);
-                        execute(req);
-                        return;
-                    }
-                }
-            }
-            throw e;
-        }
-    }
-
-    public Object getAttribute(ObjectName objectName, String key) {
-        return configRegistryJolokiaClient.getAttribute(objectName, key);
-    }
-
-    public ObjectName getAttributeON(ObjectName objectName, String key) {
-        return configRegistryJolokiaClient.getAttributeON(objectName, key);
-    }
-
-    @Override
-    public String getTransactionName() {
-        return ObjectNameUtil.getTransactionName(objectName);
-    }
-
-    @Override
-    public void validateBean(ObjectName rwON) throws ValidationException {
-        J4pExecRequest req = new J4pExecRequest(rwON, "validate", new Object[0]);
-        execute(req);
-    }
-
-    @Override
-    public void assertVersion(int expectedParentVersion,
-            int expectedCurrentVersion) {
-        if (expectedParentVersion != getParentVersion()) {
-            throw new IllegalStateException();
-        }
-        if (expectedCurrentVersion != getVersion()) {
-            throw new IllegalStateException();
-        }
-    }
-
-    @Override
-    public void setAttribute(ObjectName on, String jmxName, Attribute attribute) {
-        throw new UnsupportedOperationException();
-    }
-
-}
diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ListableJolokiaClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ListableJolokiaClient.java
deleted file mode 100644 (file)
index 6277f6a..0000000
+++ /dev/null
@@ -1,275 +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.config.util.jolokia;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import org.jolokia.client.J4pClient;
-import org.jolokia.client.exception.J4pException;
-import org.jolokia.client.exception.J4pRemoteException;
-import org.jolokia.client.request.J4pExecRequest;
-import org.jolokia.client.request.J4pListRequest;
-import org.jolokia.client.request.J4pQueryParameter;
-import org.jolokia.client.request.J4pReadRequest;
-import org.jolokia.client.request.J4pRequest;
-import org.jolokia.client.request.J4pResponse;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.AttributeEntry;
-
-abstract class ListableJolokiaClient {
-    protected final J4pClient j4pClient;
-    protected final String url;
-    protected final ObjectName objectName;
-
-    public ListableJolokiaClient(String url, ObjectName objectName) {
-        if (url == null) {
-            throw new NullPointerException("Parameter 'url' is null");
-        }
-        if (!url.endsWith("/")) {
-            throw new IllegalArgumentException(
-                    "Parameter 'url' must end with '/'");
-        }
-
-        this.url = url;
-        this.j4pClient = new J4pClient(url);
-        this.objectName = objectName;
-    }
-
-    public ObjectName getObjectName() {
-        return objectName;
-    }
-
-    protected <R extends J4pResponse<T>, T extends J4pRequest> R execute(
-            T pRequest) {
-        try {
-            Map<J4pQueryParameter, String> pProcessingOptions = new HashMap<J4pQueryParameter, String>();
-            pProcessingOptions
-                    .put(J4pQueryParameter.INCLUDE_STACKTRACE, "true");
-            pProcessingOptions.put(J4pQueryParameter.SERIALIZE_EXCEPTION,
-                    "true");
-            return j4pClient.execute(pRequest, "POST", pProcessingOptions);
-        } catch (J4pRemoteException e) {
-            tryToConvertException(e.getRemoteStackTrace(), e.getErrorValue());
-            throw new RuntimeException(e.getRemoteStackTrace(), e);
-        } catch (J4pException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    protected void tryToConvertException(String remoteStackTrace,
-            JSONObject errorValue) {
-        String conflictPrefix = ConflictingVersionException.class.getName()
-                + ": ";
-        if (remoteStackTrace.startsWith(conflictPrefix)) {
-            remoteStackTrace = remoteStackTrace.substring(conflictPrefix
-                    .length());
-            Pattern p = Pattern.compile("\r?\n");
-            remoteStackTrace = Arrays.asList(p.split(remoteStackTrace))
-                    .iterator().next();
-            throw new ConflictingVersionException(remoteStackTrace);
-        }
-        String validationExceptionPrefix = ValidationException.class.getName();
-        if (remoteStackTrace.startsWith(validationExceptionPrefix)) {
-            throw createValidationExceptionFromJSONObject(errorValue);
-        }
-    }
-
-    static ValidationException createValidationExceptionFromJSONObject(
-            JSONObject errorValue) {
-        String fValsKey = "failedValidations";
-        JSONObject failedVals = (JSONObject) errorValue.get(fValsKey);
-
-        checkArgument(
-                !failedVals.isEmpty(),
-                fValsKey + " was not present in received JSON: "
-                        + errorValue.toJSONString());
-        Map<String, Map<String, ExceptionMessageWithStackTrace>> failedValsMap = new HashMap<String, Map<String, ExceptionMessageWithStackTrace>>();
-
-        for (Object key : failedVals.keySet()) {
-            checkArgument(key instanceof String, "Unexpected key " + key
-                    + ", expected instance of String");
-            Map<String, ExceptionMessageWithStackTrace> innerMap = new HashMap<String, ValidationException.ExceptionMessageWithStackTrace>();
-            for (Object innerKey : ((JSONObject) failedVals.get(key)).keySet()) {
-                checkArgument(innerKey instanceof String, "Unexpected key "
-                        + innerKey + ", expected instance of String");
-                JSONObject exWithStackTraceVal = (JSONObject) (((JSONObject) failedVals
-                        .get(key)).get(innerKey));
-                Object mess = exWithStackTraceVal.get("message");
-                Object stack = exWithStackTraceVal.get("trace");
-                checkArgument(mess != null && stack != null,
-                        "\"Message\" and \"trace\" elements expected in received json: "
-                                + errorValue.toJSONString());
-                innerMap.put(innerKey.toString(),
-                        new ExceptionMessageWithStackTrace((String) mess,
-                                (String) stack));
-            }
-            failedValsMap.put((String) key, innerMap);
-        }
-        return new ValidationException(failedValsMap);
-    }
-
-    private static void checkArgument(boolean b, String string) {
-        if (b == false)
-            throw new IllegalArgumentException(string);
-    }
-
-    public String getUrl() {
-        return url;
-    }
-
-    public Map<String, AttributeEntry> getAttributes(ObjectName on) {
-        J4pListRequest req = new J4pListRequest(on);
-        J4pResponse<J4pListRequest> response = execute(req);
-        JSONObject listJSONResponse = response.getValue();
-        JSONObject attributes = (JSONObject) listJSONResponse.get("attr");
-
-        // Empty attributes list
-        if(attributes == null)
-            return Collections.emptyMap();
-
-        Map<String, JSONObject> listMap = new HashMap<>();
-
-        for (Object entryObject : attributes.entrySet()) {
-            Entry<String, Object> entry = (Entry<String, Object>) entryObject;
-            JSONObject entryVal = (JSONObject) entry.getValue();
-
-            // read value
-            listMap.put(entry.getKey(), entryVal);
-        }
-        J4pReadRequest j4pReadRequest = new J4pReadRequest(on, listMap.keySet()
-                .toArray(new String[0]));
-        J4pResponse<J4pReadRequest> readResponse = execute(j4pReadRequest);
-        Object readResponseValue = readResponse.getValue();
-        // readResponseValue can be String if there is just one attribute or
-        // JSONObject
-        Map<String, Object> attribsToValues = new HashMap<String, Object>();
-        if (readResponseValue instanceof JSONObject) {
-            JSONObject readJSONResponse = (JSONObject) readResponseValue;
-            for (Object entryObject : readJSONResponse.entrySet()) {
-                Entry<String, Object> entry = (Entry<String, Object>) entryObject;
-                String key = entry.getKey();
-                Object value = entry.getValue();
-                attribsToValues.put(key, value);
-            }
-        }
-
-        Map<String, AttributeEntry> resultMap = new HashMap<String, AttributeEntry>();
-        for (Entry<String, JSONObject> entry : listMap.entrySet()) {
-            String key = entry.getKey();
-            Object value = attribsToValues.size() > 0 ? attribsToValues
-                    .get(key) : readResponseValue;
-            JSONObject listJSON = entry.getValue();
-            String description = (String) listJSON.get("desc");
-            String type = (String) listJSON.get("type");
-            boolean rw = (Boolean) listJSON.get("rw");
-            AttributeEntry attributeEntry = new AttributeEntry(key,
-                    description, value, type, rw);
-            resultMap.put(key, attributeEntry);
-        }
-
-        return resultMap;
-    }
-
-    public String getConfigBeanDescripton(ObjectName on) {
-        J4pListRequest req = new J4pListRequest(on);
-        J4pResponse<J4pListRequest> response = execute(req);
-        JSONObject jsonDesc = response.getValue();
-        Object description = jsonDesc.get("desc");
-        return description == null ? null : description.toString();
-    }
-
-    protected List<ObjectName> jsonArrayToObjectNames(JSONArray jsonArray) {
-        List<ObjectName> result = new ArrayList<>(jsonArray.size());
-        for (Object entry : jsonArray) {
-            JSONObject jsonObject = (JSONObject) entry;
-            String objectNameString = (String) jsonObject.get("objectName");
-            try {
-                result.add(new ObjectName(objectNameString));
-            } catch (MalformedObjectNameException e) {
-                throw new IllegalStateException("Cannot convert "
-                        + objectNameString + " to ObjectName", e);
-            }
-        }
-        return result;
-    }
-
-    protected ObjectName extractObjectName(J4pResponse<J4pExecRequest> resp) {
-        JSONObject jsonResponse = resp.getValue();
-        return extractObjectName(jsonResponse);
-    }
-
-    protected ObjectName extractObjectName(JSONObject jsonResponse) {
-        String result = jsonResponse.get("objectName").toString();
-        return ObjectNameUtil.createON(result);
-    }
-
-    protected Set<ObjectName> lookupSomething(String signature,
-            Object[] parameters) {
-        J4pExecRequest req = new J4pExecRequest(objectName, signature,
-                parameters);
-        JSONArray jsonArray = execute(req).getValue();
-        return new HashSet<>(jsonArrayToObjectNames(jsonArray));
-    }
-
-    public Set<ObjectName> lookupConfigBeans() {
-        return lookupSomething("lookupConfigBeans()", new Object[0]);
-    }
-
-    public Set<ObjectName> lookupConfigBeans(String ifcName) {
-        return lookupSomething("lookupConfigBeans(java.lang.String)",
-                new Object[] { ifcName });
-    }
-
-    public Set<ObjectName> lookupConfigBeans(String ifcName, String instanceName) {
-        return lookupSomething(
-                "lookupConfigBeans(java.lang.String,java.lang.String)",
-                new Object[] { ifcName, instanceName });
-    }
-
-    public ObjectName lookupConfigBean(String ifcName, String instanceName)
-            throws InstanceNotFoundException {
-        J4pExecRequest req = new J4pExecRequest(objectName,
-                "lookupConfigBean(java.lang.String,java.lang.String)",
-                new Object[] { ifcName, instanceName });
-        try {
-            J4pResponse<J4pExecRequest> resp = execute(req);
-            return extractObjectName(resp);
-        } catch (RuntimeException e) {
-            if (e.getMessage() != null
-                    && e.getMessage().startsWith(
-                            InstanceNotFoundException.class.getName()))
-                throw new InstanceNotFoundException();
-            throw e;
-        }
-    }
-
-    public Set<String> getAvailableModuleNames() {
-        J4pReadRequest req = new J4pReadRequest(objectName,
-                "AvailableModuleNames");
-        List<String> value = execute(req).getValue();
-        return new HashSet<>(value);
-    }
-}
index 85397d2a20b311c40f03932ab5dd1442bba41db7..4c99c7770a4e3701719e9577fb5ccca7991c5924 100644 (file)
@@ -7,49 +7,38 @@
  */
 package org.opendaylight.controller.config.util;
 
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-import static org.junit.matchers.JUnitMatchers.containsString;
-
-import java.lang.management.ManagementFactory;
-import java.util.Set;
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.api.ConfigRegistry;
 
 import javax.management.InstanceNotFoundException;
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
+import java.lang.management.ManagementFactory;
+import java.util.Set;
 
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.config.api.ConfigRegistry;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.util.jolokia.ConfigRegistryJolokiaClient;
+import static org.junit.Assert.assertEquals;
 
 public class ConfigRegistryClientsTest {
 
-    private String jolokiaURL;
-
     private TestingConfigRegistry testingRegistry;
     private ObjectName testingRegistryON;
     private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-    private ConfigRegistryClient jmxRegistryClient, jolokiaRegistryClient;
+    private ConfigRegistryClient jmxRegistryClient;
 
     @Before
     public void setUp() throws Exception {
-        jolokiaURL = JolokiaHelper.startTestingJolokia();
         testingRegistry = new TestingConfigRegistry();
         testingRegistryON = ConfigRegistry.OBJECT_NAME;
         mbs.registerMBean(testingRegistry, testingRegistryON);
         jmxRegistryClient = new ConfigRegistryJMXClient(
                 ManagementFactory.getPlatformMBeanServer());
-        jolokiaRegistryClient = new ConfigRegistryJolokiaClient(jolokiaURL);
     }
 
     @After
     public void cleanUp() throws Exception {
-        JolokiaHelper.stopJolokia();
         if (testingRegistryON != null) {
             mbs.unregisterMBean(testingRegistryON);
         }
@@ -58,8 +47,7 @@ public class ConfigRegistryClientsTest {
     @Test
     public void testLookupRuntimeBeans() throws Exception {
         Set<ObjectName> jmxLookup = lookupRuntimeBeans(jmxRegistryClient);
-        Set<ObjectName> jolokiaLookup = lookupRuntimeBeans(jolokiaRegistryClient);
-        assertEquals(jmxLookup, jolokiaLookup);
+        assertEquals(Sets.newHashSet(testingRegistry.run2, testingRegistry.run1, testingRegistry.run3), jmxLookup);
     }
 
     private Set<ObjectName> lookupRuntimeBeans(ConfigRegistryClient client)
@@ -79,28 +67,19 @@ public class ConfigRegistryClientsTest {
                 jmxRegistryClient, TestingConfigRegistry.moduleName1,
                 TestingConfigRegistry.instName1);
         assertEquals(1, jmxLookup.size());
-        Set<ObjectName> jolokiaLookup = clientLookupRuntimeBeansWithModuleAndInstance(
-                jolokiaRegistryClient, TestingConfigRegistry.moduleName1,
-                TestingConfigRegistry.instName1);
-        assertEquals(jmxLookup, jolokiaLookup);
+        assertEquals(Sets.newHashSet(testingRegistry.run2), jmxLookup);
 
         jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance(
                 jmxRegistryClient, TestingConfigRegistry.moduleName2,
                 TestingConfigRegistry.instName2);
         assertEquals(1, jmxLookup.size());
-        jolokiaLookup = clientLookupRuntimeBeansWithModuleAndInstance(
-                jolokiaRegistryClient, TestingConfigRegistry.moduleName2,
-                TestingConfigRegistry.instName2);
-        assertEquals(jmxLookup, jolokiaLookup);
+        assertEquals(Sets.newHashSet(testingRegistry.run3), jmxLookup);
 
         jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance(
                 jmxRegistryClient, TestingConfigRegistry.moduleName1,
                 TestingConfigRegistry.instName2);
         assertEquals(0, jmxLookup.size());
-        jolokiaLookup = clientLookupRuntimeBeansWithModuleAndInstance(
-                jolokiaRegistryClient, TestingConfigRegistry.moduleName1,
-                TestingConfigRegistry.instName2);
-        assertEquals(jmxLookup, jolokiaLookup);
+        assertEquals(Sets.newHashSet(), jmxLookup);
     }
 
     private Set<ObjectName> clientLookupRuntimeBeansWithModuleAndInstance(
@@ -112,29 +91,4 @@ public class ConfigRegistryClientsTest {
         }
         return beans;
     }
-
-    @Test
-    public void testValidationExceptionDeserialization() {
-        try {
-            jolokiaRegistryClient.commitConfig(null);
-            fail();
-        } catch (ValidationException e) {
-            String moduleName = "moduleName", instanceName = "instanceName";
-            assertThat(e.getFailedValidations().containsKey(moduleName),
-                    is(true));
-            assertThat(e.getFailedValidations().size(), is(1));
-            assertThat(e.getFailedValidations().get(moduleName).size(), is(1));
-            assertThat(
-                    e.getFailedValidations().get(moduleName)
-                            .containsKey(instanceName), is(true));
-            assertThat(
-                    e.getFailedValidations().get(moduleName).get(instanceName)
-                            .getMessage(), is("message"));
-            assertThat(
-                    e.getFailedValidations().get(moduleName).get(instanceName)
-                            .getTrace(),
-                    containsString("org.opendaylight.controller.config.util.TestingConfigRegistry.commitConfig"));
-        }
-    }
-
 }
index a6df1e91a5e5188e81137aae8284ab5ad6288d94..5ce6d467995f54be7a0644da658741d163515931 100644 (file)
@@ -7,47 +7,37 @@
  */
 package org.opendaylight.controller.config.util;
 
-import static org.junit.Assert.assertEquals;
-
-import java.lang.management.ManagementFactory;
-import java.util.Set;
-
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
+import com.google.common.collect.Sets;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
 
-public class ConfigTransactionClientsTest {
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.lang.management.ManagementFactory;
+import java.util.Set;
 
+import static org.junit.Assert.assertEquals;
+
+public class ConfigTransactionClientsTest {
     private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-    private String jolokiaURL;
-    private ConfigTransactionControllerMXBean transactionController;
+    private TestingConfigTransactionController transactionController;
     private ObjectName transactionControllerON;
-    private ConfigTransactionClient jmxTransactionClient,
-            jolokiaTransactionClient;
+    private ConfigTransactionClient jmxTransactionClient;
 
     @Before
     public void setUp() throws Exception {
-        jolokiaURL = JolokiaHelper.startTestingJolokia();
         transactionController = new TestingConfigTransactionController();
         transactionControllerON = new ObjectName(ObjectNameUtil.ON_DOMAIN + ":"
                 + ObjectNameUtil.TYPE_KEY + "=TransactionController");
         mbs.registerMBean(transactionController, transactionControllerON);
-        jmxTransactionClient = new ConfigTransactionJMXClient(null,
-                transactionControllerON,
+        jmxTransactionClient = new ConfigTransactionJMXClient(null, transactionControllerON,
                 ManagementFactory.getPlatformMBeanServer());
-        jolokiaTransactionClient = new ConfigTransactionJolokiaClient(
-                jolokiaURL, transactionControllerON, null);
     }
 
     @After
     public void cleanUp() throws Exception {
-        JolokiaHelper.stopJolokia();
         if (transactionControllerON != null) {
             mbs.unregisterMBean(transactionControllerON);
         }
@@ -56,8 +46,8 @@ public class ConfigTransactionClientsTest {
     @Test
     public void testLookupConfigBeans() throws Exception {
         Set<ObjectName> jmxLookup = testClientLookupConfigBeans(jmxTransactionClient);
-        Set<ObjectName> jolokiaLookup = testClientLookupConfigBeans(jolokiaTransactionClient);
-        assertEquals(jmxLookup, jolokiaLookup);
+        assertEquals(Sets.newHashSet(transactionController.conf1,
+                transactionController.conf2, transactionController.conf3), jmxLookup);
     }
 
     private Set<ObjectName> testClientLookupConfigBeans(
@@ -69,5 +59,4 @@ public class ConfigTransactionClientsTest {
         assertEquals(3, beans.size());
         return beans;
     }
-
 }
diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/JolokiaHelper.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/JolokiaHelper.java
deleted file mode 100644 (file)
index c0a2586..0000000
+++ /dev/null
@@ -1,54 +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.config.util;
-
-import org.jolokia.jvmagent.JolokiaServer;
-import org.jolokia.jvmagent.JvmAgentConfig;
-
-public class JolokiaHelper {
-    private static JolokiaServer jolokiaServer;
-
-    /**
-     * Bind to port 17777. By convention, ports above 10000 are used for testing
-     * and < 10000 for production
-     *
-     * @return url that can be passed to new J4pClient(url)
-     */
-    public static String startTestingJolokia() {
-        return startJolokia("localhost", 17777);
-    }
-
-    /**
-     * @return url that can be passed to new J4pClient(url)
-     * @throws IOException
-     */
-    public static String startJolokia(String host, int port) {
-        String agentArgs = "host=" + host + ",port=" + port;
-        JvmAgentConfig config = new JvmAgentConfig(agentArgs);
-        Exception lastException = null;
-        for (int i = 0; i < 10; i++) {
-            try {
-                jolokiaServer = new JolokiaServer(config, false);
-                jolokiaServer.start();
-                return "http://" + host + ":" + port + "/jolokia/";
-            } catch (Exception e) {
-                lastException = e;
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException ie) {
-                    ie.printStackTrace();
-                }
-            }
-        }
-        throw new RuntimeException(lastException);
-    }
-
-    public static void stopJolokia() {
-        jolokiaServer.stop();
-    }
-}
index 07492043248718c10e2f686f2a8df1761ba633d5..4489762a47c7c83655201d3f357f2a9a15426ef7 100644 (file)
@@ -7,19 +7,8 @@
  */
 package org.opendaylight.controller.config.util;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import java.lang.management.ManagementFactory;
-import java.lang.reflect.Method;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -27,35 +16,40 @@ import org.opendaylight.controller.config.api.ConfigRegistry;
 import org.opendaylight.controller.config.api.LookupRegistry;
 import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.jolokia.ConfigRegistryJolokiaClient;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
 
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
 public class LookupTest {
 
-    private String jolokiaURL;
     private TestingConfigRegistry testingRegistry;
     private ObjectName testingRegistryON;
     private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-    private ConfigRegistryClient jmxRegistryClient, jolokiaRegistryClient;
+    private ConfigRegistryClient jmxRegistryClient;
     private ConfigTransactionControllerMXBean testingTransactionController;
     private ObjectName testingTransactionControllerON;
-    private ConfigTransactionClient jmxTransactionClient,
-            jolokiaTransactionClient;
+    private ConfigTransactionClient jmxTransactionClient;
 
     Map<LookupRegistry, ? extends Set<? extends LookupRegistry>> lookupProvidersToClients;
 
     @Before
     public void setUp() throws Exception {
-        jolokiaURL = JolokiaHelper.startTestingJolokia();
         testingRegistry = new TestingConfigRegistry();
         testingRegistryON = ConfigRegistry.OBJECT_NAME;
         mbs.registerMBean(testingRegistry, testingRegistryON);
         jmxRegistryClient = new ConfigRegistryJMXClient(
                 ManagementFactory.getPlatformMBeanServer());
-        jolokiaRegistryClient = new ConfigRegistryJolokiaClient(jolokiaURL);
+
 
         testingTransactionController = new TestingConfigTransactionController();
         testingTransactionControllerON = new ObjectName(
@@ -67,16 +61,15 @@ public class LookupTest {
         jmxTransactionClient = new ConfigTransactionJMXClient(null,
                 testingTransactionControllerON,
                 ManagementFactory.getPlatformMBeanServer());
-        jolokiaTransactionClient = new ConfigTransactionJolokiaClient(
-                jolokiaURL, testingTransactionControllerON, null);
-        lookupProvidersToClients = ImmutableMap
-                .of(testingRegistry, Sets.newHashSet(jmxRegistryClient, jolokiaRegistryClient),
-                        testingTransactionController, Sets.newHashSet(jmxTransactionClient, jolokiaTransactionClient));
+
+        HashSet<ConfigRegistryClient> registryClients = Sets.newHashSet(jmxRegistryClient);
+        HashSet<ConfigTransactionClient> configTransactionClients = Sets.newHashSet(jmxTransactionClient);
+        lookupProvidersToClients = ImmutableMap.of((LookupRegistry) testingRegistry, registryClients,
+                testingTransactionController, configTransactionClients);
     }
 
     @After
     public void cleanUp() throws Exception {
-        JolokiaHelper.stopJolokia();
         mbs.unregisterMBean(testingRegistryON);
         mbs.unregisterMBean(testingTransactionControllerON);
     }
index d4ae42d3de201c3102babd9e77e4e2b2918550d6..65341714df22e7e13315fbcbd6ca44120bf74664 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.controller.config.util;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import javax.management.InstanceNotFoundException;
@@ -143,4 +144,38 @@ public class TestingConfigRegistry implements ConfigRegistryMXBean {
         }
     }
 
+    @Override
+    public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String, Map<String, ObjectName>> getServiceMapping() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getServiceInterfaceName(String namespace, String localName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<String> getAvailableModuleFactoryQNames() {
+        throw new UnsupportedOperationException();
+    }
 }
index 67e31b05e5f065e71639ad38d01759c8d8af6380..44eb73af79e9c098b343ec7a4debb995e6e44337 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.config.util;
 
+import java.util.Map;
 import java.util.Set;
 
 import javax.management.InstanceAlreadyExistsException;
@@ -22,7 +23,7 @@ import com.google.common.collect.Sets;
 public class TestingConfigTransactionController implements
         ConfigTransactionControllerMXBean {
 
-    private final ObjectName conf1, conf2, conf3;
+    public final ObjectName conf1, conf2, conf3;
 
     public static final String moduleName1 = "moduleA";
     public static final String moduleName2 = "moduleB";
@@ -109,4 +110,59 @@ public class TestingConfigTransactionController implements
             return null;
         }
     }
+
+    @Override
+    public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removeServiceReference(String serviceInterfaceName, String refName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeAllServiceReferences() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String, Map<String, ObjectName>> getServiceMapping() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getServiceInterfaceName(String namespace, String localName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<String> getAvailableModuleFactoryQNames() {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/jolokia/ListableJolokiaClientTest.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/jolokia/ListableJolokiaClientTest.java
deleted file mode 100644 (file)
index bff8006..0000000
+++ /dev/null
@@ -1,58 +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.config.util.jolokia;
-
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.json.simple.JSONObject;
-import org.json.simple.JSONValue;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
-
-public class ListableJolokiaClientTest {
-
-    private Map<String, Map<String, ExceptionMessageWithStackTrace>> failedValidations;
-
-    private ValidationException val;
-
-    private final static String ex = "{\"message\":null,"
-            + "\"failedValidations\":"
-            + "{\"ifc2\":{\"impl1\":{\"message\":\"abc\",\"trace\":\"vvv\"},"
-            + "\"impl2\":{\"message\":\"abc2\",\"trace\":\"vvv2\"}},"
-            + "\"ifc1\":"
-            + "{\"impl1\":{\"message\":\"abc\",\"trace\":\"vvv\"},"
-            + "\"impl2\":{\"message\":\"abc2\",\"trace\":\"vvv2\"}}},"
-            + "\"localizedMessage\":null," + "\"cause\":null}";
-
-    @Before
-    public void setUp() {
-        failedValidations = new HashMap<String, Map<String, ExceptionMessageWithStackTrace>>();
-        Map<String, ExceptionMessageWithStackTrace> map1 = new HashMap<String, ValidationException.ExceptionMessageWithStackTrace>();
-        map1.put("impl1", new ExceptionMessageWithStackTrace("abc", "vvv"));
-        map1.put("impl2", new ExceptionMessageWithStackTrace("abc2", "vvv2"));
-        failedValidations.put("ifc1", map1);
-        failedValidations.put("ifc2", map1);
-        val = new ValidationException(failedValidations);
-    }
-
-    @Test
-    public void testParsing() {
-        JSONObject e = (JSONObject) JSONValue.parse(ex);
-        ValidationException val2 = ListableJolokiaClient
-                .createValidationExceptionFromJSONObject(e);
-        assertThat(val2.getMessage(), is(val.getMessage()));
-        assertThat(val2.getFailedValidations(), is(val.getFailedValidations()));
-    }
-
-}
index 99437979de214aa4177d13f739f00f7e171f6210..eba5e07c0f40cc3a2b0732dd4fab563934cb9426 100644 (file)
@@ -26,6 +26,7 @@
         <module>config-util</module>
         <module>config-persister-api</module>
         <module>config-persister-file-adapter</module>
+        <module>config-persister-file-xml-adapter</module>
         <module>yang-jmx-generator</module>
         <module>yang-jmx-generator-plugin</module>
         <module>yang-store-api</module>
@@ -39,6 +40,7 @@
         <module>netty-event-executor-config</module>
         <module>netty-timer-config</module>
         <module>config-persister-directory-adapter</module>
+        <module>config-persister-directory-xml-adapter</module>
         <module>yang-test-plugin</module>
     </modules>
 
@@ -63,7 +65,6 @@
         <osgi.version>5.0.0</osgi.version>
         <jacoco.version>0.6.2.201302030002</jacoco.version>
         <slf4j.version>1.7.2</slf4j.version>
-        <jolokia.version>1.1.1</jolokia.version>
         <opendaylight.yang.version>0.5.9-SNAPSHOT</opendaylight.yang.version>
         <opendaylight.binding.version>0.6.0-SNAPSHOT</opendaylight.binding.version>
         <opendaylight.yangtools.version>0.1.1-SNAPSHOT</opendaylight.yangtools.version>
                 <artifactId>guava</artifactId>
                 <version>14.0.1</version>
             </dependency>
-            <dependency>
-                <groupId>org.jolokia</groupId>
-                <artifactId>jolokia-core</artifactId>
-                <version>${jolokia.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.jolokia</groupId>
-                <artifactId>jolokia-jvm</artifactId>
-                <version>${jolokia.version}</version>
-                <classifier>agent</classifier>
-            </dependency>
-            <dependency>
-                <groupId>org.jolokia</groupId>
-                <artifactId>jolokia-client-java</artifactId>
-                <version>${jolokia.version}</version>
-            </dependency>
             <dependency>
                 <groupId>junit</groupId>
                 <artifactId>junit</artifactId>
index 47b68ebf9a86c0447c25d503fe87dfd7f0102e4e..35dc7a36007c8fb31a0ecc05239b1b8986335c07 100644 (file)
@@ -14,6 +14,7 @@ import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Constructor;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Header;
@@ -33,11 +34,12 @@ public class AbstractFactoryTemplate extends GeneralClassTemplate {
 
     private final String globallyUniqueName, moduleInstanceType;
     private final List<String> providedServices;
+    private final ModuleMXBeanEntry mbe;
 
     public AbstractFactoryTemplate(Header header, String packageName,
-            String abstractFactoryName, String globallyUniqueName,
-            String moduleInstanceType, List<Field> fields,
-            List<String> providedServices) {
+                                   String abstractFactoryName, String globallyUniqueName,
+                                   String moduleInstanceType, List<Field> fields,
+                                   List<String> providedServices, ModuleMXBeanEntry mbe) {
         super(header, packageName, abstractFactoryName, Collections
                 .<String> emptyList(), implementedIfcs, fields, Collections
                 .<MethodDefinition> emptyList(), true, false, Collections
@@ -45,6 +47,7 @@ public class AbstractFactoryTemplate extends GeneralClassTemplate {
         this.globallyUniqueName = globallyUniqueName;
         this.moduleInstanceType = moduleInstanceType;
         this.providedServices = providedServices;
+        this.mbe = mbe;
     }
 
     public String getGloballyUniqueName() {
@@ -92,4 +95,7 @@ public class AbstractFactoryTemplate extends GeneralClassTemplate {
         return "factory_abs_template.ftl";
     }
 
+    public ModuleMXBeanEntry getMbe() {
+        return mbe;
+    }
 }
index 115bb85b618020b61282c83c3c692c9dafca6251..28e0256c05b0cbd055636aa8cf391be97fba6d21 100644 (file)
@@ -210,8 +210,7 @@ public class TemplateFactory {
             sieTemplate.getAnnotations().add(
                     Annotation.createDescriptionAnnotation(sie
                             .getNullableDescription()));
-        sieTemplate.getAnnotations().add(Annotation.createSieAnnotation(sie.getQName(), sie.getExportedOsgiClassName
-                ()));
+        sieTemplate.getAnnotations().addAll(Annotation.createSieAnnotations(sie));
 
         return sieTemplate;
     }
@@ -236,7 +235,7 @@ public class TemplateFactory {
                 mbe.getPackageName(), mbe.getAbstractFactoryName(),
                 mbe.getGloballyUniqueName(), mbe.getFullyQualifiedName(mbe
                         .getStubModuleName()), attrProcessor.getFields(),
-                Lists.newArrayList(transformed));
+                Lists.newArrayList(transformed), mbe);
     }
 
     public static AbstractModuleTemplate abstractModuleTemplateFromMbe(
index 5ec359ea8d842fbb3462debe30e85ebe3f616739..7cf241725d78674cd6f7ca9e16aa3cebcc0f7be4 100644 (file)
@@ -7,13 +7,15 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 
 import org.opendaylight.controller.config.api.annotations.Description;
 import org.opendaylight.controller.config.api.annotations.RequireInterface;
 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
+import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName;
 import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
-import org.opendaylight.yangtools.yang.common.QName;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
@@ -42,19 +44,36 @@ public class Annotation {
                 Lists.newArrayList(new Parameter("value", q(description))));
     }
 
-    public static Annotation createSieAnnotation(QName qname,
-            String exportedClassName) {
-        Preconditions.checkNotNull(qname,
+    public static Collection<Annotation> createSieAnnotations(ServiceInterfaceEntry sie){
+
+        String exportedClassName = sie.getExportedOsgiClassName();
+        Preconditions.checkNotNull(sie.getQName(),
                 "Cannot create annotation from null qname");
         Preconditions.checkNotNull(exportedClassName,
                 "Cannot create annotation from null exportedClassName");
+        List<Annotation> result = new ArrayList<>();
+        {
+            List<Parameter> params = Lists.newArrayList(new Parameter("value", q(sie.getQName().toString())));
+            params.add(new Parameter("osgiRegistrationType", exportedClassName + ".class"));
+
+            params.add(new Parameter("namespace", q(sie.getQName().getNamespace().toString())));
+            params.add(new Parameter("revision", q(sie.getQName().getFormattedRevision())));
+            params.add(new Parameter("localName", q(sie.getQName().getLocalName())));
+
+            Annotation sieAnnotation = new Annotation(ServiceInterfaceAnnotation.class.getCanonicalName(), params);
+            result.add(sieAnnotation);
 
-        List<Parameter> params = Lists.newArrayList(new Parameter("value",
-                q(qname.getLocalName())));
-        params.add(new Parameter("osgiRegistrationType", exportedClassName
-                + ".class"));
-        return new Annotation(
-                ServiceInterfaceAnnotation.class.getCanonicalName(), params);
+        }
+        {
+            List<Parameter> params = new ArrayList<>();
+            params.add(new Parameter("namespace", q(sie.getYangModuleQName().getNamespace().toString())));
+            params.add(new Parameter("revision", q(sie.getYangModuleQName().getFormattedRevision())));
+            params.add(new Parameter("name", q(sie.getYangModuleQName().getLocalName())));
+
+            Annotation moduleQNameAnnotation = new Annotation(ModuleQName.class.getCanonicalName(), params);
+            result.add(moduleQNameAnnotation);
+        }
+        return result;
     }
 
     public static Annotation createRequireIfcAnnotation(
index a331e4e0c1ad95245f838ebee17192e2a7c61c81..b9bbf1f1b564fdc9e8238d30e486ed6234190b69 100644 (file)
@@ -2,16 +2,19 @@
 package ${packageName};
 
 <@javadocD object=javadoc/>
+@org.opendaylight.yangtools.yang.binding.annotations.ModuleQName(namespace="${mbe.getYangModuleQName().getNamespace().toString()}",revision="${mbe.getYangModuleQName().getFormattedRevision()}",name="${mbe.getYangModuleQName().getLocalName()}")
 <@typeDeclarationD object=typeDeclaration/>
 {
 
     public static final java.lang.String NAME = "${globallyUniqueName}";
-    private static final java.util.Set<Class<? extends ${abstractServiceInterfaceType}>> serviceIfcs = new java.util.HashSet<Class<? extends ${abstractServiceInterfaceType}>>();
+    private static final java.util.Set<Class<? extends ${abstractServiceInterfaceType}>> serviceIfcs;
     <#if providedServices??>
     static {
+        java.util.Set<Class<? extends ${abstractServiceInterfaceType}>> serviceIfcs2 = new java.util.HashSet<Class<? extends ${abstractServiceInterfaceType}>>();
         <#list providedServices as refId>
-        serviceIfcs.add(${refId});
+        serviceIfcs2.add(${refId});
         </#list>
+        serviceIfcs = java.util.Collections.unmodifiableSet(serviceIfcs2);
     }
     </#if>
 
@@ -25,6 +28,12 @@ package ${packageName};
         return false;
     }
 
+    @Override
+    public java.util.Set<Class<? extends ${abstractServiceInterfaceType}>> getImplementedServiceIntefaces() {
+        return serviceIfcs;
+    }
+
+
     @Override
     public ${moduleType} createModule(String instanceName, ${dependencyResolverType} dependencyResolver, ${bundleContextType} bundleContext) {
         return instantiateModule(instanceName, dependencyResolver, bundleContext);
index 1945cac1c270919d10b59481139581e848c87f0a..3ef406694a6b12b7825f860e0130fbf20a1075dd 100644 (file)
@@ -438,11 +438,11 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
                 "public static final java.lang.String NAME=\"threadfactory-naming\"");
         assertDeclaredField(
                 fieldDeclarations,
-                "private static final java.util.Set<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>> serviceIfcs=new java.util.HashSet<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>>()");
+                "private static final java.util.Set<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>> serviceIfcs");
 
         assertEquals(2, fieldDeclarations.size());
 
-        assertFactoryMethods(visitor.methods, 8);
+        assertFactoryMethods(visitor.methods, 9);
         assertEquals("Incorrenct number of generated method descriptions", 0,
                 visitor.methodDescriptions.size());
         assertEquals("Incorrenct number of generated method javadoc", 0,
index c312cc849351587096c871c5edefe9bd25954efd..c66b11256601125e4ef84980756780fc9bc20376 100644 (file)
             <artifactId>commons-lang3</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>binding-type-provider</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
index 4eba739b469d52b675b7208e0621c9ddc9f4a845..869488e777350e08106d786e85fd648f5c1028a3 100644 (file)
@@ -136,11 +136,13 @@ public class ModuleMXBeanEntry extends AbstractEntry {
     private final Map<String, QName> providedServices;
 
     private Collection<RuntimeBeanEntry> runtimeBeans;
+    private final QName yangModuleQName;
 
     public ModuleMXBeanEntry(IdentitySchemaNode id,
             Map<String, AttributeIfc> yangToAttributes, String packageName,
             Map<String, QName> providedServices2, String javaNamePrefix,
-            String namespace, Collection<RuntimeBeanEntry> runtimeBeans) {
+            String namespace, Collection<RuntimeBeanEntry> runtimeBeans,
+            QName yangModuleQName) {
         this.globallyUniqueName = id.getQName().getLocalName();
         this.yangToAttributes = yangToAttributes;
         this.nullableDescription = id.getDescription();
@@ -149,6 +151,7 @@ public class ModuleMXBeanEntry extends AbstractEntry {
         this.namespace = checkNotNull(namespace);
         this.providedServices = Collections.unmodifiableMap(providedServices2);
         this.runtimeBeans = runtimeBeans;
+        this.yangModuleQName = yangModuleQName;
     }
 
     public String getMXBeanInterfaceName() {
@@ -395,7 +398,8 @@ public class ModuleMXBeanEntry extends AbstractEntry {
                                 moduleIdentity, yangToAttributes, packageName,
                                 providedServices, javaNamePrefix, currentModule
                                         .getNamespace().toString(),
-                                runtimeBeans);
+                                runtimeBeans,
+                                ModuleUtil.getQName(currentModule));
                         moduleMXBeanEntry.setYangModuleName(currentModule
                                 .getName());
                         moduleMXBeanEntry
@@ -730,6 +734,10 @@ public class ModuleMXBeanEntry extends AbstractEntry {
         return nullableDescription;
     }
 
+    public QName getYangModuleQName() {
+        return yangModuleQName;
+    }
+
     @Override
     public String toString() {
         return "ModuleMXBeanEntry{" + "globallyUniqueName='"
diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java
new file mode 100644 (file)
index 0000000..5fea8fd
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * 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;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+public class ModuleUtil {
+
+    public static QName getQName(Module currentModule){
+        return new QName(currentModule.getNamespace(), currentModule.getRevision(), currentModule.getName());
+    }
+}
index 71cd0900eb6f985521257cc552faead563f8eba1..aa2d6a5d7f044dde8d84b49fff2d8fa3ed28f383 100644 (file)
@@ -57,13 +57,14 @@ public class ServiceInterfaceEntry extends AbstractEntry {
     private final String exportedOsgiClassName;
     private final QName qName;
     private final String nullableDescription, packageName, typeName;
+    private final QName yangModuleQName;
 
-    private ServiceInterfaceEntry(IdentitySchemaNode id, String packageName) {
-        this(Optional.<ServiceInterfaceEntry> absent(), id, packageName);
+    private ServiceInterfaceEntry(IdentitySchemaNode id, String packageName, QName yangModuleQName) {
+        this(Optional.<ServiceInterfaceEntry> absent(), id, packageName, yangModuleQName);
     }
 
     private ServiceInterfaceEntry(Optional<ServiceInterfaceEntry> base,
-            IdentitySchemaNode id, String packageName) {
+            IdentitySchemaNode id, String packageName, QName yangModuleQName) {
         checkNotNull(base);
         this.maybeBaseCache = base;
         List<UnknownSchemaNode> unknownSchemaNodes = id.getUnknownSchemaNodes();
@@ -93,6 +94,7 @@ public class ServiceInterfaceEntry extends AbstractEntry {
         nullableDescription = id.getDescription();
         typeName = getSimpleName(exportedOsgiClassName) + CLASS_NAME_SUFFIX;
         this.packageName = packageName;
+        this.yangModuleQName = yangModuleQName;
     }
 
     private static final String getSimpleName(String fullyQualifiedName) {
@@ -120,14 +122,14 @@ public class ServiceInterfaceEntry extends AbstractEntry {
      * @return Map of QNames as keys and ServiceInterfaceEntry instances as
      *         values
      */
-    public static Map<QName, ServiceInterfaceEntry> create(Module module,
+    public static Map<QName, ServiceInterfaceEntry> create(Module currentModule,
             String packageName) {
         logger.debug("Generating ServiceInterfaces from {} to package {}",
-                module.getNamespace(), packageName);
+                currentModule.getNamespace(), packageName);
 
         Map<IdentitySchemaNode, ServiceInterfaceEntry> identitiesToSIs = new HashMap<>();
         Set<IdentitySchemaNode> notVisited = new HashSet<>(
-                module.getIdentities());
+                currentModule.getIdentities());
         int lastSize = notVisited.size() + 1;
         while (notVisited.size() > 0) {
             if (notVisited.size() == lastSize) {
@@ -148,18 +150,18 @@ public class ServiceInterfaceEntry extends AbstractEntry {
                 } else if (identity.getBaseIdentity().getQName()
                         .equals(SERVICE_TYPE_Q_NAME)) {
                     // this is a base type
-                    created = new ServiceInterfaceEntry(identity, packageName);
+                    created = new ServiceInterfaceEntry(identity, packageName, ModuleUtil.getQName(currentModule));
                 } else {
                     ServiceInterfaceEntry foundBase = identitiesToSIs
                             .get(identity.getBaseIdentity());
                     // derived type, did we convert the parent?
                     if (foundBase != null) {
                         created = new ServiceInterfaceEntry(
-                                Optional.of(foundBase), identity, packageName);
+                                Optional.of(foundBase), identity, packageName, ModuleUtil.getQName(currentModule));
                     }
                 }
                 if (created != null) {
-                    created.setYangModuleName(module.getName());
+                    created.setYangModuleName(currentModule.getName());
                     // TODO how to get local name
                     created.setYangModuleLocalname(identity.getQName()
                             .getLocalName());
@@ -190,6 +192,10 @@ public class ServiceInterfaceEntry extends AbstractEntry {
         return typeName;
     }
 
+    public QName getYangModuleQName() {
+        return yangModuleQName;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o)
index 764ecd38868c7b224c1c8e0065d7989f8126fa37..c43fead0fcd0f5aa7e281768e2da0020bf149918 100644 (file)
@@ -64,4 +64,8 @@ public class TypeProviderWrapper {
     public String getJMXParamForBaseType(TypeDefinition<?> baseType) {
         return typeProvider.getConstructorPropertyName(baseType);
     }
+
+    public String getJMXParamForUnionInnerType(TypeDefinition<?> unionInnerType) {
+        return typeProvider.getParamNameFromType(unionInnerType);
+    }
 }
index 3e20e4a55ad47f58e538a33594d1f5d4f0e70d32..e01063ef92e86b217bc4c737eb89b0f7c17cf283 100644 (file)
@@ -7,20 +7,26 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.attribute;
 
+import com.google.common.base.Preconditions;
 import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 
 import javax.management.openmbean.ArrayType;
 import javax.management.openmbean.CompositeType;
 import javax.management.openmbean.OpenDataException;
 import javax.management.openmbean.OpenType;
 import javax.management.openmbean.SimpleType;
+import java.util.Arrays;
+import java.util.List;
 
 public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
 
+    public static final String DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION = "valueOfArtificialUnionProperty";
+
     private final Type type;
     private final String nullableDescription, nullableDefault, nullableDefaultWrappedForCode;
     private final TypeProviderWrapper typeProviderWrapper;
@@ -47,6 +53,11 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
         this.nullableDescription = leaf.getDescription();
     }
 
+    public boolean isUnion() {
+        TypeDefinition<?> base = getBaseType(typeProviderWrapper, typeDefinition);
+        return base instanceof UnionTypeDefinition;
+    }
+
     public TypeDefinition<?> getTypeDefinition() {
         return typeDefinition;
     }
@@ -132,13 +143,70 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
             return getArrayType();
         } else if (isEnum(baseType)) {
             return getSimpleType(baseType);
-        } else if (isDerivedType(baseType)) {
+        } else if (isUnion()) {
+            return getCompositeTypeForUnion(baseTypeDefinition);
+        } else if (isDerivedType(baseType, getType())) {
             return getCompositeType(baseType, baseTypeDefinition);
         }
 
         return getSimpleType(getType());
     }
 
+    private OpenType<?> getCompositeTypeForUnion(TypeDefinition<?> baseTypeDefinition) {
+        Preconditions.checkArgument(baseTypeDefinition instanceof UnionTypeDefinition,
+                "Expected %s instance but was %s", UnionTypeDefinition.class, baseTypeDefinition);
+
+        List<TypeDefinition<?>> types = ((UnionTypeDefinition) baseTypeDefinition).getTypes();
+
+        String[] itemNames = new String[types.size()+1];
+        OpenType<?>[] itemTypes = new OpenType[itemNames.length];
+
+        addArtificialPropertyToUnionCompositeType(baseTypeDefinition, itemNames, itemTypes);
+
+        String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription();
+
+        int i = 1;
+        for (TypeDefinition<?> innerTypeDefinition : types) {
+
+            Type innerType = typeProviderWrapper.getType(innerTypeDefinition, innerTypeDefinition);
+
+            TypeDefinition<?> baseInnerTypeDefinition = getBaseType(typeProviderWrapper, innerTypeDefinition);
+            Type innerTypeBaseType = typeProviderWrapper.getType(baseInnerTypeDefinition, baseInnerTypeDefinition);
+
+            OpenType<?> innerCompositeType;
+
+            if(isDerivedType(innerTypeBaseType, innerType)) {
+                innerCompositeType = getCompositeType(innerTypeBaseType, baseInnerTypeDefinition);
+            } else {
+                innerCompositeType = SimpleTypeResolver.getSimpleType(innerType);
+            }
+
+            itemNames[i] = typeProviderWrapper.getJMXParamForUnionInnerType(innerTypeDefinition);
+            itemTypes[i++] = innerCompositeType;
+        }
+
+        String[] descriptions = Arrays.copyOf(itemNames, itemNames.length);
+        descriptions[0] = DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION;
+
+        try {
+            return new CompositeType(getUpperCaseCammelCase(), description, itemNames, descriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new RuntimeException("Unable to create " + CompositeType.class + " with inner elements "
+                    + Arrays.toString(itemTypes), e);
+        }
+    }
+
+    public static final Class<Character> TYPE_OF_ARTIFICIAL_UNION_PROPERTY = char.class;
+
+    private void addArtificialPropertyToUnionCompositeType(TypeDefinition<?> baseTypeDefinition, String[] itemNames, OpenType<?>[] itemTypes) {
+        String artificialPropertyName = typeProviderWrapper.getJMXParamForBaseType(baseTypeDefinition);
+        itemNames[0] = artificialPropertyName;
+
+        OpenType<?> artificialPropertyType = getArrayOpenTypeForSimpleType(TYPE_OF_ARTIFICIAL_UNION_PROPERTY.getName(),
+                SimpleTypeResolver.getSimpleType(TYPE_OF_ARTIFICIAL_UNION_PROPERTY.getName()));
+        itemTypes[0] = artificialPropertyType;
+    }
+
     private boolean isEnum(Type baseType) {
         return baseType.getFullyQualifiedName().equals(Enum.class.getName());
     }
@@ -163,12 +231,15 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
             throw new RuntimeException("Unable to create " + CompositeType.class + " with inner element of type "
                     + itemTypes, e);
         }
-
     }
 
     private OpenType<?> getArrayType() {
         String innerTypeFullyQName = getInnerType(getType());
         SimpleType<?> innerSimpleType = SimpleTypeResolver.getSimpleType(innerTypeFullyQName);
+        return getArrayOpenTypeForSimpleType(innerTypeFullyQName, innerSimpleType);
+    }
+
+    private OpenType<?> getArrayOpenTypeForSimpleType(String innerTypeFullyQName, SimpleType<?> innerSimpleType) {
         try {
             ArrayType<Object> arrayType = isPrimitive(innerTypeFullyQName) ? new ArrayType<>(innerSimpleType, true)
                     : new ArrayType<>(1, innerSimpleType);
@@ -191,8 +262,8 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
         return type.getName().endsWith("[]");
     }
 
-    private boolean isDerivedType(Type baseType) {
-        return  baseType.equals(getType()) == false;
+    private boolean isDerivedType(Type baseType, Type currentType) {
+        return  baseType.equals(currentType) == false;
     }
 
     private static String getInnerType(Type type) {
index 87b55f3756a0e042c98c89739d91bf0f92ab5285..f4bd979faca43fa5f4bdce943ceeb389ca07b42b 100644 (file)
@@ -59,6 +59,8 @@ public class SimpleTypeResolver {
         JAVA_TYPE_TO_SIMPLE_TYPE.put(Date.class.getName(), SimpleType.DATE);
         JAVA_TYPE_TO_SIMPLE_TYPE.put(Double.class.getName(), SimpleType.DOUBLE);
         JAVA_TYPE_TO_SIMPLE_TYPE.put(double.class.getName(), SimpleType.DOUBLE);
+
+        JAVA_TYPE_TO_SIMPLE_TYPE.put(char.class.getName(), SimpleType.CHARACTER);
     }
 
 }
diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/controller/config/test/types/rev131127/UnionTestBuilder.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/controller/config/test/types/rev131127/UnionTestBuilder.java
new file mode 100644 (file)
index 0000000..c49319b
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127;
+
+
+/**
+**/
+public class UnionTestBuilder {
+
+    public static UnionTest getDefaultInstance(String defaultValue) {
+        try {
+            int i = Integer.valueOf(defaultValue);
+            return new UnionTest(new ExtendTwice(i));
+        } catch (NumberFormatException e) {
+            return new UnionTest(defaultValue);
+        }
+    }
+
+}
index 9ad7a44915b15bdfbce7a64cbdaf2eb02f8bba14..f7cea0a52abbb0b46edb5b431d140dc4482fe76d 100644 (file)
@@ -61,10 +61,6 @@ module config-test-impl {
                     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 {
@@ -136,6 +132,16 @@ module config-test-impl {
                 default ONE;
             }
 
+            leaf ip {
+                type inet:ip-address;
+                default 0:0:0:0:0:0:0:1;
+            }
+
+            leaf union-test-attr {
+                type tt:unionTest;
+                default 456;
+            }
+
             leaf sleep-factor {
                 type decimal64 {
                     fraction-digits 2;
index 84fbcb089d6390ba4478c24a0503442ad0bfd8d1..8c086d8aceb1d5ec21c06f398e57fcd46d8bda62 100644 (file)
@@ -23,4 +23,12 @@ module test-types {
         }
     }
 
+      typedef unionTest {
+        type union {
+          type string;
+          type uint32;
+          type extend-twice;
+        }
+      }
+
 }
index 4c0b81f7d71a4e4ce9a15c527050bfe23977740c..35e160e8274e9fe5ee09bc49ce90f77841218425 100644 (file)
           <artifactId>config-persister-file-adapter</artifactId>
           <version>${config.version}</version>
         </dependency>
-          <dependency>
-              <groupId>org.opendaylight.controller</groupId>
-              <artifactId>config-persister-directory-adapter</artifactId>
-              <version>${config.version}</version>
-          </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>config-persister-file-xml-adapter</artifactId>
+          <version>${config.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>config-persister-directory-adapter</artifactId>
+          <version>${config.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>config-persister-directory-xml-adapter</artifactId>
+          <version>${config.version}</version>
+        </dependency>
 
        <!-- Netconf -->
         <dependency>
           <artifactId>ietf-netconf-monitoring</artifactId>
           <version>${netconf.version}</version>
         </dependency>
+        <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>ietf-netconf-monitoring-extension</artifactId>
+          <version>${netconf.version}</version>
+        </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>config-persister-impl</artifactId>
index 7d57e6005e65774519d579838c90c9cbd4f8fe85..ba5d862c5789357a7d1eec08985d5569fa2ad457 100644 (file)
@@ -29,8 +29,16 @@ netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.confi
 netconf.config.persister.1.properties.directoryStorage=configuration/initial/
 netconf.config.persister.1.readonly=true
 
-netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
-netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.txt
+#netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
+#netconf.config.persister.3.properties.directoryStorage=configuration/initialXml/
+#netconf.config.persister.3.readonly=true
+
+#netconf.config.persister.4.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+#netconf.config.persister.4.properties.fileStorage=configuration/current/controller.currentconfig.txt
+#netconf.config.persister.4.properties.numberOfBackups=1
+
+netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
+netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.xml
 netconf.config.persister.2.properties.numberOfBackups=1
 
 
index fa33215ea6e9454d5c016e5e2f2fb58474099b55..edee185c172bc32a9169e7832b5bd3605579139f 100644 (file)
@@ -16,9 +16,9 @@
                <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>
-            <!-- to switch to the clustered data store, comment out the ref_hash-map-data-store <name> and uncomment the ref_cluster-data-store one -->
-            <name>ref_hash-map-data-store</name>
-            <!-- <name>ref_cluster-data-store</name> -->
+            <!-- to switch to the clustered data store, comment out the hash-map-data-store <name> and uncomment the cluster-data-store one -->
+            <name>hash-map-data-store</name>
+            <!-- <name>cluster-data-store</name> -->
                </data-store>
        </module>
        <module>
                <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>
+                       <name>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>
+                       <name>binding-data-broker</name>
                </data-broker>
        </module>
        <module>
                <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>
+                       <name>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>
+                       <name>runtime-mapping-singleton</name>
                </mapping-service>
        </module>
 //SERVICES START
        <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>
+                       <name>yang-schema-service</name>
                        <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>
+                       <name>binding-notification-broker</name>
                        <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>
+                       <name>hash-map-data-store</name>
                        <provider>/modules/module[type='hash-map-data-store'][name='hash-map-data-store']</provider>
                </instance>
                <instance>
-                       <name>ref_cluster-data-store</name>
+                       <name>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>
+                       <name>binding-osgi-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>
+                       <name>runtime-mapping-singleton</name>
                        <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>
+                       <name>dom-broker</name>
                        <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>
+                       <name>binding-data-broker</name>
                        <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
                </instance>
        </service>
index f5c5620d7cccf3e023211d64629b1f77a55470c7..09585d6273a0c2cecd32e90d4f442313bf685946 100644 (file)
@@ -21,12 +21,22 @@ import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter64;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsUpdatedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForGivenMatchOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsFromFlowTableInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsFromFlowTableOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsOutputBuilder;
@@ -292,4 +302,39 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
         return builder.build();
     }
 
+    @Override
+    public Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> getAggregateFlowStatisticsFromFlowTableForAllFlows(
+            GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput input) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForGivenMatchOutput>> getAggregateFlowStatisticsFromFlowTableForGivenMatch(
+            GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput input) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Future<RpcResult<GetAllFlowStatisticsFromFlowTableOutput>> getAllFlowStatisticsFromFlowTable(
+            GetAllFlowStatisticsFromFlowTableInput input) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Future<RpcResult<GetAllFlowsStatisticsFromAllFlowTablesOutput>> getAllFlowsStatisticsFromAllFlowTables(
+            GetAllFlowsStatisticsFromAllFlowTablesInput input) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Future<RpcResult<GetFlowStatisticsFromFlowTableOutput>> getFlowStatisticsFromFlowTable(
+            GetFlowStatisticsFromFlowTableInput input) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
 }
index 7dcd254ad7cc751e64d30bf275a8629781f625be..1ed1b6827bdc6ace925576b207b7d818d27ac8b5 100644 (file)
@@ -9,7 +9,7 @@ module opendaylight-match-types {
     revision "2013-10-26" {
         description "Initial revision of macth types";
     }
-
+    
     grouping "mac-address-filter" {
         leaf address {
             mandatory true;
@@ -61,14 +61,14 @@ module opendaylight-match-types {
         container vlan-id {
             description "VLAN id.";
             presence "Match field is active and set";
-            
+
+            leaf vlan-id-present {
+                type boolean;
+            }
+                        
             leaf vlan-id {
-                mandatory true;
                 type l2t:vlan-id; 
             }
-            leaf mask {
-                type binary;
-            }
         }
         leaf vlan-pcp {
             description "VLAN priority.";
index 81303d68672464c6a203f0ea0c56714565499678..43754a1dfdad4e7d8354d43005ed52661e47c202 100644 (file)
@@ -332,7 +332,11 @@ module opendaylight-action-types {
                  }            
              }
             }
-             
+
+           case strip-vlan-action-case {
+                container strip-vlan-action {
+                }
+             }
 
             case sw-path-action-case {            
                 container sw-path-action {
@@ -340,4 +344,4 @@ module opendaylight-action-types {
              }  
          }
      }
-}
\ No newline at end of file
+}
index e83306db50db1155ab1d9fb7147fd71e2329cfff..2bcd40522330901eaaf08824d68680cfdb48d381 100644 (file)
@@ -12,6 +12,41 @@ module opendaylight-flow-types {
         description "Initial revision of flow service";
     }
     
+    typedef output-port-values {
+        type enumeration {
+            enum MAX {
+                value 1;
+            }
+            enum IN_PORT {
+                value 2;
+            }
+            enum TABLE {
+                value 3;
+            }
+            enum NORMAL {
+                value 4;
+            }
+            enum FLOOD {
+                value 5;
+            }
+            enum ALL {
+                value 6;
+            }
+            enum CONTROLLER {
+                value 7;
+            }
+            enum LOCAL {
+                value 8;
+            }
+            enum ANY {
+                value 9;
+            }
+            enum NONE {
+                value 10;
+            }
+
+        }
+    }
     grouping instruction-list {
         list instruction {
             key "order";
@@ -227,4 +262,4 @@ module opendaylight-flow-types {
             uses match:match;
         }
     }
-}
\ No newline at end of file
+}
index f0b7e97a15ff5b2a221ed9e15212b7516459de7f..bc05894da82637cfae12f61257fc79bdd2609500 100644 (file)
@@ -4,6 +4,7 @@ module opendaylight-port-types {
 
     import ietf-inet-types {prefix inet; revision-date "2010-09-24";}
     import ietf-yang-types {prefix yang; revision-date "2010-09-24";}
+    import opendaylight-queue-types {prefix queue-types; revision-date "2013-09-25";}
     
     revision "2013-09-25" {
         description "Initial revision of Port Inventory model";
@@ -86,6 +87,13 @@ module opendaylight-port-types {
         uses flow-capable-port;
     }
     
+    grouping queues {
+       list queue {
+               key "queue-id";
+               uses queue-types:queue-packet;
+       }
+    }
+    
     grouping flow-capable-port {    
                 
         uses common-port;
@@ -126,6 +134,8 @@ module opendaylight-port-types {
             units "kbps";
             description "Max port bit rate in kbps";            
         }
+        
+        uses queues;
     }    
     
     grouping port-mod {
index 57a92378c095d6c020af990e750d90d85452d9fc..06f832e114dab818e3e888bbdbcf0113485b2983 100644 (file)
@@ -9,6 +9,11 @@ module opendaylight-queue-types {
         description "Initial revision of Queue Inventory model";
     }
     
+    typedef queue-id {
+            type yang:counter32;
+            description "id for the specific queue.";  
+        }
+    
     typedef queue-properties {
         type enumeration {
             enum min_rate;
@@ -37,8 +42,6 @@ module opendaylight-queue-types {
         }
            
     }
-    
-    
       
     grouping queue-prop-max-rate       {
                
@@ -54,7 +57,7 @@ module opendaylight-queue-types {
                
                
         leaf queue-id {
-            type uint32;
+            type queue-id;
             description "id for the specific queue.";  
         }
         
index 3774f950fc63aa139b35749cfaf9e2c4ffad0af4..5e747e47221ae7557f98b9a22ec9a5caf9fbccc9 100644 (file)
@@ -11,6 +11,10 @@ module opendaylight-table-types {
         description "Initial revision of table service";
     }
 
+    typedef table-id {
+       type uint8;
+    }
+
     typedef table-ref {
         type instance-identifier;
     }
index d717e87f761ea5b8c0897d6b4fc87d4fedf89581..e55c50fb29612f2511adef62063a25b0468575cd 100644 (file)
@@ -15,7 +15,60 @@ module flow-node-inventory {
     revision "2013-08-19" {
         description "Flow Capable Node extensions to the Inventory model";
     }
-
+    
+    identity feature-capability {
+    }
+    
+    identity flow-feature-capability-flow-stats {
+        description "Flow statistics"; 
+        base feature-capability;      
+    }
+    
+    identity flow-feature-capability-table-stats {
+        description "Table statistics";
+        base feature-capability;        
+    }
+    
+    identity flow-feature-capability-port-stats {
+        description "Port statistics";
+        base feature-capability;        
+    }
+    
+    identity flow-feature-capability-stp {
+        description "802.1d spanning tree";
+        base feature-capability;        
+    }
+    
+    identity flow-feature-capability-reserved {
+        description "Reserved, must be zero";
+        base feature-capability;        
+    }
+    
+    identity flow-feature-capability-ip-reasm {
+        description "Can reassemble IP fragments";
+        base feature-capability;        
+    }
+    
+    identity flow-feature-capability-queue-stats {
+        description "Queue statistics";
+        base feature-capability;        
+    }
+    
+    identity flow-feature-capability-arp-match-ip {
+        description "Match IP addresses in ARP pkts";
+        base feature-capability;        
+    }
+    
+    identity flow-feature-capability-group-stats {
+        description "Group statistics";
+        base feature-capability;        
+    }
+    
+    identity flow-feature-capability-port-blocked {
+        description "Switch will block looping ports";
+        base feature-capability;        
+    }
+    
     grouping feature {
         leaf support-state {
             type inv:support-type;
@@ -70,7 +123,8 @@ module flow-node-inventory {
             uses meter:meter;
         }
     }
-
+    
+    
     grouping flow-node {
 
         leaf manufacturer {
@@ -122,6 +176,24 @@ module flow-node-inventory {
                 }
             }
         }
+        
+        container switch-features {
+            
+            leaf max_buffers {
+                type uint32;
+            }
+            
+            leaf max_tables {
+                type uint8;
+            }
+            
+            leaf-list capabilities {
+                type identityref {
+                    base feature-capability;
+                }
+            }
+            
+        }
     }
     
     grouping flow-node-connector {
@@ -149,9 +221,10 @@ module flow-node-inventory {
         ext:augment-identifier "flow-capable-node-connector-update-fields";
         uses flow-node-connector;
     }
-
+    
     augment "/inv:node-connector-updated" {
         ext:augment-identifier "flow-capable-node-connector-updated";
         uses flow-node-connector;
     }
+
 }
\ No newline at end of file
index 87d1559e4921ffed91ad38c8a431ec78523fd4d2..3bd37bcf3387ae4500f45d372f6a6454c949526f 100644 (file)
@@ -3,28 +3,156 @@ module opendaylight-flow-statistics {
     prefix flowstat;
 
     import yang-ext {prefix ext; revision-date "2013-07-09";}
+    import ietf-yang-types {prefix yang; revision-date "2010-09-24";}   
     import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
     import opendaylight-flow-types {prefix flow-types;revision-date "2013-10-26";}
-    import sal-flow {prefix flow;}
     import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";}
+    import opendaylight-table-types {prefix table-types;revision-date "2013-10-26";}
+    import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";}
+    import flow-capable-transaction {prefix tr;}
+    import sal-flow {prefix flow;}
+    
 
     revision "2013-08-19" {
-        description "Initial revision of flow service";
+        description "Initial revision of flow statistics service";
+    }
+       
+       //Augment flow statistics data to the flow-capable-node->table->flow
+       augment "/inv:nodes/inv:node/flow-node:table/flow-node:flow" {
+        ext:augment-identifier "flow-statistics-data";
+        uses flow-statistics;
+    }
+       
+       grouping flow-statistics {
+        container flow-statistics {
+            //config "false";
+               uses flow-types:flow;
+               uses stat-types:generic-statistics;
+        }
+       }    
+       
+       typedef flow-id {
+               description "flow id";
+               type yang:counter32;
+       }
+       
+       grouping flow-and-statistics-map-list {
+               description "List of flow and statistics map";
+               list flow-and-statistics-map-list {
+                       key "flow-id";
+                       leaf flow-id {
+                               type flow-id;
+                       }
+                       uses flow-and-statistics-map;
+               }
+       }
+       
+       grouping flow-and-statistics-map{
+               description "Mapping between flow and its statistics";
+               uses flow-types:flow;
+               uses stat-types:generic-statistics;
+       }
+       
+    // RPC calls to fetch flow statistics
+    rpc get-all-flows-statistics-from-all-flow-tables {
+       description "Fetch statistics of all the flow present in all the flow tables of the switch"; 
+        input {
+            uses inv:node-context-ref;
+        }
+        output {
+            uses flow-and-statistics-map-list;
+            uses tr:transaction-aware;
+        }
+    
     }
 
-    rpc get-node-connector-statistics {
+    rpc get-all-flow-statistics-from-flow-table {
+       description "Fetch statistics of all the flow present in the specific flow table of the switch"; 
         input {
             uses inv:node-context-ref;
-            leaf node-connector {
-                type inv:node-connector-ref;
+            leaf table-id {
+               type table-types:table-id;
             }
         }
         output {
-            uses stat-types:node-connector-statistics;
+            uses flow-and-statistics-map-list;
+            uses tr:transaction-aware;
         }
     }
 
-    rpc get-flow-statistics {
+    rpc get-flow-statistics-from-flow-table {
+       description "Fetch statistics of the specific flow present in the specific flow table of the switch"; 
+        input {
+            uses inv:node-context-ref;
+            uses flow-types:flow;
+        }
+        output {
+            uses flow-and-statistics-map-list;
+            uses tr:transaction-aware;
+        }
+    }
+
+    notification flows-statistics-update {
+       description "Flows statistics sent by switch";
+               leaf moreReplies {
+            type boolean;
+        }
+        uses inv:node;
+               uses flow-and-statistics-map-list;
+               uses tr:transaction-aware;
+    }
+
+       //Models for aggregate flow statistics collection
+       augment "/inv:nodes/inv:node/flow-node:table" {
+        ext:augment-identifier "aggregate-flow-statistics-data";
+        uses aggregate-flow-statistics;
+    }
+       
+       grouping aggregate-flow-statistics {
+        container aggregate-flow-statistics {
+            //config "false";
+               uses stat-types:aggregate-flow-statistics;
+        }
+       }    
+       
+    // RPC calls to fetch flow statistics
+    rpc get-aggregate-flow-statistics-from-flow-table-for-all-flows {
+       description "Fetch aggregate statistics for all the flows present in the specific flow table of the switch"; 
+        input {
+            uses inv:node-context-ref;
+            leaf table-id {
+               type table-types:table-id;
+            }
+        }
+        output {
+               uses stat-types:aggregate-flow-statistics;
+            uses tr:transaction-aware;
+        }
+    }
+    rpc get-aggregate-flow-statistics-from-flow-table-for-given-match {
+       description "Fetch aggregate statistics for all the flow matches to the given match from the given table of the switch"; 
+        input {
+            uses inv:node-context-ref;
+            uses flow-types:flow;
+        }
+        output {
+               uses stat-types:aggregate-flow-statistics;
+            uses tr:transaction-aware;
+        }
+    }
+
+    notification aggregate-flow-statistics-update {
+       description "Aggregate flow statistics for a table, sent by switch";
+               leaf moreReplies {
+            type boolean;
+        }
+        uses inv:node;
+               uses stat-types:aggregate-flow-statistics;
+               uses tr:transaction-aware;
+    }
+       
+       //Keeping flow statistics RPC call for backward compatibility for sal-compatibility layer --START
+       rpc get-flow-statistics {
         input {
             uses inv:node-context-ref;
             uses flow-types:flow;
@@ -45,6 +173,25 @@ module opendaylight-flow-statistics {
         }
     }
 
+    notification flow-statistics-updated {
+        uses flow-types:flow-statistics;
+    }
+       
+       //Keeping flow statistics RPC call for backward compatibility for sal-compatibility layer --END
+       
+       //RPC call to fetch node connector statistics
+    rpc get-node-connector-statistics {
+        input {
+            uses inv:node-context-ref;
+            leaf node-connector {
+                type inv:node-connector-ref;
+            }
+        }
+        output {
+            uses stat-types:node-connector-statistics;
+        }
+    }
+
     rpc get-all-node-connector-statistics {
         input {
             uses inv:node-context-ref;
@@ -56,10 +203,6 @@ module opendaylight-flow-statistics {
         }
     }
 
-    notification flow-statistics-updated {
-        uses flow-types:flow-statistics;
-    }
-
     rpc get-flow-table-statistics {
         input {
             uses inv:node-context-ref;
@@ -79,6 +222,4 @@ module opendaylight-flow-statistics {
     notification node-connector-statistics-updated {
         uses stat-types:node-connector-statistics;
     }
-
-
 }
diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-table-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-table-statistics.yang
new file mode 100644 (file)
index 0000000..b823354
--- /dev/null
@@ -0,0 +1,69 @@
+module opendaylight-flow-table-statistics {
+    namespace "urn:opendaylight:flow:table:statistics";
+    prefix flowtablestat;
+
+       import flow-capable-transaction {prefix tr;}
+    import yang-ext {prefix ext; revision-date "2013-07-09";}
+    import ietf-yang-types {prefix yang; revision-date "2010-09-24";}
+    import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
+    import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";}
+    import opendaylight-table-types {prefix table-types;revision-date "2013-10-26";}
+    import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";}
+    
+
+    contact
+        "Anilkumar Vishnoi
+        Email: avishnoi@in.ibm.com";
+
+    revision "2013-12-15" {
+        description "Initial revision of flow table statistics model";
+    }
+    
+    //Augment flow table statistics data to the table
+       augment "/inv:nodes/inv:node/flow-node:table" {
+        ext:augment-identifier "flow-table-statistics-data";
+        uses flow-table-statistics;
+    }
+       
+       grouping flow-table-statistics {
+        container flow-table-statistics {
+            //config "false";
+               uses stat-types:generic-table-statistics;
+        }
+       }    
+    
+    //RPC calls to fetch flow table statistics
+    grouping flow-table-and-statistics-map {
+       list flow-table-and-statistics-map {
+               key "table-id";
+               leaf table-id {
+                       type table-types:table-id;
+               }
+               uses stat-types:generic-table-statistics;
+       }
+    }
+    
+    rpc get-flow-tables-statistics {
+       description "Fetch statistics of all the flow tables present on the tarnet node";
+       input {
+               uses inv:node-context-ref;
+       }
+       output {
+               uses flow-table-and-statistics-map;
+               uses tr:transaction-aware;
+       }
+    }
+    
+    //Notification to receive table statistics update
+    
+    notification flow-table-statistics-update {
+       description "Receive flow table statistics update";
+       
+               leaf moreReplies {
+            type boolean;
+        }
+        uses inv:node;
+               uses flow-table-and-statistics-map;
+               uses tr:transaction-aware;
+    }
+}
diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/port-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/port-statistics.yang
new file mode 100644 (file)
index 0000000..0cb6a60
--- /dev/null
@@ -0,0 +1,78 @@
+module opendaylight-port-statistics {
+    namespace "urn:opendaylight:port:statistics";
+    prefix portstat;
+
+       import flow-capable-transaction {prefix tr;}
+    import yang-ext {prefix ext; revision-date "2013-07-09";}
+    import ietf-yang-types {prefix yang; revision-date "2010-09-24";}   
+    import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
+    import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";}
+
+    contact
+        "Anilkumar Vishnoi
+        Email: avishnoi@in.ibm.com";
+
+    revision "2013-12-14" {
+        description "Initial revision of port statistics model";
+    }
+    
+    //Augment port statistics data to the flow-capable-node-connector
+       augment "/inv:nodes/inv:node/inv:node-connector" {
+        ext:augment-identifier "flow-capable-node-connector-statistics-data";
+        uses flow-capable-node-connector-statistics;
+    }
+       
+       grouping flow-capable-node-connector-statistics {
+        container flow-capable-node-connector-statistics {
+            //config "false";
+            uses stat-types:node-connector-statistics;
+        }
+       }    
+       
+    // RPC calls
+    rpc get-all-ports-statistics {
+       description "Get statistics for all the ports from the node";
+        input {
+            uses inv:node-context-ref;
+        }
+        output {
+            uses stat-types:node-connector-statistics;
+            uses tr:transaction-aware;
+        }
+    }
+    
+    rpc get-port-statistics {
+       description "Get statistics for given port from the node";
+       input {
+               uses inv:node-context-ref;
+               leaf node-connector-id {
+                       type inv:node-connector-id;
+               }
+       }
+       output {
+            uses stat-types:node-connector-statistics;
+            uses tr:transaction-aware;
+       }
+    }
+    
+    //Notification for port statistics update
+       grouping node-connector-statistics-and-port-number-map {
+               description "List of flow and statistics map";
+               list node-connector-statistics-and-port-number-map {
+                       key "node-connector-id";
+                       leaf node-connector-id {
+                               type inv:node-connector-id;
+                       }
+                       uses stat-types:node-connector-statistics;
+               }
+       }
+
+       notification port-statistics-update {
+        leaf moreReplies {
+            type boolean;
+        }
+        uses inv:node;
+               uses node-connector-statistics-and-port-number-map;
+        uses tr:transaction-aware;
+    }
+}
diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/queue-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/queue-statistics.yang
new file mode 100644 (file)
index 0000000..7665ef7
--- /dev/null
@@ -0,0 +1,101 @@
+module opendaylight-queue-statistics {
+    namespace "urn:opendaylight:queue:statistics";
+    prefix queuestat;
+
+       import flow-capable-transaction {prefix tr;}
+    import yang-ext {prefix ext; revision-date "2013-07-09";}
+    import ietf-yang-types {prefix yang; revision-date "2010-09-24";}   
+    import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
+    import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";}
+    import opendaylight-queue-types {prefix queue-types;revision-date "2013-09-25";}
+    import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";}
+
+    contact
+        "Anilkumar Vishnoi
+        Email: avishnoi@in.ibm.com";
+
+    revision "2013-12-16" {
+        description "Initial revision of queue statistics model";
+    }
+    
+    //Augment queue statistics data to the flow-capable-node-connector
+       augment "/inv:nodes/inv:node/inv:node-connector/flow-node:queue" {
+        ext:augment-identifier "flow-capable-node-connector-queue-statistics-data";
+        uses flow-capable-node-connector-queue-statistics;
+    }
+       
+       grouping flow-capable-node-connector-queue-statistics {
+        container flow-capable-node-connector-queue-statistics {
+            //config "false";
+            uses stat-types:generic-queue-statistics;
+        }
+       }    
+       
+       //RPC calls to fetch queue statistics
+    grouping queue-id-and-statistics-map {
+       list queue-id-and-statistics-map {
+               key "queue-id node-connector-id";
+               leaf queue-id {
+                       type queue-types:queue-id;
+               }
+               leaf node-connector-id {
+                       type inv:node-connector-id;
+               }
+               
+            uses stat-types:generic-queue-statistics;
+       }
+    }
+    
+    rpc get-all-queues-statistics-from-all-ports {
+       description "Get statistics for all the queues attached to all the ports from the node";
+        input {
+            uses inv:node-context-ref;
+        }
+        output {
+            uses queue-id-and-statistics-map;
+            uses tr:transaction-aware;
+        }
+    }
+    
+    rpc get-all-queues-statistics-from-given-port {
+       description "Get statistics for all queues for given port of the node";
+       input {
+               uses inv:node-context-ref;
+               leaf node-connector-id {
+                       type inv:node-connector-id;
+               }
+       }
+       output {
+            uses queue-id-and-statistics-map;
+            uses tr:transaction-aware;
+       }
+    }
+    
+    rpc get-queue-statistics-from-given-port {
+       description "Get statistics for given queues from given port of the node";
+       input {
+               uses inv:node-context-ref;
+               leaf node-connector-id {
+                       type inv:node-connector-id;
+               }
+               leaf queue-id {
+                       type queue-types:queue-id;
+               }
+       }
+       output {
+            uses queue-id-and-statistics-map;
+            uses tr:transaction-aware;
+       }
+    }
+
+    //Notification for port statistics update
+
+       notification queue-statistics-update {
+        leaf moreReplies {
+            type boolean;
+        }
+        uses inv:node;
+               uses queue-id-and-statistics-map;
+        uses tr:transaction-aware;
+    }
+}
index d0b2e6a95931f8abdebf7f0f0c7353791a49b481..7bde486e91da8c4228086a9a6e1e08f8637b8707 100644 (file)
@@ -7,7 +7,18 @@ module opendaylight-statistics-types {
     
     revision "2013-09-25" {
         description "Initial revision of flow service";
-    }    
+    }
+    
+    grouping duration {
+        container duration {
+            leaf second {
+                type yang:counter32;
+            }
+            leaf nanosecond {
+                type yang:counter32;
+            }
+        }
+    }
 
     grouping node-connector-statistics {
        container packets {
@@ -50,14 +61,62 @@ module opendaylight-statistics-types {
         leaf collision-count {
             type uint64;
         }
-        
-        container duration {
-            leaf second {
-                type yang:counter32;
-            }
-            leaf nanosecond {
-                type yang:counter32;
-            }
+        uses duration;
+    }
+    
+    grouping generic-statistics {
+       description "Generic grouping for statistics";
+        leaf packet-count {
+            type yang:counter64;
+        }
+
+        leaf byte-count {
+            type yang:counter64;
+        }
+       uses duration;
+       }
+    
+    grouping generic-table-statistics {
+       description "Generic grouping holding generic statistics related to switch table";
+       leaf active-flows {
+            type yang:counter32;
+       }
+       leaf packets-looked-up {
+               type yang:counter64;
+       }
+       leaf packets-matched {
+               type yang:counter64;
+       }
+    }
+    
+    grouping aggregate-flow-statistics {
+       description "Aggregate flow statistics";
+        leaf packet-count {
+            type yang:counter64;
+        }
+
+        leaf byte-count {
+            type yang:counter64;
         }
+        leaf flow-count {
+            type yang:counter32;
+        }
+    }
+    
+    grouping generic-queue-statistics {
+       description "Generic statistics of switch port attached queues.";
+       leaf transmitted-bytes {
+                       type yang:counter64;
+       }
+       
+       leaf transmitted-packets {
+                       type yang:counter64;
+       }
+       
+       leaf transmission-errors {
+                       type yang:counter64;
+       }
+               uses duration;          
     }
+    
 }
\ No newline at end of file
index b34621d02d6f8da7a7b24e6e60cff5e641b9a8d4..4f2b255afd50c08005fae6abcf0d683db73dd86f 100644 (file)
         <sonar.host.url>https://sonar.opendaylight.org/</sonar.host.url>
         <sonar.branch>${user.name}-private-view</sonar.branch>
         <sonar.language>java</sonar.language>
+        <exam.version>3.0.0</exam.version>
     </properties>
 
     <pluginRepositories>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
             </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.8</version>
+                <executions>
+                    <execution>
+                        <id>add-source</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${project.build.directory}/generated-sources/config</source>
+                                <source>${project.build.directory}/generated-sources/sal</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java
new file mode 100644 (file)
index 0000000..e25b939
--- /dev/null
@@ -0,0 +1,5 @@
+package org.opendaylight.controller.sal.binding.api;
+
+public interface RpcAvailabilityListener {
+
+}
index f9f72094f816d8166c0067f7e1e1aff0829a2aac..1b0f78384f1a6c166b46fed6f4f89152e276c77c 100644 (file)
             <artifactId>ietf-inet-types</artifactId>
             <version>2010.09.24.2-SNAPSHOT</version>
         </dependency>
+        <dependency>
+        <groupId>org.opendaylight.yangtools.model</groupId>
+        <artifactId>ietf-topology-l3-unicast-igp</artifactId>
+        <version>2013.10.21.0-SNAPSHOT</version>
+        <scope>test</scope>
+        </dependency>
         <dependency>
                <groupId>org.opendaylight.controller.model</groupId>
                <artifactId>model-flow-base</artifactId>
index 74b6ad8a235fabbbee093063b25dc40cefb37081..01dc6b8c0cd6162be049fe44d6806524da820f7a 100644 (file)
@@ -16,7 +16,7 @@ import java.util.concurrent.ScheduledExecutorService;
 import org.opendaylight.controller.config.yang.md.sal.binding.statistics.DataBrokerRuntimeMXBeanImpl;\r
 import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter;\r
 import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;\r
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;\r
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;\r
 import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;\r
 import org.opendaylight.controller.sal.core.api.Broker;\r
 import org.opendaylight.controller.sal.core.api.data.DataProviderService;\r
@@ -63,7 +63,7 @@ public final class DataBrokerImplModule extends
         BindingIndependentMappingService mappingService = getMappingServiceDependency();\r
         \r
         if (domBroker != null && mappingService != null) {\r
-            BindingIndependentDataServiceConnector runtimeMapping = new BindingIndependentDataServiceConnector();\r
+            BindingIndependentConnector runtimeMapping = new BindingIndependentConnector();\r
             runtimeMapping.setMappingService(mappingService);\r
             runtimeMapping.setBaDataService(dataBindingBroker);\r
             domBroker.registerProvider(runtimeMapping, getBundleContext());\r
index 1bf15c182f5f93196fe0c3d27fc0438295df2812..99b7ed8acf777a61d4a73c37cbf80500241274ba 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.controller.config.yang.md.sal.binding.impl;
 
 import javassist.ClassPool;
 
+import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
 import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl;
 import org.osgi.framework.BundleContext;
 
@@ -50,8 +51,7 @@ public final class RuntimeMappingModule extends
     @Override
     public java.lang.AutoCloseable createInstance() {
         RuntimeGeneratedMappingServiceImpl service = new RuntimeGeneratedMappingServiceImpl();
-        ClassPool pool = new ClassPool(); // Should be default singleton
-        service.setPool(pool);
+        service.setPool(SingletonHolder.CLASS_POOL);
         service.start(getBundleContext());
         return service;
     }
index f0f92da18e5c3b2235eb77a9cf3d0e32b8df371c..dff0d215b2ac14dece9c9139d677db4de3d74f65 100644 (file)
@@ -76,7 +76,6 @@ class RuntimeCodeHelper {
         if (field == null) throw new UnsupportedOperationException(
             "Unable to set routing table. Table field does not exists");
         field.set(target,routingTable);
-        
     }
 
 }
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java
new file mode 100644 (file)
index 0000000..780d0bd
--- /dev/null
@@ -0,0 +1,161 @@
+package org.opendaylight.controller.sal.binding.codegen.impl;
+
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.spi.RpcRouter;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.HashMap;
+
+import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.RpcImplementation;
+import org.opendaylight.controller.md.sal.common.api.routing.MutableRoutingTable;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class RpcRouterCodegenInstance<T extends RpcService> implements //
+        RpcRouter<T>, RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RpcRouterCodegenInstance.class);
+
+    private T defaultService;
+
+    private final Class<T> serviceType;
+
+    private final T invocationProxy;
+
+    private final Set<Class<? extends BaseIdentity>> contexts;
+
+    private final ListenerRegistry<RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> listeners;
+
+    private final Map<Class<? extends BaseIdentity>, RpcRoutingTableImpl<? extends BaseIdentity, T>> routingTables;
+
+    public RpcRouterCodegenInstance(Class<T> type, T routerImpl, Set<Class<? extends BaseIdentity>> contexts,
+            Set<Class<? extends DataContainer>> inputs) {
+        this.listeners = ListenerRegistry.create();
+        this.serviceType = type;
+        this.invocationProxy = routerImpl;
+        this.contexts = ImmutableSet.copyOf(contexts);
+        Map<Class<? extends BaseIdentity>, RpcRoutingTableImpl<? extends BaseIdentity, T>> mutableRoutingTables = new HashMap<>();
+        for (Class<? extends BaseIdentity> ctx : contexts) {
+            RpcRoutingTableImpl<? extends BaseIdentity, T> table = new RpcRoutingTableImpl<>(ctx);
+            Map invokerView = table.getRoutes();
+            setRoutingTable((RpcService) invocationProxy, ctx, invokerView);
+            mutableRoutingTables.put(ctx, table);
+            table.registerRouteChangeListener(this);
+        }
+        this.routingTables = ImmutableMap.copyOf(mutableRoutingTables);
+    }
+
+    @Override
+    public Class<T> getServiceType() {
+        return serviceType;
+    }
+
+    @Override
+    public T getInvocationProxy() {
+        return invocationProxy;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <C extends BaseIdentity> RpcRoutingTable<C, T> getRoutingTable(Class<C> routeContext) {
+        return (RpcRoutingTable<C, T>) routingTables.get(routeContext);
+    }
+
+    @Override
+    public T getDefaultService() {
+        return defaultService;
+    }
+
+    @Override
+    public Set<Class<? extends BaseIdentity>> getContexts() {
+        return contexts;
+    }
+
+    @Override
+    public <L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
+            L listener) {
+        return listeners.registerWithType(listener);
+    }
+
+    @Override
+    public void onRouteChange(RouteChange<Class<? extends BaseIdentity>, InstanceIdentifier<?>> change) {
+        for (ListenerRegistration<RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> listener : listeners) {
+            try {
+                listener.getInstance().onRouteChange(change);
+            } catch (Exception e) {
+                LOG.error("Error occured during invoker listener {}", listener.getInstance(), e);
+            }
+        }
+    }
+
+    @Override
+    public T getService(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+        return routingTables.get(context).getRoute(path);
+    }
+
+    @Override
+    public RoutedRpcRegistration<T> addRoutedRpcImplementation(T service) {
+        return new RoutedRpcRegistrationImpl(service);
+    }
+
+    @Override
+    public RpcRegistration<T> registerDefaultService(T service) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    private class RoutedRpcRegistrationImpl extends AbstractObjectRegistration<T> implements RoutedRpcRegistration<T> {
+
+        public RoutedRpcRegistrationImpl(T instance) {
+            super(instance);
+        }
+
+        @Override
+        public Class<T> getServiceType() {
+            return serviceType;
+        }
+
+        @Override
+        public void registerPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+            routingTables.get(context).updateRoute(path, getInstance());
+        }
+
+        @Override
+        public void unregisterPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+            routingTables.get(context).removeRoute(path, getInstance());
+
+        }
+
+        @Override
+        public void registerInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<?> instance) {
+            registerPath(context, instance);
+        }
+
+        @Override
+        public void unregisterInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<?> instance) {
+            unregisterPath(context, instance);
+        }
+
+        @Override
+        protected void removeRegistration() {
+
+        }
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend
deleted file mode 100644 (file)
index b6dcde1..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.opendaylight.controller.sal.binding.codegen.impl
-
-import org.opendaylight.yangtools.yang.binding.RpcService
-import org.opendaylight.controller.sal.binding.spi.RpcRouter
-import org.opendaylight.yangtools.yang.binding.BaseIdentity
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*
-import java.util.Set
-import java.util.HashMap
-import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable
-import org.opendaylight.yangtools.yang.binding.DataContainer
-import org.opendaylight.yangtools.yang.binding.RpcImplementation
-
-class RpcRouterCodegenInstance<T extends RpcService> implements RpcRouter<T> {
-
-    @Property
-    val T invocationProxy
-
-    @Property
-    val RpcImplementation invokerDelegate;
-
-    @Property
-    val Class<T> serviceType
-
-    @Property
-    val Set<Class<? extends BaseIdentity>> contexts
-
-    @Property
-    val Set<Class<? extends DataContainer>> supportedInputs;
-
-    val routingTables = new HashMap<Class<? extends BaseIdentity>, RpcRoutingTableImpl<? extends BaseIdentity, ? extends RpcService>>;
-
-    @Property
-    var T defaultService
-
-    new(Class<T> type, T routerImpl, Set<Class<? extends BaseIdentity>> contexts,
-        Set<Class<? extends DataContainer>> inputs) {
-        _serviceType = type
-        _invocationProxy = routerImpl
-        _invokerDelegate = routerImpl as RpcImplementation
-        _contexts = contexts
-        _supportedInputs = inputs;
-
-        for (ctx : contexts) {
-            val table = XtendHelper.createRoutingTable(ctx)
-            invocationProxy.setRoutingTable(ctx, table.routes);
-            routingTables.put(ctx, table);
-        }
-    }
-
-    override <C extends BaseIdentity> getRoutingTable(Class<C> table) {
-        routingTables.get(table) as RpcRoutingTable<C,T>
-    }
-
-    override getService(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
-        val table = getRoutingTable(context);
-        return table.getRoute(path);
-    }
-
-    override <T extends DataContainer> invoke(Class<T> type, T input) {
-        return invokerDelegate.invoke(type, input);
-    }
-
-}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java
new file mode 100644 (file)
index 0000000..f959235
--- /dev/null
@@ -0,0 +1,125 @@
+package org.opendaylight.controller.sal.binding.codegen.impl;
+
+import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Mutable;
+
+class RpcRoutingTableImpl<C extends BaseIdentity, S extends RpcService> //
+implements //
+        Mutable, //
+        RpcRoutingTable<C, S>, //
+        RouteChangePublisher<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
+
+    private final Class<C> identifier;
+    private final ConcurrentMap<InstanceIdentifier<?>, S> routes;
+    private final Map<InstanceIdentifier<?>, S> unmodifiableRoutes;
+
+    private RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> listener;
+    private S defaultRoute;
+
+    public RpcRoutingTableImpl(Class<C> identifier) {
+        super();
+        this.identifier = identifier;
+        this.routes = new ConcurrentHashMap<>();
+        this.unmodifiableRoutes = Collections.unmodifiableMap(routes);
+    }
+
+    @Override
+    public void setDefaultRoute(S target) {
+        defaultRoute = target;
+    }
+
+    @Override
+    public S getDefaultRoute() {
+        return defaultRoute;
+    }
+
+    @Override
+    public <L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
+            L listener) {
+        return (ListenerRegistration<L>) new SingletonListenerRegistration<L>(listener);
+    }
+        
+    @Override
+    public Class<C> getIdentifier() {
+        return identifier;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void updateRoute(InstanceIdentifier<?> path, S service) {
+        S previous = this.routes.put(path, service);
+        @SuppressWarnings("rawtypes")
+        RouteChangeListener listenerCapture = listener;
+        if (previous == null && listenerCapture != null) {
+            listenerCapture.onRouteChange(RoutingUtils.announcementChange(identifier, path));
+        }
+    }
+
+    
+    @Override
+    @SuppressWarnings("unchecked")
+    public void removeRoute(InstanceIdentifier<?> path) {
+        S previous = this.routes.remove(path);
+        @SuppressWarnings("rawtypes")
+        RouteChangeListener listenerCapture = listener;
+        if (previous != null && listenerCapture != null) {
+            listenerCapture.onRouteChange(RoutingUtils.removalChange(identifier, path));
+        }
+    }
+    
+    public void removeRoute(InstanceIdentifier<?> path, S service) {
+        @SuppressWarnings("rawtypes")
+        RouteChangeListener listenerCapture = listener;
+        if (routes.remove(path, service) && listenerCapture != null) {
+            listenerCapture.onRouteChange(RoutingUtils.removalChange(identifier, path));
+        }
+    }
+
+    @Override
+    public S getRoute(InstanceIdentifier<?> nodeInstance) {
+        S route = routes.get(nodeInstance);
+        if (route != null) {
+            return route;
+        }
+        return getDefaultRoute();
+    }
+
+    @Override
+    public Map<InstanceIdentifier<?>, S> getRoutes() {
+        return unmodifiableRoutes;
+    }
+    
+    protected void removeAllReferences(S service) {
+        
+    }
+
+    private class SingletonListenerRegistration<L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> extends
+            AbstractObjectRegistration<L>
+            implements ListenerRegistration<L> {
+
+        public SingletonListenerRegistration(L instance) {
+            super(instance);
+            listener = instance;
+        }
+
+        @Override
+        protected void removeRegistration() {
+            listener = null;
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend
deleted file mode 100644 (file)
index 116a817..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.opendaylight.controller.sal.binding.codegen.impl
-
-import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable
-import org.opendaylight.yangtools.yang.binding.BaseIdentity
-import org.opendaylight.yangtools.yang.binding.RpcService
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import java.util.Map
-import org.opendaylight.yangtools.yang.binding.DataObject
-import java.util.HashMap
-
-class RpcRoutingTableImpl<C extends BaseIdentity,S extends RpcService> implements RpcRoutingTable<C,S>{
-    
-    @Property
-    val Class<C> identifier;
-    
-    @Property
-    var S defaultRoute;
-    
-    @Property
-    val Map<InstanceIdentifier<? extends DataObject>,S> routes;
-    
-    new(Class<C> ident, Map<InstanceIdentifier<? extends DataObject>,S> route) {
-        _identifier = ident
-        _routes = route
-    }
-    
-    new(Class<C> ident) {
-        _identifier = ident
-        _routes = new HashMap
-    }
-    
-    
-    override getRoute(InstanceIdentifier<? extends Object> nodeInstance) {
-        val ret = routes.get(nodeInstance);
-        if(ret !== null) {
-            return ret;
-        }
-        return defaultRoute;
-    }
-    
-    override removeRoute(InstanceIdentifier<? extends Object> path) {
-        routes.remove(path);
-    }
-    
-    @SuppressWarnings("rawtypes")
-    override updateRoute(InstanceIdentifier<? extends Object> path, S service) {
-        routes.put(path as InstanceIdentifier<? extends DataObject>,service);
-    }
-}
\ No newline at end of file
index 90fcbd99aaaad0a6f6448faf0428cbc46cc52b4d..7ebcf02e41fb0ba7e17268aeee1d13f679ff3d31 100644 (file)
@@ -27,7 +27,7 @@ import org.opendaylight.yangtools.yang.binding.Notification
 import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.*
 import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
 import java.util.HashSet
-import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.*
+import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.*
 import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory
 import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker
 import java.util.Set
@@ -37,6 +37,8 @@ import org.opendaylight.yangtools.yang.binding.annotations.QName
 import org.opendaylight.yangtools.yang.binding.DataContainer
 import org.opendaylight.yangtools.yang.binding.RpcImplementation
 import org.opendaylight.controller.sal.binding.codegen.util.JavassistUtils
+import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils
+import javassist.LoaderClassPath
 
 class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory {
 
@@ -45,40 +47,70 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co
     val extension JavassistUtils utils;
     val Map<Class<? extends NotificationListener>, RuntimeGeneratedInvokerPrototype> invokerClasses;
 
-    public new(ClassPool pool) {
+
+    new(ClassPool pool) {
         classPool = pool;
         utils = new JavassistUtils(pool);
         invokerClasses = new WeakHashMap();
         BROKER_NOTIFICATION_LISTENER = org.opendaylight.controller.sal.binding.api.NotificationListener.asCtClass;
+        pool.appendClassPath(new LoaderClassPath(RpcService.classLoader));
     }
 
     override <T extends RpcService> getDirectProxyFor(Class<T> iface) {
-        val supertype = iface.asCtClass
-        val targetCls = createClass(iface.directProxyName, supertype) [
-            field(DELEGATE_FIELD, iface);
-            implementMethodsFrom(supertype) [
-                body = '''
-                {
-                    if(«DELEGATE_FIELD» == null) {
+        val T instance =  withClassLoaderAndLock(iface.classLoader,lock) [|
+            val proxyName = iface.directProxyName;
+            val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(proxyName)
+            if(potentialClass != null) {
+                return potentialClass.newInstance as T;
+            }
+            val supertype = iface.asCtClass
+            val createdCls = createClass(iface.directProxyName, supertype) [
+                field(DELEGATE_FIELD, iface);
+                implementsType(RpcImplementation.asCtClass)
+                implementMethodsFrom(supertype) [
+                    body = '''
+                    {
+                        if(«DELEGATE_FIELD» == null) {
+                            throw new java.lang.IllegalStateException("No provider is processing supplied message");
+                        }
+                        return ($r) Â«DELEGATE_FIELD».«it.name»($$);
+                    }
+                    '''
+                ]
+                implementMethodsFrom(RpcImplementation.asCtClass) [
+                    body = '''
+                    {
                         throw new java.lang.IllegalStateException("No provider is processing supplied message");
+                        return ($r) null;
                     }
-                    return ($r) Â«DELEGATE_FIELD».«it.name»($$);
-                }
-                '''
+                    '''
+                ]
             ]
+            return createdCls.toClass(iface.classLoader).newInstance as T
         ]
-        return targetCls.toClass(iface.classLoader).newInstance as T
+        return instance;
     }
 
     override <T extends RpcService> getRouterFor(Class<T> iface) {
-        val instance = <RpcRouterCodegenInstance<T>>withClassLoaderAndLock(iface.classLoader,lock) [ |
+        val metadata = withClassLoader(iface.classLoader) [|
+            val supertype = iface.asCtClass
+            return supertype.rpcMetadata;
+        ]
+        
+        val instance = <T>withClassLoaderAndLock(iface.classLoader,lock) [ |
             val supertype = iface.asCtClass
-            val metadata = supertype.rpcMetadata;
+            val routerName = iface.routerName;
+            val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(routerName)
+            if(potentialClass != null) {
+                return potentialClass.newInstance as T;
+            }
+            
             val targetCls = createClass(iface.routerName, supertype) [
-                addInterface(RpcImplementation.asCtClass)
+                
                 
                 field(DELEGATE_FIELD, iface)
                 //field(REMOTE_INVOKER_FIELD,iface);
+                implementsType(RpcImplementation.asCtClass)
                 
                 for (ctx : metadata.contexts) {
                     field(ctx.routingTableField, Map)
@@ -105,35 +137,18 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co
                     }
                 ]
                 implementMethodsFrom(RpcImplementation.asCtClass) [
-                    switch (name) {
-                        case "getSupportedInputs":
-                            body = '''
-                            {
-                                throw new java.lang.UnsupportedOperationException("Not implemented yet");
-                                return ($r) null;
-                            }'''
-                        case "invoke": {
-                            val tmpBody = '''
-                            {
-                                Â«FOR input : metadata.supportedInputs SEPARATOR " else "»
-                                Â«val rpcMetadata = metadata.rpcInputs.get(input)»
-                                if(«input.name».class.equals($1)) {
-                                    return ($r) this.«rpcMetadata.methodName»((«input.name») $2);
-                                }
-                                Â«ENDFOR»
-                                throw new java.lang.IllegalArgumentException("Not supported message type");
-                                return ($r) null;
-                            }
-                            '''
-                            body = tmpBody
-                        }
+                    body = '''
+                    {
+                        throw new java.lang.IllegalStateException("No provider is processing supplied message");
+                        return ($r) null;
                     }
+                    '''
                 ]
             ]
-            val instance = targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T
-            return new RpcRouterCodegenInstance(iface, instance, metadata.contexts,metadata.supportedInputs);
+            return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T
+            
         ];
-        return instance;
+        return new RpcRouterCodegenInstance(iface, instance, metadata.contexts,metadata.supportedInputs);
     }
 
     private def RpcServiceMetadata getRpcMetadata(CtClass iface) {
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java
new file mode 100644 (file)
index 0000000..266293f
--- /dev/null
@@ -0,0 +1,14 @@
+package org.opendaylight.controller.sal.binding.codegen.impl;
+
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
+import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory;
+
+import javassist.ClassPool;
+
+public class SingletonHolder {
+
+    public static final ClassPool CLASS_POOL = new ClassPool(); 
+    public static final org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator RPC_GENERATOR_IMPL = new org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator(CLASS_POOL);
+    public static final RuntimeCodeGenerator RPC_GENERATOR = RPC_GENERATOR_IMPL;
+    public static final NotificationInvokerFactory INVOKER_FACTORY = RPC_GENERATOR_IMPL.getInvokerFactory();
+}
index 802e7acb5bb993976a8a5d04a1c1776a6c8a67c8..74efffafc6f590ed0a1804abc22409c219a877d3 100644 (file)
@@ -12,9 +12,16 @@ import javassist.LoaderClassPath
 import javassist.ClassClassPath
 import java.util.concurrent.locks.Lock
 import java.util.concurrent.locks.ReentrantLock
+import org.slf4j.LoggerFactory
+import java.util.HashMap
+import java.util.WeakHashMap
 
 class JavassistUtils {
 
+    private static val LOG = LoggerFactory.getLogger(JavassistUtils);
+
+    private val loaderClassPaths = new WeakHashMap<ClassLoader,LoaderClassPath>();
+
     ClassPool classPool
     
     @Property
@@ -95,14 +102,27 @@ class JavassistUtils {
         try {
             return pool.get(cls.name)
         } catch (NotFoundException e) {
-            pool.appendClassPath(new LoaderClassPath(cls.classLoader));
+            appendClassLoaderIfMissing(cls.classLoader)
             try {
                 return pool.get(cls.name)
-
             } catch (NotFoundException ef) {
+                LOG.warn("Appending ClassClassPath for {}",cls);
                 pool.appendClassPath(new ClassClassPath(cls));
+                
                 return pool.get(cls.name)
             }
         }
     }
+    
+    def void appendClassLoaderIfMissing(ClassLoader loader) {
+        if(loaderClassPaths.containsKey(loader)) {
+            return;
+        }
+        val ctLoader = new LoaderClassPath(loader);
+        classPool.appendClassPath(ctLoader);
+    }
+    
+    def void ensureClassLoader(Class<?> child) {
+        appendClassLoaderIfMissing(child.classLoader);
+    }
 }
index 39bd0816f50fb63e68bbbdb85ca7cbdce74812b6..f1ba5843bac1320c5dac335cae8e07761b7ae557 100644 (file)
@@ -175,7 +175,7 @@ public class LazyGeneratedCodecRegistry implements //
                     });
             return ret;
         } catch (Exception e) {
-            LOG.error("Could not find augmentable for {}", augmentation, e);
+            LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e);
             return null;
         }
     }
@@ -389,8 +389,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());
+        for (Entry<QName, GeneratedTOBuilder> identity : context.getIdentities().entrySet()) {
+            typeToQname.put(
+                    new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()),
+                    identity.getKey());
         }
         captureCases(context.getCases(), schemaContext);
     }
@@ -947,12 +949,12 @@ public class LazyGeneratedCodecRegistry implements //
         @Override
         public Class<?> deserialize(QName input) {
             Type type = qnamesToIdentityMap.get(input);
-            if(type == null) {
+            if (type == null) {
                 return null;
             }
             ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
             WeakReference<Class> softref = typeToClass.get(typeref);
-            if(softref == null) {
+            if (softref == null) {
                 return null;
             }
             return softref.get();
@@ -963,12 +965,12 @@ public class LazyGeneratedCodecRegistry implements //
             checkArgument(BaseIdentity.class.isAssignableFrom(input));
             bindingClassEncountered(input);
             QName qname = identityQNames.get(input);
-            if(qname != null) {
+            if (qname != null) {
                 return qname;
             }
             ConcreteType typeref = Types.typeForClass(input);
             qname = typeToQname.get(typeref);
-            if(qname != null) {
+            if (qname != null) {
                 identityQNames.put(input, qname);
             }
             return qname;
@@ -980,4 +982,26 @@ public class LazyGeneratedCodecRegistry implements //
             return serialize((Class) input);
         }
     }
+
+    public boolean isCodecAvailable(Class<? extends DataContainer> cls) {
+        if (containerCodecs.containsKey(cls)) {
+            return true;
+        }
+        if (identifierCodecs.containsKey(cls)) {
+            return true;
+        }
+        if (choiceCodecs.containsKey(cls)) {
+            return true;
+        }
+        if (caseCodecs.containsKey(cls)) {
+            return true;
+        }
+        if (augmentableCodecs.containsKey(cls)) {
+            return true;
+        }
+        if (augmentationCodecs.containsKey(cls)) {
+            return true;
+        }
+        return false;
+    }
 }
\ No newline at end of file
index 13975cad4c807abc636870f99fbea2a921e4a312..1b3acf7674eda63e4430ec8d61b7ef186a2b6c80 100644 (file)
@@ -43,6 +43,11 @@ 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
+import org.opendaylight.yangtools.yang.binding.RpcService
+import java.util.Set
+import org.opendaylight.yangtools.yang.common.QName
+import com.google.common.collect.FluentIterable
+import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
 
 class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
 
@@ -65,6 +70,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
 
     @Property
     val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
+    
+    @Property
+    val ConcurrentMap<Type,Set<QName>> serviceTypeToRpc = new ConcurrentHashMap(); 
 
     val promisedTypeDefinitions = HashMultimap.<Type, SettableFuture<GeneratedTypeBuilder>>create;
 
@@ -85,10 +93,17 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
 
             registry.onModuleContextAdded(schemaContext, entry.key, entry.value);
             binding.pathToType.putAll(entry.value.childNodes)
-            //val module = entry.key;
+            val module = entry.key;
             val context = entry.value;
             updateBindingFor(context.childNodes, schemaContext);
             updateBindingFor(context.cases, schemaContext);
+            val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module);
+            
+            if(!module.rpcs.empty) {
+            val rpcs = FluentIterable.from(module.rpcs).transform[QName].toSet
+            val serviceClass = new ReferencedTypeImpl(namespace,BindingGeneratorUtil.parseToClassName(module.name)+"Service");
+                serviceTypeToRpc.put(serviceClass,rpcs);
+            }
 
             val typedefs = context.typedefs;
             for (typedef : typedefs.entrySet) {
@@ -170,7 +185,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
              */
             return;
         }
-        
+        if(registry.isCodecAvailable(class1)) {
+            return;
+        }
         val ref = Types.typeForClass(class1);
         getSchemaWithRetry(ref);
     }
@@ -184,15 +201,7 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
     }
 
     override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode node) {
-        return tryDeserialization[ |
-            if (node == null) {
-                return null;
-            }
-            val targetType = path.targetType
-            val transformer = registry.getCodecForDataObject(targetType);
-            val ret = transformer.deserialize(node)?.value as DataObject;
-            return ret;
-        ]
+         dataObjectFromDataDom(path.targetType,node) as DataObject;
     }
 
     override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) {
@@ -241,30 +250,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
             listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable<String, String>());
         }
     }
-
-    private def getTypeDefinition(Type type) {
-        val typeDef = typeToDefinition.get(type);
-        if (typeDef !== null) {
-            return typeDef;
-        }
-        return type.getTypeDefInFuture.get();
-    }
-
-    private def Future<GeneratedTypeBuilder> getTypeDefInFuture(Type type) {
-        val future = SettableFuture.<GeneratedTypeBuilder>create()
-        promisedTypeDefinitions.put(type, future);
-        return future;
-    }
-
-    private def void updatePromisedTypeDefinitions(GeneratedTypeBuilder builder) {
-        val futures = promisedTypeDefinitions.get(builder);
-        if (futures === null || futures.empty) {
-            return;
-        }
-        for (future : futures) {
-            future.set(builder);
-        }
-        promisedTypeDefinitions.removeAll(builder);
+    
+    override getRpcQNamesFor(Class<? extends RpcService> service) {
+        return serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name,service.simpleName));
     }
 
     private def getSchemaWithRetry(Type type) {
@@ -297,5 +285,16 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
     override close() throws Exception {
         listenerRegistration?.unregister();
     }
+    
+    override dataObjectFromDataDom(Class<? extends DataContainer> container, CompositeNode domData) {
+        return tryDeserialization[ |
+            if (domData == null) {
+                return null;
+            }
+            val transformer = registry.getCodecForDataObject(container);
+            val ret = transformer.deserialize(domData)?.value as DataObject;
+            return ret;
+        ]
+    }
 
 }
index b2d25af8850bd5b40a369e136baf710d9e669735..4271ef9c1a9bb5824f04673cbcf1e86f466c7c52 100644 (file)
@@ -51,6 +51,11 @@ import org.opendaylight.yangtools.yang.model.util.ExtendedType
 import org.opendaylight.yangtools.yang.model.util.EnumerationType
 import static com.google.common.base.Preconditions.*
 import org.opendaylight.yangtools.yang.model.api.SchemaPath
+import javassist.CtMethod
+import javassist.CannotCompileException
+import java.util.concurrent.locks.Lock
+import java.util.concurrent.Callable
+import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils
 
 class TransformerGenerator {
 
@@ -91,7 +96,7 @@ class TransformerGenerator {
 
     @Property
     var GeneratorListener listener;
-    
+
     public static val CLASS_TYPE = Types.typeForClass(Class);
 
     public new(ClassPool pool) {
@@ -276,7 +281,7 @@ class TransformerGenerator {
                 implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = '''
+                    bodyChecked = '''
                         {
                             Â«QName.name» _resultName;
                             if($1 != null) {
@@ -298,7 +303,7 @@ class TransformerGenerator {
                 ]
                 method(Object, "fromDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = '''
+                    bodyChecked = '''
                         {
                             if($2 == null){
                                 return  null;
@@ -319,7 +324,7 @@ class TransformerGenerator {
                     '''
                 ]
                 method(Object, "serialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         {
                             java.util.Map.Entry _input =  (java.util.Map.Entry) $1;
                             Â«QName.name» _localQName = («QName.name») _input.getKey();
@@ -329,7 +334,7 @@ class TransformerGenerator {
                     '''
                 ]
                 method(Object, "deserialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         return fromDomStatic(QNAME,$1);
                     '''
                 ]
@@ -357,7 +362,7 @@ class TransformerGenerator {
                 staticField(it, IDENTITYREF_CODEC, BindingCodec)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = '''
+                    bodyChecked = '''
                         {
                             Â«QName.name» _resultName = Â«QName.name».create($1,QNAME.getLocalName());
                             java.util.List _childNodes = new java.util.ArrayList();
@@ -368,7 +373,7 @@ class TransformerGenerator {
                     '''
                 ]
                 method(Object, "serialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         {
                             java.util.Map.Entry _input = (java.util.Map.Entry) $1;
                             Â«QName.name» _localName = QNAME;
@@ -381,10 +386,10 @@ class TransformerGenerator {
                 ]
                 method(Object, "fromDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = deserializeBody(type, node)
+                    bodyChecked = deserializeBody(type, node)
                 ]
                 method(Object, "deserialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         {
                             //System.out.println("«type.name»#deserialize: " +$1);
                             java.util.Map.Entry _input = (java.util.Map.Entry) $1;
@@ -418,10 +423,10 @@ class TransformerGenerator {
                 implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = serializeBodyFacade(typeSpec, node)
+                    bodyChecked = serializeBodyFacade(typeSpec, node)
                 ]
                 method(Object, "serialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         {
                             java.util.Map.Entry _input = (java.util.Map.Entry) $1;
                             Â«QName.name» _localName = QNAME;
@@ -434,10 +439,10 @@ class TransformerGenerator {
                 ]
                 method(Object, "fromDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = deserializeBody(typeSpec, node)
+                    bodyChecked = deserializeBody(typeSpec, node)
                 ]
                 method(Object, "deserialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         return fromDomStatic(QNAME,$1);
                     '''
                 ]
@@ -468,7 +473,7 @@ class TransformerGenerator {
                 implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = '''
+                    bodyChecked = '''
                         {
                             //System.out.println("Qname " + $1);
                             //System.out.println("Value " + $2);
@@ -485,7 +490,7 @@ class TransformerGenerator {
                     '''
                 ]
                 method(Object, "serialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         {
                         java.util.Map.Entry _input = (java.util.Map.Entry) $1;
                         Â«QName.name» _localName = QNAME;
@@ -498,7 +503,7 @@ class TransformerGenerator {
                 ]
                 method(Object, "fromDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = '''
+                    bodyChecked = '''
                         {
                             Â«QName.name» _localQName = QNAME;
                             
@@ -522,7 +527,7 @@ class TransformerGenerator {
                     '''
                 ]
                 method(Object, "deserialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         return fromDomStatic(QNAME,$1);
                     '''
                 ]
@@ -553,7 +558,7 @@ class TransformerGenerator {
                 implementsType(BINDING_CODEC)
                 method(List, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = '''
+                    bodyChecked = '''
                         {
                             if($2 == null) {
                                 return null;
@@ -572,13 +577,13 @@ class TransformerGenerator {
                     '''
                 ]
                 method(Object, "serialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         throw new Â«UnsupportedOperationException.name»("Direct invocation not supported.");
                     '''
                 ]
                 method(Object, "fromDomStatic", QName, Map) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = '''
+                    bodyChecked = '''
                         {
                             Â«BINDING_CODEC.name» _codec = («BINDING_CODEC.name») Â«COMPOSITE_TO_CASE».get($2);
                             if(_codec != null) {
@@ -589,7 +594,7 @@ class TransformerGenerator {
                     '''
                 ]
                 method(Object, "deserialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         throw new Â«UnsupportedOperationException.name»("Direct invocation not supported.");
                     '''
                 ]
@@ -822,17 +827,15 @@ class TransformerGenerator {
                 val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
-            var hasBinding = false;
-            try {
-                val bindingCodecClass = loadClassWithTCCL(BINDING_CODEC.name);
-                hasBinding = bindingCodecClass !== null;
-            } catch (ClassNotFoundException e) {
-                hasBinding = false;
+            if (returnType.name == 'char[]') {
+                val ctCls = createUnionImplementation(inputType, typeSpec);
+                val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+                return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
-            val hasYangBinding = hasBinding
+
             val ctCls = createClass(typeSpec.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
-                if (hasYangBinding) {
+                if (inputType.isYangBindingAvailable) {
                     implementsType(BINDING_CODEC)
                     staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
                     staticField(it, IDENTITYREF_CODEC, BindingCodec)
@@ -840,7 +843,8 @@ class TransformerGenerator {
                 }
                 method(Object, "toDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = '''
+                    val ctSpec = typeSpec.asCtClass;
+                    bodyChecked = '''
                         {
                             //System.out.println("«inputType.simpleName»#toDomValue: "+$1);
                             
@@ -857,7 +861,7 @@ class TransformerGenerator {
                     '''
                 ]
                 method(Object, "serialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         {
                             return toDomValue($1);
                         }
@@ -865,7 +869,7 @@ class TransformerGenerator {
                 ]
                 method(Object, "fromDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = '''
+                    bodyChecked = '''
                         {
                             //System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
                             
@@ -879,7 +883,7 @@ class TransformerGenerator {
                     '''
                 ]
                 method(Object, "deserialize", Object) [
-                    body = '''{
+                    bodyChecked = '''{
                             return fromDomValue($1);
                     }
                     '''
@@ -898,18 +902,104 @@ class TransformerGenerator {
 
     }
 
+    def createUnionImplementation(Class<?> inputType, GeneratedTransferObject typeSpec) {
+        return createClass(typeSpec.codecClassName) [
+            val properties = typeSpec.allProperties;
+            //staticField(Map,"AUGMENTATION_SERIALIZERS");
+            if (inputType.isYangBindingAvailable) {
+                implementsType(BINDING_CODEC)
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                implementsType(BindingDeserializer.asCtClass)
+            }
+            method(Object, "toDomValue", Object) [
+                modifiers = PUBLIC + FINAL + STATIC
+                val ctSpec = inputType.asCtClass;
+                bodyChecked = '''
+                    {
+                        //System.out.println("«inputType.simpleName»#toDomValue: "+$1);
+                        
+                        if($1 == null) {
+                            return null;
+                        }
+                        Â«typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1;
+                        Â«FOR property : properties.entrySet»
+                            Â«IF property.key != "getValue"»
+                                Â«property.value.resolvedName» Â«property.key» = («property.value.resolvedName») _value.«property.key»();
+                                if(«property.key» != null) { 
+                                    return Â«serializeValue(property.value, property.key)»;
+                                }
+                            Â«ENDIF»
+                        Â«ENDFOR»
+                        
+                        return null;
+                    }
+                '''
+            ]
+            method(Object, "serialize", Object) [
+                bodyChecked = '''
+                    {
+                        return toDomValue($1);
+                    }
+                '''
+            ]
+            method(Object, "fromDomValue", Object) [
+                modifiers = PUBLIC + FINAL + STATIC
+                bodyChecked = '''
+                    {
+                        //System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
+                        
+                        if($1 == null) {
+                            return null;
+                        }
+                        if($1 instanceof String) {
+                            String _simpleValue = (String) $1;
+                            return new Â«typeSpec.resolvedName»(_simpleValue.toCharArray());
+                        }
+                        return null;
+                    }
+                '''
+            ]
+            method(Object, "deserialize", Object) [
+                bodyChecked = '''{
+                            return fromDomValue($1);
+                    }
+                    '''
+            ]
+        ]
+    }
+
+    def boolean isYangBindingAvailable(Class<?> class1) {
+        try {
+            val bindingCodecClass = class1.classLoader.loadClass(BINDING_CODEC.name);
+            return bindingCodecClass !== null;
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+    }
+
     private def createDummyImplementation(Class<?> object, GeneratedTransferObject typeSpec) {
         log.info("Generating Dummy DOM Codec for {} with {}", object, object.classLoader)
         return createClass(typeSpec.codecClassName) [
-            //staticField(Map,"AUGMENTATION_SERIALIZERS");
-            implementsType(BINDING_CODEC)
-            implementsType(BindingDeserializer.asCtClass)
+            if (object.isYangBindingAvailable) {
+                implementsType(BINDING_CODEC)
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, IDENTITYREF_CODEC, BindingCodec)
+                implementsType(BindingDeserializer.asCtClass)
+            }
+            //implementsType(BindingDeserializer.asCtClass)
             method(Object, "toDomValue", Object) [
                 modifiers = PUBLIC + FINAL + STATIC
-                body = '''return null;'''
+                bodyChecked = '''{
+                    if($1 == null) {
+                        return null;
+                    }
+                    return $1.toString();
+                    
+                    }'''
             ]
             method(Object, "serialize", Object) [
-                body = '''
+                bodyChecked = '''
                     {
                         return toDomValue($1);
                     }
@@ -917,10 +1007,10 @@ class TransformerGenerator {
             ]
             method(Object, "fromDomValue", Object) [
                 modifiers = PUBLIC + FINAL + STATIC
-                body = '''return null;'''
+                bodyChecked = '''return null;'''
             ]
             method(Object, "deserialize", Object) [
-                body = '''{
+                bodyChecked = '''{
                         return fromDomValue($1);
                     }
                     '''
@@ -952,7 +1042,7 @@ class TransformerGenerator {
                 //implementsType(BINDING_CODEC)
                 method(Object, "toDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = '''{
+                    bodyChecked = '''{
                             if($1 == null) {
                                 return null;
                             }
@@ -967,13 +1057,13 @@ class TransformerGenerator {
                     '''
                 ]
                 method(Object, "serialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         return toDomValue($1);
                     '''
                 ]
                 method(Object, "fromDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = '''
+                    bodyChecked = '''
                         {
                             if($1 == null) {
                                 return null;
@@ -989,7 +1079,7 @@ class TransformerGenerator {
                     '''
                 ]
                 method(Object, "deserialize", Object) [
-                    body = '''
+                    bodyChecked = '''
                         return fromDomValue($1);
                     '''
                 ]
@@ -1200,9 +1290,12 @@ 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)) {
+        } else if (CLASS_TYPE.equals(signature)) {
             return '''(«QName.resolvedName») Â«IDENTITYREF_CODEC».serialize(«property»)'''
         }
+        if ("char[]" == signature.name) {
+            return '''new String(«property»)''';
+        }
         return '''«property»''';
     }
 
@@ -1316,6 +1409,21 @@ class TransformerGenerator {
         throw exception;
     }
 
+    private def setBodyChecked(CtMethod method, String body) {
+        try {
+            method.setBody(body);
+        } catch (CannotCompileException e) {
+            log.error("Cannot compile method: {}#{} {}, Reason: {} Body: {}", method.declaringClass, method.name,
+                method.signature, e.message, body)
+            throw e;
+        }
+    }
+
+    private def <V> V withClassLoaderAndLock(ClassLoader cls, Lock lock, Callable<V> function) throws Exception {
+        appendClassLoaderIfMissing(cls);
+        ClassLoaderUtils.withClassLoaderAndLock(cls, lock, function);
+    }
+
 }
 
 @Data
index 9381a5a070e67e7c82226c5b920b06f9a952cc67..8d3545fbbb169f7faafd40330660dc5b109342ef 100644 (file)
@@ -13,7 +13,6 @@ import org.opendaylight.yangtools.yang.binding.RpcService
 import javassist.ClassPool
 import org.osgi.framework.BundleContext
 import java.util.Map
-import java.util.HashMap
 import javassist.LoaderClassPath
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker
 import java.util.Hashtable
@@ -49,29 +48,14 @@ import java.util.concurrent.Callable
 import java.util.WeakHashMap
 import javax.annotation.concurrent.GuardedBy
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry
+import org.opendaylight.yangtools.concepts.ListenerRegistration
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry
 
-class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry, AutoCloseable {
+class BindingAwareBrokerImpl extends RpcProviderRegistryImpl implements BindingAwareBroker, AutoCloseable {
     private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl)
 
     private InstanceIdentifier<? extends DataObject> root = InstanceIdentifier.builder().toInstance();
 
-    private static val clsPool = ClassPool.getDefault()
-    public static var RuntimeCodeGenerator generator;
-
-    /**
-     * Map of all Managed Direct Proxies
-     * 
-     */
-    private val Map<Class<? extends RpcService>, RpcProxyContext> managedProxies = new ConcurrentHashMap();
-
-    /**
-     * 
-     * Map of all available Rpc Routers
-     * 
-     * 
-     */
-    private val Map<Class<? extends RpcService>, RpcRouter<? extends RpcService>> rpcRouters = new WeakHashMap();
-
     @Property
     private var NotificationProviderService notifyBroker
 
@@ -81,43 +65,15 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry,
     @Property
     var BundleContext brokerBundleContext
 
-    ServiceRegistration<NotificationProviderService> notifyProviderRegistration
-
-    ServiceRegistration<NotificationService> notifyConsumerRegistration
-
-    ServiceRegistration<DataProviderService> dataProviderRegistration
-
-    ServiceRegistration<DataBrokerService> dataConsumerRegistration
-
-    private val proxyGenerationLock = new ReentrantLock;
-
-    private val routerGenerationLock = new ReentrantLock;
-
     public new(BundleContext bundleContext) {
         _brokerBundleContext = bundleContext;
     }
 
     def start() {
         log.info("Starting MD-SAL: Binding Aware Broker");
-        initGenerator();
-
-        val executor = Executors.newCachedThreadPool;
-
-        // Initialization of notificationBroker
-        log.info("Starting MD-SAL: Binding Aware Notification Broker");
-
-        log.info("Starting MD-SAL: Binding Aware Data Broker");
-
-        log.info("Starting MD-SAL: Binding Aware Data Broker");
-        log.info("MD-SAL: Binding Aware Broker Started");
     }
 
-    def initGenerator() {
 
-        // YANG Binding Class Loader
-        clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader));
-        generator = new RuntimeCodeGenerator(clsPool);
-    }
 
     override registerConsumer(BindingAwareConsumer consumer, BundleContext bundleCtx) {
         val ctx = consumer.createContext(bundleCtx)
@@ -139,247 +95,9 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry,
     private def createContext(BindingAwareProvider provider, BundleContext providerCtx) {
         new OsgiProviderContext(providerCtx, this)
     }
-
-    /**
-     * Returns a Managed Direct Proxy for supplied class
-     * 
-     * Managed direct proxy is a generated proxy class conforming to the supplied interface
-     * which delegates all calls to the backing delegate.
-     * 
-     * Proxy does not do any validation, null pointer checks or modifies data in any way, it
-     * is only use to avoid exposing direct references to backing implementation of service.
-     * 
-     * If proxy class does not exist for supplied service class it will be generated automatically.
-     */
-    private def <T extends RpcService> getManagedDirectProxy(Class<T> service) {
-        var RpcProxyContext existing = null
-
-        if ((existing = managedProxies.get(service)) != null) {
-            return existing.proxy
-        }
-        return withLock(proxyGenerationLock) [ |
-            val maybeProxy = managedProxies.get(service);
-            if (maybeProxy !== null) {
-                return maybeProxy.proxy;
-            }
-            
-            
-            val proxyInstance = generator.getDirectProxyFor(service)
-            val rpcProxyCtx = new RpcProxyContext(proxyInstance.class)
-            val properties = new Hashtable<String, String>()
-            rpcProxyCtx.proxy = proxyInstance as RpcService
-            properties.salServiceType = SAL_SERVICE_TYPE_CONSUMER_PROXY
-            rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties)
-            managedProxies.put(service, rpcProxyCtx)
-            return rpcProxyCtx.proxy
-        ]
-    }
-
-    private static def <T> T withLock(ReentrantLock lock, Callable<T> method) {
-        try {
-            lock.lock();
-            val ret = method.call;
-            return ret;
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    /**
-     * Registers RPC Implementation
-     * 
-     */
-    override <T extends RpcService> addRpcImplementation(Class<T> type, T service) {
-        checkNotNull(type, "Service type should not be null")
-        checkNotNull(service, "Service type should not be null")
-        
-        val proxy = getManagedDirectProxy(type)
-        checkState(proxy.delegate === null, "The Service for type %s is already registered", type)
-
-        proxy.delegate = service;
-        return new RpcServiceRegistrationImpl<T>(type, service, this);
-    }
-
-    override <T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> type, T service) {
-        checkNotNull(type, "Service type should not be null")
-        checkNotNull(service, "Service type should not be null")
-        
-        val router = resolveRpcRouter(type);
-        checkState(router !== null)
-        return new RoutedRpcRegistrationImpl<T>(service, router, this)
-    }
     
-    override <T extends RpcService> getRpcService(Class<T> service) {
-        checkNotNull(service, "Service should not be null");
-        return getManagedDirectProxy(service) as T;
-    }
-
-    private def <T extends RpcService> RpcRouter<T> resolveRpcRouter(Class<T> type) {
-
-        val router = rpcRouters.get(type);
-        if (router !== null) {
-            return router as RpcRouter<T>;
-        }
-
-        // We created Router
-        return withLock(routerGenerationLock) [ |
-            val maybeRouter = rpcRouters.get(type);
-            if (maybeRouter !== null) {
-                return maybeRouter as RpcRouter<T>;
-            }
-            
-            val newRouter = generator.getRouterFor(type);
-            checkState(newRouter !== null);
-            rpcRouters.put(type, newRouter);
-            // We create / update Direct Proxy for router
-            val proxy = getManagedDirectProxy(type);
-            proxy.delegate = newRouter.invocationProxy
-            return newRouter;
-        ]
-
-    }
-
-    protected def <T extends RpcService> void registerPath(RoutedRpcRegistrationImpl<T> registration,
-        Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> path) {
-
-        val router = registration.router;
-        val paths = registration.registeredPaths;
-
-        val routingTable = router.getRoutingTable(context)
-        checkState(routingTable != null);
-
-        // Updating internal structure of registration
-        routingTable.updateRoute(path, registration.instance)
-
-        // Update routing table / send announce to message bus
-        val success = paths.put(context, path);
-    }
-
-    protected def <T extends RpcService> void unregisterPath(RoutedRpcRegistrationImpl<T> registration,
-        Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> path) {
-
-        val router = registration.router;
-        val paths = registration.registeredPaths;
-
-        val routingTable = router.getRoutingTable(context)
-        checkState(routingTable != null);
-
-        // Updating internal structure of registration
-        val target = routingTable.getRoute(path)
-        checkState(target === registration.instance)
-        routingTable.removeRoute(path)
-        checkState(paths.remove(context, path));
-    }
-
-    protected def <T extends RpcService> void unregisterRoutedRpcService(RoutedRpcRegistrationImpl<T> registration) {
-
-        val router = registration.router;
-        val paths = registration.registeredPaths;
-
-        for (ctxMap : registration.registeredPaths.entries) {
-            val context = ctxMap.key
-            val routingTable = router.getRoutingTable(context)
-            val path = ctxMap.value
-            routingTable.removeRoute(path)
-        }
-    }
-
-    protected def <T extends RpcService> void unregisterRpcService(RpcServiceRegistrationImpl<T> registration) {
-
-        val type = registration.serviceType;
-
-        val proxy = managedProxies.get(type);
-        if (proxy.proxy.delegate === registration.instance) {
-            proxy.proxy.delegate = null;
-        }
-    }
-
-    def createDelegate(Class<? extends RpcService> type) {
-        getManagedDirectProxy(type);
-    }
-
-    def getRpcRouters() {
-        return Collections.unmodifiableMap(rpcRouters);
-    }
-
-    override close() {
-        dataConsumerRegistration.unregister()
-        dataProviderRegistration.unregister()
-        notifyConsumerRegistration.unregister()
-        notifyProviderRegistration.unregister()
-    }
-
-}
-
-class RoutedRpcRegistrationImpl<T extends RpcService> extends AbstractObjectRegistration<T> implements RoutedRpcRegistration<T> {
-
-    @Property
-    private val BindingAwareBrokerImpl broker;
-
-    @Property
-    private val RpcRouter<T> router;
-
-    @Property
-    private val Multimap<Class<? extends BaseIdentity>, InstanceIdentifier<?>> registeredPaths = HashMultimap.create();
-
-    private var closed = false;
-
-    new(T instance, RpcRouter<T> backingRouter, BindingAwareBrokerImpl broker) {
-        super(instance)
-        _router = backingRouter;
-        _broker = broker;
-    }
-
-    override protected removeRegistration() {
-        closed = true
-        broker.unregisterRoutedRpcService(this)
-    }
-
-    override registerInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> instance) {
-        registerPath(context, instance);
-    }
-
-    override unregisterInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> instance) {
-        unregisterPath(context, instance);
-    }
-
-    override registerPath(Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> path) {
-        checkClosed()
-        broker.registerPath(this, context, path);
-    }
-
-    override unregisterPath(Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> path) {
-        checkClosed()
-        broker.unregisterPath(this, context, path);
-    }
-
-    override getServiceType() {
-        return router.serviceType;
-    }
-
-    private def checkClosed() {
-        if (closed)
-            throw new IllegalStateException("Registration was closed.");
-    }
-
-}
-
-class RpcServiceRegistrationImpl<T extends RpcService> extends AbstractObjectRegistration<T> implements RpcRegistration<T> {
-
-    private var BindingAwareBrokerImpl broker;
-
-    @Property
-    val Class<T> serviceType;
-
-    public new(Class<T> type, T service, BindingAwareBrokerImpl broker) {
-        super(service);
-        this._serviceType = type;
-        this.broker = broker;
-    }
-
-    override protected removeRegistration() {
-        broker.unregisterRpcService(this);
-        broker = null;
+    override close() throws Exception {
+        
     }
 
-}
+}
\ No newline at end of file
index e8b3850b77b665113b3bac0d9e33c8029cc592fc..b10c06f0c53e359ec2cabe3028b7243339c6f53b 100644 (file)
@@ -20,8 +20,8 @@ import org.opendaylight.yangtools.concepts.AbstractObjectRegistration
 import org.opendaylight.yangtools.concepts.ListenerRegistration\r
 import org.opendaylight.yangtools.concepts.Registration\r
 import org.opendaylight.yangtools.yang.binding.Notification\r
-import org.slf4j.LoggerFactory\r
-\r
+import org.slf4j.LoggerFactory\rimport org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder
+
 class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable {\r
 \r
     val Multimap<Class<? extends Notification>, NotificationListener<?>> listeners;\r
@@ -29,6 +29,11 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab
     @Property\r
     var ExecutorService executor;\r
 \r
+    new() {\r
+        listeners = HashMultimap.create()\r
+    }\r
+\r
+    @Deprecated\r
     new(ExecutorService executor) {\r
         listeners = HashMultimap.create()\r
         this.executor = executor;\r
@@ -100,7 +105,7 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab
 \r
     override registerNotificationListener(\r
         org.opendaylight.yangtools.yang.binding.NotificationListener listener) {\r
-        val invoker = BindingAwareBrokerImpl.generator.invokerFactory.invokerFor(listener);\r
+        val invoker = SingletonHolder.INVOKER_FACTORY.invokerFor(listener);\r
         for (notifyType : invoker.supportedNotifications) {\r
             listeners.put(notifyType, invoker.invocationProxy)\r
         }\r
index bc53108675798173dd271b9bf18bf6db6fd3bb65..644c50b86ad1699989720403c67f041c296a1b42 100644 (file)
@@ -45,8 +45,7 @@ class OsgiConsumerContext implements ConsumerContext {
                 val ref = services.iterator().next() as ServiceReference<T>;
                 return bundleContext.getService(ref) as T;
             } else {
-                broker.createDelegate(module);
-                return getRpcService(module);
+                return broker.getRpcService(module);
             }
         } catch (InvalidSyntaxException e) {
             log.error("Created filter was invalid:", e.message, e)
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java
new file mode 100644 (file)
index 0000000..bc86288
--- /dev/null
@@ -0,0 +1,166 @@
+package org.opendaylight.controller.sal.binding.impl;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import javax.swing.tree.ExpandVetoException;
+
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
+import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper;
+import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
+import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier;
+import org.opendaylight.controller.sal.binding.spi.RpcRouter;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+
+import static com.google.common.base.Preconditions.*;
+
+public class RpcProviderRegistryImpl implements //
+        RpcProviderRegistry, //
+        RouteChangePublisher<RpcContextIdentifier, InstanceIdentifier<?>> {
+
+    private RuntimeCodeGenerator rpcFactory = SingletonHolder.RPC_GENERATOR_IMPL;
+
+    private final Map<Class<? extends RpcService>, RpcService> publicProxies = new WeakHashMap<>();
+    private final Map<Class<? extends RpcService>, RpcRouter<?>> rpcRouters = new WeakHashMap<>();
+    private final ListenerRegistry<RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> routeChangeListeners = ListenerRegistry
+            .create();
+
+    @Override
+    public final <T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> type,
+            T implementation) throws IllegalStateException {
+        return getRpcRouter(type).addRoutedRpcImplementation(implementation);
+    }
+
+    @Override
+    public final <T extends RpcService> RpcRegistration<T> addRpcImplementation(Class<T> type, T implementation)
+            throws IllegalStateException {
+        RpcRouter<T> potentialRouter = (RpcRouter<T>) rpcRouters.get(type);
+        if (potentialRouter != null) {
+            checkState(potentialRouter.getDefaultService() == null,
+                    "Default service for routed RPC already registered.");
+            return potentialRouter.registerDefaultService(implementation);
+        }
+        T publicProxy = getRpcService(type);
+        RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy);
+        checkState(currentDelegate == null, "Rpc service is already registered");
+        RuntimeCodeHelper.setDelegate(publicProxy, implementation);
+        return new RpcProxyRegistration<T>(type, implementation, this);
+    }
+
+    @Override
+    public final <T extends RpcService> T getRpcService(Class<T> type) {
+
+        RpcService potentialProxy = publicProxies.get(type);
+        if (potentialProxy != null) {
+            return (T) potentialProxy;
+        }
+        T proxy = rpcFactory.getDirectProxyFor(type);
+        publicProxies.put(type, proxy);
+        return proxy;
+    }
+
+    private <T extends RpcService> RpcRouter<T> getRpcRouter(Class<T> type) {
+        RpcRouter<?> potentialRouter = rpcRouters.get(type);
+        if (potentialRouter != null) {
+            return (RpcRouter<T>) potentialRouter;
+        }
+        RpcRouter<T> router = rpcFactory.getRouterFor(type);
+        router.registerRouteChangeListener(new RouteChangeForwarder(type));
+        RuntimeCodeHelper.setDelegate(getRpcService(type), router.getInvocationProxy());
+        rpcRouters.put(type, router);
+        return router;
+    }
+
+    public <L extends RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
+            L listener) {
+        return (ListenerRegistration<L>) routeChangeListeners.register(listener);
+    }
+
+    public RuntimeCodeGenerator getRpcFactory() {
+        return rpcFactory;
+    }
+
+    public void setRpcFactory(RuntimeCodeGenerator rpcFactory) {
+        this.rpcFactory = rpcFactory;
+    }
+
+    private class RouteChangeForwarder<T extends RpcService> implements
+            RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
+
+        private final Class<T> type;
+
+        public RouteChangeForwarder(Class<T> type) {
+            this.type = type;
+        }
+
+        @Override
+        public void onRouteChange(RouteChange<Class<? extends BaseIdentity>, InstanceIdentifier<?>> change) {
+            Map<RpcContextIdentifier, Set<InstanceIdentifier<?>>> announcements = new HashMap<>();
+            for (Entry<Class<? extends BaseIdentity>, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements()
+                    .entrySet()) {
+                RpcContextIdentifier key = RpcContextIdentifier.contextFor(type, entry.getKey());
+                announcements.put(key, entry.getValue());
+            }
+            Map<RpcContextIdentifier, Set<InstanceIdentifier<?>>> removals = new HashMap<>();
+            for (Entry<Class<? extends BaseIdentity>, Set<InstanceIdentifier<?>>> entry : change.getRemovals()
+                    .entrySet()) {
+                RpcContextIdentifier key = RpcContextIdentifier.contextFor(type, entry.getKey());
+                removals.put(key, entry.getValue());
+            }
+            RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> toPublish = RoutingUtils
+                    .<RpcContextIdentifier, InstanceIdentifier<?>> change(announcements, removals);
+            for (ListenerRegistration<RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> listener : routeChangeListeners) {
+                try {
+                    listener.getInstance().onRouteChange(toPublish);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    public static class RpcProxyRegistration<T extends RpcService> extends AbstractObjectRegistration<T> implements
+            RpcRegistration<T> {
+
+        private final Class<T> serviceType;
+        private RpcProviderRegistryImpl registry;
+
+        public RpcProxyRegistration(Class<T> type, T service, RpcProviderRegistryImpl registry) {
+            super(service);
+            serviceType = type;
+        }
+
+        @Override
+        public Class<T> getServiceType() {
+            return serviceType;
+        }
+
+        @Override
+        protected void removeRegistration() {
+            if (registry != null) {
+                T publicProxy = registry.getRpcService(serviceType);
+                RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy);
+                if (currentDelegate == getInstance()) {
+                    RuntimeCodeHelper.setDelegate(publicProxy, null);
+                }
+                registry = null;
+            }
+        }
+    }
+}
@@ -1,42 +1,78 @@
 package org.opendaylight.controller.sal.binding.impl.connect.dom;
 
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
+
 import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 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.DataCommitHandlerRegistration;
 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
+import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
+import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier;
+import org.opendaylight.controller.sal.binding.spi.RpcRouter;
 import org.opendaylight.controller.sal.common.util.Rpcs;
 import org.opendaylight.controller.sal.core.api.Provider;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
 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.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcInput;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+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;
 
-public class BindingIndependentDataServiceConnector implements //
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+
+import static com.google.common.base.Preconditions.*;
+import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.*;
+
+public class BindingIndependentConnector implements //
         RuntimeDataProvider, //
-        Provider, AutoCloseable {
+        Provider, //
+        AutoCloseable {
 
-    private final Logger LOG = LoggerFactory.getLogger(BindingIndependentDataServiceConnector.class);
+    private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
 
     private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
 
@@ -59,26 +95,41 @@ public class BindingIndependentDataServiceConnector implements //
 
     private Registration<DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>> biCommitHandlerRegistration;
 
+    private RpcProvisionRegistry biRpcRegistry;
+    private RpcProviderRegistryImpl baRpcRegistry;
+
+    private ListenerRegistration<DomToBindingRpcForwardingManager> domToBindingRpcManager;
+    // private ListenerRegistration<BindingToDomRpcForwardingManager>
+    // bindingToDomRpcManager;
+
+    private Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
+
+        @Override
+        public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier<?> input) {
+            return mappingService.toDataDom(input);
+        }
+
+    };
+
     @Override
     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)) {
+
+            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<?>) {
+                if (parentTo instanceof Augmentable<?>) {
                     return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
                 }
-                
+
             }
             return mappingService.dataObjectFromDataDom(path, result);
-            
+
         } catch (DeserializationException e) {
             throw new IllegalStateException(e);
         }
@@ -183,11 +234,24 @@ public class BindingIndependentDataServiceConnector implements //
         this.baDataService = baDataService;
     }
 
+    public RpcProviderRegistry getRpcRegistry() {
+        return baRpcRegistry;
+    }
+
+    public void setRpcRegistry(RpcProviderRegistryImpl rpcRegistry) {
+        this.baRpcRegistry = rpcRegistry;
+    }
+
     public void start() {
         baDataService.registerDataReader(ROOT, this);
         baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler);
         biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
         baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
+
+        if (baRpcRegistry != null && biRpcRegistry != null) {
+            domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager());
+
+        }
     }
 
     public void setMappingService(BindingIndependentMappingService mappingService) {
@@ -205,6 +269,14 @@ public class BindingIndependentDataServiceConnector implements //
         start();
     }
 
+    public <T extends RpcService> void onRpcRouterCreated(Class<T> serviceType, RpcRouter<T> router) {
+
+    }
+
+    public void setDomRpcRegistry(RpcProvisionRegistry registry) {
+        biRpcRegistry = registry;
+    }
+
     @Override
     public void close() throws Exception {
         if (baCommitHandlerRegistration != null) {
@@ -358,4 +430,204 @@ public class BindingIndependentDataServiceConnector implements //
             return forwardedTransaction;
         }
     }
+
+    private class DomToBindingRpcForwardingManager implements
+            RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>> {
+
+        private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
+
+        @Override
+        public void onRouteChange(RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
+            for (Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
+                bindingRoutesAdded(entry);
+            }
+        }
+
+        private void bindingRoutesAdded(Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry) {
+            Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
+            Class<? extends RpcService> service = entry.getKey().getRpcService();
+            if (context != null) {
+                getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
+            }
+        }
+
+        private DomToBindingRpcForwarder getRpcForwarder(Class<? extends RpcService> service,
+                Class<? extends BaseIdentity> context) {
+            DomToBindingRpcForwarder potential = forwarders.get(service);
+            if (potential != null) {
+                return potential;
+            }
+            if (context == null) {
+                potential = new DomToBindingRpcForwarder(service);
+            } else {
+                potential = new DomToBindingRpcForwarder(service, context);
+            }
+            forwarders.put(service, potential);
+            return potential;
+        }
+
+    }
+
+    private class DomToBindingRpcForwarder implements RpcImplementation {
+
+        private final Set<QName> supportedRpcs;
+        private final WeakReference<Class<? extends RpcService>> rpcServiceType;
+        private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
+
+        public DomToBindingRpcForwarder(Class<? extends RpcService> service) {
+            this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
+            this.supportedRpcs = mappingService.getRpcQNamesFor(service);
+            for (QName rpc : supportedRpcs) {
+                biRpcRegistry.addRpcImplementation(rpc, this);
+            }
+            registrations = ImmutableSet.of();
+        }
+
+        public DomToBindingRpcForwarder(Class<? extends RpcService> service, Class<? extends BaseIdentity> context) {
+            this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
+            this.supportedRpcs = mappingService.getRpcQNamesFor(service);
+            registrations = new HashSet<>();
+            for (QName rpc : supportedRpcs) {
+                registrations.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
+            }
+            registrations = ImmutableSet.copyOf(registrations);
+        }
+
+        public void registerPaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
+                Set<InstanceIdentifier<?>> set) {
+            QName ctx = BindingReflections.findQName(context);
+            for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
+                    toDOMInstanceIdentifier)) {
+                for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
+                    reg.registerPath(ctx, path);
+                }
+            }
+        }
+
+        public void removePaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
+                Set<InstanceIdentifier<?>> set) {
+            QName ctx = BindingReflections.findQName(context);
+            for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
+                    toDOMInstanceIdentifier)) {
+                for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
+                    reg.unregisterPath(ctx, path);
+                }
+            }
+        }
+
+        @Override
+        public Set<QName> getSupportedRpcs() {
+            return supportedRpcs;
+        }
+
+        @Override
+        public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode domInput) {
+            checkArgument(rpc != null);
+            checkArgument(domInput != null);
+
+            Class<? extends RpcService> rpcType = rpcServiceType.get();
+            checkState(rpcType != null);
+            RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
+            checkState(rpcService != null);
+            CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
+            try {
+                return resolveInvocationStrategy(rpc, rpcType).invokeOn(rpcService, domUnwrappedInput);
+            } catch (Exception e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc,
+                final Class<? extends RpcService> rpcType) throws Exception {
+            return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
+                @Override
+                public RpcInvocationStrategy call() throws Exception {
+                    String methodName = BindingMapping.getMethodName(rpc);
+                    Method targetMethod = null;
+                    for (Method possibleMethod : rpcType.getMethods()) {
+                        if (possibleMethod.getName().equals(methodName)
+                                && BindingReflections.isRpcMethod(possibleMethod)) {
+                            targetMethod = possibleMethod;
+                            break;
+                        }
+                    }
+                    checkState(targetMethod != null, "Rpc method not found");
+                    Optional<Class<?>> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod);
+                    Optional<Class<? extends DataContainer>> inputClass = BindingReflections
+                            .resolveRpcInputClass(targetMethod);
+
+                    RpcInvocationStrategy strategy = null;
+                    if (outputClass.isPresent()) {
+                        if (inputClass.isPresent()) {
+                            strategy = new DefaultInvocationStrategy(targetMethod, outputClass.get(), inputClass.get());
+                        } else {
+                            strategy = new NoInputNoOutputInvocationStrategy(targetMethod);
+                        }
+                    } else {
+                        strategy = null;
+                    }
+                    return strategy;
+                }
+
+            });
+        }
+    }
+
+    private abstract class RpcInvocationStrategy {
+
+        protected final Method targetMethod;
+
+        public RpcInvocationStrategy(Method targetMethod) {
+            this.targetMethod = targetMethod;
+        }
+
+        public abstract RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput)
+                throws Exception;
+
+        public RpcResult<CompositeNode> invokeOn(RpcService rpcService, CompositeNode domInput) throws Exception {
+            return uncheckedInvoke(rpcService, domInput);
+        }
+    }
+
+    private class DefaultInvocationStrategy extends RpcInvocationStrategy {
+
+        @SuppressWarnings("rawtypes")
+        private WeakReference<Class> inputClass;
+
+        @SuppressWarnings("rawtypes")
+        private WeakReference<Class> outputClass;
+
+        public DefaultInvocationStrategy(Method targetMethod, Class<?> outputClass,
+                Class<? extends DataContainer> inputClass) {
+            super(targetMethod);
+            this.outputClass = new WeakReference(outputClass);
+            this.inputClass = new WeakReference(inputClass);
+        }
+
+        @Override
+        public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
+            DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
+            Future<RpcResult<?>> result = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
+            if (result == null) {
+                return Rpcs.getRpcResult(false);
+            }
+            RpcResult<?> bindingResult = result.get();
+            return Rpcs.getRpcResult(true);
+        }
+
+    }
+
+    private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
+
+        public NoInputNoOutputInvocationStrategy(Method targetMethod) {
+            super(targetMethod);
+        }
+
+        public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
+            Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
+            RpcResult<Void> bindingResult = result.get();
+            return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors());
+        }
+
+    }
 }
index b1983fe224d89da96f4445efa86469cc0e0e6b9d..e16ae48ef4af289d4f6ebcd170f886670e35a97f 100644 (file)
@@ -1,10 +1,13 @@
 package org.opendaylight.controller.sal.binding.impl.connect.dom;
 
 import java.util.Map.Entry;
+import java.util.Set;
 
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 public interface BindingIndependentMappingService {
@@ -19,5 +22,9 @@ public interface BindingIndependentMappingService {
     DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result) throws DeserializationException;
 
     InstanceIdentifier<?> fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry)  throws DeserializationException;
+    
+    Set<QName> getRpcQNamesFor(Class<? extends RpcService> service);
+
+    DataContainer dataObjectFromDataDom(Class<? extends DataContainer> inputClass, CompositeNode domInput);
 
 }
index d230fd17f9475c24bd920094a233734291593901..e0eb10299256a9d6ff48e0bb305f15c57fee1848 100644 (file)
@@ -56,6 +56,8 @@ public final class ClassLoaderUtils {
     public static Class<?> loadClassWithTCCL(String name) throws ClassNotFoundException {
         if ("byte[]".equals(name)) {
             return byte[].class;
+        } else if("char[]".equals(name)) {
+            return char[].class;
         }
         try {
             return Thread.currentThread().getContextClassLoader().loadClass(name);
@@ -78,8 +80,7 @@ public final class ClassLoaderUtils {
         try {
             return loadClassWithTCCL(fullyQualifiedName);
         } catch (ClassNotFoundException e) {
-
+            return null;
         }
-        return null;
     }
 }
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java
new file mode 100644 (file)
index 0000000..49e056b
--- /dev/null
@@ -0,0 +1,5 @@
+package org.opendaylight.controller.sal.binding.spi;
+
+public class RoutingContext {
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java
new file mode 100644 (file)
index 0000000..33569eb
--- /dev/null
@@ -0,0 +1,65 @@
+package org.opendaylight.controller.sal.binding.spi;
+
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+
+public final  class RpcContextIdentifier implements Immutable{
+
+    public final Class<? extends RpcService> rpcService;
+    public final Class<? extends BaseIdentity> routingContext;
+   
+    private RpcContextIdentifier(Class<? extends RpcService> rpcService, Class<? extends BaseIdentity> routingContext) {
+        super();
+        this.rpcService = rpcService;
+        this.routingContext = routingContext;
+    }
+
+    public Class<? extends RpcService> getRpcService() {
+        return rpcService;
+    }
+
+    public Class<? extends BaseIdentity> getRoutingContext() {
+        return routingContext;
+    }
+    
+    public static final RpcContextIdentifier contextForGlobalRpc(Class<? extends RpcService> serviceType) {
+        return new RpcContextIdentifier(serviceType, null);
+    }
+    
+    public static final RpcContextIdentifier contextFor(Class<? extends RpcService> serviceType,Class<? extends BaseIdentity> routingContext) {
+        return new RpcContextIdentifier(serviceType, routingContext);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((routingContext == null) ? 0 : routingContext.hashCode());
+        result = prime * result + ((rpcService == null) ? 0 : rpcService.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        RpcContextIdentifier other = (RpcContextIdentifier) obj;
+        if (routingContext == null) {
+            if (other.routingContext != null)
+                return false;
+        } else if (!routingContext.equals(other.routingContext))
+            return false;
+        if (rpcService == null) {
+            if (other.rpcService != null)
+                return false;
+        } else if (!rpcService.equals(other.rpcService))
+            return false;
+        return true;
+    }
+
+}
index 7db90b62fdefd090910eb0a6ecdbe1df8ca597be..621d048dfd771694d5b479588980140e9e873066 100644 (file)
@@ -9,6 +9,9 @@ package org.opendaylight.controller.sal.binding.spi;
 
 import java.util.Set;
 
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.RpcImplementation;
@@ -26,7 +29,8 @@ import org.opendaylight.yangtools.yang.binding.RpcService;
  *            Type of RpcService for which router provides routing information
  *            and route selection.
  */
-public interface RpcRouter<T extends RpcService> extends RpcImplementation{
+public interface RpcRouter<T extends RpcService> extends //
+        RouteChangePublisher<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
 
     /**
      * Returns a type of RpcService which is served by this instance of router.
@@ -72,12 +76,11 @@ public interface RpcRouter<T extends RpcService> extends RpcImplementation{
      * @return default instance responsible for processing RPCs.
      */
     T getDefaultService();
-    
-    /**
-     * 
-     */
-    void setDefaultService(T service);
 
     Set<Class<? extends BaseIdentity>> getContexts();
+    
+    RoutedRpcRegistration<T> addRoutedRpcImplementation(T service);
+    
+    RpcRegistration<T> registerDefaultService(T service);
 
 }
index a7a70c2839ca848bae7a0e45adc702c620ec4bcb..633506fec65b3ea4f186e1ba8520aed98750f0b1 100644 (file)
@@ -12,7 +12,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;
 import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
 import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
 import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
index 1a97bd693a19c96ab295cb8f88cd63e213dc43f3..9c9841a4a5dc8deed41f717f7ce50d208f1c6b9f 100644 (file)
@@ -65,9 +65,6 @@ public class RuntimeCodeGeneratorTest {
         assertNotNull(product);
         assertNotNull(product.getInvocationProxy());
 
-        assertNotNull(product.getSupportedInputs());
-        assertTrue(product.getSupportedInputs().contains(SimpleInput.class));
-        assertTrue(product.getSupportedInputs().contains(InheritedContextInput.class));
         assertEquals("2 fields should be generated.", 2, product.getInvocationProxy().getClass().getFields().length);
 
         verifyRouting(product);
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java
new file mode 100644 (file)
index 0000000..2057619
--- /dev/null
@@ -0,0 +1,45 @@
+package org.opendaylight.controller.sal.binding.test.bugfix;
+
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.Prefix;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.PrefixBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+
+
+
+
+
+
+
+import static org.junit.Assert.*;
+
+public class UnionSerializationTest extends AbstractDataServiceTest {
+    
+    public static final String PREFIX_STRING = "192.168.0.1/32";
+    
+    
+    @Test
+    public void testPrefixSerialization() throws Exception {
+        
+        Ipv4Prefix ipv4prefix = new Ipv4Prefix(PREFIX_STRING);
+        IpPrefix ipPrefix = new IpPrefix(ipv4prefix);
+        Prefix prefix = new PrefixBuilder().setPrefix(ipPrefix).build();
+        
+        CompositeNode serialized = testContext.getBindingToDomMappingService().toDataDom(prefix);
+        assertNotNull(serialized);
+        assertNotNull(serialized.getFirstSimpleByName(Prefix.QNAME));
+        assertEquals(PREFIX_STRING, serialized.getFirstSimpleByName(Prefix.QNAME).getValue());
+        
+        Prefix deserialized = (Prefix) testContext.getBindingToDomMappingService().dataObjectFromDataDom(InstanceIdentifier.builder().node(Prefix.class).build(), serialized);
+        assertNotNull(deserialized);
+        assertNotNull(deserialized.getPrefix());
+        assertNotNull(deserialized.getPrefix().getIpv4Prefix());
+        assertEquals(PREFIX_STRING, deserialized.getPrefix().getIpv4Prefix().getValue());
+    }
+
+}
index 4e611c5fe2131651a0ccd6bf5744b57c72acd2d4..3217a31329939e5b8d27c67f3114bbb82b9f498a 100644 (file)
@@ -7,15 +7,22 @@ import java.util.Set;
 
 import javassist.ClassPool;
 
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.controller.sal.binding.impl.BindingAwareBrokerImpl;
 import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;
+import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;
 import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
 import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.controller.sal.core.api.data.DataStore;
+import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
 import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
 import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
+import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl;
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -31,7 +38,7 @@ import com.google.common.util.concurrent.MoreExecutors;
 
 import static com.google.common.base.Preconditions.*;
 
-public class BindingTestContext {
+public class BindingTestContext implements AutoCloseable {
     
     
     public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
@@ -40,10 +47,15 @@ public class BindingTestContext {
     private static final Logger LOG = LoggerFactory.getLogger(BindingTestContext.class);
     
     private RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
+    
+    
+    private BindingAwareBrokerImpl baBrokerImpl;
     private DataBrokerImpl baDataImpl;
+    private NotificationBrokerImpl baNotifyImpl;
+    private BindingIndependentConnector baConnectDataServiceImpl;
+
     private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl;
-    
-    private BindingIndependentDataServiceConnector connectorServiceImpl;
+    private BrokerImpl biBrokerImpl;
     private HashMapDataStore rawDataStore;
     private SchemaAwareDataStoreAdapter schemaAwareDataStore;
     private DataStoreStatsWrapper dataStoreStats;
@@ -56,6 +68,7 @@ public class BindingTestContext {
     private final ClassPool classPool;
 
     private final boolean startWithSchema;
+
     
     protected BindingTestContext(ListeningExecutorService executor, ClassPool classPool, boolean startWithSchema) {
         this.executor = executor;
@@ -93,15 +106,29 @@ public class BindingTestContext {
         baDataImpl.setExecutor(executor);
     }
     
+    public void startBindingBroker() {
+        checkState(executor != null,"Executor needs to be set");
+        checkState(baDataImpl != null,"Binding Data Broker must be started");
+        checkState(baNotifyImpl != null, "Notification Service must be started");
+        baBrokerImpl = new BindingAwareBrokerImpl(null);
+        
+        baBrokerImpl.setDataBroker(baDataImpl);
+        baBrokerImpl.setNotifyBroker(baNotifyImpl);
+        
+        baBrokerImpl.start();
+    }
+    
     public void startBindingToDomDataConnector() {
         checkState(baDataImpl != null,"Binding Data Broker needs to be started");
         checkState(biDataImpl != null,"DOM Data Broker needs to be started.");
         checkState(mappingServiceImpl != null,"DOM Mapping Service needs to be started.");
-        connectorServiceImpl = new BindingIndependentDataServiceConnector();
-        connectorServiceImpl.setBaDataService(baDataImpl);
-        connectorServiceImpl.setBiDataService(biDataImpl);
-        connectorServiceImpl.setMappingService(mappingServiceImpl);
-        connectorServiceImpl.start();
+        baConnectDataServiceImpl = new BindingIndependentConnector();
+        baConnectDataServiceImpl.setRpcRegistry(baBrokerImpl);
+        baConnectDataServiceImpl.setDomRpcRegistry(getDomRpcRegistry());
+        baConnectDataServiceImpl.setBaDataService(baDataImpl);
+        baConnectDataServiceImpl.setBiDataService(biDataImpl);
+        baConnectDataServiceImpl.setMappingService(mappingServiceImpl);
+        baConnectDataServiceImpl.start();
     }
     
     public void startBindingToDomMappingService() {
@@ -149,8 +176,11 @@ public class BindingTestContext {
     
     public void start() {
         startBindingDataBroker();
+        startBindingNotificationBroker();
+        startBindingBroker();
         startDomDataBroker();
         startDomDataStore();
+        startDomBroker();
         startBindingToDomMappingService();
         startBindingToDomDataConnector();
         if(startWithSchema) {
@@ -158,6 +188,19 @@ public class BindingTestContext {
         }
     }
 
+    private void startDomBroker() {
+        checkState(executor != null);
+        biBrokerImpl = new BrokerImpl();
+        biBrokerImpl.setExecutor(executor);
+        biBrokerImpl.setRouter(new RpcRouterImpl("test"));
+    }
+
+    public void startBindingNotificationBroker() {
+        checkState(executor != null);
+        baNotifyImpl = new NotificationBrokerImpl(executor);
+        
+    }
+
     public void loadYangSchemaFromClasspath() {
         String[] files = getAllYangFilesOnClasspath();
         updateYangSchema(files);
@@ -196,4 +239,24 @@ public class BindingTestContext {
                 dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(),
                 dataStoreStats.getRequestCommitAverageTime());
     }
+
+    public RpcProviderRegistry getBindingRpcRegistry() {
+        return baBrokerImpl;
+    }
+
+    public RpcProvisionRegistry getDomRpcRegistry() {
+        if(biBrokerImpl == null) {
+            return null;
+        }
+        return biBrokerImpl.getRouter();
+    }
+    
+    public RpcImplementation getDomRpcInvoker() {
+        return biBrokerImpl.getRouter();
+    }
+    
+    @Override
+    public void close() throws Exception {
+        
+    }
 }
index 6525fa078ed991ed26bed4e9491b79b4dd4ebe95..7391139d0f11c0c63eace374f08b97356e0b5918 100644 (file)
@@ -13,7 +13,6 @@
         <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
         <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
     </scm>
-
     <build>
         <plugins>
             <plugin>
     </build>
 
     <dependencies>
+        <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-container-native</artifactId>
+          <scope>test</scope>
+          <version>${exam.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-binding-broker-impl</artifactId>
index 848fb6b1900eab43a3e3e2886d654c92c2135c24..c311161c4424343a9b386408cfb05f4e95f37422 100644 (file)
@@ -7,9 +7,13 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 
+import javassist.ClassPool;
+
+import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
@@ -23,6 +27,9 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
 import static org.junit.Assert.*;
 
 public class DOMCodecBug02Test extends AbstractDataServiceTest {
@@ -54,15 +61,32 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest {
     private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA);
 
     /**
-     * 
+     * This test is ignored, till found out better way to test generation
+     * of classes without leaking of instances from previous run
      * 
      * @throws Exception
      */
+    
+    public void setUp() {
+        ListeningExecutorService executor = MoreExecutors.sameThreadExecutor();
+        BindingBrokerTestFactory factory = new BindingBrokerTestFactory();
+        factory.setExecutor(executor);
+        factory.setClassPool(new ClassPool());
+        factory.setStartWithParsedSchema(getStartWithSchema());
+        testContext = factory.getTestContext();
+        testContext.start();
+        
+        baDataService = testContext.getBindingDataBroker();
+        biDataService = testContext.getDomDataBroker();
+        dataStore = testContext.getDomDataStore();
+        mappingService = testContext.getBindingToDomMappingService();
+    };
+    
     @Test
     public void testSchemaContextNotAvailable() throws Exception {
 
         ExecutorService testExecutor = Executors.newFixedThreadPool(1);
-        
+        testContext.loadYangSchemaFromClasspath();
         Future<Future<RpcResult<TransactionStatus>>> future = testExecutor.submit(new Callable<Future<RpcResult<TransactionStatus>>>() {
             @Override
             public Future<RpcResult<TransactionStatus>> call() throws Exception {
@@ -74,11 +98,10 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest {
             }
         });
         
-        testContext.loadYangSchemaFromClasspath();
+        
         RpcResult<TransactionStatus> result = future.get().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
         
-        
         Nodes nodes = checkForNodes();
         assertNotNull(nodes);
 
diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java
new file mode 100644 (file)
index 0000000..92a0a3a
--- /dev/null
@@ -0,0 +1,159 @@
+package org.opendaylight.controller.sal.binding.test.connect.dom;
+
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.concurrent.Future;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
+import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+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.AddFlowOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContext;
+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.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+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.impl.CompositeNodeTOImpl;
+
+import static junit.framework.Assert.*;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public class CrossBrokerRpcTest {
+
+    protected RpcProviderRegistry baRpcRegistry;
+    protected RpcProvisionRegistry biRpcRegistry;
+    private BindingTestContext testContext;
+    private RpcImplementation biRpcInvoker;
+    private MessageCapturingFlowService flowService;
+
+    public static final NodeId NODE_A = new NodeId("a");
+    public static final NodeId NODE_B = new NodeId("b");
+    public static final NodeId NODE_C = new NodeId("c");
+    public static final NodeId NODE_D = new NodeId("d");
+
+    public static final InstanceIdentifier<Node> BA_NODE_A_ID = createBANodeIdentifier(NODE_A);
+    public static final InstanceIdentifier<Node> BA_NODE_B_ID = createBANodeIdentifier(NODE_B);
+    public static final InstanceIdentifier<Node> BA_NODE_C_ID = createBANodeIdentifier(NODE_C);
+    public static final InstanceIdentifier<Node> BA_NODE_D_ID = createBANodeIdentifier(NODE_D);
+
+    public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_A_ID = createBINodeIdentifier(NODE_A);
+    public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_B_ID = createBINodeIdentifier(NODE_B);
+    public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_C_ID = createBINodeIdentifier(NODE_C);
+    public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_D_ID = createBINodeIdentifier(NODE_D);
+
+    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+    private static final QName ADD_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "add-flow");
+    private static final QName REMOVE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "remove-flow");
+    private static final QName UPDATE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "update-flow");
+
+    @Before
+    public void setup() {
+        BindingBrokerTestFactory testFactory = new BindingBrokerTestFactory();
+        testFactory.setExecutor(MoreExecutors.sameThreadExecutor());
+        testFactory.setStartWithParsedSchema(true);
+        testContext = testFactory.getTestContext();
+
+        testContext.start();
+        baRpcRegistry = testContext.getBindingRpcRegistry();
+        biRpcRegistry = testContext.getDomRpcRegistry();
+        biRpcInvoker = testContext.getDomRpcInvoker();
+        assertNotNull(baRpcRegistry);
+        assertNotNull(biRpcRegistry);
+
+        flowService = MessageCapturingFlowService.create(baRpcRegistry);
+
+    }
+
+    @Test
+    public void bindingRoutedRpcProvider_DomInvokerTest() {
+
+        flowService//
+                .registerPath(NodeContext.class, BA_NODE_A_ID) //
+                .registerPath(NodeContext.class, BA_NODE_B_ID) //
+                .setAddFlowResult(addFlowResult(true, 10));
+
+        SalFlowService baFlowInvoker = baRpcRegistry.getRpcService(SalFlowService.class);
+        assertNotSame(flowService, baFlowInvoker);
+
+        AddFlowInput addFlowA = addFlow(BA_NODE_A_ID) //
+                .setPriority(100).setBarrier(true).build();
+
+        CompositeNode addFlowDom = toDomRpc(ADD_FLOW_QNAME, addFlowA);
+        assertNotNull(addFlowDom);
+        RpcResult<CompositeNode> domResult = biRpcInvoker.invokeRpc(ADD_FLOW_QNAME, addFlowDom);
+        assertNotNull(domResult);
+        assertTrue("DOM result is successful.", domResult.isSuccessful());
+        assertTrue("Bidning Add Flow RPC was captured.", flowService.getReceivedAddFlows().containsKey(BA_NODE_A_ID));
+        assertEquals(addFlowA, flowService.getReceivedAddFlows().get(BA_NODE_A_ID).iterator().next());
+    }
+
+    public void bindingRpcInvoker_DomRoutedProviderTest() {
+
+    }
+
+    private CompositeNode toDomRpcInput(DataObject addFlowA) {
+        return testContext.getBindingToDomMappingService().toDataDom(addFlowA);
+    }
+
+    @After
+    public void teardown() throws Exception {
+        testContext.close();
+    }
+
+    private static InstanceIdentifier<Node> createBANodeIdentifier(NodeId node) {
+        return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(node)).toInstance();
+    }
+
+    private static org.opendaylight.yangtools.yang.data.api.InstanceIdentifier createBINodeIdentifier(NodeId node) {
+        return org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder().node(Nodes.QNAME)
+                .nodeWithKey(Node.QNAME, NODE_ID_QNAME, node.getValue()).toInstance();
+    }
+
+    private Future<RpcResult<AddFlowOutput>> addFlowResult(boolean success, long xid) {
+        AddFlowOutput output = new AddFlowOutputBuilder() //
+                .setTransactionId(new TransactionId(BigInteger.valueOf(xid))).build();
+        RpcResult<AddFlowOutput> result = Rpcs.getRpcResult(success, output, ImmutableList.<RpcError> of());
+        return Futures.immediateFuture(result);
+    }
+
+    private static AddFlowInputBuilder addFlow(InstanceIdentifier<Node> nodeId) {
+        AddFlowInputBuilder builder = new AddFlowInputBuilder();
+        builder.setNode(new NodeRef(nodeId));
+        return builder;
+    }
+
+    private CompositeNode toDomRpc(QName rpcName, AddFlowInput addFlowA) {
+        return new CompositeNodeTOImpl(rpcName, null,
+                Collections.<org.opendaylight.yangtools.yang.data.api.Node<?>> singletonList(toDomRpcInput(addFlowA)));
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java
new file mode 100644 (file)
index 0000000..74f0781
--- /dev/null
@@ -0,0 +1,122 @@
+package org.opendaylight.controller.sal.binding.test.connect.dom;
+
+import static junit.framework.Assert.assertNotNull;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+
+public class MessageCapturingFlowService implements SalFlowService, AutoCloseable {
+
+    private Future<RpcResult<AddFlowOutput>> addFlowResult;
+    private Future<RpcResult<RemoveFlowOutput>> removeFlowResult;
+    private Future<RpcResult<UpdateFlowOutput>> updateFlowResult;
+
+    private final Multimap<InstanceIdentifier<?>, AddFlowInput> receivedAddFlows = HashMultimap.create();
+    private final Multimap<InstanceIdentifier<?>, RemoveFlowInput> receivedRemoveFlows = HashMultimap.create();
+    private final Multimap<InstanceIdentifier<?>, UpdateFlowInput> receivedUpdateFlows = HashMultimap.create();
+    private RoutedRpcRegistration<SalFlowService> registration;
+
+    @Override
+    public Future<RpcResult<AddFlowOutput>> addFlow(AddFlowInput arg0) {
+        receivedAddFlows.put(arg0.getNode().getValue(), arg0);
+        return addFlowResult;
+    }
+
+    @Override
+    public Future<RpcResult<RemoveFlowOutput>> removeFlow(RemoveFlowInput arg0) {
+        receivedRemoveFlows.put(arg0.getNode().getValue(), arg0);
+        return removeFlowResult;
+    }
+
+    @Override
+    public Future<RpcResult<UpdateFlowOutput>> updateFlow(UpdateFlowInput arg0) {
+        receivedUpdateFlows.put(arg0.getNode().getValue(), arg0);
+        return updateFlowResult;
+    }
+
+    public Future<RpcResult<AddFlowOutput>> getAddFlowResult() {
+        return addFlowResult;
+    }
+
+    public MessageCapturingFlowService setAddFlowResult(Future<RpcResult<AddFlowOutput>> addFlowResult) {
+        this.addFlowResult = addFlowResult;
+        return this;
+    }
+
+    public Future<RpcResult<RemoveFlowOutput>> getRemoveFlowResult() {
+        return removeFlowResult;
+    }
+
+    public MessageCapturingFlowService setRemoveFlowResult(Future<RpcResult<RemoveFlowOutput>> removeFlowResult) {
+        this.removeFlowResult = removeFlowResult;
+        return this;
+    }
+
+    public Future<RpcResult<UpdateFlowOutput>> getUpdateFlowResult() {
+        return updateFlowResult;
+    }
+
+    public MessageCapturingFlowService setUpdateFlowResult(Future<RpcResult<UpdateFlowOutput>> updateFlowResult) {
+        this.updateFlowResult = updateFlowResult;
+        return this;
+    }
+
+    public Multimap<InstanceIdentifier<?>, AddFlowInput> getReceivedAddFlows() {
+        return receivedAddFlows;
+    }
+
+    public Multimap<InstanceIdentifier<?>, RemoveFlowInput> getReceivedRemoveFlows() {
+        return receivedRemoveFlows;
+    }
+
+    public Multimap<InstanceIdentifier<?>, UpdateFlowInput> getReceivedUpdateFlows() {
+        return receivedUpdateFlows;
+    }
+
+    public MessageCapturingFlowService registerTo(RpcProviderRegistry registry) {
+        registration = registry.addRoutedRpcImplementation(SalFlowService.class, this);
+        assertNotNull(registration);
+        return this;
+    }
+
+    public void close() throws Exception {
+        registration.close();
+    }
+
+    public MessageCapturingFlowService registerPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+        registration.registerPath(context, path);
+        return this;
+    }
+
+    public MessageCapturingFlowService unregisterPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+        registration.unregisterPath(context, path);
+        return this;
+    }
+    
+    public static MessageCapturingFlowService create() {
+        return new MessageCapturingFlowService();
+    }
+    
+    public static MessageCapturingFlowService create(RpcProviderRegistry registry) {
+        MessageCapturingFlowService ret = new MessageCapturingFlowService();
+        ret.registerTo(registry);
+        return ret;
+    }
+    
+    
+}
\ No newline at end of file
index 15616215d35f13950c08167abe7b687490ba1078..112b57cd33fc2fbb43c08059a5274f9647574084 100644 (file)
@@ -54,6 +54,7 @@ public class TestHelper {
                 mavenBundle(CONTROLLER, "config-persister-api").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "netconf-api").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "ietf-netconf-monitoring").versionAsInProject(), //
+                mavenBundle(CONTROLLER, "ietf-netconf-monitoring-extension").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "netconf-monitoring").versionAsInProject(), //
 
                 mavenBundle(CONTROLLER, "netconf-client").versionAsInProject(), //
index 89851c939323ce256585e341a2674d1ad98e259f..bee29a1ad19677820e18e36562bd6892d5be765e 100644 (file)
@@ -4,5 +4,5 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration;
 
 public interface RouteChangePublisher<C,P> {
 
-    ListenerRegistration<RouteChangeListener<C,P>> registerRouteChangeListener(RouteChangeListener<C,P> listener);
+    <L extends RouteChangeListener<C,P>> ListenerRegistration<L> registerRouteChangeListener(L listener);
 }
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java
new file mode 100644 (file)
index 0000000..60d0cdf
--- /dev/null
@@ -0,0 +1,92 @@
+package org.opendaylight.controller.md.sal.common.impl.routing;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class RoutingUtils {
+    
+    public static <C,P> RouteChange<C,P> removalChange(C context,P path) {
+        final ImmutableMap<C, Set<P>> announcements = ImmutableMap.<C,Set<P>>of();
+        final ImmutableMap<C, Set<P>> removals = ImmutableMap.<C,Set<P>>of(context, ImmutableSet.of(path));
+        return new RouteChangeImpl<C,P>(announcements, removals);
+    }
+    
+    public static <C,P> RouteChange<C,P> announcementChange(C context,P path) {
+        final ImmutableMap<C, Set<P>> announcements = ImmutableMap.<C,Set<P>>of(context, ImmutableSet.of(path));
+        final ImmutableMap<C, Set<P>> removals = ImmutableMap.<C,Set<P>>of();
+        return new RouteChangeImpl<C,P>(announcements, removals);
+    }
+    
+    
+    public static <C,P> RouteChange<C,P> change(Map<C, Set<P>> announcements,
+            Map<C, Set<P>> removals) {
+        final ImmutableMap<C, Set<P>> immutableAnnouncements = ImmutableMap.<C,Set<P>>copyOf(announcements);
+        final ImmutableMap<C, Set<P>> immutableRemovals = ImmutableMap.<C,Set<P>>copyOf(removals);
+        return new RouteChangeImpl<C,P>(immutableAnnouncements, immutableRemovals);
+    }
+    
+    
+    private static class RouteChangeImpl<C,P> implements RouteChange<C, P> {
+        private final Map<C, Set<P>> removal;
+        private final Map<C, Set<P>> announcement;
+
+        public RouteChangeImpl(ImmutableMap<C, Set<P>> removal, ImmutableMap<C, Set<P>> announcement) {
+            super();
+            this.removal = removal;
+            this.announcement = announcement;
+        }
+
+        @Override
+        public Map<C, Set<P>> getAnnouncements() {
+            return announcement;
+        }
+        
+        @Override
+        public Map<C, Set<P>> getRemovals() {
+            return removal;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((announcement == null) ? 0 : announcement.hashCode());
+            result = prime * result + ((removal == null) ? 0 : removal.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            RouteChangeImpl other = (RouteChangeImpl) obj;
+            if (announcement == null) {
+                if (other.announcement != null)
+                    return false;
+            } else if (!announcement.equals(other.announcement))
+                return false;
+            if (removal == null) {
+                if (other.removal != null) {
+                    return false;
+                }
+            } else if (!removal.equals(other.removal))
+                return false;
+            return true;
+        }
+    }
+
+
+    
+}
index 7e8069a9b38253b3f434918462034d60a74bee34..ff15e72ba6fc3d1106a46bfadd08dfcd2e67bd60 100644 (file)
       <artifactId>concepts</artifactId>
       <version>0.1.1-SNAPSHOT</version>
     </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
   </dependencies>
 
   <packaging>bundle</packaging>
index 54e1a065f4b45374848bbc53a27b534864d98f7d..356ec8ff7c5ee6e84692970d702910b7bdc8c091 100644 (file)
@@ -11,17 +11,31 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+
+import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 
+import com.google.common.collect.ImmutableList;
+
 public class Rpcs {
+    
+    public static <T> RpcResult<T> getRpcResult(boolean successful) {
+        RpcResult<T> ret = new RpcResultTO<T>(successful, null, ImmutableList.<RpcError>of());
+        return ret;
+    }
+    
     public static <T> RpcResult<T> getRpcResult(boolean successful, T result,
             Collection<RpcError> errors) {
         RpcResult<T> ret = new RpcResultTO<T>(successful, result, errors);
         return ret;
     }
 
-    private static class RpcResultTO<T> implements RpcResult<T>, Serializable {
+    public static <T> RpcResult<T> getRpcResult(boolean successful, Collection<RpcError> errors) {
+        return new RpcResultTO<T>(successful, null, errors);
+    }
+    
+    private static class RpcResultTO<T> implements RpcResult<T>, Serializable, Immutable {
 
         private final Collection<RpcError> errors;
         private final T result;
@@ -31,8 +45,7 @@ public class Rpcs {
                 Collection<RpcError> errors) {
             this.successful = successful;
             this.result = result;
-            this.errors = Collections.unmodifiableList(new ArrayList<RpcError>(
-                    errors));
+            this.errors = ImmutableList.copyOf(errors);
         }
 
         @Override
index 7ef594bad94cddd77db1136f6a2e9a311d4203e9..8f179987b9c769e9fb6bab288b4063f40bd3b873 100644 (file)
@@ -29,8 +29,10 @@ import org.slf4j.LoggerFactory
 import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter
 import org.opendaylight.yangtools.concepts.ListenerRegistration
 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
+import org.opendaylight.controller.sal.core.api.RpcImplementation
 
-public class BrokerImpl implements Broker, AutoCloseable {
+public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
     private static val log = LoggerFactory.getLogger(BrokerImpl);
 
     // Broker Generic Context
@@ -115,4 +117,12 @@ public class BrokerImpl implements Broker, AutoCloseable {
         deactivator?.close();
     }
     
+    override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException {
+        router.addRpcImplementation(rpcType,implementation);
+    }
+    
+    override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
+        router.addRoutedRpcImplementation(rpcType,implementation);
+    }
+    
 }
index d8680ce3b4fba50da12903344a4bad551de87075..5ee19a0e8fec876faf5d465ee3a140d373e53cd3 100644 (file)
@@ -15,6 +15,8 @@ import org.opendaylight.yangtools.concepts.AbstractObjectRegistration
 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
 import org.slf4j.LoggerFactory
 import org.opendaylight.yangtools.concepts.util.ListenerRegistry
+import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
 
 class RpcRouterImpl implements RpcRouter, Identifiable<String> {
 
@@ -35,6 +37,20 @@ class RpcRouterImpl implements RpcRouter, Identifiable<String> {
     }
 
     override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
+                checkNotNull(rpcType, "Rpc Type should not be null");
+        checkNotNull(implementation, "Implementation should not be null.");
+        val reg = new RoutedRpcRegistrationImpl(rpcType, implementation, this);
+        implementations.put(rpcType, reg)
+
+        for (listener : rpcRegistrationListeners.listeners) {
+            try {
+                listener.instance.onRpcImplementationAdded(rpcType);
+            } catch (Exception e) {
+                log.error("Unhandled exception during invoking listener", e);
+            }
+        }
+
+        return reg;
     }
 
     override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException {
@@ -102,5 +118,23 @@ class RpcRegistrationImpl extends AbstractObjectRegistration<RpcImplementation>
     override protected removeRegistration() {
         router.remove(this);
     }
+}
+class RoutedRpcRegistrationImpl extends RpcRegistrationImpl implements RoutedRpcRegistration {
+
+
+    new(QName type, RpcImplementation instance, RpcRouterImpl router) {
+        super(type,instance,router)
+    }
 
+    override protected removeRegistration() {
+        router.remove(this);
+    }
+    override registerPath(QName context, InstanceIdentifier path) {
+        //
+        
+    }
+
+    override unregisterPath(QName context, InstanceIdentifier path) {
+        //
+    }
 }
index 4f4fadcc443a755809394998246fccfeb7845aa8..75e96491b68c2bf5ffd93b08412002f846b94b89 100644 (file)
@@ -151,19 +151,20 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
         this.schema = null;
     }
 
-    protected CompositeNode mergeData(InstanceIdentifier path, CompositeNode stored, CompositeNode modified, boolean config) {
+    protected CompositeNode mergeData(InstanceIdentifier path, CompositeNode stored, CompositeNode modified,
+            boolean config) {
         long startTime = System.nanoTime();
         try {
-        DataSchemaNode node = schemaNodeFor(path);
-        return YangDataOperations.merge(node,stored,modified,config);
+            DataSchemaNode node = schemaNodeFor(path);
+            return YangDataOperations.merge(node, stored, modified, config);
         } finally {
-            //System.out.println("Merge time: " + ((System.nanoTime() - startTime) / 1000.0d));
+            // System.out.println("Merge time: " + ((System.nanoTime() -
+            // startTime) / 1000.0d));
         }
     }
-    
-    
+
     private DataSchemaNode schemaNodeFor(InstanceIdentifier path) {
-        checkState(schema != null,"YANG Schema is not available");
+        checkState(schema != null, "YANG Schema is not available");
         return YangSchemaUtils.getSchemaNode(schema, path);
     }
 
@@ -171,16 +172,16 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
             DataModification<InstanceIdentifier, CompositeNode> original) {
         // NOOP for now
         NormalizedDataModification normalized = new NormalizedDataModification(original);
-        for (Entry<InstanceIdentifier,CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
+        for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
             normalized.putConfigurationData(entry.getKey(), entry.getValue());
         }
-        for (Entry<InstanceIdentifier,CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
+        for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
             normalized.putOperationalData(entry.getKey(), entry.getValue());
         }
         for (InstanceIdentifier entry : original.getRemovedConfigurationData()) {
             normalized.removeConfigurationData(entry);
         }
-        for(InstanceIdentifier entry : original.getRemovedOperationalData()) {
+        for (InstanceIdentifier entry : original.getRemovedOperationalData()) {
             normalized.removeOperationalData(entry);
         }
         return normalized;
@@ -284,7 +285,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
             }
         }
     }
-    
+
     private class NormalizedDataModification extends AbstractDataModification<InstanceIdentifier, CompositeNode> {
 
         private Object identifier;
@@ -295,12 +296,12 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
             identifier = original;
             status = TransactionStatus.NEW;
         }
-        
+
         @Override
         public Object getIdentifier() {
             return this.identifier;
         }
-        
+
         @Override
         public TransactionStatus getStatus() {
             return status;
@@ -310,18 +311,19 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
         public Future<RpcResult<TransactionStatus>> commit() {
             throw new UnsupportedOperationException("Commit should not be invoked on this");
         }
-        
+
         @Override
-        protected CompositeNode mergeConfigurationData(InstanceIdentifier path,CompositeNode stored, CompositeNode modified) {
-            return mergeData(path,stored, modified,true);
+        protected CompositeNode mergeConfigurationData(InstanceIdentifier path, CompositeNode stored,
+                CompositeNode modified) {
+            return mergeData(path, stored, modified, true);
         }
-        
+
         @Override
-        protected CompositeNode mergeOperationalData(InstanceIdentifier path,CompositeNode stored, CompositeNode modified) {
+        protected CompositeNode mergeOperationalData(InstanceIdentifier path, CompositeNode stored,
+                CompositeNode modified) {
             // TODO Auto-generated method stub
-            return mergeData(path,stored,modified,false);
+            return mergeData(path, stored, modified, false);
         }
-        
     }
 
 }
index 44ee2a31b0d2135c41967867398aed18e3893347..3ff1d1d6cbafa87a7479945965542eaf8235368e 100644 (file)
@@ -80,10 +80,11 @@ public class YangSchemaUtils {
                 checkArgument(!iterator.hasNext(), "Path nests inside leaf node, which is not allowed.");
                 return currentNode;
             }
+            checkState(currentNode != null, "Current node should not be null for %s",path);
         }
+        checkState(previous instanceof DataSchemaNode, "Schema node for %s should be instance of DataSchemaNode. Found %s",path,previous);
         return (DataSchemaNode) previous;
     }
-    
 
     private static DataSchemaNode searchInChoices(DataNodeContainer node, QName arg) {
         Set<DataSchemaNode> children = node.getChildNodes();
index fed56fe297a8ed9cc929437329701799ce06ccfb..930aa663bb4cc91b013d42dec40b5775921e95c2 100644 (file)
@@ -34,11 +34,12 @@ 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
+import org.slf4j.LoggerFactory
+import com.google.common.collect.FluentIterable
 
 class ControllerContext implements SchemaServiceListener {
-
+    val static LOG = LoggerFactory.getLogger(ControllerContext)
     val static ControllerContext INSTANCE = new ControllerContext
-
     val static NULL_VALUE = "null"
 
     var SchemaContext schemas;
@@ -292,6 +293,7 @@ class ControllerContext implements SchemaServiceListener {
         checkArgument(node instanceof LeafSchemaNode);
         val urlDecoded = URLDecoder.decode(uriValue);
         val typedef = (node as LeafSchemaNode).type;
+        
         var decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
         if(decoded == null) {
             var baseType = typedef
@@ -329,8 +331,10 @@ class ControllerContext implements SchemaServiceListener {
     private def QName toQName(String name) {
         val module = name.toModuleName;
         val node = name.toNodeName;
-        val namespace = moduleNameToUri.get(module);
-        return new QName(namespace, null, node);
+        val namespace = FluentIterable.from(schemas.modules.sort[o1,o2 | o1.revision.compareTo(o2.revision)]) //
+            .transform[QName.create(namespace,revision,it.name)].findFirst[module == localName]
+        ;
+        return QName.create(namespace,node);
     }
 
     def getRpcDefinition(String name) {
@@ -340,7 +344,7 @@ class ControllerContext implements SchemaServiceListener {
     override onGlobalContextUpdated(SchemaContext context) {
         this.schemas = context;
         for (operation : context.operations) {
-            val qname = new QName(operation.QName.namespace, null, operation.QName.localName);
+            val qname = operation.QName;
             qnameToRpc.put(qname, operation);
         }
     }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ReadConfAndOperDataTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ReadConfAndOperDataTest.java
new file mode 100644 (file)
index 0000000..bc77430
--- /dev/null
@@ -0,0 +1,125 @@
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Future;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
+import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
+import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import com.google.common.base.Charsets;
+
+public class ReadConfAndOperDataTest extends JerseyTest {
+
+    private static ControllerContext controllerContext;
+    private static BrokerFacade brokerFacade;
+    private static RestconfImpl restconfImpl;
+    private static final MediaType MEDIA_TYPE_DRAFT02 = new MediaType("application", "yang.data+xml");
+
+    @BeforeClass
+    public static void init() throws FileNotFoundException {
+        Set<Module> allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs")
+                .getPath());
+        SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules);
+        controllerContext = ControllerContext.getInstance();
+        controllerContext.setSchemas(schemaContext);
+        brokerFacade = mock(BrokerFacade.class);
+        restconfImpl = RestconfImpl.getInstance();
+        restconfImpl.setBroker(brokerFacade);
+        restconfImpl.setControllerContext(controllerContext);
+    }
+
+    @Before
+    public void logs() {
+        List<LogRecord> loggedRecords = getLoggedRecords();
+        for (LogRecord l : loggedRecords) {
+            System.out.println(l.getMessage());
+        }
+    }
+
+    @Test
+    public void testReadConfigurationData() throws UnsupportedEncodingException, FileNotFoundException {
+
+        String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0");
+
+        InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+        CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream);
+        when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode);
+
+        Response response = target(uri).request(MEDIA_TYPE_DRAFT02).get();
+        assertEquals(200, response.getStatus());
+        
+        uri = createUri("/config/", "ietf-interfaces:interfaces/interface/example");
+        when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(null);
+        
+        response = target(uri).request(MEDIA_TYPE_DRAFT02).get();
+        assertEquals(404, response.getStatus());
+    }
+
+    @Test
+    public void testReadOperationalData() throws UnsupportedEncodingException, FileNotFoundException {
+        String uri = createUri("/operational/", "ietf-interfaces:interfaces/interface/eth0");
+
+        InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+        CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream);
+        when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode);
+
+        Response response = target(uri).request(MEDIA_TYPE_DRAFT02).get();
+        assertEquals(200, response.getStatus());
+        
+        uri = createUri("/config/", "ietf-interfaces:interfaces/interface/example");
+        when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(null);
+        
+        response = target(uri).request(MEDIA_TYPE_DRAFT02).get();
+        assertEquals(404, response.getStatus());
+    }
+
+    private String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException {
+        return URI.create(prefix + URLEncoder.encode(encodedPart, Charsets.US_ASCII.name()).toString()).toASCIIString();
+    }
+
+    @Override
+    protected Application configure() {
+        enable(TestProperties.LOG_TRAFFIC);
+        enable(TestProperties.DUMP_ENTITY);
+        enable(TestProperties.RECORD_LOG_LEVEL);
+        set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+
+        ResourceConfig resourceConfig = new ResourceConfig();
+        resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE,
+                XmlToCompositeNodeProvider.INSTANCE);
+        return resourceConfig;
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java
new file mode 100644 (file)
index 0000000..11cce72
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
+
+/**
+ * Main responsibility of the class is to manage multipart response 
+ * for multipart request. It also handles the flow aggregate request
+ * and response mapping. 
+ * @author avishnoi@in.ibm.com
+ *
+ */
+public class MultipartMessageManager {
+
+    private static Map<TransactionId,Short> txIdTotableIdMap = new ConcurrentHashMap<TransactionId,Short>();
+    
+    public MultipartMessageManager(){}
+    
+    public Short getTableIdForTxId(TransactionId id){
+        
+        return txIdTotableIdMap.get(id);
+        
+    }
+    
+    public void setTxIdAndTableIdMapEntry(TransactionId id,Short tableId){
+        txIdTotableIdMap.put(id, tableId);
+    }
+}
index c48ac311abb33dc0ffdfe5ee1ca4c3f26595111b..e84b437b533f8c1deba3d3d67634ee70f5096c15 100644 (file)
@@ -7,15 +7,26 @@
  */
 package org.opendaylight.controller.md.statistics.manager;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeatures;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeatures;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericQueueStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericTableStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics;
 
 public class NodeStatistics {
 
@@ -33,6 +44,21 @@ public class NodeStatistics {
     
     private MeterFeatures meterFeatures;
     
+    private final Map<Short,Map<Flow,GenericStatistics>> flowAndStatsMap= 
+            new HashMap<Short,Map<Flow,GenericStatistics>>();
+    
+    private final Map<Short,AggregateFlowStatistics> tableAndAggregateFlowStatsMap = 
+            new HashMap<Short,AggregateFlowStatistics>();
+    
+    private final Map<NodeConnectorId,NodeConnectorStatistics> nodeConnectorStats = 
+            new ConcurrentHashMap<NodeConnectorId,NodeConnectorStatistics>();
+    
+    private final Map<Short,GenericTableStatistics> flowTableAndStatisticsMap = 
+            new HashMap<Short,GenericTableStatistics>();
+    
+    private final Map<NodeConnectorId,Map<QueueId,GenericQueueStatistics>> NodeConnectorAndQueuesStatsMap = 
+            new HashMap<NodeConnectorId,Map<QueueId,GenericQueueStatistics>>();
+    
     public NodeStatistics(){
         
     }
@@ -92,5 +118,23 @@ public class NodeStatistics {
     public void setMeterFeatures(MeterFeatures meterFeatures) {
         this.meterFeatures = meterFeatures;
     }
-    
+
+    public Map<Short,Map<Flow,GenericStatistics>> getFlowAndStatsMap() {
+        return flowAndStatsMap;
+    }
+
+    public Map<Short, GenericTableStatistics> getFlowTableAndStatisticsMap() {
+        return flowTableAndStatisticsMap;
+    }
+
+    public Map<Short, AggregateFlowStatistics> getTableAndAggregateFlowStatsMap() {
+        return tableAndAggregateFlowStatsMap;
+    }
+    public Map<NodeConnectorId, NodeConnectorStatistics> getNodeConnectorStats() {
+        return nodeConnectorStats;
+    }
+
+    public Map<NodeConnectorId, Map<QueueId, GenericQueueStatistics>> getNodeConnectorAndQueuesStatsMap() {
+        return NodeConnectorAndQueuesStatsMap;
+    }
 }
index f22ca00b2ab4d0dc20d551aa08d58522848923a7..6dafa58c7ef47da223bf4e650487c07bb2366df8 100644 (file)
@@ -7,9 +7,11 @@
  */
 package org.opendaylight.controller.md.statistics.manager;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
 import org.eclipse.xtext.xbase.lib.Exceptions;
@@ -17,6 +19,15 @@ import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder;
@@ -26,11 +37,18 @@ 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.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllPortsStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllPortsStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
 import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.NotificationListener;
@@ -50,6 +68,16 @@ public class StatisticsProvider implements AutoCloseable {
     
     private OpendaylightMeterStatisticsService meterStatsService;
     
+    private OpendaylightFlowStatisticsService flowStatsService;
+    
+    private OpendaylightPortStatisticsService portStatsService;
+
+    private OpendaylightFlowTableStatisticsService flowTableStatsService;
+
+    private OpendaylightQueueStatisticsService queueStatsService;
+
+    private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager();
+    
     private Thread statisticsRequesterThread;
     
     private final  InstanceIdentifier<Nodes> nodesIdentifier = InstanceIdentifier.builder(Nodes.class).toInstance();
@@ -76,6 +104,10 @@ public class StatisticsProvider implements AutoCloseable {
       this.nps = notificationService;
     }
 
+    public MultipartMessageManager getMultipartMessageManager() {
+        return multipartMessageManager;
+    }
+
     private final StatisticsUpdateCommiter updateCommiter = new StatisticsUpdateCommiter(StatisticsProvider.this);
     
     private Registration<NotificationListener> listenerRegistration;
@@ -92,7 +124,19 @@ public class StatisticsProvider implements AutoCloseable {
         
         meterStatsService = StatisticsManagerActivator.getProviderContext().
                 getRpcService(OpendaylightMeterStatisticsService.class);
+        
+        flowStatsService = StatisticsManagerActivator.getProviderContext().
+                getRpcService(OpendaylightFlowStatisticsService.class);
+
+        portStatsService = StatisticsManagerActivator.getProviderContext().
+                getRpcService(OpendaylightPortStatisticsService.class);
 
+        flowTableStatsService = StatisticsManagerActivator.getProviderContext().
+                getRpcService(OpendaylightFlowTableStatisticsService.class);
+        
+        queueStatsService = StatisticsManagerActivator.getProviderContext().
+                getRpcService(OpendaylightQueueStatisticsService.class);
+        
         statisticsRequesterThread = new Thread( new Runnable(){
 
             @Override
@@ -124,21 +168,37 @@ public class StatisticsProvider implements AutoCloseable {
     
     private void statsRequestSender(){
         
-        //Need to call API to receive all the nodes connected to controller.
         List<Node> targetNodes = getAllConnectedNodes();
         
         if(targetNodes == null)
             return;
+        
 
         for (Node targetNode : targetNodes){
+            
+            InstanceIdentifier<Node> targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance();
+            NodeRef targetNodeRef = new NodeRef(targetInstanceId);
+            
+            try {
+                
+                sendAggregateFlowsStatsFromAllTablesRequest(targetNode.getKey());
 
-            if(targetNode.getAugmentation(FlowCapableNode.class) != null){
+                sendAllFlowsStatsFromAllTablesRequest(targetNodeRef);
 
-                spLogger.info("Send request for stats collection to node : {})",targetNode.getId());
+                sendAllPortStatisticsRequest(targetNodeRef);
                 
-                InstanceIdentifier<Node> targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance();
-                NodeRef targetNodeRef = new NodeRef(targetInstanceId);
+                sendAllFlowTablesStatisticsRequest(targetNodeRef);
                 
+                sendAllQueueStatsFromAllNodeConnector (targetNodeRef);
+
+            }catch(Exception e){
+                spLogger.error("Exception occured while sending statistics requests : {}",e);
+            }
+
+            if(targetNode.getAugmentation(FlowCapableNode.class) != null){
+
+                spLogger.info("Send request for stats collection to node : {})",targetNode.getId());
+
                 try{
                   sendAllGroupStatisticsRequest(targetNodeRef);
                   Thread.sleep(1000);
@@ -149,17 +209,85 @@ public class StatisticsProvider implements AutoCloseable {
                   sendMeterConfigStatisticsRequest(targetNodeRef);
                   Thread.sleep(1000);
                 }catch(Exception e){
-                    spLogger.error("Exception occured while sending statistics request : {}", e);
+                    spLogger.error("Exception occured while sending statistics requests : {}", e);
                 }
             }
         }
     }
+
+    private void sendAllFlowTablesStatisticsRequest(NodeRef targetNodeRef) {
+        final GetFlowTablesStatisticsInputBuilder input = 
+                new GetFlowTablesStatisticsInputBuilder();
+        
+        input.setNode(targetNodeRef);
+
+        @SuppressWarnings("unused")
+        Future<RpcResult<GetFlowTablesStatisticsOutput>> response = 
+                flowTableStatsService.getFlowTablesStatistics(input.build());
+    }
+
+    private void sendAllFlowsStatsFromAllTablesRequest(NodeRef targetNode){
+        final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input =
+                new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder();
+        
+        input.setNode(targetNode);
+        
+        @SuppressWarnings("unused")
+        Future<RpcResult<GetAllFlowsStatisticsFromAllFlowTablesOutput>> response = 
+                flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build());
+        
+    }
     
+    private void sendAggregateFlowsStatsFromAllTablesRequest(NodeKey targetNodeKey) throws InterruptedException, ExecutionException{
+        
+        List<Short> tablesId = getTablesFromNode(targetNodeKey);
+        
+        if(tablesId.size() != 0){
+            for(Short id : tablesId){
+                
+                spLogger.info("Send aggregate stats request for flow table {} to node {}",id,targetNodeKey);
+                GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = 
+                        new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder();
+                
+                input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance()));
+                input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(id));
+                Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> response = 
+                        flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build());
+                
+                multipartMessageManager.setTxIdAndTableIdMapEntry(response.get().getResult().getTransactionId(), id);
+            }
+        }
+        
+        //Note: Just for testing, because i am not able to fetch table list from datastore
+        // Bug-225 is raised for investigation.
+        
+//                spLogger.info("Send aggregate stats request for flow table {} to node {}",1,targetNodeKey);
+//                GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = 
+//                        new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder();
+//                
+//                input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance()));
+//                input.setTableId(new TableId((short)1));
+//                Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> response = 
+//                        flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build());`
+//                
+//                multipartMessageManager.setTxIdAndTableIdMapEntry(response.get().getResult().getTransactionId(), (short)1);
+    }
+
+    private void sendAllPortStatisticsRequest(NodeRef targetNode){
+        
+        final GetAllPortsStatisticsInputBuilder input = new GetAllPortsStatisticsInputBuilder();
+        
+        input.setNode(targetNode);
+
+        @SuppressWarnings("unused")
+        Future<RpcResult<GetAllPortsStatisticsOutput>> response = 
+                portStatsService.getAllPortsStatistics(input.build());
+    }
+
     private void sendAllGroupStatisticsRequest(NodeRef targetNode){
         
         final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder();
         
-        input.setNode(targetNode);
         input.setNode(targetNode);
 
         @SuppressWarnings("unused")
@@ -197,9 +325,18 @@ public class StatisticsProvider implements AutoCloseable {
         @SuppressWarnings("unused")
         Future<RpcResult<GetAllMeterConfigStatisticsOutput>> response = 
                 meterStatsService.getAllMeterConfigStatistics(input.build());
-        
     }
     
+    private void sendAllQueueStatsFromAllNodeConnector(NodeRef targetNode) {
+        GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder();
+        
+        input.setNode(targetNode);
+        
+        @SuppressWarnings("unused")
+        Future<RpcResult<GetAllQueuesStatisticsFromAllPortsOutput>> response = 
+                queueStatsService.getAllQueuesStatisticsFromAllPorts(input.build());
+    }
+
     public ConcurrentMap<NodeId, NodeStatistics> getStatisticsCache() {
         return statisticsCache;
     }
@@ -213,6 +350,20 @@ public class StatisticsProvider implements AutoCloseable {
         spLogger.info("Number of connected nodes : {}",nodes.getNode().size());
         return nodes.getNode();
     }
+    
+    private List<Short> getTablesFromNode(NodeKey nodeKey){
+        InstanceIdentifier<FlowCapableNode> nodesIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class,nodeKey).augmentation(FlowCapableNode.class).toInstance();
+        
+        FlowCapableNode node = (FlowCapableNode)dps.readConfigurationData(nodesIdentifier);
+        List<Short> tablesId = new ArrayList<Short>();
+        if(node != null && node.getTable()!=null){
+            spLogger.info("Number of tables {} supported by node {}",node.getTable().size(),nodeKey);
+            for(Table table: node.getTable()){
+                tablesId.add(table.getId());
+            }
+        }
+        return tablesId;
+    }
 
     @SuppressWarnings("deprecation")
     @Override
index 86e6114b5f67a9df25f02e8ae98677d0d842cc54..7169b39b77a77f5c11abb3553b621a9f3c9d6a0f 100644 (file)
@@ -7,9 +7,44 @@
  */
 package org.opendaylight.controller.md.statistics.manager;
 
+import java.util.HashMap;
+import java.util.List;
 import java.util.concurrent.ConcurrentMap;
 
 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.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowTableStatisticsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.NodeConnectorStatisticsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated;
@@ -26,6 +61,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.
 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.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.nodes.NodeKey;
@@ -42,13 +80,37 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterConfigStatsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericQueueStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.PortStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsListener,
-        OpendaylightMeterStatisticsListener {
+        OpendaylightMeterStatisticsListener, 
+        OpendaylightFlowStatisticsListener,
+        OpendaylightPortStatisticsListener,
+        OpendaylightFlowTableStatisticsListener,
+        OpendaylightQueueStatisticsListener{
     
+    public final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class);
+
     private final StatisticsProvider statisticsManager;
+    
+    private final int unaccountedFlowsCounter = 1;
 
     public StatisticsUpdateCommiter(final StatisticsProvider manager){
 
@@ -264,9 +326,417 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
         it.commit();
     }
 
+    @Override
+    public void onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
+        NodeKey key = new NodeKey(notification.getId());
+        sucLogger.info("Received flow stats update : {}",notification.toString());
+        
+        for(FlowAndStatisticsMapList map: notification.getFlowAndStatisticsMapList()){
+            short tableId = map.getTableId();
+            
+            DataModificationTransaction it = this.statisticsManager.startChange();
+
+            boolean foundOriginalFlow = false;
+
+            FlowBuilder flowBuilder = new FlowBuilder();
+
+            FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
+
+            FlowBuilder flow = new FlowBuilder();
+            flow.setContainerName(map.getContainerName());
+            flow.setBufferId(map.getBufferId());
+            flow.setCookie(map.getCookie());
+            flow.setCookieMask(map.getCookieMask());
+            flow.setFlags(map.getFlags());
+            flow.setFlowName(map.getFlowName());
+            flow.setHardTimeout(map.getHardTimeout());
+            if(map.getFlowId() != null)
+                flow.setId(new FlowId(map.getFlowId().getValue()));
+            flow.setIdleTimeout(map.getIdleTimeout());
+            flow.setInstallHw(map.isInstallHw());
+            flow.setInstructions(map.getInstructions());
+            if(map.getFlowId()!= null)
+                flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
+            flow.setMatch(map.getMatch());
+            flow.setOutGroup(map.getOutGroup());
+            flow.setOutPort(map.getOutPort());
+            flow.setPriority(map.getPriority());
+            flow.setStrict(map.isStrict());
+            flow.setTableId(tableId);
+                
+            Flow flowRule = flow.build();
+                
+            FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
+            stats.setByteCount(map.getByteCount());
+            stats.setPacketCount(map.getPacketCount());
+            stats.setDuration(map.getDuration());
+                
+            GenericStatistics flowStats = stats.build();
+                
+            //Add statistics to local cache
+            ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
+            if(!cache.containsKey(notification.getId())){
+                cache.put(notification.getId(), new NodeStatistics());
+            }
+            if(!cache.get(notification.getId()).getFlowAndStatsMap().containsKey(tableId)){
+                cache.get(notification.getId()).getFlowAndStatsMap().put(tableId, new HashMap<Flow,GenericStatistics>());
+            }
+            cache.get(notification.getId()).getFlowAndStatsMap().get(tableId).put(flowRule,flowStats);
+                
+            //Augment the data to the flow node
+
+            FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder();
+            flowStatistics.setByteCount(flowStats.getByteCount());
+            flowStatistics.setPacketCount(flowStats.getPacketCount());
+            flowStatistics.setDuration(flowStats.getDuration());
+            flowStatistics.setContainerName(map.getContainerName());
+            flowStatistics.setBufferId(map.getBufferId());
+            flowStatistics.setCookie(map.getCookie());
+            flowStatistics.setCookieMask(map.getCookieMask());
+            flowStatistics.setFlags(map.getFlags());
+            flowStatistics.setFlowName(map.getFlowName());
+            flowStatistics.setHardTimeout(map.getHardTimeout());
+            flowStatistics.setIdleTimeout(map.getIdleTimeout());
+            flowStatistics.setInstallHw(map.isInstallHw());
+            flowStatistics.setInstructions(map.getInstructions());
+            flowStatistics.setMatch(map.getMatch());
+            flowStatistics.setOutGroup(map.getOutGroup());
+            flowStatistics.setOutPort(map.getOutPort());
+            flowStatistics.setPriority(map.getPriority());
+            flowStatistics.setStrict(map.isStrict());
+            flowStatistics.setTableId(tableId);
+
+            flowStatisticsData.setFlowStatistics(flowStatistics.build());
+                
+            sucLogger.debug("Flow : {}",flowRule.toString());
+            sucLogger.debug("Statistics to augment : {}",flowStatistics.build().toString());
+
+            InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
+                    .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
+            
+            Table table= (Table)it.readConfigurationData(tableRef);
+
+            //TODO: Not a good way to do it, need to figure out better way.
+            //TODO: major issue in any alternate approach is that flow key is incrementally assigned 
+            //to the flows stored in data store.
+            if(table != null){
+
+                for(Flow existingFlow : table.getFlow()){
+                    sucLogger.debug("Existing flow in data store : {}",existingFlow.toString());
+                    if(flowEquals(flowRule,existingFlow)){
+                        InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
+                                .augmentation(FlowCapableNode.class)
+                                .child(Table.class, new TableKey(tableId))
+                                .child(Flow.class,existingFlow.getKey()).toInstance();
+                        flowBuilder.setKey(existingFlow.getKey());
+                        flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+                        sucLogger.debug("Found matching flow in the datastore, augmenting statistics");
+                        foundOriginalFlow = true;
+                        it.putOperationalData(flowRef, flowBuilder.build());
+                        it.commit();
+                        break;
+                    }
+                }
+            }
+            
+            if(!foundOriginalFlow){
+                sucLogger.info("Associated original flow is not found in data store. Augmenting flow in operational data st");
+                //TODO: Temporary fix: format [ 0+tableid+0+unaccounted flow counter]
+                long flowKey = Long.getLong(new String("0"+Short.toString(tableId)+"0"+Integer.toString(this.unaccountedFlowsCounter)));
+                FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
+                InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
+                        .augmentation(FlowCapableNode.class)
+                        .child(Table.class, new TableKey(tableId))
+                        .child(Flow.class,newFlowKey).toInstance();
+                flowBuilder.setKey(newFlowKey);
+                flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+                sucLogger.debug("Flow was no present in data store, augmenting statistics as an unaccounted flow");
+                it.putOperationalData(flowRef, flowBuilder.build());
+                it.commit();
+            }
+        }
+    }
+
+    @Override
+    public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
+        NodeKey key = new NodeKey(notification.getId());
+        sucLogger.debug("Received aggregate flow statistics update : {}",notification.toString());
+        
+        Short tableId = this.statisticsManager.getMultipartMessageManager().getTableIdForTxId(notification.getTransactionId());
+        if(tableId != null){
+            
+            DataModificationTransaction it = this.statisticsManager.startChange();
+
+            InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
+                    .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
+
+            AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
+            AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder();
+            aggregateFlowStatisticsBuilder.setByteCount(notification.getByteCount());
+            aggregateFlowStatisticsBuilder.setFlowCount(notification.getFlowCount());
+            aggregateFlowStatisticsBuilder.setPacketCount(notification.getPacketCount());
+            aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
+            
+            ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
+            if(!cache.containsKey(notification.getId())){
+                cache.put(notification.getId(), new NodeStatistics());
+            }
+            cache.get(notification.getId()).getTableAndAggregateFlowStatsMap().put(tableId,aggregateFlowStatisticsBuilder.build());
+            
+            sucLogger.debug("Augment aggregate statistics: {} for table {} on Node {}",aggregateFlowStatisticsBuilder.build().toString(),tableId,key);
+
+            TableBuilder tableBuilder = new TableBuilder();
+            tableBuilder.setKey(new TableKey(tableId));
+            tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
+            it.putOperationalData(tableRef, tableBuilder.build());
+            it.commit();
+
+        }
+    }
+
+    @Override
+    public void onPortStatisticsUpdate(PortStatisticsUpdate notification) {
+        NodeKey key = new NodeKey(notification.getId());
+        sucLogger.info("Received port stats update : {}",notification.toString());
+        
+        //Add statistics to local cache
+        ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
+        if(!cache.containsKey(notification.getId())){
+            cache.put(notification.getId(), new NodeStatistics());
+        }
+
+
+        List<NodeConnectorStatisticsAndPortNumberMap> portsStats = notification.getNodeConnectorStatisticsAndPortNumberMap();
+        for(NodeConnectorStatisticsAndPortNumberMap portStats : portsStats){
+            
+            DataModificationTransaction it = this.statisticsManager.startChange();
+
+            FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder 
+                                            = new FlowCapableNodeConnectorStatisticsBuilder();
+            statisticsBuilder.setBytes(portStats.getBytes());
+            statisticsBuilder.setCollisionCount(portStats.getCollisionCount());
+            statisticsBuilder.setDuration(portStats.getDuration());
+            statisticsBuilder.setPackets(portStats.getPackets());
+            statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError());
+            statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops());
+            statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors());
+            statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError());
+            statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError());
+            statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops());
+            statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors());
+            
+            //Update data in the cache
+            cache.get(notification.getId()).getNodeConnectorStats().put(portStats.getNodeConnectorId(), statisticsBuilder.build());
+            
+            //Augment data to the node-connector
+            FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder = 
+                    new FlowCapableNodeConnectorStatisticsDataBuilder();
+            
+            statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
+            
+            InstanceIdentifier<NodeConnector> nodeConnectorRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance();
+            
+            NodeConnector nodeConnector = (NodeConnector)it.readOperationalData(nodeConnectorRef);
+            
+            if(nodeConnector != null){
+                sucLogger.debug("Augmenting port statistics {} to port {}",statisticsDataBuilder.build().toString(),nodeConnectorRef.toString());
+                NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
+                nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, statisticsDataBuilder.build());
+                it.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
+                it.commit();
+            }
+        }
+    }
+
+    @Override
+    public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
+        NodeKey key = new NodeKey(notification.getId());
+        sucLogger.debug("Received flow table statistics update : {}",notification.toString());
+        
+        List<FlowTableAndStatisticsMap> flowTablesStatsList = notification.getFlowTableAndStatisticsMap();
+        for (FlowTableAndStatisticsMap ftStats : flowTablesStatsList){
+            
+            DataModificationTransaction it = this.statisticsManager.startChange();
+
+            InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
+                    .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance();
+            
+            FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
+            
+            FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder();
+            statisticsBuilder.setActiveFlows(ftStats.getActiveFlows());
+            statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp());
+            statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched());
+            
+            statisticsDataBuilder.setFlowTableStatistics(statisticsBuilder.build());
+            
+            ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
+            if(!cache.containsKey(notification.getId())){
+                cache.put(notification.getId(), new NodeStatistics());
+            }
+            cache.get(notification.getId()).getFlowTableAndStatisticsMap().put(ftStats.getTableId().getValue(),statisticsBuilder.build());
+            
+            sucLogger.debug("Augment flow table statistics: {} for table {} on Node {}",statisticsBuilder.build().toString(),ftStats.getTableId(),key);
+            
+            TableBuilder tableBuilder = new TableBuilder();
+            tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue()));
+            tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
+            it.putOperationalData(tableRef, tableBuilder.build());
+            it.commit();
+        }
+    }
+
+    @Override
+    public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) {
+        NodeKey key = new NodeKey(notification.getId());
+        sucLogger.info("Received queue stats update : {}",notification.toString());
+        
+        //Add statistics to local cache
+        ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
+        if(!cache.containsKey(notification.getId())){
+            cache.put(notification.getId(), new NodeStatistics());
+        }
+        
+        List<QueueIdAndStatisticsMap> queuesStats = notification.getQueueIdAndStatisticsMap();
+        for(QueueIdAndStatisticsMap swQueueStats : queuesStats){
+            
+            if(!cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap().containsKey(swQueueStats.getNodeConnectorId())){
+                cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap().put(swQueueStats.getNodeConnectorId(), new HashMap<QueueId,GenericQueueStatistics>());
+            }
+            
+            FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
+            
+            FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
+            
+            queueStatisticsBuilder.fieldsFrom(swQueueStats);
+            
+            queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
+            
+            cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap()
+                                            .get(swQueueStats.getNodeConnectorId())
+                                            .put(swQueueStats.getQueueId(), queueStatisticsBuilder.build());
+            
+            
+            DataModificationTransaction it = this.statisticsManager.startChange();
+
+            InstanceIdentifier<Queue> queueRef 
+                    = InstanceIdentifier.builder(Nodes.class)
+                                        .child(Node.class, key)
+                                        .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId()))
+                                        .augmentation(FlowCapableNodeConnector.class)
+                                        .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance();
+            
+            QueueBuilder queueBuilder = new QueueBuilder();
+            queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, queueStatisticsDataBuilder.build());
+            queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
+
+            sucLogger.info("Augmenting queue statistics {} of queue {} to port {}"
+                                        ,queueStatisticsDataBuilder.build().toString(),
+                                        swQueueStats.getQueueId(),
+                                        swQueueStats.getNodeConnectorId());
+            
+            it.putOperationalData(queueRef, queueBuilder.build());
+            it.commit();
+            
+        }
+        
+    }
+
+    @Override
+    public void onFlowStatisticsUpdated(FlowStatisticsUpdated notification) {
+        // TODO Auto-generated method stub
+        //TODO: Depricated, will clean it up once sal-compatibility is fixed.
+        //Sal-Compatibility code usage this notification event.
+        
+    }
+
+    @Override
+    public void onFlowTableStatisticsUpdated(FlowTableStatisticsUpdated notification) {
+        // TODO Auto-generated method stub
+        //TODO: Need to implement it yet
+        
+    }
+
+    @Override
+    public void onNodeConnectorStatisticsUpdated(NodeConnectorStatisticsUpdated notification) {
+        // TODO Auto-generated method stub
+        //TODO: Need to implement it yet
+        
+    }
+
     private NodeRef getNodeRef(NodeKey nodeKey){
         InstanceIdentifierBuilder<?> builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey);
         return new NodeRef(builder.toInstance());
     }
+    
+    public boolean flowEquals(Flow statsFlow, Flow storedFlow) {
+        if (statsFlow.getClass() != storedFlow.getClass()) {
+            return false;
+        }
+        if (statsFlow.getBufferId()== null) {
+            if (storedFlow.getBufferId() != null) {
+                return false;
+            }
+        } else if(!statsFlow.getBufferId().equals(storedFlow.getBufferId())) {
+            return false;
+        }
+        if (statsFlow.getContainerName()== null) {
+            if (storedFlow.getContainerName()!= null) {
+                return false;
+            }
+        } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) {
+            return false;
+        }
+        if (statsFlow.getCookie()== null) {
+            if (storedFlow.getCookie()!= null) {
+                return false;
+            }
+        } else if(!statsFlow.getCookie().equals(storedFlow.getCookie())) {
+            return false;
+        }
+        if (statsFlow.getMatch()== null) {
+            if (storedFlow.getMatch() != null) {
+                return false;
+            }
+        } else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) {
+            return false;
+        }
+        if (statsFlow.getCookie()== null) {
+            if (storedFlow.getCookie()!= null) {
+                return false;
+            }
+        } else if(!statsFlow.getCookie().equals(storedFlow.getCookie())) {
+            return false;
+        }
+        if (statsFlow.getHardTimeout() == null) {
+            if (storedFlow.getHardTimeout() != null) {
+                return false;
+            }
+        } else if(!statsFlow.getHardTimeout().equals(storedFlow.getHardTimeout() )) {
+            return false;
+        }
+        if (statsFlow.getIdleTimeout()== null) {
+            if (storedFlow.getIdleTimeout() != null) {
+                return false;
+            }
+        } else if(!statsFlow.getIdleTimeout().equals(storedFlow.getIdleTimeout())) {
+            return false;
+        }
+        if (statsFlow.getPriority() == null) {
+            if (storedFlow.getPriority() != null) {
+                return false;
+            }
+        } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) {
+            return false;
+        }
+        if (statsFlow.getTableId() == null) {
+            if (storedFlow.getTableId() != null) {
+                return false;
+            }
+        } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) {
+            return false;
+        }
+        return true;
+    }
 
 }
index 697b811d51c90c9b7cab4f05f266292d25d2a260..cf0e71e67a52ab9983b5a2599519cf9f3014118c 100644 (file)
@@ -29,12 +29,16 @@ public abstract class AttributeIfcSwitchStatement<T> {
 
         this.lastAttribute = attributeIfc;
 
+        OpenType<?> openType = attributeIfc.getOpenType();
+
         if (attributeIfc instanceof JavaAttribute) {
             try {
                 if(((JavaAttribute)attributeIfc).getTypeDefinition() instanceof BinaryTypeDefinition) {
-                    return caseJavaBinaryAttribute(attributeIfc.getOpenType());
+                    return caseJavaBinaryAttribute(openType);
+                } else if(((JavaAttribute)attributeIfc).isUnion()) {
+                    return caseJavaUnionAttribute(openType);
                 } else
-                    return caseJavaAttribute(attributeIfc.getOpenType());
+                    return caseJavaAttribute(openType);
             } catch (UnknownOpenTypeException e) {
                 throw getIllegalArgumentException(attributeIfc);
             }
@@ -42,9 +46,9 @@ public abstract class AttributeIfcSwitchStatement<T> {
         } else if (attributeIfc instanceof DependencyAttribute) {
             return caseDependencyAttribute(((DependencyAttribute) attributeIfc).getOpenType());
         } else if (attributeIfc instanceof ListAttribute) {
-            return caseListAttribute((ArrayType<?>) attributeIfc.getOpenType());
+            return caseListAttribute((ArrayType<?>) openType);
         } else if (attributeIfc instanceof ListDependenciesAttribute) {
-            return caseListDependeciesAttribute((ArrayType<?>) attributeIfc.getOpenType());
+            return caseListDependeciesAttribute((ArrayType<?>) openType);
         } else if (attributeIfc instanceof TOAttribute) {
             return caseTOAttribute(((TOAttribute) attributeIfc).getOpenType());
         }
@@ -52,6 +56,10 @@ public abstract class AttributeIfcSwitchStatement<T> {
         throw getIllegalArgumentException(attributeIfc);
     }
 
+    protected T caseJavaUnionAttribute(OpenType<?> openType) {
+        return caseJavaAttribute(openType);
+    }
+
     protected T caseJavaBinaryAttribute(OpenType<?> openType) {
         return caseJavaAttribute(openType);
     }
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java
new file mode 100644 (file)
index 0000000..23cdabf
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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;
+
+public class AttributesConstants {
+
+    /**
+     * Property placed into object names for dependencies to preserve reference name
+     */
+    public static final String REF_NAME_ON_PROPERTY_KEY = "X-refName";
+}
index a2691f241cfa9a6c273c95c653c2fa9720d03cb9..97c0f4d834ba7d7a810d9d36a08a1a74deb748e7 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attri
 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.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;
@@ -47,6 +48,12 @@ public class ObjectXmlReader extends AttributeIfcSwitchStatement<AttributeReadin
         return new SimpleBinaryAttributeReadingStrategy(lastAttribute.getNullableDefault());
     }
 
+    @Override
+    protected AttributeReadingStrategy caseJavaUnionAttribute(OpenType<?> openType) {
+        String mappingKey = JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION;
+        return new SimpleUnionAttributeReadingStrategy(lastAttribute.getNullableDefault(), mappingKey);
+    }
+
     @Override
     public AttributeReadingStrategy caseJavaSimpleAttribute(SimpleType<?> openType) {
         return new SimpleAttributeReadingStrategy(lastAttribute.getNullableDefault());
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleUnionAttributeReadingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleUnionAttributeReadingStrategy.java
new file mode 100644 (file)
index 0000000..2e8b459
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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.collect.Maps;
+
+import java.util.List;
+import java.util.Map;
+
+public class SimpleUnionAttributeReadingStrategy extends SimpleAttributeReadingStrategy {
+
+    private final String key;
+
+    public SimpleUnionAttributeReadingStrategy(String nullableDefault, String key) {
+        super(nullableDefault);
+        this.key = key;
+    }
+
+    protected Object postprocessParsedValue(String textContent) {
+        char[] charArray = textContent.toCharArray();
+        List<String> chars = Lists.newArrayListWithCapacity(charArray.length);
+
+        for (char c : charArray) {
+            chars.add(Character.toString(c));
+        }
+
+        Map<String, Object> map = Maps.newHashMap();
+        map.put(key, chars);
+        return map;
+    }
+
+    @Override
+    protected Object postprocessNullableDefault(String nullableDefault) {
+        return nullableDefault == null ? null : postprocessParsedValue(nullableDefault);
+    }
+}
index 252b13bf6850c498d6c122565044359647dd5520..368e1f12a642e54dc90ac8231818619a0de96815 100644 (file)
@@ -53,17 +53,21 @@ public class CompositeAttributeMappingStrategy extends
         Map<String, Object> retVal = Maps.newHashMap();
 
         for (String jmxName : jmxToJavaNameMapping.keySet()) {
-            String innerAttrJmxName = jmxName;
-            Object innerValue = compositeData.get(innerAttrJmxName);
-
-            AttributeMappingStrategy<?, ? extends OpenType<?>> attributeMappingStrategy = innerStrategies
-                    .get(innerAttrJmxName);
-            Optional<?> mapAttribute = attributeMappingStrategy.mapAttribute(innerValue);
-            if (mapAttribute.isPresent())
-                retVal.put(jmxToJavaNameMapping.get(innerAttrJmxName), mapAttribute.get());
+            Optional<?> mapped = mapInnerAttribute(compositeData, jmxName, expectedType.getDescription(jmxName));
+            if(mapped.isPresent())
+                retVal.put(jmxToJavaNameMapping.get(jmxName), mapped.get());
         }
 
         return Optional.of(retVal);
     }
 
+    protected Optional<?> mapInnerAttribute(CompositeDataSupport compositeData, String jmxName, String description) {
+        Object innerValue = compositeData.get(jmxName);
+
+        AttributeMappingStrategy<?, ? extends OpenType<?>> attributeMappingStrategy = innerStrategies
+                .get(jmxName);
+        Optional<?> mapAttribute = attributeMappingStrategy.mapAttribute(innerValue);
+        return mapAttribute;
+    }
+
 }
index 6e5bd0d3fe8229597ab6984f37150f1833cd3525..fb385221c8877b9ffceadf53cd355f8c78197811 100644 (file)
@@ -90,6 +90,22 @@ public class ObjectMapper extends AttributeIfcSwitchStatement<AttributeMappingSt
         return new CompositeAttributeMappingStrategy(openType, innerStrategies, attributeMapping);
     }
 
+    @Override
+    protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaUnionAttribute(OpenType<?> openType) {
+        Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies = Maps.newHashMap();
+
+        Map<String, String> attributeMapping = Maps.newHashMap();
+
+        CompositeType compositeType = (CompositeType) openType;
+        for (String innerAttributeKey : compositeType.keySet()) {
+
+            innerStrategies.put(innerAttributeKey, caseJavaAttribute(compositeType.getType(innerAttributeKey)));
+            attributeMapping.put(innerAttributeKey, innerAttributeKey);
+        }
+
+        return new UnionCompositeAttributeMappingStrategy(compositeType, innerStrategies, attributeMapping);
+    }
+
     private String serviceNameOfDepAttr;
     private String namespaceOfDepAttr;
 
index f4d88c7c8e371e0bbc8fd8614c76b79bc69a7a50..842634163607315bd018d00d43c29b1db2dd83d0 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attri
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributesConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
 
@@ -42,7 +43,11 @@ public class ObjectNameAttributeMappingStrategy extends
         Util.checkType(value, ObjectName.class);
 
         ObjectName on = (ObjectName) value;
-        String refName = tracker.addServiceEntry(namespace, serviceName, on);
+
+        String expectedRefName = on.getKeyProperty(AttributesConstants.REF_NAME_ON_PROPERTY_KEY);
+
+        String refName = expectedRefName == null ? tracker.getRefName(namespace, serviceName, on, Optional.<String> absent())
+                : tracker.getRefName(namespace, serviceName, on, Optional.of(expectedRefName));
 
         return Optional.of(new MappedDependency(namespace, serviceName, refName));
     }
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/UnionCompositeAttributeMappingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/UnionCompositeAttributeMappingStrategy.java
new file mode 100644 (file)
index 0000000..81a1e53
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
+
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import java.util.Map;
+
+public class UnionCompositeAttributeMappingStrategy extends
+        CompositeAttributeMappingStrategy {
+
+
+    public UnionCompositeAttributeMappingStrategy(CompositeType compositeType, Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies, Map<String, String> jmxToJavaNameMapping) {
+        super(compositeType, innerStrategies, jmxToJavaNameMapping);
+    }
+
+    @Override
+    protected Optional<?> mapInnerAttribute(CompositeDataSupport compositeData, String jmxName, String description) {
+        if(description.equals(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION) == false)
+            return Optional.absent();
+
+        return super.mapInnerAttribute(compositeData, jmxName, description);
+    }
+}
index c477821051b08d03288d129fc29c1aaddd32eef6..e8e97f990f44cd45608fb8df92e042437351e319 100644 (file)
@@ -21,7 +21,7 @@ import javax.management.openmbean.OpenDataException;
 import javax.management.openmbean.OpenType;
 import java.util.Map;
 
-final class CompositeAttributeResolvingStrategy extends
+class CompositeAttributeResolvingStrategy extends
         AbstractAttributeResolvingStrategy<CompositeDataSupport, CompositeType> {
     private final Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerTypes;
     private final Map<String, String> yangToJavaAttrMapping;
@@ -49,6 +49,7 @@ final class CompositeAttributeResolvingStrategy extends
 
         Util.checkType(value, Map.class);
         Map<?, ?> valueMap = (Map<?, ?>) value;
+        valueMap = preprocessValueMap(valueMap);
 
         Map<String, Object> items = Maps.newHashMap();
         Map<String, OpenType<?>> openTypes = Maps.newHashMap();
@@ -82,4 +83,8 @@ final class CompositeAttributeResolvingStrategy extends
 
         return Optional.of(parsedValue);
     }
+
+    protected Map<?, ?> preprocessValueMap(Map<?, ?> valueMap) {
+        return valueMap;
+    }
 }
index c6f306b3605cdc83652efd36e53cca6bb9b9f446..d8f0e2357ea0fb57063121b2758aca908b553eb5 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attri
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributesConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance;
@@ -46,6 +47,8 @@ public class ObjectNameAttributeResolvingStrategy extends AbstractAttributeResol
 
         ServiceInstance byRefName = serviceTracker.getByServiceAndRefName(namespace, serviceName, refName);
         ObjectName on = ObjectNameUtil.createReadOnlyModuleON(byRefName.getModuleName(), byRefName.getInstanceName());
+        on = ObjectNameUtil.createON(on.toString() + "," + AttributesConstants.REF_NAME_ON_PROPERTY_KEY + "=" + refName);
+
         logger.debug("Attribute {} : {} parsed to type {}", attrName, value, getOpenType());
         return Optional.of(on);
     }
index f5a25112602ac6b92c6d08faa46b311dbd11533c..a3e2813fa0d383f6db78c6a2c2d52e32d03dc5e1 100644 (file)
@@ -72,13 +72,30 @@ public class ObjectResolver extends AttributeIfcSwitchStatement<AttributeResolvi
     @Override
     protected AttributeResolvingStrategy<?, ? extends OpenType<?>>  caseJavaCompositeAttribute(CompositeType openType) {
         Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap = Maps.newHashMap();
-
         Map<String, String> yangToJmxMapping = Maps.newHashMap();
+
+        fillMappingForComposite(openType, innerMap, yangToJmxMapping);
+        return new CompositeAttributeResolvingStrategy(innerMap, openType, yangToJmxMapping);
+    }
+
+    private void fillMappingForComposite(CompositeType openType, Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap, Map<String, String> yangToJmxMapping) {
         for (String innerAttributeKey : openType.keySet()) {
             innerMap.put(innerAttributeKey, caseJavaAttribute(openType.getType(innerAttributeKey)));
             yangToJmxMapping.put(innerAttributeKey, innerAttributeKey);
         }
-        return new CompositeAttributeResolvingStrategy(innerMap, openType, yangToJmxMapping);
+    }
+
+    @Override
+    protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaUnionAttribute(OpenType<?> openType) {
+
+        Preconditions.checkState(openType instanceof CompositeType, "Unexpected open type, expected %s but was %s");
+        CompositeType compositeType = (CompositeType) openType;
+
+        Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap = Maps.newHashMap();
+        Map<String, String> yangToJmxMapping = Maps.newHashMap();
+        fillMappingForComposite(compositeType, innerMap, yangToJmxMapping);
+
+        return new UnionCompositeAttributeResolvingStrategy(innerMap, compositeType, yangToJmxMapping);
     }
 
     @Override
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/UnionCompositeAttributeResolvingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/UnionCompositeAttributeResolvingStrategy.java
new file mode 100644 (file)
index 0000000..bc99ecf
--- /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.resolving;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
+
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import java.util.Map;
+
+final class UnionCompositeAttributeResolvingStrategy extends CompositeAttributeResolvingStrategy {
+
+    UnionCompositeAttributeResolvingStrategy(Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerTypes,
+                                        CompositeType openType, Map<String, String> yangToJavaAttrMapping) {
+        super(innerTypes, openType, yangToJavaAttrMapping);
+    }
+
+    protected Map<String, Object> preprocessValueMap(Map<?, ?> valueMap) {
+        CompositeType openType = getOpenType();
+
+        Preconditions.checkArgument(
+                valueMap.size() == 1 && valueMap.containsKey(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION),
+                "Unexpected structure of incoming map, expecting one element under %s, but was %s",
+                JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION, valueMap);
+
+        Map<String, Object> newMap = Maps.newHashMap();
+
+        for (String key : openType.keySet()) {
+            if (openType.getDescription(key).equals(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION))
+                newMap.put(key, valueMap.get(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION));
+            else
+                newMap.put(key, null);
+        }
+        return newMap;
+    }
+}
index a174e9a25160e8aa3d52ab66891c9d1314e58185..4e870f042d8cf45605546750d0f99868772fa897 100644 (file)
@@ -73,6 +73,11 @@ public class ObjectXmlWriter extends AttributeIfcSwitchStatement<AttributeWritin
         return new SimpleCompositeAttributeWritingStrategy(document, key);
     }
 
+    @Override
+    protected AttributeWritingStrategy caseJavaUnionAttribute(OpenType<?> openType) {
+        return new SimpleUnionAttributeWritingStrategy(document, key);
+    }
+
     @Override
     protected AttributeWritingStrategy caseDependencyAttribute(SimpleType<?> openType) {
         return new ObjectNameAttributeWritingStrategy(document, key);
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleUnionAttributeWritingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleUnionAttributeWritingStrategy.java
new file mode 100644 (file)
index 0000000..d75feb2
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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 org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.w3c.dom.Document;
+
+import java.util.List;
+import java.util.Map;
+
+public class SimpleUnionAttributeWritingStrategy extends SimpleAttributeWritingStrategy {
+
+    /**
+     * @param document
+     * @param key
+     */
+    public SimpleUnionAttributeWritingStrategy(Document document, String key) {
+        super(document, key);
+    }
+
+    protected Object preprocess(Object value) {
+        Util.checkType(value, Map.class);
+        Preconditions.checkArgument(((Map)value).size() == 1, "Unexpected number of values in %s, expected 1", value);
+        Object listOfStrings = ((Map) value).values().iterator().next();
+        Util.checkType(listOfStrings, List.class);
+
+        StringBuilder b = new StringBuilder();
+        for (Object character: (List)listOfStrings) {
+            Util.checkType(character, String.class);
+            b.append(character);
+        }
+
+        return b.toString();
+    }
+
+}
index f33a32271fd189dd39a61b7403069d765e4d1615..3a5fa1170fec28922155e8e7b2748eb7393448b5 100644 (file)
@@ -14,6 +14,7 @@ import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
@@ -53,7 +54,7 @@ public class Config {
     }
 
     public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
-                                                                                Services serviceTracker, Map<String, Map<String, ModuleConfig>> configs) {
+                                                                                Map<String, Map<String, ModuleConfig>> configs) {
         Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
 
         Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
@@ -75,13 +76,6 @@ public class Config {
 
                 innerRetVal.put(moduleName, instances);
 
-                // All found instances add to service tracker in advance
-                // This way all instances will be serialized as all available
-                // services when get-config is triggered
-                // (even if they are not used as services by other instances)
-                // = more user friendly
-                addServices(serviceTracker, instances, mbeEntry.getValue().getProvidedServices());
-
             }
 
             retVal.put(namespace, innerRetVal);
@@ -89,15 +83,6 @@ public class Config {
         return retVal;
     }
 
-    private static void addServices(Services serviceTracker, Collection<ObjectName> instances,
-            Multimap<String, String> providedServices) {
-        for (ObjectName instanceOn : instances) {
-            for (Entry<String, String> serviceName : providedServices.entries()) {
-                serviceTracker.addServiceEntry(serviceName.getKey(), serviceName.getValue(), instanceOn);
-            }
-        }
-    }
-
     private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
         Multimap<String, ObjectName> retVal = HashMultimap.create();
 
@@ -114,11 +99,10 @@ public class Config {
     // }
 
     public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
-            Element dataElement) {
-        Services serviceTracker = new Services();
+            Element dataElement, Services serviceTracker) {
 
         Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
-                serviceTracker, moduleConfigs);
+                moduleConfigs);
 
         Element root = dataElement;
         if (maybeNamespace.isPresent()) {
@@ -167,13 +151,13 @@ public class Config {
     // TODO refactor, replace string representing namespace with namespace class
     // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
     // class
-    public Map<String, Multimap<String, ModuleElementResolved>> fromXml(XmlElement xml, Set<ObjectName> instancesForFillingServiceRefMapping,
-                                                                        EditStrategyType defaultEditStrategyType) {
+    public ConfigElementResolved fromXml(XmlElement xml,
+                                         EditStrategyType defaultEditStrategyType, ServiceReferenceReadableRegistry taClient) {
         Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
 
         List<XmlElement> recognisedChildren = Lists.newArrayList();
 
-        Services serviceTracker = fromXmlServices(xml, recognisedChildren, instancesForFillingServiceRefMapping);
+        Services serviceTracker = fromXmlServices(xml, recognisedChildren, taClient);
         List<XmlElement> moduleElements = fromXmlModules(xml, recognisedChildren);
 
         xml.checkUnrecognisedElements(recognisedChildren);
@@ -182,7 +166,26 @@ public class Config {
             resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType);
         }
 
-        return retVal;
+        return new ConfigElementResolved(retVal, serviceTracker);
+    }
+
+    public static class ConfigElementResolved {
+
+        private final Map<String, Multimap<String, ModuleElementResolved>> resolvedModules;
+        private final Services services;
+
+        public ConfigElementResolved(Map<String, Multimap<String, ModuleElementResolved>> retVal, Services serviceTracker) {
+            this.resolvedModules = retVal;
+            this.services = serviceTracker;
+        }
+
+        public Map<String, Multimap<String, ModuleElementResolved>> getResolvedModules() {
+            return resolvedModules;
+        }
+
+        public Services getServices() {
+            return services;
+        }
     }
 
     private List<XmlElement> fromXmlModules(XmlElement xml, List<XmlElement> recognisedChildren) {
@@ -224,7 +227,8 @@ public class Config {
         innerMap.put(factoryName, moduleElementResolved);
     }
 
-    private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren, Set<ObjectName> instancesForFillingServiceRefMapping) {
+    private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren,
+                                     ServiceReferenceReadableRegistry taClient) {
         Optional<XmlElement> servicesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
                 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
 
@@ -235,22 +239,7 @@ public class Config {
         } else {
             mappedServices = new HashMap<>();
         }
-        Services services = Services.resolveServices(mappedServices);
-        // merge with what candidate db contains by default - ref_
-
-        for(ObjectName existingON: instancesForFillingServiceRefMapping) {
-            logger.trace("Filling services from {}", existingON);
-            // get all its services
-            String factoryName = ObjectNameUtil.getFactoryName(existingON);
-            ModuleConfig moduleConfig = moduleNamesToConfigs.get(factoryName);
-
-            checkState(moduleConfig != null, "Cannot find ModuleConfig with name " + factoryName + " in " + moduleNamesToConfigs);
-            // Set<String> services = ;
-            for (Entry<String, String> serviceName : moduleConfig.getProvidedServices().entries()) {
-
-                services.addServiceEntry(serviceName.getKey(), serviceName.getValue(), existingON);
-            }
-        }
+        Services services = Services.resolveServices(mappedServices, taClient);
 
         return services;
     }
index 33858746cb0f06bdd4d7387ad8141f29a6d23b51..aae1636165c07c6822fbadf10ddfeafad2d28653 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
@@ -128,7 +129,7 @@ public final class InstanceConfig {
     }
 
     public InstanceConfigElementResolved fromXml(XmlElement moduleElement, Services services, String moduleNamespace,
-                                                 EditStrategyType defaultStrategy) {
+            EditStrategyType defaultStrategy, Multimap<String, String> providedServices) {
         Map<String, AttributeConfigElement> retVal = Maps.newHashMap();
 
         Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig);
@@ -153,7 +154,7 @@ public final class InstanceConfig {
                 XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
 
         InstanceConfigElementResolved instanceConfigElementResolved = perInstanceEditStrategy.equals("") ? new InstanceConfigElementResolved(
-                retVal, defaultStrategy) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy);
+                retVal, defaultStrategy, providedServices) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy, providedServices);
 
         resolveConfiguration(instanceConfigElementResolved, services);
         return instanceConfigElementResolved;
index e4bd9212e90995ae7515026c49815645afe6ff3e..55cb60bed5e7df0268908b160650ecd46101e137 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
 
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Multimap;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigStrategy;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser;
@@ -24,16 +25,19 @@ public class InstanceConfigElementResolved {
 
     private final EditStrategyType editStrategy;
     private final Map<String, AttributeConfigElement> configuration;
+    private final Multimap<String, String> providedServices;
 
-    public InstanceConfigElementResolved(String currentStrategy, Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy) {
+    public InstanceConfigElementResolved(String currentStrategy, Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy, Multimap<String, String> providedServices) {
         EditStrategyType valueOf = checkStrategy(currentStrategy, defaultStrategy);
         this.editStrategy = valueOf;
         this.configuration = configuration;
+        this.providedServices = providedServices;
     }
 
-    public InstanceConfigElementResolved(Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy) {
+    public InstanceConfigElementResolved(Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy, Multimap<String, String> providedServices) {
         editStrategy = defaultStrategy;
         this.configuration = configuration;
+        this.providedServices = providedServices;
     }
 
 
@@ -54,7 +58,7 @@ public class InstanceConfigElementResolved {
 
 
     public EditConfigStrategy getEditStrategy() {
-        return editStrategy.getFittingStrategy();
+        return editStrategy.getFittingStrategy(providedServices);
     }
 
     public Map<String, AttributeConfigElement> getConfiguration() {
index 2e2a26400f19899b3f172e80f0de00f7c46ce1c6..2ac6fe0a9bb650116e5f3591fb35cdf8655ee311 100644 (file)
@@ -87,7 +87,7 @@ public class ModuleConfig {
     public ModuleElementResolved fromXml(XmlElement moduleElement, Services depTracker, String instanceName,
             String moduleNamespace, EditStrategyType defaultStrategy) {
 
-        InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy);
+        InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy, providedServices);
         return new ModuleElementResolved(instanceName, ice);
     }
 
index f522668733497333b7b2ac2052fe5949985f8f51..77f3cf283fc2daf77c18766c4a9dacd4185f2536 100644 (file)
@@ -9,10 +9,14 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
 import com.google.common.collect.Sets;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectNameAttributeReadingStrategy;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
@@ -22,9 +26,9 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-import javax.annotation.Nullable;
 import javax.management.ObjectName;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -33,6 +37,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 public final class Services {
+
     private static final Logger logger = LoggerFactory.getLogger(Services.class);
 
     private static final String PROVIDER_KEY = "provider";
@@ -42,58 +47,33 @@ public final class Services {
 
     private long suffix = 1;
 
-    private final Map<ServiceInstance, String> instanceToRef = Maps.newHashMap();
     private final Map<String /*Namespace*/, Map<String/* ServiceName */, Map<String/* refName */, ServiceInstance>>> namespaceToServiceNameToRefNameToInstance = Maps
             .newHashMap();
+    private ServiceReferenceReadableRegistry configServiceRefRegistry;
 
-    public String addServiceEntry(String namespace, String serviceName, ObjectName on) {
-
-        String moduleName = on.getKeyProperty("moduleFactoryName");
-        String instanceName = on.getKeyProperty("instanceName");
-
-        String refName = addServiceEntry(namespace, serviceName, moduleName, instanceName);
-        logger.trace("Added service entry to tracker. Service name {}, ref name {}, module name {}, instance name {}",
-                serviceName, refName, moduleName, instanceName);
-        return refName;
+    public Services(ServiceReferenceReadableRegistry configServiceRefRegistry) {
+        this.configServiceRefRegistry = configServiceRefRegistry;
     }
 
     @VisibleForTesting
-    public String addServiceEntry(String namespace, String serviceName, String moduleName, String instanceName) {
-        ServiceInstance serviceInstance = new ServiceInstance(moduleName, instanceName);
-        serviceInstance.setServiceName(serviceName);
+    public String getNewDefaultRefName(String namespace, String serviceName, String moduleName, String instanceName) {
+        String refName;
+        refName = "ref_" + instanceName;
 
-        String refName = instanceToRef.get(serviceInstance);
+        Map<String, Map<String, String>> serviceNameToRefNameToInstance = getMappedServices().get(namespace);
 
-        Map<String, Map<String, ServiceInstance>> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace);
-        if (serviceNameToRefNameToInstance == null) {
-            serviceNameToRefNameToInstance = Maps.newHashMap();
-            namespaceToServiceNameToRefNameToInstance.put(namespace, serviceNameToRefNameToInstance);
-        }
+        Map<String, String> refNameToInstance;
+        if(serviceNameToRefNameToInstance == null || serviceNameToRefNameToInstance.containsKey(serviceName) == false) {
+            refNameToInstance = Collections.emptyMap();
+        } else
+            refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
 
-        Map<String, ServiceInstance> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
-        if (refNameToInstance == null) {
-            refNameToInstance = Maps.newHashMap();
-            serviceNameToRefNameToInstance.put(serviceName, refNameToInstance);
+        final Set<String> refNamesAsSet = toSet(refNameToInstance.keySet());
+        if (refNamesAsSet.contains(refName)) {
+            refName = findAvailableRefName(refName, refNamesAsSet);
         }
 
-        if (refName != null) {
-            if (serviceNameToRefNameToInstance.get(serviceName).containsKey(moduleName) == false) {
-                refNameToInstance.put(refName, serviceInstance);
-            }
-            return refName;
-        } else {
-            refName = "ref_" + instanceName;
-
-            final Set<String> refNamesAsSet = toSet(instanceToRef.values());
-            if (refNamesAsSet.contains(refName)) {
-                refName = findAvailableRefName(refName, refNamesAsSet);
-            }
-
-            instanceToRef.put(serviceInstance, refName);
-            refNameToInstance.put(refName, serviceInstance);
-
-            return refName;
-        }
+        return refName;
     }
 
     private Set<String> toSet(Collection<String> values) {
@@ -109,15 +89,19 @@ public final class Services {
     }
 
     public ServiceInstance getByServiceAndRefName(String namespace, String serviceName, String refName) {
-        Map<String, Map<String, ServiceInstance>> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace);
-        Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace + " , "
-                + serviceNameToRefNameToInstance.keySet());
+        Map<String, Map<String, String>> serviceNameToRefNameToInstance = getMappedServices().get(namespace);
+
+        Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace);
 
-        Map<String, ServiceInstance> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
+        Map<String, String> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
         Preconditions.checkArgument(refNameToInstance != null, "No serviceInstances mapped to " + serviceName + " , "
                 + serviceNameToRefNameToInstance.keySet());
 
-        ServiceInstance serviceInstance = refNameToInstance.get(refName);
+        String instanceId = refNameToInstance.get(refName);
+        Preconditions.checkArgument(instanceId != null, "No serviceInstances mapped to " + serviceName + ":"
+                + refName + ", " + serviceNameToRefNameToInstance.keySet());
+
+        ServiceInstance serviceInstance = ServiceInstance.fromString(instanceId);
         Preconditions.checkArgument(serviceInstance != null, "No serviceInstance mapped to " + refName
                 + " under service name " + serviceName + " , " + refNameToInstance.keySet());
         return serviceInstance;
@@ -136,26 +120,61 @@ public final class Services {
 
             for (String serviceName : serviceNameToRefNameToInstance.keySet()) {
 
-                Map<String, String> innerInnerRetVal = Maps.transformValues(
-                        serviceNameToRefNameToInstance.get(serviceName), new Function<ServiceInstance, String>() {
-                            @Nullable
-                            @Override
-                            public String apply(@Nullable ServiceInstance serviceInstance) {
-                                return serviceInstance.toString();
-                            }
-                        });
+                Map<String, String> innerInnerRetVal = Maps.newHashMap();
+                for (Entry<String, ServiceInstance> refNameToSi : serviceNameToRefNameToInstance.get(serviceName).entrySet()) {
+                    innerInnerRetVal.put(refNameToSi.getKey(), refNameToSi.getValue().toString());
+                }
                 innerRetVal.put(serviceName, innerInnerRetVal);
             }
             retVal.put(namespace, innerRetVal);
         }
 
+        Map<String, Map<String, ObjectName>> serviceMapping = configServiceRefRegistry.getServiceMapping();
+        for (String serviceQName : serviceMapping.keySet())
+            for (String refName : serviceMapping.get(serviceQName).keySet()) {
+
+                ObjectName on = serviceMapping.get(serviceQName).get(refName);
+                ServiceInstance si = ServiceInstance.fromObjectName(on);
+
+                // FIXME use QName's new String constructor, after its implemented
+                Pattern p = Pattern.compile("\\(([^\\(\\?]+)\\?[^\\?\\)]*\\)([^\\)]+)");
+                Matcher matcher = p.matcher(serviceQName);
+                Preconditions.checkArgument(matcher.matches());
+                String namespace = matcher.group(1);
+                String localName = matcher.group(2);
+
+                Map<String, Map<String, String>> serviceToRefs = retVal.get(namespace);
+                if(serviceToRefs==null) {
+                    serviceToRefs = Maps.newHashMap();
+                    retVal.put(namespace, serviceToRefs);
+                }
+
+                Map<String, String> refsToSis = serviceToRefs.get(localName);
+                if(refsToSis==null) {
+                    refsToSis = Maps.newHashMap();
+                    serviceToRefs.put(localName, refsToSis);
+                }
+
+                Preconditions.checkState(refsToSis.containsKey(refName) == false,
+                        "Duplicate reference name %s for service %s:%s, now for instance %s", refName, namespace,
+                        localName, on);
+                refsToSis.put(refName, si.toString());
+            }
+
         return retVal;
     }
 
+    /**
+     *
+     */
+    public Map<String, Map<String, Map<String, ServiceInstance>>> getNamespaceToServiceNameToRefNameToInstance() {
+        return namespaceToServiceNameToRefNameToInstance;
+    }
+
     // TODO hide resolveServices, call it explicitly in fromXml
 
-    public static Services resolveServices(Map<String, Map<String, Map<String, String>>> mappedServices) {
-        Services tracker = new Services();
+    public static Services resolveServices(Map<String, Map<String, Map<String, String>>> mappedServices, ServiceReferenceReadableRegistry taClient) {
+        Services tracker = new Services(taClient);
 
         for (Entry<String, Map<String, Map<String, String>>> namespaceEntry : mappedServices.entrySet()) {
             String namespace = namespaceEntry.getKey();
@@ -179,18 +198,18 @@ public final class Services {
                     }
 
                     String refName = refEntry.getKey();
-                    Preconditions.checkState(false == refNameToInstance.containsKey(refName),
-                            "Duplicate reference name to service " + refName + " under service " + serviceName);
+
                     ServiceInstance serviceInstance = ServiceInstance.fromString(refEntry.getValue());
                     refNameToInstance.put(refName, serviceInstance);
 
-                    tracker.instanceToRef.put(serviceInstance, refEntry.getKey());
                 }
             }
         }
         return tracker;
     }
 
+    // TODO support edit strategies on services
+
     public static Map<String, Map<String, Map<String, String>>> fromXml(XmlElement xml) {
         Map<String, Map<String, Map<String, String>>> retVal = Maps.newHashMap();
 
@@ -275,6 +294,51 @@ public final class Services {
         return root;
     }
 
+    public String getRefName(String namespace, String serviceName, ObjectName on, Optional<String> expectedRefName) {
+        Optional<String> refNameOptional = getRefNameOptional(namespace, serviceName, on, expectedRefName);
+        Preconditions.checkState(refNameOptional.isPresent(), "No reference names mapped to %s, %s, %s", namespace,
+                serviceName, on);
+        return refNameOptional.get();
+    }
+
+    public Optional<String> getRefNameOptional(String namespace, String serviceName, ObjectName on,
+            Optional<String> expectedRefName) {
+        Map<String, Map<String, String>> services = getMappedServices().get(namespace);
+
+        if(services == null) return Optional.absent();
+        Map<String, String> refs = services.get(serviceName);
+
+        if(refs == null) return Optional.absent();
+        Multimap<ServiceInstance, String> reverted = revertMap(refs);
+
+        ServiceInstance serviceInstance = ServiceInstance.fromObjectName(on);
+        Collection<String> references = reverted.get(serviceInstance);
+
+        if (expectedRefName.isPresent() && references.contains(expectedRefName.get())) {
+            logger.debug("Returning expected ref name {} for {}", expectedRefName.get(), on);
+            return expectedRefName;
+        } else if (references.size() > 0) {
+            String next = references.iterator().next();
+            logger.debug("Returning random ref name {} for {}", next, on);
+            return Optional.of(next);
+        } else
+            return Optional.absent();
+    }
+
+    private Multimap<ServiceInstance, String> revertMap(Map<String, String> refs) {
+        Multimap<ServiceInstance, String> multimap = HashMultimap.create();
+
+        for (Entry<String, String> e : refs.entrySet()) {
+            multimap.put(ServiceInstance.fromString(e.getValue()), e.getKey());
+        }
+
+        return multimap;
+    }
+
+    public boolean hasRefName(String key, String value, ObjectName on) {
+        return getRefNameOptional(key, value, on, Optional.<String>absent()).isPresent();
+    }
+
     public static final class ServiceInstance {
         public ServiceInstance(String moduleName, String instanceName) {
             this.moduleName = moduleName;
@@ -372,6 +436,13 @@ public final class Services {
             return true;
         }
 
+        public ObjectName getObjectName(String transactionName) {
+            return ObjectNameUtil.createTransactionModuleON(transactionName, moduleName, instanceName);
+        }
+
+        public static ServiceInstance fromObjectName(ObjectName on) {
+            return new ServiceInstance(ObjectNameUtil.getFactoryName(on), ObjectNameUtil.getInstanceName(on));
+        }
     }
 
 }
index 64f295a4d885f784a1f2c6a0ddaea915bc19ee8e..89c782c51c86e6acda56b426e6d76a70c2bc0c30 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.runti
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
@@ -60,8 +61,8 @@ public class Runtime {
         return retVal;
     }
 
-    public Element toXml(Set<ObjectName> instancesToMap, Set<ObjectName> configBeans, Document document) {
-        Services serviceTracker = new Services();
+    public Element toXml(Set<ObjectName> instancesToMap, Set<ObjectName> configBeans, Document document, ServiceReferenceReadableRegistry serviceRegistry) {
+        Services serviceTracker = new Services(serviceRegistry);
 
         Element root = document.createElement(XmlNetconfConstants.DATA_KEY);
 
@@ -72,7 +73,7 @@ public class Runtime {
 
         Map<String, Multimap<String, ObjectName>> moduleToRuntimeInstance = mapInstancesToModules(instancesToMap);
         Map<String, Map<String, Collection<ObjectName>>> moduleToConfigInstance = Config.getMappedInstances(
-                configBeans, serviceTracker, moduleConfigs);
+                configBeans, moduleConfigs);
 
         for (String localNamespace : moduleConfigs.keySet()) {
 
index d8ea7d7af7ac955b339d629312d84b98a9fdf617..65df965afd1e08167c63f70ba0c56159a085d2db 100644 (file)
@@ -8,38 +8,38 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
 
-import java.util.Map;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+
 public abstract class AbstractEditConfigStrategy implements EditConfigStrategy {
 
     private static final Logger logger = LoggerFactory.getLogger(AbstractEditConfigStrategy.class);
 
     @Override
     public void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
-            ConfigTransactionClient ta) {
+                                     ConfigTransactionClient ta, Services services) {
 
         try {
             ObjectName on = ta.lookupConfigBean(module, instance);
             logger.debug("ServiceInstance for {} {} located successfully under {}", module, instance, on);
-            executeStrategy(configuration, ta, on);
+            executeStrategy(configuration, ta, on, services);
         } catch (InstanceNotFoundException e) {
-            handleMissingInstance(configuration, ta, module, instance);
+            handleMissingInstance(configuration, ta, module, instance, services);
         }
 
     }
 
     abstract void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
-            String module, String instance);
+                                        String module, String instance, Services services);
 
     abstract void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
-            ObjectName objectName);
+                                  ObjectName objectName, Services services);
 
 }
index ffe107f8ce726953f376e98327be466f80d69437..12beaf8f8e19ff29048cb12c426c372ff047d14c 100644 (file)
@@ -8,28 +8,40 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
 
-import java.util.Map;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+
 public class DeleteEditConfigStrategy extends AbstractEditConfigStrategy {
 
     private static final Logger logger = LoggerFactory.getLogger(DeleteEditConfigStrategy.class);
 
+    private final Multimap<String, String> providedServices;
+
+    public DeleteEditConfigStrategy() {
+        this.providedServices = HashMultimap.create();
+    }
+
+    public DeleteEditConfigStrategy(Multimap<String, String> providedServices) {
+        this.providedServices = providedServices;
+    }
+
     @Override
     void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
-            String module, String instance) {
+                               String module, String instance, Services services) {
         throw new IllegalStateException("Unable to delete " + module + ":" + instance + " , ServiceInstance not found");
     }
 
     @Override
-    void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+    void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, Services services) {
         try {
             ta.destroyModule(on);
             logger.debug("ServiceInstance {} deleted successfully", on);
index 1fca16433a9ac7d1e3af41c64c9167138b5afd65..1bb1d9bfba7babf8fa2dc504909e4f89b6730530 100644 (file)
@@ -26,6 +26,7 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
@@ -36,6 +37,7 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
+import javax.management.InstanceNotFoundException;
 import javax.management.ObjectName;
 import java.util.HashMap;
 import java.util.Map;
@@ -61,6 +63,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
     @VisibleForTesting
     Element getResponseInternal(final Document document,
             final EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
+
         if (editConfigExecution.shouldTest()) {
             executeTests(configRegistryClient, editConfigExecution);
         }
@@ -91,7 +94,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
     private void executeTests(ConfigRegistryClient configRegistryClient,
             EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
         try {
-            test(configRegistryClient, editConfigExecution.getResolvedXmlElements(), editConfigExecution.getDefaultStrategy());
+            test(configRegistryClient, editConfigExecution, editConfigExecution.getDefaultStrategy());
         } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) {
             logger.warn("Test phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e);
             final Map<String, String> errorInfo = new HashMap<>();
@@ -103,7 +106,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
     }
 
     private void test(ConfigRegistryClient configRegistryClient,
-                      Map<String, Multimap<String, ModuleElementResolved>> resolvedModules, EditStrategyType editStrategyType) {
+                      EditConfigExecution execution, EditStrategyType editStrategyType) {
         ObjectName taON = transactionProvider.getTestTransaction();
         try {
 
@@ -111,7 +114,9 @@ public class EditConfig extends AbstractConfigNetconfOperation {
             if (editStrategyType == EditStrategyType.replace) {
                 transactionProvider.wipeTestTransaction(taON);
             }
-            setOnTransaction(configRegistryClient, resolvedModules, taON);
+
+            setOnTransaction(configRegistryClient, execution.getResolvedXmlElements(), execution.getServices(), taON);
+            // TODO add service reference persistance testing here
             transactionProvider.validateTestTransaction(taON);
         } finally {
             transactionProvider.abortTestTransaction(taON);
@@ -126,11 +131,45 @@ public class EditConfig extends AbstractConfigNetconfOperation {
         if (editConfigExecution.getDefaultStrategy() == EditStrategyType.replace) {
             transactionProvider.wipeTransaction();
         }
-        setOnTransaction(configRegistryClient, editConfigExecution.getResolvedXmlElements(), taON);
+
+        setOnTransaction(configRegistryClient, editConfigExecution.getResolvedXmlElements(),
+                editConfigExecution.getServices(), taON);
+        setServicesOnTransaction(configRegistryClient, editConfigExecution.getServices(), taON);
+    }
+
+    private void setServicesOnTransaction(ConfigRegistryClient configRegistryClient, Services services,
+                ObjectName taON) {
+        ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
+
+        Map<String, Map<String, Map<String, Services.ServiceInstance>>> namespaceToServiceNameToRefNameToInstance = services
+                .getNamespaceToServiceNameToRefNameToInstance();
+
+        for (String serviceNamespace : namespaceToServiceNameToRefNameToInstance.keySet()) {
+            for (String serviceName : namespaceToServiceNameToRefNameToInstance.get(serviceNamespace).keySet()) {
+
+                String qnameOfService = getQname(ta, serviceNamespace, serviceName);
+                Map<String, Services.ServiceInstance> refNameToInstance = namespaceToServiceNameToRefNameToInstance
+                        .get(serviceNamespace).get(serviceName);
+
+                for (String refName : refNameToInstance.keySet()) {
+                    ObjectName on = refNameToInstance.get(refName).getObjectName(ta.getTransactionName());
+                    // TODO check for duplicates
+                    try {
+                        ta.saveServiceReference(qnameOfService, refName, on);
+                    } catch (InstanceNotFoundException e) {
+                        throw new IllegalStateException("Unable to save ref name " + refName + " for instance " + on, e);
+                    }
+                }
+            }
+        }
+    }
+
+    private String getQname(ConfigTransactionClient ta, String namespace, String serviceName) {
+        return ta.getServiceInterfaceName(namespace, serviceName);
     }
 
     private void setOnTransaction(ConfigRegistryClient configRegistryClient,
-            Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements, ObjectName taON) {
+                                  Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements, Services services, ObjectName taON) {
         ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
 
         for (Multimap<String, ModuleElementResolved> modulesToResolved : resolvedXmlElements.values()) {
@@ -142,7 +181,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
 
                 InstanceConfigElementResolved ice = moduleElementResolved.getInstanceConfigElementResolved();
                 EditConfigStrategy strategy = ice.getEditStrategy();
-                strategy.executeConfiguration(moduleName, instanceName, ice.getConfiguration(), ta);
+                strategy.executeConfiguration(moduleName, instanceName, ice.getConfiguration(), ta, services);
             }
         }
     }
index 6b7b622d56cb785370d1a578c8045dbba3f94338..23166e8cca5c6e0d4c6fbc955de83de8db94a6f3 100644 (file)
@@ -10,12 +10,13 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ed
 
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 
 import java.util.Map;
 
 public interface EditConfigStrategy {
 
     void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
-            ConfigTransactionClient ta);
+                              ConfigTransactionClient ta, Services services);
 
 }
index 3d4e5b6d0c2b9b431ae1d73cae22ea035cb304b6..81327133b82a440c9b7599672134e7b63fd00f49 100644 (file)
@@ -12,10 +12,13 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Multimap;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
@@ -25,9 +28,7 @@ import org.slf4j.LoggerFactory;
 
 import javax.management.ObjectName;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.Map;
-import java.util.Set;
 
 public class EditConfigXmlParser {
 
@@ -47,6 +48,8 @@ public class EditConfigXmlParser {
                                                     TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient)
             throws NetconfDocumentedException {
 
+        //TODO remove transactionProvider and CfgRegistry from parameters, accept only service ref store
+
         EditStrategyType editStrategyType = EditStrategyType.getDefaultStrategy();
 
         xml.checkName(EditConfigXmlParser.EDIT_CONFIG);
@@ -92,21 +95,14 @@ public class EditConfigXmlParser {
             logger.trace("Setting merge strategy to {}", mergeStrategyString);
             editStrategyType = EditStrategyType.valueOf(mergeStrategyString);
         }
-        Set<ObjectName> instancesForFillingServiceRefMapping = Collections.emptySet();
-        if (editStrategyType == EditStrategyType.merge) {
-            instancesForFillingServiceRefMapping = Datastore.getInstanceQueryStrategy(targetDatastore, transactionProvider)
-                    .queryInstances(configRegistryClient);
-            logger.trace("Pre-filling services from following instances: {}", instancesForFillingServiceRefMapping);
-        }
 
         XmlElement configElement = xml.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.CONFIG_KEY);
 
-        return new EditConfigXmlParser.EditConfigExecution(xml, cfgMapping, configElement, testOption,
-                instancesForFillingServiceRefMapping, editStrategyType);
-    }
+        ObjectName taON = transactionProvider.getOrCreateTransaction();
+        ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
 
-    private void removeMountpointsFromConfig(XmlElement configElement, XmlElement mountpointsElement) {
-        configElement.getDomElement().removeChild(mountpointsElement.getDomElement());
+        return new EditConfigXmlParser.EditConfigExecution(cfgMapping, configElement, testOption,
+                ta, editStrategyType);
     }
 
     @VisibleForTesting
@@ -135,15 +131,16 @@ public class EditConfigXmlParser {
 
     @VisibleForTesting
     static class EditConfigExecution {
-        private final XmlElement editConfigXml;
+
         private final Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements;
         private final TestOption testOption;
         private final EditStrategyType defaultEditStrategyType;
+        private final Services services;
 
-        EditConfigExecution(XmlElement xml, Config configResolver, XmlElement configElement, TestOption testOption, Set<ObjectName> instancesForFillingServiceRefMapping,
-                            EditStrategyType defaultStrategy) {
-            this.editConfigXml = xml;
-            this.resolvedXmlElements = configResolver.fromXml(configElement, instancesForFillingServiceRefMapping, defaultStrategy);
+        EditConfigExecution(Config configResolver, XmlElement configElement, TestOption testOption, ServiceReferenceReadableRegistry ta, EditStrategyType defaultStrategy) {
+            Config.ConfigElementResolved configElementResolved = configResolver.fromXml(configElement, defaultStrategy, ta);
+            this.resolvedXmlElements = configElementResolved.getResolvedModules();
+            this.services = configElementResolved.getServices();
             this.testOption = testOption;
             this.defaultEditStrategyType = defaultStrategy;
         }
@@ -163,5 +160,9 @@ public class EditConfigXmlParser {
         EditStrategyType getDefaultStrategy() {
             return defaultEditStrategyType;
         }
+
+        Services getServices() {
+            return services;
+        }
     }
 }
index cb03342a1e1febf8d883b1a47ac271ade2c96637..676467553bb61c5c46e380c8b8e33331778ea141 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
 
+import com.google.common.collect.Multimap;
+
 import java.util.EnumSet;
 import java.util.Set;
 
@@ -40,14 +42,14 @@ public enum EditStrategyType {
         }
     }
 
-    public EditConfigStrategy getFittingStrategy() {
+    public EditConfigStrategy getFittingStrategy(Multimap<String, String> providedServices) {
         switch (this) {
         case merge:
-            return new MergeEditConfigStrategy();
+            return new MergeEditConfigStrategy(providedServices);
         case replace:
-            return new ReplaceEditConfigStrategy();
+            return new ReplaceEditConfigStrategy(providedServices);
         case delete:
-            return new DeleteEditConfigStrategy();
+            return new DeleteEditConfigStrategy(providedServices);
         case remove:
             return new RemoveEditConfigStrategy();
         case none:
index 2a4a784a8a7bea85a4bcfdc3ee10836d00b5aa1d..06befb0565067592b58465782d66caa74a568100 100644 (file)
@@ -8,37 +8,67 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
 
-import java.util.Map;
-import java.util.Map.Entry;
-
-import javax.management.Attribute;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.management.Attribute;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+import java.util.Map.Entry;
+
 public class MergeEditConfigStrategy extends AbstractEditConfigStrategy {
 
     private static final Logger logger = LoggerFactory.getLogger(MergeEditConfigStrategy.class);
+    private final Multimap<String, String> providedServices;
+
+    public MergeEditConfigStrategy() {
+        this.providedServices = HashMultimap.create();
+    }
+
+    public MergeEditConfigStrategy(Multimap<String, String> providedServices) {
+        this.providedServices = providedServices;
+    }
 
     @Override
     void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
-            String module, String instance) {
-        ObjectName on;
+                               String module, String instance, Services services) {
+        ObjectName on = null;
         try {
             on = ta.createModule(module, instance);
             logger.info("New instance for {} {} created under name {}", module, instance, on);
-            executeStrategy(configuration, ta, on);
+            addRefNames(services, providedServices, module, instance, ta, on);
+            executeStrategy(configuration, ta, on, services);
         } catch (InstanceAlreadyExistsException e1) {
             throw new IllegalStateException("Unable to create instance for " + module + " : " + instance);
+        } catch (InstanceNotFoundException e) {
+            throw new IllegalStateException("Unable to save default ref name for instance " + on, e);
+        }
+    }
+
+    private void addRefNames(Services services, Multimap<String, String> providedServices, String module,
+            String instance, ConfigTransactionClient ta, ObjectName on) throws InstanceNotFoundException {
+        for (Entry<String, String> namespaceToService : providedServices.entries()) {
+
+            if(services.hasRefName(namespaceToService.getKey(),
+                    namespaceToService.getValue(), on))
+                continue;
+
+            String refName = services.getNewDefaultRefName(namespaceToService.getKey(), namespaceToService.getValue(),
+                    module, instance);
+            ta.saveServiceReference(
+                    ta.getServiceInterfaceName(namespaceToService.getKey(), namespaceToService.getValue()), refName, on);
         }
     }
 
     @Override
-    void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+    void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, Services services) {
         for (Entry<String, AttributeConfigElement> configAttributeEntry : configuration.entrySet()) {
             try {
                 AttributeConfigElement ace = configAttributeEntry.getValue();
index db11ce381eb82db6076189fa092adcffb97ff998..8347c6b88e23325fa579527a5f30785a99216b7d 100644 (file)
@@ -12,6 +12,7 @@ import java.util.Map;
 
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -21,7 +22,7 @@ public class NoneEditConfigStrategy implements EditConfigStrategy {
 
     @Override
     public void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
-            ConfigTransactionClient ta) {
+                                     ConfigTransactionClient ta, Services services) {
         logger.debug("Skipping configuration element for {}:{}", module, instance);
     }
 
index 76ca09433adc8b9b4f98d3508eb586aa16c79b48..64f082da40773b4a6dab473bed7e45722847ffca 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ed
 
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -21,7 +22,7 @@ public class RemoveEditConfigStrategy extends DeleteEditConfigStrategy {
 
     @Override
     void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
-            String module, String instance) {
+                               String module, String instance, Services services) {
         logger.warn("Unable to delete {}:{}, ServiceInstance not found", module, instance);
     }
 }
index 0091d6cc84ca7a42ed13d08259685dd127fa4d56..43d852e76a32f3b35a8bee016b6ca4ab4f8c6d04 100644 (file)
@@ -8,37 +8,68 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
 
-import java.util.Map;
-import java.util.Map.Entry;
-
-import javax.management.Attribute;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.management.Attribute;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+import java.util.Map.Entry;
+
 public class ReplaceEditConfigStrategy extends AbstractEditConfigStrategy {
 
     private static final Logger logger = LoggerFactory.getLogger(ReplaceEditConfigStrategy.class);
 
+    private final Multimap<String, String> providedServices;
+
+    public ReplaceEditConfigStrategy() {
+        this.providedServices = HashMultimap.create();
+    }
+
+    public ReplaceEditConfigStrategy(Multimap<String, String> providedServices) {
+        this.providedServices = providedServices;
+    }
+
     @Override
     void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
-            String module, String instance) {
+                               String module, String instance, Services services) {
+        ObjectName on = null;
         try {
-            ObjectName on = ta.createModule(module, instance);
+            on = ta.createModule(module, instance);
             logger.debug("New instance for {} {} created under name {}", module, instance, on);
-            executeStrategy(configuration, ta, on);
+            addRefNames(services, providedServices, module, instance, ta, on);
+            executeStrategy(configuration, ta, on, services);
         } catch (InstanceAlreadyExistsException e) {
             logger.warn("Error creating instance {}:{}, replace failed", module, instance, e);
             throw new IllegalStateException("Unable to create new instance for " + module + " : " + instance, e);
+        } catch (InstanceNotFoundException e) {
+            throw new IllegalStateException("Unable to save default ref name for instance " + on, e);
         }
     }
 
+    private void addRefNames(Services services, Multimap<String, String> providedServices, String module,
+                             String instance, ConfigTransactionClient ta, ObjectName on) throws InstanceNotFoundException {
+        for (Entry<String, String> namespaceToService : providedServices.entries()) {
+
+            if(services.hasRefName(namespaceToService.getKey(),
+                    namespaceToService.getValue(), on))
+                continue;
+
+            String refName = services.getNewDefaultRefName(namespaceToService.getKey(), namespaceToService.getValue(),
+                    module, instance);
+            ta.saveServiceReference(
+                    ta.getServiceInterfaceName(namespaceToService.getKey(), namespaceToService.getValue()), refName, on);
+        }
+    }
     @Override
-    void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+    void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, Services services) {
         for (Entry<String, AttributeConfigElement> configAttributeEntry : configuration.entrySet()) {
             try {
                 AttributeConfigElement ace = configAttributeEntry.getValue();
index 7ee13aeb589c713351f760464f19a4aff48647d3..efe4f7dde9b483bd488e753a90cee2a335b4de05 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ge
 
 import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
@@ -25,6 +26,7 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtim
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.slf4j.Logger;
@@ -42,11 +44,13 @@ public class Get extends AbstractConfigNetconfOperation {
 
     private final YangStoreSnapshot yangStoreSnapshot;
     private static final Logger logger = LoggerFactory.getLogger(Get.class);
+    private final TransactionProvider transactionProvider;
 
     public Get(YangStoreSnapshot yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
-            String netconfSessionIdForReporting) {
+               String netconfSessionIdForReporting, TransactionProvider transactionProvider) {
         super(configRegistryClient, netconfSessionIdForReporting);
         this.yangStoreSnapshot = yangStoreSnapshot;
+        this.transactionProvider = transactionProvider;
     }
 
     private Map<String, Map<String, ModuleRuntime>> createModuleRuntimes(ConfigRegistryClient configRegistryClient,
@@ -144,7 +148,9 @@ public class Get extends AbstractConfigNetconfOperation {
 
         final Runtime runtime = new Runtime(moduleRuntimes, moduleConfigs);
 
-        final Element element = runtime.toXml(runtimeBeans, configBeans, document);
+        ObjectName txOn = transactionProvider.getOrCreateTransaction();
+        ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(txOn);
+        final Element element = runtime.toXml(runtimeBeans, configBeans, document, ta);
 
         logger.info("{} operation successful", XmlNetconfConstants.GET);
 
index f2dfc7079c869d5f8db32db4550e677bdca8a19f..d75cfd5d6f049d9d586ac856fa0ccd7b70b3c00c 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ge
 import com.google.common.base.Optional;
 import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -20,6 +21,7 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorT
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
@@ -83,7 +85,13 @@ public class GetConfig extends AbstractConfigNetconfOperation {
 
         final Config configMapping = new Config(transform(configRegistryClient,
                 yangStoreSnapshot.getModuleMXBeanEntryMap()));
-        dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement);
+
+
+        ObjectName on = transactionProvider.getOrCreateTransaction();
+        ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(on);
+
+        Services serviceTracker = new Services(ta);
+        dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement, serviceTracker);
 
         logger.info("{} operation successful", GET_CONFIG);
 
index ec1915d6fc31aaab6d55aed10ecc95e4d9177613..77c58501cd42942e8bb55793d18408f6a31c3441 100644 (file)
@@ -56,7 +56,7 @@ final class NetconfOperationProvider {
         ops.add(new EditConfig(yangStoreSnapshot, transactionProvider, configRegistryClient,
                 netconfSessionIdForReporting));
         ops.add(new Commit(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
-        ops.add(new Get(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting));
+        ops.add(new Get(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting, transactionProvider));
         ops.add(new DiscardChanges(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
         ops.add(new Validate(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
         ops.add(new RuntimeRpc(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting));
index ed8f02bf569974daeb14b91eeccd81e32d7f0a25..7cd43bd79a01b4b4436a12cfa5721e14108e165d 100644 (file)
@@ -8,12 +8,16 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Sets;
+import org.opendaylight.controller.config.api.LookupRegistry;
 import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
 import org.opendaylight.controller.config.yang.store.api.YangStoreException;
 import org.opendaylight.controller.config.yang.store.api.YangStoreService;
 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
 import org.opendaylight.controller.netconf.mapping.api.Capability;
@@ -42,12 +46,38 @@ public class NetconfOperationServiceImpl implements NetconfOperationService {
             String netconfSessionIdForReporting) throws YangStoreException {
 
         yangStoreSnapshot = yangStoreService.getYangStoreSnapshot();
+        checkConsistencyBetweenYangStoreAndConfig(jmxClient, yangStoreSnapshot);
+
         transactionProvider = new TransactionProvider(jmxClient, netconfSessionIdForReporting);
         operationProvider = new NetconfOperationProvider(yangStoreSnapshot, jmxClient, transactionProvider,
                 netconfSessionIdForReporting);
         capabilities = setupCapabilities(yangStoreSnapshot);
     }
 
+
+    @VisibleForTesting
+    static void checkConsistencyBetweenYangStoreAndConfig(LookupRegistry jmxClient, YangStoreSnapshot yangStoreSnapshot) {
+        Set<String> missingModulesFromConfig = Sets.newHashSet();
+
+        Set<String> modulesSeenByConfig = jmxClient.getAvailableModuleFactoryQNames();
+        Map<String, Map<String, ModuleMXBeanEntry>> moduleMXBeanEntryMap = yangStoreSnapshot.getModuleMXBeanEntryMap();
+
+        for (Map<String, ModuleMXBeanEntry> moduleNameToMBE : moduleMXBeanEntryMap.values()) {
+            for (ModuleMXBeanEntry moduleMXBeanEntry : moduleNameToMBE.values()) {
+                String moduleSeenByYangStore = moduleMXBeanEntry.getYangModuleQName().toString();
+                if(modulesSeenByConfig.contains(moduleSeenByYangStore) == false)
+                    missingModulesFromConfig.add(moduleSeenByYangStore);
+            }
+        }
+
+        Preconditions
+                .checkState(
+                        missingModulesFromConfig.isEmpty(),
+                        "There are inconsistencies between configuration subsystem and yangstore in terms of discovered yang modules, yang modules missing from config subsystem but present in yangstore: %s, %sAll modules present in config: %s",
+                        missingModulesFromConfig, System.lineSeparator(), modulesSeenByConfig);
+
+    }
+
     @Override
     public void close() {
         yangStoreSnapshot.close();
index b8113a090313d270c4b1a391777d0d6e2e7d759e..0fa005e04a7930df7b1e85fc3aa933da4db98ac4 100644 (file)
@@ -137,13 +137,14 @@ public class TransactionProvider implements AutoCloseable {
     }
 
     /**
-     * Wiping means removing all module instances keeping the transaction open.
+     * Wiping means removing all module instances keeping the transaction open + service references.
      */
     synchronized void wipeInternal(ObjectName taON, boolean isTest, String moduleName) {
         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
 
         Set<ObjectName> lookupConfigBeans = moduleName == null ? transactionClient.lookupConfigBeans()
                 : transactionClient.lookupConfigBeans(moduleName);
+        int i = lookupConfigBeans.size();
         for (ObjectName instance : lookupConfigBeans) {
             try {
                 transactionClient.destroyModule(instance);
@@ -156,7 +157,10 @@ public class TransactionProvider implements AutoCloseable {
                 throw new IllegalStateException("Unable to clean configuration in transactiom " + taON, e);
             }
         }
-        logger.debug("Transaction {} wiped clean", taON);
+        logger.debug("Transaction {} wiped clean of {} config beans", taON, i);
+
+        transactionClient.removeAllServiceReferences();
+        logger.debug("Transaction {} wiped clean of all service references", taON);
     }
 
     public void wipeTransaction() {
index 26719592bbbe4dd7e553534a1d9fbafe89fbc097..1c806742e9b141c7f836d9565a9f449255406b69 100644 (file)
@@ -38,7 +38,7 @@ public final class Util {
 
     public static void checkType(final Object value, final Class<?> clazz) {
         Preconditions.checkArgument(clazz.isAssignableFrom(value.getClass()), "Unexpected type " + value.getClass()
-                + " should be " + clazz);
+                + " should be " + clazz + " of " + value);
     }
 
     // TODO: add message and proper error types
index f8916ecac2244943b55abe0dd036e0e52204f3f3..11cf1aae6a42bc184dda8288dddcafa9ba47f419 100644 (file)
@@ -12,12 +12,16 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.apache.commons.lang3.StringUtils;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.matchers.JUnitMatchers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
@@ -55,23 +59,28 @@ 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;
+import javax.management.InstanceNotFoundException;
 import javax.management.ObjectName;
 import javax.xml.parsers.ParserConfigurationException;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigInteger;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -82,7 +91,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
 public class NetconfMappingTest extends AbstractConfigTest {
     private static final Logger logger = LoggerFactory.getLogger(NetconfMappingTest.class);
 
-    private static final String INSTANCE_NAME = "test1";
+    private static final String INSTANCE_NAME = "instance-from-code";
     private static final String NETCONF_SESSION_ID = "foo";
     private NetconfTestImplModuleFactory factory;
     private DepTestImplModuleFactory factory2;
@@ -105,24 +114,122 @@ public class NetconfMappingTest extends AbstractConfigTest {
         transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID);
     }
 
-    private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException {
+    private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException {
         final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
 
         final ObjectName on = transaction.createModule(this.factory.getImplementationName(), instanceName);
         final NetconfTestImplModuleMXBean mxBean = transaction.newMXBeanProxy(on, NetconfTestImplModuleMXBean.class);
-        setModule(mxBean, transaction);
+        setModule(mxBean, transaction, instanceName + "_dep");
 
+        int i = 1;
+        for (Class<? extends AbstractServiceInterface> sInterface : factory.getImplementedServiceIntefaces()) {
+            ServiceInterfaceAnnotation annotation = sInterface.getAnnotation(ServiceInterfaceAnnotation.class);
+            transaction.saveServiceReference(
+                    transaction.getServiceInterfaceName(annotation.namespace(), annotation.localName()), "ref_from_code_to_" + instanceName + "_" + i++,
+                    on);
+
+        }
         transaction.commit();
         return on;
     }
 
+    @Test
+    public void testServicePersistance() throws Exception {
+        createModule(INSTANCE_NAME);
+
+        edit("netconfMessages/editConfig.xml");
+        Element config = getConfigCandidate();
+        assertCorrectServiceNames(config, 6, "ref_test2", "user_to_instance_from_code", "ref_dep_user",
+                "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
+                "ref_from_code_to_instance-from-code_1");
+
+        edit("netconfMessages/editConfig_addServiceName.xml");
+        config = getConfigCandidate();
+        assertCorrectServiceNames(config, 7, "ref_test2", "user_to_instance_from_code", "ref_dep_user",
+                "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
+                "ref_from_code_to_instance-from-code_1", "ref_dep_user_another");
+
+        commit();
+        config = getConfigRunning();
+        assertCorrectRefNamesForDependencies(config);
+        assertCorrectServiceNames(config, 7, "ref_test2", "user_to_instance_from_code", "ref_dep_user",
+                "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
+                "ref_from_code_to_instance-from-code_1", "ref_dep_user_another");
+
+        edit("netconfMessages/editConfig_replace_default.xml");
+        config = getConfigCandidate();
+        assertCorrectServiceNames(config, 2, "ref_dep", "ref_dep2");
+
+        edit("netconfMessages/editConfig_remove.xml");
+        config = getConfigCandidate();
+        assertCorrectServiceNames(config, 0);
+
+        commit();
+        config = getConfigCandidate();
+        assertCorrectServiceNames(config, 0);
+
+    }
+
+    private void assertCorrectRefNamesForDependencies(Element config) {
+        NodeList modulesList = config.getElementsByTagName("modules");
+        assertEquals(1, modulesList.getLength());
+
+        Element modules = (Element) modulesList.item(0);
+
+        String trimmedModules = XmlUtil.toString(modules).replaceAll("\\s", "");
+        int defaultRefNameCount = StringUtils.countMatches(trimmedModules, "ref_dep2");
+        int userRefNameCount = StringUtils.countMatches(trimmedModules, "ref_dep_user_two");
+
+        assertEquals(0, defaultRefNameCount);
+        assertEquals(2, userRefNameCount);
+    }
+
+    private void assertCorrectServiceNames(Element configCandidate, int servicesSize, String... refNames) {
+        NodeList elements = configCandidate.getElementsByTagName("provider");
+        assertEquals(servicesSize, elements.getLength());
+
+        NodeList servicesList = configCandidate.getElementsByTagName("services");
+        assertEquals(1, servicesList.getLength());
+
+        Element services = (Element) servicesList.item(0);
+        String trimmedServices = XmlUtil.toString(services).replaceAll("\\s", "");
+
+        for (String s : refNames) {
+            assertThat(trimmedServices, JUnitMatchers.containsString(s));
+        }
+    }
+
+    @Test
+    public void testConfigNetconfUnionTypes() throws Exception {
+
+        createModule(INSTANCE_NAME);
+
+        edit("netconfMessages/editConfig.xml");
+        commit();
+        Element response = getConfigRunning();
+        String trimmedResponse = XmlUtil.toString(response).replaceAll("\\s", "");
+        assertContainsString(trimmedResponse, "<ipxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">0:0:0:0:0:0:0:1</ip>");
+        assertContainsString(trimmedResponse, "<union-test-attrxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">456</union-test-attr>");
+
+
+        edit("netconfMessages/editConfig_setUnions.xml");
+        commit();
+        response = getConfigRunning();
+
+        trimmedResponse = XmlUtil.toString(response).replaceAll("\\s", "");
+        assertContainsString(trimmedResponse, "<ipxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">127.1.2.3</ip>");
+        assertContainsString(trimmedResponse, "<union-test-attrxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">randomStringForUnion</union-test-attr>");
+
+    }
+
     @Test
     public void testConfigNetconf() throws Exception {
 
         createModule(INSTANCE_NAME);
 
         edit("netconfMessages/editConfig.xml");
-        checkBinaryLeafEdited(getConfigCandidate());
+        Element configCandidate = getConfigCandidate();
+        checkBinaryLeafEdited(configCandidate);
 
 
         // default-operation:none, should not affect binary leaf
@@ -205,6 +312,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
         return executeOp(getConfigOp, "netconfMessages/getConfig.xml");
     }
 
+    @Ignore("second edit message corrupted")
     @Test(expected = NetconfDocumentedException.class)
     public void testConfigNetconfReplaceDefaultEx() throws Exception {
 
@@ -394,7 +502,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
 
         for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
             String name = moduleElement.getOnlyChildElement("name").getTextContent();
-            if(name.equals("test1")) {
+            if(name.equals(INSTANCE_NAME)) {
                 XmlElement enumAttr = moduleElement.getOnlyChildElement(enumName);
                 assertEquals(enumContent, enumAttr.getTextContent());
 
@@ -415,16 +523,20 @@ public class NetconfMappingTest extends AbstractConfigTest {
         XmlElement modulesElement = XmlElement.fromDomElement(response).getOnlyChildElement("data")
                 .getOnlyChildElement("modules");
 
-        XmlElement configAttributeType = null;
+        List<String> expectedValues = Lists.newArrayList("default-string", "configAttributeType");
+        Set<String> configAttributeType = Sets.newHashSet();
+
         for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
             for (XmlElement type : moduleElement.getChildElements("type")) {
                 if (type.getAttribute(XmlUtil.XMLNS_ATTRIBUTE_KEY).equals("") == false) {
-                    configAttributeType = type;
+                    configAttributeType.add(type.getTextContent());
                 }
             }
         }
 
-        assertEquals("configAttributeType", configAttributeType.getTextContent());
+        for (String expectedValue : expectedValues) {
+            assertTrue(configAttributeType.contains(expectedValue));
+        }
     }
 
     private Map<String, Map<String, ModuleMXBeanEntry>> getMbes() throws Exception {
@@ -480,7 +592,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
     }
 
     private Element get() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
-        Get getOp = new Get(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
+        Get getOp = new Get(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID, transactionProvider);
         return executeOp(getOp, "netconfMessages/get.xml");
     }
 
@@ -516,8 +628,8 @@ public class NetconfMappingTest extends AbstractConfigTest {
         return Lists.newArrayList(yangDependencies);
     }
 
-    private void setModule(final NetconfTestImplModuleMXBean mxBean, final ConfigTransactionJMXClient transaction)
-            throws InstanceAlreadyExistsException {
+    private void setModule(final NetconfTestImplModuleMXBean mxBean, final ConfigTransactionJMXClient transaction, String depName)
+            throws InstanceAlreadyExistsException, InstanceNotFoundException {
         mxBean.setSimpleInt((long) 44);
         mxBean.setBinaryLeaf(new byte[] { 8, 7, 9 });
         final DtoD dtob = getDtoD();
@@ -547,7 +659,15 @@ public class NetconfMappingTest extends AbstractConfigTest {
         mxBean.setComplexList(Lists.<ComplexList> newArrayList());
         mxBean.setSimpleList(Lists.<Integer> newArrayList());
 
-        final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), "dep");
+        final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), depName);
+        int i = 1;
+        for (Class<? extends AbstractServiceInterface> sInterface : factory2.getImplementedServiceIntefaces()) {
+            ServiceInterfaceAnnotation annotation = sInterface.getAnnotation(ServiceInterfaceAnnotation.class);
+            transaction.saveServiceReference(
+                    transaction.getServiceInterfaceName(annotation.namespace(), annotation.localName()), "ref_from_code_to_" + depName + "_" + i++,
+                    testingDepOn);
+
+        }
         mxBean.setTestingDep(testingDepOn);
     }
 
index 425ecf6d02628962de3b8268d21b119c72370bf2..d5ba976ccfd1feabbf5ec97412b09e9f0ce1f8f9 100644 (file)
@@ -13,7 +13,6 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 
 public class ServiceTrackerTest {
 
@@ -28,44 +27,4 @@ public class ServiceTrackerTest {
         assertEquals(serviceInstance, serviceInstance2);
     }
 
-    @Test
-    public void testOneInstanceMultipleServices() {
-        Services services = new Services();
-        services.addServiceEntry("nm", "s1", "module", "instance");
-        assertEquals(1, services.getMappedServices().size());
-
-        services.addServiceEntry("nm2", "s2", "module", "instance");
-        assertEquals(2, services.getMappedServices().size());
-    }
-
-    @Test
-    public void testMultipleInstancesOneName() throws Exception {
-        Services services = new Services();
-        services.addServiceEntry("nm", "s1", "module", "instance");
-        assertEquals(1, services.getMappedServices().size());
-
-        services.addServiceEntry("nm", "s1", "module2", "instance");
-        assertEquals(1, services.getMappedServices().size());
-        assertEquals(2, services.getMappedServices().get("nm").get("s1").size());
-        assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance"));
-        assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_1"));
-    }
-
-    @Test
-    public void testMultipleInstancesOneName2() throws Exception {
-        Services services = new Services();
-        services.addServiceEntry("nm", "s1", "module", "instance_1");
-
-        services.addServiceEntry("nm2", "s2", "module2", "instance");
-        services.addServiceEntry("nm2", "s2", "module3", "instance");
-        services.addServiceEntry("nm", "s1", "module3", "instance");
-
-        assertEquals(2, services.getMappedServices().get("nm").get("s1").size());
-        assertEquals(2, services.getMappedServices().get("nm2").get("s2").size());
-        assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_2"));
-        assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_1"));
-        assertTrue(services.getMappedServices().get("nm2").get("s2").containsKey("ref_instance"));
-        assertTrue(services.getMappedServices().get("nm2").get("s2").containsKey("ref_instance_2"));
-    }
-
 }
index 1b8e24702aa32300a600518704250b02bdd480c1..6e7a225f38452250ca4803c17ac56a2d2999822f 100644 (file)
@@ -16,24 +16,23 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.ValidateTest;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 
 import javax.management.ObjectName;
 import java.util.Collections;
 import java.util.Map;
-import java.util.Set;
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyMap;
@@ -82,18 +81,11 @@ public class EditConfigTest {
         EditConfig edit = new EditConfig(yangStoreSnapshot, provider, configRegistry,
                 ValidateTest.NETCONF_SESSION_ID_FOR_REPORTING);
         EditConfigStrategy editStrat = mock(EditConfigStrategy.class);
-        doNothing().when(editStrat).executeConfiguration(anyString(), anyString(), anyMap(),
-                any(ConfigTransactionClient.class));
-        Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements = getMapping(editStrat);
 
-        Config cfg = mock(Config.class);
-        XmlElement xmlElement = mock(XmlElement.class);
-        Set<ObjectName> instancesForFillingServiceRefMapping = Collections.emptySet();
-        EditStrategyType defaultStrategy = EditStrategyType.getDefaultStrategy();
-        doReturn(resolvedXmlElements).when(cfg).fromXml(xmlElement, instancesForFillingServiceRefMapping, defaultStrategy);
+        doNothing().when(editStrat).executeConfiguration(anyString(), anyString(), anyMap(),
+                any(ConfigTransactionClient.class), any(Services.class));
 
-        EditConfigExecution editConfigExecution = new EditConfigExecution(null, cfg, xmlElement,
-                EditConfigXmlParser.TestOption.testThenSet, instancesForFillingServiceRefMapping, defaultStrategy);
+        EditConfigExecution editConfigExecution = mockExecution(editStrat);
 
         edit.getResponseInternal(XmlUtil.newDocument(), editConfigExecution);
 
@@ -105,7 +97,31 @@ public class EditConfigTest {
 
         // For every instance execute strat
         verify(editStrat, times(2/* Test */+ 2/* Set */)).executeConfiguration(anyString(), anyString(), anyMap(),
-                any(ConfigTransactionClient.class));
+                any(ConfigTransactionClient.class), any(Services.class));
+    }
+
+    private EditConfigExecution mockExecution(EditConfigStrategy editStrat) {
+        EditConfigExecution mock = mock(EditConfigExecution.class);
+        doReturn(getMapping(editStrat)).when(mock).getResolvedXmlElements();
+        doReturn(EditStrategyType.merge).when(mock).getDefaultStrategy();
+        doReturn(true).when(mock).shouldSet();
+        doReturn(true).when(mock).shouldTest();
+        doReturn(mockServices()).when(mock).getServices();
+        return mock;
+    }
+
+    private static ServiceReferenceReadableRegistry mockServiceRegistry() {
+        ServiceReferenceReadableRegistry mock = mock(ServiceReferenceReadableRegistry.class);
+        doReturn(
+                Collections.emptyMap())
+                .when(mock).getServiceMapping();
+        doReturn("mockedServiceReg").when(mock).toString();
+
+        return mock;
+    }
+
+    static Services mockServices() {
+        return new Services(mockServiceRegistry());
     }
 
     private Map<String, Multimap<String, ModuleElementResolved>> getMapping(EditConfigStrategy editStrat) {
index 704da6dc0d8d0819923ed67f973c01e3fa3ef045..78a2043e202413786f1000954c10289ce5395696 100644 (file)
@@ -48,7 +48,7 @@ public class ReplaceEditConfigStrategyTest {
 
         doReturn(Sets.newHashSet(mockON(), mockON())).when(ta).lookupConfigBeans();
 
-        strat.executeConfiguration("m1", "i1", map, ta);
+        strat.executeConfiguration("m1", "i1", map, ta, EditConfigTest.mockServices());
 
         verify(ta).lookupConfigBean(anyString(), anyString());
         verify(ta).setAttribute(any(ObjectName.class), anyString(), any(Attribute.class));
diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImplTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImplTest.java
new file mode 100644 (file)
index 0000000..0d459cf
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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.osgi;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.matchers.JUnitMatchers;
+import org.opendaylight.controller.config.api.LookupRegistry;
+import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.yangtools.yang.common.QName;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.Map;
+import java.util.Set;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+public class NetconfOperationServiceImplTest {
+
+    private Date date = new Date(0);
+
+    @Test
+    public void testCheckConsistencyBetweenYangStoreAndConfig_ok() throws Exception {
+        NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(
+                mockJmxClient("qname1", "qname2"),
+                mockYangStoreSnapshot("qname2", "qname1"));
+    }
+
+    @Test
+    public void testCheckConsistencyBetweenYangStoreAndConfig_ok2() throws Exception {
+        NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(
+                mockJmxClient("qname1", "qname2", "qname4", "qname5"),
+                mockYangStoreSnapshot("qname2", "qname1"));
+    }
+
+    @Test
+    public void testCheckConsistencyBetweenYangStoreAndConfig_ok3() throws Exception {
+        NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(
+                mockJmxClient(),
+                mockYangStoreSnapshot());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testCheckConsistencyBetweenYangStoreAndConfig_yangStoreMore() throws Exception {
+        try {
+            NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(mockJmxClient("qname1"),
+                    mockYangStoreSnapshot("qname2", "qname1"));
+        } catch (IllegalStateException e) {
+            String message = e.getMessage();
+            Assert.assertThat(
+                    message,
+                    JUnitMatchers
+                            .containsString(" missing from config subsystem but present in yangstore: [(namespace?revision=1970-01-01)qname2]"));
+            Assert.assertThat(
+                    message,
+                    JUnitMatchers
+                            .containsString("All modules present in config: [(namespace?revision=1970-01-01)qname1]"));
+            throw e;
+        }
+    }
+
+    private YangStoreSnapshot mockYangStoreSnapshot(String... qnames) {
+        YangStoreSnapshot mock = mock(YangStoreSnapshot.class);
+
+        Map<String, Map<String, ModuleMXBeanEntry>> map = Maps.newHashMap();
+
+        Map<String, ModuleMXBeanEntry> innerMap = Maps.newHashMap();
+
+        int i = 1;
+        for (String qname : qnames) {
+            innerMap.put(Integer.toString(i++), mockMBeanEntry(qname));
+        }
+
+        map.put("1", innerMap);
+
+        doReturn(map).when(mock).getModuleMXBeanEntryMap();
+
+        return mock;
+    }
+
+    private ModuleMXBeanEntry mockMBeanEntry(String qname) {
+        ModuleMXBeanEntry mock = mock(ModuleMXBeanEntry.class);
+        QName q = getQName(qname);
+        doReturn(q).when(mock).getYangModuleQName();
+        return mock;
+    }
+
+    private QName getQName(String qname) {
+        return new QName(URI.create("namespace"), date, qname);
+    }
+
+    private LookupRegistry mockJmxClient(String... visibleQNames) {
+        LookupRegistry mock = mock(LookupRegistry.class);
+        Set<String> qnames = Sets.newHashSet();
+        for (String visibleQName : visibleQNames) {
+            QName q = getQName(visibleQName);
+            qnames.add(q.toString());
+        }
+        doReturn(qnames).when(mock).getAvailableModuleFactoryQNames();
+        return mock;
+    }
+}
index c6caf417a17484aca119f7c2e5e655ce08102440..20bd386063419523d439dcb46102851208b6a7db 100644 (file)
@@ -43,7 +43,9 @@
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
-            <artifactId>config-persister-file-adapter</artifactId>
+            <artifactId>config-persister-file-xml-adapter</artifactId>
+            <scope>test</scope>
+            <version>${config.version}</version>
         </dependency>
 
         <!-- test dependencies -->
@@ -60,8 +62,8 @@
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
-            <artifactId>config-persister-directory-adapter</artifactId>
-            <version>${parent.version}</version>
+            <artifactId>config-persister-directory-xml-adapter</artifactId>
+            <version>${config.version}</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
@@ -88,6 +90,7 @@
                             org.opendaylight.controller.netconf.client,
                             org.opendaylight.controller.netconf.util.osgi,
                             org.opendaylight.controller.netconf.util.xml,
+                            org.opendaylight.controller.netconf.util.messages,
                             io.netty.channel,
                             io.netty.channel.nio,
                             io.netty.util.concurrent,
index 044346e2c5a06e2576b7f687975085dc1e2d60f1..0b623baaa480dde170d6866d7fe1564242ed704e 100644 (file)
@@ -8,14 +8,24 @@
 
 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 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;
+
+import javax.annotation.concurrent.Immutable;
+
 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.messages.NetconfMessageAdditionalHeader;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -25,14 +35,8 @@ 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;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 
 @Immutable
 public class ConfigPusher {
@@ -127,10 +131,14 @@ public class ConfigPusher {
 
         long deadline = pollingStart + timeout;
 
+        String additionalHeader = NetconfMessageAdditionalHeader.toString("unknown", address.getAddress().getHostAddress(),
+                Integer.toString(address.getPort()), "tcp", Optional.of("persister"));
+
         Set<String> latestCapabilities = new HashSet<>();
         while (System.currentTimeMillis() < deadline) {
             attempt++;
-            NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup);
+            NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup,
+                    nettyThreadgroup, additionalHeader);
             NetconfClient netconfClient;
             try {
                 netconfClient = new NetconfClient(this.toString(), address, delay, netconfClientDispatcher);
@@ -169,7 +177,7 @@ public class ConfigPusher {
         NetconfMessage message = createEditConfigMessage(xmlToBePersisted, "/netconfOp/editConfig.xml");
 
         // sending message to netconf
-        NetconfMessage responseMessage = netconfClient.sendMessage(message, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+        NetconfMessage responseMessage = getResponse(message, netconfClient);
 
         XmlElement element = XmlElement.fromDomDocument(responseMessage.getDocument());
         Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
@@ -178,7 +186,7 @@ public class ConfigPusher {
         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);
+        responseMessage = getResponse(getNetconfMessageFromResource("/netconfOp/commit.xml"), netconfClient);
 
         element = XmlElement.fromDomDocument(responseMessage.getDocument());
         Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
@@ -192,6 +200,15 @@ public class ConfigPusher {
         logger.trace("Detailed message {}", response);
     }
 
+    private static NetconfMessage getResponse(NetconfMessage request, NetconfClient netconfClient) {
+        try {
+            return netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+        } catch(RuntimeException e) {
+            logger.error("Error while sending message {} to {}", request, netconfClient);
+            throw e;
+        }
+    }
+
     private static NetconfMessage createEditConfigMessage(Element dataElement, String editConfigResourcename) {
         try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcename)) {
             Preconditions.checkNotNull(stream, "Unable to load resource " + editConfigResourcename);
index 7e9dce67bd78586459b8d8d2c40e248b392ecf01..f168bb36348103525b6895582d73c5c833b3eaed 100644 (file)
@@ -34,7 +34,7 @@ import java.util.ListIterator;
  * Example configuration:<pre>
  netconf.config.persister.active=2,3
  # read startup configuration
- netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter
+ netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
  netconf.config.persister.1.properties.fileStorage=configuration/initial/
 
  netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
index 981be827b74a7714ae7316aedc7a0347d8263f4c..d9466ff00b6d6a0d1e9c034d43ad310600407dd3 100644 (file)
@@ -1,10 +1,9 @@
-/**
- * @author Tomas Olvecky
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
- * 11 2013
- *
- * Copyright (c) 2013 by Cisco Systems, Inc.
- * 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;
 
index 227018bf5b8761e82b88760cdd3dc8a4a6e23705..acea75a7432d37dbede7c219ed961784b1f63b86 100644 (file)
@@ -11,7 +11,7 @@ package org.opendaylight.controller.netconf.persist.impl;
 import org.junit.Test;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter;
+import org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter;
 import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
 import org.opendaylight.controller.netconf.persist.impl.osgi.PropertiesProviderBaseImpl;
 
@@ -93,7 +93,7 @@ public class PersisterAggregatorTest {
         List<PersisterWithConfiguration> persisters = persisterAggregator.getPersisterWithConfigurations();
         assertEquals(1, persisters.size());
         PersisterWithConfiguration persister = persisters.get(0);
-        assertEquals(FileStorageAdapter.class.getName() ,persister.getStorage().getClass().getName());
+        assertEquals(XmlFileStorageAdapter.class.getName() ,persister.getStorage().getClass().getName());
         assertFalse(persister.isReadOnly());
     }
 
index 222e7cef47029f1229a338017c141081112fef2e..729c67d6c59e364b57b65360c87384138370cdc1 100644 (file)
@@ -1,9 +1,9 @@
 netconf.config.persister.active=2
 # read startup configuration
-netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter
+netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
 netconf.config.persister.1.properties.directoryStorage=target/configuration/initial/
 netconf.config.persister.1.readonly=true
 
-netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
 netconf.config.persister.2.properties.fileStorage=target/configuration/current/controller.config.2.txt
 netconf.config.persister.2.properties.numberOfBackups=3
index a1645ad8c40e4ddeed4dbcf651880facc19204d3..90ba77273b2d7b58144b5d038555d08290a32ba1 100644 (file)
@@ -1,4 +1,4 @@
 netconf.config.persister.active=3
-netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
 netconf.config.persister.3.properties.fileStorage=target/configuration/current/controller.config.2.txt
 netconf.config.persister.3.properties.numberOfBackups=0
diff --git a/opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml b/opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml
new file mode 100644 (file)
index 0000000..aebaaeb
--- /dev/null
@@ -0,0 +1,101 @@
+<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">
+    <parent>
+        <artifactId>netconf-subsystem</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.2.3-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>ietf-netconf-monitoring-extension</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>bundle</packaging>
+
+      <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>ietf-netconf-monitoring</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+    </dependencies>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>${yangtools.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        target/generated-sources/monitoring
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.yangtools</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>${yangtools.binding.version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.7</version>
+                <executions>
+                    <execution>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>target/generated-sources/sal</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Import-Package>
+                            com.google.common.collect,
+                            org.opendaylight.yangtools.yang.binding,
+                            org.opendaylight.yangtools.yang.common,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004,
+                        </Import-Package>
+                        <Export-Package>
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210,
+                        </Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/opendaylight/netconf/ietf-netconf-monitoring-extension/src/main/yang/ietf-netconf-monitoring-extension.yang b/opendaylight/netconf/ietf-netconf-monitoring-extension/src/main/yang/ietf-netconf-monitoring-extension.yang
new file mode 100644 (file)
index 0000000..e8f2ec3
--- /dev/null
@@ -0,0 +1,31 @@
+module ietf-netconf-monitoring-extension {
+
+    yang-version 1;
+
+    namespace
+      "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring-extension";
+
+    prefix ncme;
+
+    import ietf-netconf-monitoring {
+      prefix ncm;
+    }
+
+    revision "2013-12-10" {
+      description "Initial revision.";
+
+    }
+
+    identity netconf-tcp {
+      base ncm:transport;
+      description
+        "NETCONF over TCP.";
+    }
+
+    augment "/ncm:netconf-state/ncm:sessions/ncm:session" {
+      leaf session-identifier {
+        type string;
+      }
+    }
+
+}
\ No newline at end of file
diff --git a/opendaylight/netconf/ietf-netconf-monitoring/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/netconf/monitoring/rev101004/netconf/state/schemas/LocationBuilder.java b/opendaylight/netconf/ietf-netconf-monitoring/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/netconf/monitoring/rev101004/netconf/state/schemas/LocationBuilder.java
new file mode 100644 (file)
index 0000000..0a084b0
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema.Location;
+
+
+/**
+**/
+public class LocationBuilder {
+
+    public static Location getDefaultInstance(String defaultValue) {
+        return defaultValue.equals("NETCONF") ? new Location(Location.Enumeration.NETCONF) : new Location(new Uri(
+                defaultValue));
+    }
+
+}
index 0fce4748a40af53113d865492dd1f6ada93ce19a..856bd77c202ee73ee0cd65758f64ad598fd96f6a 100644 (file)
             <groupId>${project.groupId}</groupId>
             <artifactId>ietf-netconf-monitoring</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ietf-netconf-monitoring-extension</artifactId>
+            <version>${project.version}</version>
+        </dependency>
 
         <dependency>
             <groupId>org.opendaylight.bgpcep</groupId>
index a0fddd79f2f0fcff8afced3ab91fcf21aeeea44d..7877843ccb99c7ad91230467720b7bbf17f72e25 100644 (file)
@@ -8,9 +8,10 @@
 
 package org.opendaylight.controller.netconf.api;
 
-import com.google.common.base.Optional;
 import org.w3c.dom.Document;
 
+import com.google.common.base.Optional;
+
 /**
  * NetconfMessage represents a wrapper around org.w3c.dom.Document. Needed for
  * implementing ProtocolMessage interface.
index 95f526b2ecb535787570fd60fe97e96094421420..2ce779a1f54e9ce4f68b9c7f1db478d9de4e0201 100644 (file)
@@ -88,6 +88,7 @@ public class NetconfClient implements Closeable {
     }
 
     public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) {
+        long startTime = System.currentTimeMillis();
         Preconditions.checkState(clientSession.isUp(), "Session was not up yet");
         clientSession.sendMessage(message);
         try {
@@ -96,6 +97,9 @@ public class NetconfClient implements Closeable {
             throw new RuntimeException(this + " Cannot read message from " + address, e);
         } catch (IllegalStateException e) {
             throw new IllegalStateException(this + " Cannot read message from " + address, e);
+        } finally {
+            long diffMillis = System.currentTimeMillis() - startTime;
+            logger.debug("Total time spent waiting for response {}", diffMillis);
         }
     }
 
index 6ac57a88c9f4750513d8be139354f78abd5575a6..fc6f87db5d797748d622364b8db3dd5e9a65f58e 100644 (file)
@@ -13,8 +13,10 @@ import io.netty.channel.socket.SocketChannel;
 import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.Promise;
+
 import java.io.Closeable;
 import java.net.InetSocketAddress;
+
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
@@ -26,6 +28,8 @@ import org.opendaylight.protocol.framework.SessionListenerFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Optional;
+
 public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener> implements Closeable {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
@@ -36,7 +40,13 @@ public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSes
     public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup) {
         super(bossGroup, workerGroup);
         timer = new HashedWheelTimer();
-        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer);
+        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent());
+    }
+
+    public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, String additionalHeader) {
+        super(bossGroup, workerGroup);
+        timer = new HashedWheelTimer();
+        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader));
     }
 
     public Future<NetconfClientSession> createClient(InetSocketAddress address,
index db0b953bddf4f7c730fcd271bb7e5e603bcc0eb1..abfbdd526c5f7bb6796c7c0273060e7b91aa8933 100644 (file)
@@ -8,10 +8,13 @@
 
 package org.opendaylight.controller.netconf.client;
 
-import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
+
+import java.io.IOException;
+import java.io.InputStream;
+
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -20,15 +23,18 @@ import org.opendaylight.protocol.framework.SessionNegotiator;
 import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
 import org.xml.sax.SAXException;
 
-import java.io.IOException;
-import java.io.InputStream;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 
 public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory {
 
     private final Timer timer;
 
-    public NetconfClientSessionNegotiatorFactory(Timer timer) {
+    private final Optional<String> additionalHeader;
+
+    public NetconfClientSessionNegotiatorFactory(Timer timer, Optional<String> additionalHeader) {
         this.timer = timer;
+        this.additionalHeader = additionalHeader;
     }
 
     private static NetconfMessage loadHelloMessageTemplate() {
@@ -45,7 +51,11 @@ public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorF
     public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel,
             Promise promise) {
         // Hello message needs to be recreated every time
-        NetconfSessionPreferences proposal = new NetconfSessionPreferences(loadHelloMessageTemplate());
+        NetconfMessage helloMessage = loadHelloMessageTemplate();
+        if(this.additionalHeader.isPresent()) {
+            helloMessage = new NetconfMessage(helloMessage.getDocument(), additionalHeader.get());
+        }
+        NetconfSessionPreferences proposal = new NetconfSessionPreferences(helloMessage);
         return new NetconfClientSessionNegotiator(proposal, promise, channel, timer,
                 sessionListenerFactory.getSessionListener());
     }
index 4de6cc35c0dad3f00afe949821a1dab59f4bc3da..ee07b3949d6dd2f040da183a46dde263abe6d9af 100644 (file)
@@ -14,8 +14,10 @@ import io.netty.channel.socket.SocketChannel;
 import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.Promise;
+
 import java.io.IOException;
 import java.net.InetSocketAddress;
+
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
@@ -31,6 +33,8 @@ import org.opendaylight.protocol.framework.ReconnectStrategy;
 import org.opendaylight.protocol.framework.SessionListener;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 
+import com.google.common.base.Optional;
+
 public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
 
     private AuthenticationHandler authHandler;
@@ -42,7 +46,15 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
         super(bossGroup, workerGroup);
         this.authHandler = authHandler;
         this.timer = new HashedWheelTimer();
-        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer);
+        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent());
+    }
+
+    public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup,
+            EventLoopGroup workerGroup, String additionalHeader) {
+        super(bossGroup, workerGroup, additionalHeader);
+        this.authHandler = authHandler;
+        this.timer = new HashedWheelTimer();
+        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader));
     }
 
     public Future<NetconfClientSession> createClient(InetSocketAddress address,
index e073aaca8d039dddf4f6c976dcbe1e30de1b4dd7..b056f9be873feff65d2b731d66b6ef8fe0d8c4cd 100644 (file)
             <groupId>${project.groupId}</groupId>
             <artifactId>ietf-netconf-monitoring</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ietf-netconf-monitoring-extension</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-util</artifactId>
                             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state,
                             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions,
                             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210,
+                            org.opendaylight.yangtools.yang.binding,
                         </Import-Package>
                     </instructions>
                 </configuration>
index b6921794296e3f04d02d6e36ef45762a8888ecec..4cc05b7b42fa40a17f9552e2d459b1bfdb85cea6 100644 (file)
@@ -8,13 +8,21 @@
 
 package org.opendaylight.controller.netconf.impl;
 
-import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
 import org.opendaylight.protocol.framework.SessionListener;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.NetconfTcp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1Builder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Transport;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
@@ -25,10 +33,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import com.google.common.base.Preconditions;
 
 public class NetconfServerSession extends NetconfSession implements NetconfManagementSession {
 
@@ -91,14 +96,18 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag
         builder.setOutNotifications(new ZeroBasedCounter32(0L));
 
         builder.setKey(new SessionKey(getSessionId()));
+
+        Session1Builder builder1 = new Session1Builder();
+        builder1.setSessionIdentifier(header.getSessionType());
+        builder.addAugmentation(Session1.class, builder1.build());
+
         return builder.build();
     }
 
     private Class<? extends Transport> getTransportForString(String transport) {
         switch(transport) {
             case "ssh" : return NetconfSsh.class;
-            // TODO what about tcp
-            case "tcp" : return NetconfSsh.class;
+            case "tcp" : return NetconfTcp.class;
             default: throw new IllegalArgumentException("Unknown transport type " + transport);
         }
     }
index 01ac018b3eadc3ee85d6ffd7a5e12fb8cbaf2daa..8ba4cdc052057333df0154162153adf9ee663e2f 100644 (file)
@@ -8,28 +8,27 @@
 
 package org.opendaylight.controller.netconf.impl;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
+
+import java.net.InetSocketAddress;
+
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
+import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil;
 import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
 import org.opendaylight.protocol.framework.SessionListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import com.google.common.base.Optional;
 
 public class NetconfServerSessionNegotiator extends
         AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession> {
 
     static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiator.class);
 
-    private static final AdditionalHeader DEFAULT_HEADER = new AdditionalHeader();
-
     protected NetconfServerSessionNegotiator(NetconfServerSessionPreferences sessionPreferences,
             Promise<NetconfServerSession> promise, Channel channel, Timer timer, SessionListener sessionListener) {
         super(sessionPreferences, promise, channel, timer, sessionListener);
@@ -41,36 +40,28 @@ public class NetconfServerSessionNegotiator extends
 
         AdditionalHeader parsedHeader;
         if (additionalHeader.isPresent()) {
-            parsedHeader = new AdditionalHeader(additionalHeader.get());
+            parsedHeader = AdditionalHeaderUtil.fromString(additionalHeader.get());
         } else {
-            parsedHeader = DEFAULT_HEADER;
+            parsedHeader = new AdditionalHeader("unknown", ((InetSocketAddress)channel.localAddress()).getHostString(),
+                    "tcp", "client");
         }
         logger.debug("Additional header from hello parsed as {} from {}", parsedHeader, additionalHeader);
 
         return new NetconfServerSession(sessionListener, channel, sessionPreferences.getSessionId(), parsedHeader);
     }
 
-    static class AdditionalHeader {
+    public static class AdditionalHeader {
 
-        private static final Pattern pattern = Pattern
-                .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+)[^\\]]+\\]");
         private final String username;
         private final String address;
         private final String transport;
+        private final String sessionIdentifier;
 
-        public AdditionalHeader(String addHeaderAsString) {
-            addHeaderAsString = addHeaderAsString.trim();
-            Matcher matcher = pattern.matcher(addHeaderAsString);
-            Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s",
-                    addHeaderAsString, pattern);
-            this.username = matcher.group("username");
-            this.address = matcher.group("address");
-            this.transport = matcher.group("transport");
-        }
-
-        private AdditionalHeader() {
-            this.username = this.address = "unknown";
-            this.transport = "ssh";
+        public AdditionalHeader(String userName, String hostAddress, String transport, String sessionIdentifier) {
+            this.address = hostAddress;
+            this.username = userName;
+            this.transport = transport;
+            this.sessionIdentifier = sessionIdentifier;
         }
 
         String getUsername() {
@@ -85,6 +76,10 @@ public class NetconfServerSessionNegotiator extends
             return transport;
         }
 
+        String getSessionType() {
+            return sessionIdentifier;
+        }
+
         @Override
         public String toString() {
             final StringBuffer sb = new StringBuffer("AdditionalHeader{");
@@ -95,4 +90,5 @@ public class NetconfServerSessionNegotiator extends
             return sb.toString();
         }
     }
+
 }
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java
new file mode 100644 (file)
index 0000000..5c630dd
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.impl.util;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiator.AdditionalHeader;
+
+import com.google.common.base.Preconditions;
+
+public class AdditionalHeaderUtil {
+
+    private static final Pattern pattern = Pattern
+            .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+)[^\\]]+\\]");
+    private static final Pattern customHeaderPattern = Pattern
+            .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+);(?<sessionIdentifier>[a-z]+)[^\\]]+\\]");
+
+    public static AdditionalHeader fromString(String additionalHeader) {
+        additionalHeader = additionalHeader.trim();
+        Matcher matcher = pattern.matcher(additionalHeader);
+        Matcher matcher2 = customHeaderPattern.matcher(additionalHeader);
+        Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s",
+                additionalHeader, pattern);
+        String username = matcher.group("username");
+        String address = matcher.group("address");
+        String transport = matcher.group("transport");
+        String sessionIdentifier = "client";
+        if (matcher2.matches()) {
+            sessionIdentifier = matcher2.group("sessionIdentifier");
+        }
+        return new AdditionalHeader(username, address, transport, sessionIdentifier);
+    }
+
+}
index 2f8fac23f5beac0e2461d0348baef9e4395f0846..97d9a98b5777b01e37468c00a98e8ea54f4dc889 100644 (file)
@@ -8,14 +8,16 @@
 package org.opendaylight.controller.netconf.impl;
 
 import junit.framework.Assert;
+
 import org.junit.Test;
+import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil;
 
 public class AdditionalHeaderParserTest {
 
     @Test
     public void testParsing() throws Exception {
         String s = "[netconf;10.12.0.102:48528;ssh;;;;;;]";
-        NetconfServerSessionNegotiator.AdditionalHeader header = new NetconfServerSessionNegotiator.AdditionalHeader(s);
+        NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s);
         Assert.assertEquals("netconf", header.getUsername());
         Assert.assertEquals("10.12.0.102", header.getAddress());
         Assert.assertEquals("ssh", header.getTransport());
@@ -24,7 +26,7 @@ public class AdditionalHeaderParserTest {
     @Test
     public void testParsing2() throws Exception {
         String s = "[tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]";
-        NetconfServerSessionNegotiator.AdditionalHeader header = new NetconfServerSessionNegotiator.AdditionalHeader(s);
+        NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s);
         Assert.assertEquals("tomas", header.getUsername());
         Assert.assertEquals("10.0.0.0", header.getAddress());
         Assert.assertEquals("tcp", header.getTransport());
@@ -33,6 +35,6 @@ public class AdditionalHeaderParserTest {
     @Test(expected = IllegalArgumentException.class)
     public void testParsingNoUsername() throws Exception {
         String s = "[10.12.0.102:48528;ssh;;;;;;]";
-        new NetconfServerSessionNegotiator.AdditionalHeader(s);
+        AdditionalHeaderUtil.fromString(s);
     }
 }
index ce5233c494e6ddac78339709e9ae23dc5df05658..8d3476f4b8dfa9b08507cb0e29eb2a6393a972e9 100644 (file)
@@ -8,12 +8,31 @@
 
 package org.opendaylight.controller.netconf.impl;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+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.DataOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.ObjectName;
+
 import org.apache.commons.io.IOUtils;
 import org.junit.After;
 import org.junit.AfterClass;
@@ -44,31 +63,15 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
-import javax.management.ObjectName;
-import java.io.DataOutputStream;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
 
 public class ConcurrentClientsTest {
 
     private static final int CONCURRENCY = 16;
     private static EventLoopGroup nettyGroup = new NioEventLoopGroup();
-    public static final NetconfClientDispatcher NETCONF_CLIENT_DISPATCHER = new NetconfClientDispatcher( nettyGroup, nettyGroup);
+    public static final NetconfClientDispatcher NETCONF_CLIENT_DISPATCHER =
+            new NetconfClientDispatcher( nettyGroup, nettyGroup);
 
     @Mock
     private YangStoreService yangStoreService;
index 244e4ba4a94330d0ac446bca6354cfbe8af38a62..3a7b7de7a0b2a589b410ddd76996556412e64434 100644 (file)
@@ -7,14 +7,27 @@
  */
 package org.opendaylight.controller.netconf.it;
 
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
+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.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
 import junit.framework.Assert;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.matchers.JUnitMatchers;
@@ -48,20 +61,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
 
 public class NetconfMonitoringITTest extends AbstractConfigTest {
 
index 31e427191c4827771d25cb480f42749b41f2678d..8e1e599c719a6794d17b91b2792efbf27f85e458 100644 (file)
                             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
                             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924,
                             org.osgi.util.tracker,
+                            org.opendaylight.yangtools.yang.common,
                             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state,
                             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions,
                             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004,
                             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210,
+                            org.opendaylight.yangtools.yang.binding,
                         </Import-Package>
                     </instructions>
                 </configuration>
index 25fb5d44dcc3a15ee0b72282293292cf53fc529d..55aee72fda98af82b894a8f6be83a1d339d904ac 100644 (file)
@@ -7,13 +7,13 @@
  */
 package org.opendaylight.controller.netconf.monitoring.xml.model;
 
-import com.google.common.base.Preconditions;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
-
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlTransient;
 
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+import org.opendaylight.yangtools.yang.common.QName;
+
 final class MonitoringSession {
 
     @XmlTransient
@@ -67,8 +67,17 @@ final class MonitoringSession {
 
     @XmlElement(name = "transport")
     public String getTransport() {
-        Preconditions.checkState(managementSession.getTransport() == NetconfSsh.class);
-        return "netconf-ssh";
+        try {
+            QName qName = (QName) managementSession.getTransport().getField("QNAME").get(null);
+            return qName.getLocalName();
+        } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+            throw new IllegalArgumentException("Unknown transport type " + managementSession.getTransport(), e);
+        }
+    }
+
+    @XmlElement(name= "session-identifier")
+    public String getSessionType() {
+        return managementSession.getAugmentation(Session1.class).getSessionIdentifier();
     }
 
     @XmlElement(name = "username")
index cb6e59f83f2463d022971bc10ff6cfe26b9b4133..1e3f343624726e9ff0af80f98c3da32e9233f7c5 100644 (file)
@@ -7,13 +7,18 @@
 */
 package org.opendaylight.controller.netconf.monitoring.xml;
 
-import com.google.common.collect.Lists;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.util.Date;
+
 import org.junit.Test;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
@@ -25,10 +30,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.ZeroBasedCounter32;
 import org.w3c.dom.Element;
 
-import java.util.Date;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.collect.Lists;
 
 public class JaxBSerializerTest {
 
@@ -54,6 +56,8 @@ public class JaxBSerializerTest {
 
     private Session getMockSession() {
         Session mocked = mock(Session.class);
+        Session1 mockedSession1 = mock(Session1.class);
+        doReturn("client").when(mockedSession1).getSessionIdentifier();
         doReturn(1L).when(mocked).getSessionId();
         doReturn(new DateAndTime(new Date().toString())).when(mocked).getLoginTime();
         doReturn(new Host(new DomainName("address/port"))).when(mocked).getSourceHost();
@@ -63,6 +67,7 @@ public class JaxBSerializerTest {
         doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutRpcErrors();
         doReturn(NetconfSsh.class).when(mocked).getTransport();
         doReturn("username").when(mocked).getUsername();
+        doReturn(mockedSession1).when(mocked).getAugmentation(Session1.class);
         return mocked;
     }
 }
index 95d2feb65c482ea564bce7794d61d6360e35f379..e30ce5b47e961f87adccebcce363f2092da9c165 100644 (file)
@@ -10,8 +10,9 @@ package org.opendaylight.controller.netconf.util;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-
 import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.ssl.SslHandler;
 import io.netty.util.Timeout;
 import io.netty.util.Timer;
@@ -19,9 +20,8 @@ import io.netty.util.TimerTask;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.GenericFutureListener;
 import io.netty.util.concurrent.Promise;
-
-import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
 import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
 import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
@@ -44,11 +44,14 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
 
     // TODO what time ?
     private static final long INITIAL_HOLDTIMER = 1;
+
     private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSessionNegotiator.class);
+    public static final String NAME_OF_EXCEPTION_HANDLER = "lastExceptionHandler";
 
     protected final P sessionPreferences;
 
     private final SessionListener sessionListener;
+    private Timeout timeout;
 
     /**
      * Possible states for Finite State Machine
@@ -69,7 +72,7 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
     }
 
     @Override
-    protected void startNegotiation() throws Exception {
+    protected void startNegotiation() {
         final Optional<SslHandler> sslHandler = getSslHandler(channel);
         if (sslHandler.isPresent()) {
             Future<Channel> future = sslHandler.get().handshakeFuture();
@@ -94,10 +97,25 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
         final NetconfMessage helloMessage = this.sessionPreferences.getHelloMessage();
         logger.debug("Session negotiation started with hello message {}", XmlUtil.toString(helloMessage.getDocument()));
 
-        sendMessage(helloMessage);
-        changeState(State.OPEN_WAIT);
+        channel.pipeline().addLast(NAME_OF_EXCEPTION_HANDLER, new ChannelHandler() {
+            @Override
+            public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
+            }
+
+            @Override
+            public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
+            }
+
+            @Override
+            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+                logger.warn("An exception occurred during negotiation on channel {}", channel.localAddress(), cause);
+                cancelTimeout();
+                negotiationFailed(cause);
+                changeState(State.FAILED);
+            }
+        });
 
-        this.timer.newTimeout(new TimerTask() {
+        timeout = this.timer.newTimeout(new TimerTask() {
             @Override
             public void run(final Timeout timeout) throws Exception {
                 synchronized (this) {
@@ -106,10 +124,19 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
                                 "Session was not established after " + timeout);
                         negotiationFailed(cause);
                         changeState(State.FAILED);
-                    }
+                    } else
+                        channel.pipeline().remove(NAME_OF_EXCEPTION_HANDLER);
                 }
             }
         }, INITIAL_HOLDTIMER, TimeUnit.MINUTES);
+
+        sendMessage(helloMessage);
+        changeState(State.OPEN_WAIT);
+    }
+
+    private void cancelTimeout() {
+        if(timeout!=null)
+            timeout.cancel();
     }
 
     private void sendMessage(NetconfMessage message) {
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageAdditionalHeader.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageAdditionalHeader.java
new file mode 100644 (file)
index 0000000..457e226
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.util.messages;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * Additional header can be used with hello message to carry information about
+ * session's connection. Provided information can be reported via netconf
+ * monitoring.
+ * <pre>
+ * It has pattern "[username; host-address:port; transport; session-identifier;]"
+ * username - name of account on a remote
+ * host-address - client's IP address
+ * port - port number
+ * transport - tcp, ssh
+ * session-identifier - persister, client
+ * Session-identifier is optional, others mandatory.
+ * </pre>
+ */
+public class NetconfMessageAdditionalHeader {
+
+    private static final String SC = ";";
+
+    public static String toString(String userName, String hostAddress, String port, String transport,
+            Optional<String> sessionIdentifier) {
+        Preconditions.checkNotNull(userName);
+        Preconditions.checkNotNull(hostAddress);
+        Preconditions.checkNotNull(port);
+        Preconditions.checkNotNull(transport);
+        String identifier = sessionIdentifier.isPresent() ? sessionIdentifier.get() : "";
+        return "[" + userName + SC + hostAddress + ":" + port + SC + transport + SC + identifier + SC + "]"
+                + System.lineSeparator();
+    }
+}
index 891d40cf74fa520be681aa73109765424f5ab8e8..526708ab580238e34ba26a1c70a1d89289571ca6 100644 (file)
@@ -8,9 +8,12 @@
 
 package org.opendaylight.controller.netconf.util.messages;
 
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Lists;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
 import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -24,11 +27,9 @@ import org.w3c.dom.Comment;
 import org.w3c.dom.Document;
 import org.xml.sax.SAXException;
 
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
 
 /**
  * NetconfMessageFactory for (de)serializing DOM documents.
@@ -114,7 +115,14 @@ public final class NetconfMessageFactory implements ProtocolMessageFactory<Netco
             Comment comment = netconfMessage.getDocument().createComment("clientId:" + clientId.get());
             netconfMessage.getDocument().appendChild(comment);
         }
-        final ByteBuffer msgBytes = Charsets.UTF_8.encode(xmlToString(netconfMessage.getDocument()));
+        ByteBuffer msgBytes;
+        if(netconfMessage.getAdditionalHeader().isPresent()) {
+            String header = netconfMessage.getAdditionalHeader().get();
+            logger.trace("Header of netconf message parsed \n{}", header);
+            msgBytes = Charsets.UTF_8.encode(header + xmlToString(netconfMessage.getDocument()));
+        } else {
+            msgBytes = Charsets.UTF_8.encode(xmlToString(netconfMessage.getDocument()));
+        }
         String content = xmlToString(netconfMessage.getDocument());
 
         logger.trace("Putting message \n{}", content);
index 94b73f4b100754e17918b9d5d75bed8542130f46..35cf2c6a1423e090a3205376a0c2f953c0fd4b48 100644 (file)
@@ -11,7 +11,7 @@
             <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
 
                 <module>
-                    <name>dep</name>
+                    <name>instance-from-code_dep</name>
                     <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
                         test-impl:impl-dep
                     </type>
@@ -29,7 +29,7 @@
                         test-impl:impl-netconf
                     </type>
 
-                    <name>test1</name>
+                    <name>instance-from-code</name>
 
                     <sleep-factor>
                         2.58
                     </peers>
                     <testing-dep>
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep</name>
+                        <name>ref_dep_user</name>
                     </testing-dep>
 
                     <testing-deps>
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep</name>
+                        <name>ref_dep_user</name>
                     </testing-deps>
                     <testing-deps>
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep_2</name>
+                        <name>ref_dep_user_two</name>
                     </testing-deps>
                 </module>
 
 
                     <testing-dep>
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep_2</name>
+                        <name>ref_dep_user_two</name>
                     </testing-dep>
                 </module>
             </modules>
                 <service>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
-                        <name>ref_dep</name>
-                        <provider>/modules/module[type='impl-dep'][name='dep']
+                        <name>ref_dep_user</name>
+                        <provider>/modules/module[type='impl-dep'][name='instance-from-code_dep']
                         </provider>
                     </instance>
                     <instance>
-                        <name>ref_dep_2</name>
+                        <name>ref_dep_user_two</name>
                         <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
                         </provider>
                     </instance>
                     <instance>
-                        <name>ref_test1</name>
+                        <name>user_to_instance_from_code</name>
                         <provider>
-                            /modules/module[type='impl-netconf'][name='test1']
+                            /modules/module[type='impl-netconf'][name='instance-from-code']
                         </provider>
                     </instance>
                 </service>
diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_addServiceName.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_addServiceName.xml
new file mode 100644 (file)
index 0000000..30be98e
--- /dev/null
@@ -0,0 +1,34 @@
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <edit-config>
+        <target>
+            <candidate/>
+        </target>
+        <test-option>
+            set
+        </test-option>
+        <default-operation>merge</default-operation>
+        <config>
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+                <module>
+                    <name>instance-from-code_dep</name>
+                    <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+                        test-impl:impl-dep
+                    </type>
+                </module>
+
+            </modules>
+
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <service>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+                    <instance>
+                        <name>ref_dep_user_another</name>
+                        <provider>/modules/module[type='impl-dep'][name='instance-from-code_dep']
+                        </provider>
+                    </instance>
+                </service>
+            </services>
+        </config>
+    </edit-config>
+</rpc>
index ad7c84f3c96e46d799923532c70939b7c2a0073a..25976707d4eb1295da0b1d802f218a34426dfedb 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8" ?>
 <rpc message-id="6"
      xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
                     </name-prefix>
                 </module>
             </modules>
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <service>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl">prefix:threadfactory</type>
+                    <instance>
+                        <name>user_to_instance_from_code</name>
+                        <provider>
+                            /modules/module[type='threadfactory-naming'][name='threadfactory-naming-instance']</provider>
+                    </instance>
+                </service>
+            </services>
         </config>
     </edit-config>
 </rpc>
index b48730d3f71e74a86fde37131c38602d3f1169c1..a7f1c863910f4b24b421531b82ffb9cb68499452 100644 (file)
@@ -8,7 +8,7 @@
         <config>
             <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
                 <module>
-                    <name>dep</name>
+                    <name>instance-from-code_dep</name>
                     <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
                         test-impl:impl-dep
                     </type>
@@ -21,6 +21,7 @@
                     </type>
                 </module>
 
+
                 <module>
                     <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
                         test-impl:impl-netconf
                         <simple-int3>456</simple-int3>
                         <core-size>44</core-size>
                     </peers>
-                    <testing-dep>
-                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep</name>
-                    </testing-dep>
                 </module>
                 <module>
                     <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
                         test-impl:impl-netconf
                     </type>
                     <name>test2</name>
-                    <testing-dep>
-                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep</name>
-                    </testing-dep>
                 </module>
             </modules>
+
             <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-                <service>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                    <instance>
-                        <name>ref_dep</name>
-                        <provider>/modules/module[type='impl-dep'][name='dep']
-                        </provider>
-                    </instance>
-                    <instance>
-                        <name>ref_dep_2</name>
-                        <provider>/modules/module[type='impl-dep'][name='dep2']
-                        </provider>
-                    </instance>
-                    <instance>
-                        <name>ref_test1</name>
-                        <provider>
-                            /modules/module[type='impl-netconf'][name='test1']
-                        </provider>
-                    </instance>
-                </service>
             </services>
         </config>
     </edit-config>
index 9d06d98f1c131b2cc405b130288fb6c375851771..e07f18cb5119b3acef99c58e684614ebff2799d7 100644 (file)
@@ -6,6 +6,15 @@
         <default-operation>none</default-operation>
         <config>
             <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <module xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+                        nc:operation="remove">
+                    <name>instance-from-code_dep</name>
+                    <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+                        test-impl:impl-dep
+                    </type>
+                </module>
+
+
                 <module xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
                         nc:operation="remove">
                     <name>dep</name>
@@ -27,7 +36,7 @@
                     <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
                         test-impl:impl-netconf
                     </type>
-                    <name>test1</name>
+                    <name>instance-from-code</name>
                 </module>
 
                 <module xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_setUnions.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_setUnions.xml
new file mode 100644 (file)
index 0000000..21db4b8
--- /dev/null
@@ -0,0 +1,30 @@
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <edit-config>
+        <target>
+            <candidate/>
+        </target>
+        <test-option>
+            set
+        </test-option>
+        <default-operation>merge</default-operation>
+        <config>
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <module>
+                    <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+                        test-impl:impl-netconf
+                    </type>
+
+                    <name>instance-from-code</name>
+
+                    <ip xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">127.1.2.3</ip>
+                    <union-test-attr xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">randomStringForUnion</union-test-attr>
+
+                </module>
+            </modules>
+
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+            </services>
+        </config>
+    </edit-config>
+</rpc>
index 46b833cf68cb3f4ff41442880bfe043575faf63b..5de3de1de223592bac091e830109fdb54820fe18 100644 (file)
@@ -1,6 +1,6 @@
 <rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <no-arg xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
-        <context-instance>/modules/module[type='impl-netconf' and name='test1']</context-instance>
+        <context-instance>/modules/module[type='impl-netconf' and name='instance-from-code']</context-instance>
         <arg1>
             testarg1
         </arg1>
index 3d5117e3bdf15bee2f2b51539dd5435db58874ec..da9afd7bf1e00677313215d81c26fae5af88113b 100644 (file)
@@ -1,7 +1,7 @@
 <rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <noArgInner xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
         <context-instance>
-            /modules/module[name='test1'][type='impl-netconf']/inner-running-data-additional[key='1']
+            /modules/module[name='instance-from-code'][type='impl-netconf']/inner-running-data-additional[key='1']
         </context-instance>
     </noArgInner>
 </rpc>
index 4ba0349f9b7d32c2b4532f1c78eccd9d4e71fc99..a5b83e6db6f39a470462ebecda59a37e1de384bb 100644 (file)
@@ -2,7 +2,7 @@
     <leaf-list-output
             xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
         <context-instance>
-            /modules/module[type='impl-netconf'][name='test1']/inner-running-data[key='0']/inner-inner-running-data[key='1']
+            /modules/module[type='impl-netconf'][name='instance-from-code']/inner-running-data[key='0']/inner-inner-running-data[key='1']
         </context-instance>
     </leaf-list-output>
 </rpc>
index 52b7370e35fa51d97806a66062a280ca595ff80a..e70df1b9493634806c701b5ebd861bac36ab4b6d 100644 (file)
@@ -31,6 +31,7 @@
         <module>../../third-party/com.siemens.ct.exi</module>
         <module>netconf-monitoring</module>
         <module>ietf-netconf-monitoring</module>
+        <module>ietf-netconf-monitoring-extension</module>
     </modules>
 
     <profiles>
index 012807eee9ff622e5469a035b2a0e0e7b3294496..811135252da07b5137d33d9a9f78380229346f42 100644 (file)
@@ -125,7 +125,7 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
     private Boolean throttling = false; // if true, no more batching.
     private volatile Boolean shuttingDown = false;
 
-    private LLDPTLV chassisIdTlv, portIdTlv, ttlTlv, customTlv;
+    private LLDPTLV chassisIdTlv, systemNameTlv, portIdTlv, ttlTlv, customTlv;
     private IPluginOutConnectionService connectionOutService;
 
     class DiscoveryTransmit implements Runnable {
@@ -217,6 +217,11 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
         chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()).setLength((short) cidValue.length)
                 .setValue(cidValue);
 
+        // Create LLDP SystemName TLV
+        byte[] snValue = LLDPTLV.createSystemNameTLVValue(nodeConnector.getNode().toString());
+        systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()).setLength((short) snValue.length)
+                .setValue(snValue);
+
         // Create LLDP PortID TLV
         String portId = nodeConnector.getNodeConnectorIDString();
         byte[] pidValue = LLDPTLV.createPortIDTLVValue(portId);
@@ -233,7 +238,8 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
 
         // Create discovery pkt
         LLDP discoveryPkt = new LLDP();
-        discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setOptionalTLVList(customList);
+        discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setSystemNameId(systemNameTlv)
+                .setOptionalTLVList(customList);
 
         RawPacket rawPkt = null;
         try {
@@ -1462,6 +1468,10 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
         chassisIdTlv = new LLDPTLV();
         chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue());
 
+        // Create LLDP SystemName TLV
+        systemNameTlv = new LLDPTLV();
+        systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue());
+
         // Create LLDP PortID TLV
         portIdTlv = new LLDPTLV();
         portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue());
index 6a896c6c712aee0e06d94b7be31bbf27529c7845..95edca943bc8a61681c34c582f4aeb9dddb7972e 100644 (file)
@@ -21,9 +21,10 @@ import org.opendaylight.controller.sal.utils.NetUtils;
 
 public class LLDP extends Packet {
     private static final String CHASSISID = "ChassisId";
+    private static final String SYSTEMNAMEID = "SystemNameID";
     private static final String PORTID = "PortId";
     private static final String TTL = "TTL";
-    private static final int LLDPDefaultTlvs = 3;
+    private static final int LLDPDefaultTlvs = 4;
     private static LLDPTLV emptyTLV = new LLDPTLV().setLength((short) 0)
             .setType((byte) 0);
     public static final byte[] LLDPMulticastMac = { 1, (byte) 0x80,
@@ -101,6 +102,22 @@ public class LLDP extends Packet {
         return this;
     }
 
+    /**
+     * @return the SystemName TLV
+     */
+    public LLDPTLV getSystemNameId() {
+        return getTLV(SYSTEMNAMEID);
+    }
+
+    /**
+     * @param LLDPTLV
+     *            - the chassisId to set
+     */
+    public LLDP setSystemNameId(LLDPTLV systemNameId) {
+        tlvList.put(getType(SYSTEMNAMEID), systemNameId);
+        return this;
+    }
+
     /**
      * @return LLDPTLV - the portId TLV
      */
index bf674022596d8eb09df2b99bdb72314bdbdaf2cc..27660221ceb56da61d3c6c68cdfd46a13622ef96 100644 (file)
@@ -187,6 +187,18 @@ public class LLDPTLV extends Packet {
                 getfieldnumBits(VALUE)); // variable
     }
 
+    /**
+     * Creates the SystemName TLV value
+     *
+     * @param nodeId
+     *            node identifier string
+     * @return the SystemName TLV value in byte array
+     */
+    static public byte[] createSystemNameTLVValue(String nodeId) {
+        byte[] nid = nodeId.getBytes();
+        return nid;
+    }
+
     /**
      * Creates the ChassisID TLV value including the subtype and ChassisID
      * string
index da4cd5388380f81f69fd9dc9a431da61093a67a6..9cd551664cb945bb4a0c7ed279507a9870fe9b1e 100644 (file)
@@ -73,7 +73,11 @@ public abstract class NodeConnectorCreator {
     public static NodeConnector createNodeConnector(
             String nodeConnectorType, Object portId, Node node) {
         try {
-            return new NodeConnector(nodeConnectorType, portId, node);
+            if (nodeConnectorType.equals(Node.NodeIDType.OPENFLOW) && (portId.getClass() == String.class)) {
+                return new NodeConnector(nodeConnectorType, Short.parseShort((String) portId), node);
+            } else {
+                return new NodeConnector(nodeConnectorType, portId, node);
+            }
         } catch (ConstructionException e1) {
             logger.error("",e1);
             return null;
index f33fa18e299f62b8680389150c916a28efb06254..16c09fe3f6a4ddfe62623293b055b53eabde15c0 100644 (file)
@@ -244,10 +244,7 @@ public class Subnet implements Cloneable, Serializable {
         if (p == null) {
             return false;
         }
-        if (this.isFlatLayer2()) {
-            return true;
-        }
-        return this.nodeConnectors.contains(p);
+        return isFlatLayer2() || nodeConnectors.contains(p);
     }
 
     public boolean isMutualExclusive(Subnet otherSubnet) {
index 217b8d46904aad44eee3ed399b2651d77826da0e..b5d0a48c28709e575f13646971e00ab1ddbc3ea0 100644 (file)
@@ -319,7 +319,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
     @Override
     public SubnetConfig getSubnetConfig(String subnet) {
         // if there are no subnets, return the default subnet
-        if(subnetsConfigList.size() == 0 && subnet == DEFAULT_SUBNET_NAME){
+        if(subnetsConfigList.isEmpty() && subnet.equalsIgnoreCase(DEFAULT_SUBNET_NAME)){
             return DEFAULT_SUBNETCONFIG;
         }else{
             return subnetsConfigList.get(subnet);
@@ -428,11 +428,11 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
     }
 
     private Status semanticCheck(SubnetConfig conf) {
-        Subnet newSubnet = new Subnet(conf);
         Set<InetAddress> IPs = subnets.keySet();
         if (IPs == null) {
             return new Status(StatusCode.SUCCESS);
         }
+        Subnet newSubnet = new Subnet(conf);
         for (InetAddress i : IPs) {
             Subnet existingSubnet = subnets.get(i);
             if ((existingSubnet != null) && !existingSubnet.isMutualExclusive(newSubnet)) {
@@ -462,7 +462,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
                 return status;
             }
         } else {
-            if (conf.getName().equals(DEFAULT_SUBNET_NAME)) {
+            if (conf.getName().equalsIgnoreCase(DEFAULT_SUBNET_NAME)) {
                 return new Status(StatusCode.NOTALLOWED, "The specified subnet gateway cannot be removed");
             }
         }
@@ -475,6 +475,16 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
             status = updateConfig(conf, isAdding);
             if(!status.isSuccess()) {
                 updateDatabase(conf, (!isAdding));
+            } else {
+                // update the listeners
+                Subnet subnetCurr = subnets.get(conf.getIPAddress());
+                Subnet subnet;
+                if (subnetCurr == null) {
+                    subnet = new Subnet(conf);
+                } else {
+                    subnet = subnetCurr.clone();
+                }
+                notifySubnetChange(subnet, isAdding);
             }
         }
 
@@ -496,7 +506,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
 
     @Override
     public Status removeSubnet(String name) {
-        if (name.equals(DEFAULT_SUBNET_NAME)) {
+        if (name.equalsIgnoreCase(DEFAULT_SUBNET_NAME)) {
             return new Status(StatusCode.NOTALLOWED, "The specified subnet gateway cannot be removed");
         }
         SubnetConfig conf = subnetsConfigList.get(name);
@@ -681,12 +691,9 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
             return DEFAULT_SUBNET;
         }
 
-        Subnet sub;
-        Set<InetAddress> indices = subnets.keySet();
-        for (InetAddress i : indices) {
-            sub = subnets.get(i);
-            if (sub.isSubnetOf(networkAddress)) {
-                return sub;
+        for(Map.Entry<InetAddress,Subnet> subnetEntry : subnets.entrySet()) {
+            if(subnetEntry.getValue().isSubnetOf(networkAddress)) {
+                return subnetEntry.getValue();
             }
         }
         return null;
index d4d3d1c85764dd6be1439404cd6447c5f83d8d25..5dfa1632f74c4d323cb87e8cbe8bb8885ada9e35 100644 (file)
   <artifactId>topologymanager.integrationtest</artifactId>
   <version>0.4.0-SNAPSHOT</version>
   <dependencies>
+    <dependency>
+      <groupId>org.ops4j.pax.exam</groupId>
+      <artifactId>pax-exam-container-native</artifactId>
+      <version>${exam.version}</version>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>protocol_plugins.stub</artifactId>