Merge "Added flags for flow removed event"
authorEd Warnicke <eaw@cisco.com>
Thu, 21 Nov 2013 09:30:59 +0000 (09:30 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 21 Nov 2013 09:30:59 +0000 (09:30 +0000)
157 files changed:
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/ModuleInternalTransactionalInfo.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java
opendaylight/config/netty-config-api/pom.xml [new file with mode: 0644]
opendaylight/config/netty-config-api/src/main/yang/netty.yang [new file with mode: 0644]
opendaylight/config/netty-event-executor-config/pom.xml
opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java
opendaylight/config/netty-event-executor-config/src/main/yang/netty-event-executor.yang
opendaylight/config/netty-threadgroup-config/pom.xml
opendaylight/config/netty-threadgroup-config/src/main/java/org/opendaylight/controller/config/yang/netty/threadgroup/NettyThreadgroupModule.java
opendaylight/config/netty-threadgroup-config/src/main/yang/netty-threadgroup.yang [moved from opendaylight/config/netty-threadgroup-config/src/main/yang/nsos-netty-threadgroup.yang with 83% similarity]
opendaylight/config/netty-timer-config/pom.xml [new file with mode: 0644]
opendaylight/config/netty-timer-config/src/main/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModule.java [new file with mode: 0644]
opendaylight/config/netty-timer-config/src/main/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleFactory.java [new file with mode: 0644]
opendaylight/config/netty-timer-config/src/main/yang/netty-timer.yang [new file with mode: 0644]
opendaylight/config/netty-timer-config/src/test/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java [new file with mode: 0644]
opendaylight/config/pom.xml
opendaylight/config/threadpool-config-api/pom.xml
opendaylight/config/threadpool-config-api/src/main/yang/threadpool.yang
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-store-api/pom.xml
opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/api/YangStoreService.java
opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/spi/YangStoreListener.java [deleted file]
opendaylight/config/yang-store-impl/pom.xml
opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTracker.java [moved from opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTrackerCustomizer.java with 51% similarity]
opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/MbeParser.java
opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/YangStoreActivator.java
opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/YangStoreSnapshotImpl.java
opendaylight/config/yang-store-impl/src/test/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTrackerCustomizerTest.java
opendaylight/config/yang-store-impl/src/test/java/org/opendaylight/controller/config/yang/store/impl/HardcodedYangStoreService.java
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/forwardingrulesmanager_mdsal/openflow/pom.xml [deleted file]
opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend
opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.xtend
opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/SampleConsumer.java
opendaylight/md-sal/forwardingrules-manager/pom.xml [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FRMConsumerImpl.java [moved from opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/FRMConsumerImpl.java with 98% similarity]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FRMUtil.java [moved from opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/FRMUtil.java with 99% similarity]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FlowConsumerImpl.java [moved from opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/FlowConsumerImpl.java with 99% similarity]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/GroupConsumerImpl.java [moved from opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/GroupConsumerImpl.java with 99% similarity]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/IForwardingRulesManager.java [moved from opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/IForwardingRulesManager.java with 91% similarity]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/MeterConsumerImpl.java [moved from opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/MeterConsumerImpl.java with 99% similarity]
opendaylight/md-sal/model/model-flow-base/src/main/yang/action-types.yang
opendaylight/md-sal/model/model-flow-base/src/main/yang/port-types.yang
opendaylight/md-sal/model/model-flow-management/src/main/yang/flow-config.yang
opendaylight/md-sal/model/model-flow-management/src/main/yang/group-config.yang
opendaylight/md-sal/model/model-flow-management/src/main/yang/meter-config.yang
opendaylight/md-sal/model/model-flow-management/src/main/yang/port-config.yang
opendaylight/md-sal/model/model-flow-management/src/main/yang/table-config.yang
opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-error.yang
opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-service.yang
opendaylight/md-sal/model/model-flow-service/src/main/yang/port-service.yang
opendaylight/md-sal/model/model-flow-statistics/src/main/yang/group-statistics.yang
opendaylight/md-sal/model/model-flow-statistics/src/main/yang/meter-statistics.yang
opendaylight/md-sal/pom.xml
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.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/XtendHelper.java
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/api/AugmentationCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCaseCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DataContainerCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DomCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentifierCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/InstanceIdentifierCodec.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ValueWithQName.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecTypeUtils.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/StaticFieldInitializer.java [new file with mode: 0644]
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/NotificationBrokerImpl.xtend
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/connect/dom/BindingMapping.xtend [deleted file]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/ConnectorActivator.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/MappingServiceImpl.xtend [deleted file]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/RuntimeGeneratedMappingServiceImpl.xtend [deleted file]
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/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/bugfix/DOMCodecBug01Test.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java [deleted file]
opendaylight/md-sal/sal-binding-config/src/main/yang/opendaylight-md-sal-binding.yang
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connector/netconf/test/MountTest.java [deleted file]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfServiceLegacy.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfApplication.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/UnsupportedFormatException.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/UnsupportedJsonFormatException.java [deleted file]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNodeTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNodeTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicDataTypesTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlProvidersTest.java
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/array-with-null.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/empty-data.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/empty-data1.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-items-in-list.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-leaflist-items.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container-yang/simple-container.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list1.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list2.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level1.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level2.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level3.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container-yang/data-container.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list-yang/data-container.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list-yang/data-list.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/empty-data.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/simple-data-types.yang
opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/xml/data.xml
opendaylight/md-sal/sal-zeromq-connector/pom.xml
opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChangeListener.java [deleted file]
opendaylight/md-sal/zeromq-routingtable/implementation/pom.xml [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChangeListener.java [moved from opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/api/YangStoreListenerRegistration.java with 56% similarity]
opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java [moved from opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java with 69% similarity]
opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTableException.java [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/SystemException.java [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/integrationtest/pom.xml [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java [new file with mode: 0644]
opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/resources/logback.xml [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivator.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java
third-party/ganymed/src/main/java/ch/ethz/ssh2/channel/ChannelManager.java [new file with mode: 0644]

index f93409f99ed21d980316df9c85a2bf144f061f3f..84c2c6dd4dd46b57372d1fbf14a46f43ed225181 100644 (file)
@@ -275,6 +275,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
             ModuleJMXRegistrator newModuleJMXRegistrator = baseJMXRegistrator
                     .createModuleJMXRegistrator();
 
+            OsgiRegistration osgiRegistration = null;
             if (entry.hasOldModule()) {
                 ModuleInternalInfo oldInternalInfo = entry.getOldInternalInfo();
                 DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo
@@ -282,19 +283,21 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                 currentConfig.remove(entry.getName());
 
                 // test if old instance == new instance
-                if (oldReadableConfigBean.getInstance().equals(
-                        module.getInstance())) {
+                if (oldReadableConfigBean.getInstance().equals(module.getInstance())) {
                     // reused old instance:
                     // wrap in readable dynamic mbean
                     reusedInstances.add(primaryReadOnlyON);
+                    osgiRegistration = oldInternalInfo.getOsgiRegistration();
                 } else {
                     // recreated instance:
                     // it is responsibility of module to call the old instance -
                     // we just need to unregister configbean
                     recreatedInstances.add(primaryReadOnlyON);
+
+                    // close old osgi registration
+                    oldInternalInfo.getOsgiRegistration().close();
                 }
-                // close old osgi registration in any case
-                oldInternalInfo.getOsgiRegistration().close();
+
                 // close old module jmx registrator
                 oldInternalInfo.getModuleJMXRegistrator().close();
             } else {
@@ -316,10 +319,10 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
             }
 
             // register to OSGi
-            OsgiRegistration osgiRegistration = beanToOsgiServiceManager
-                    .registerToOsgi(module.getClass(),
-                            newReadableConfigBean.getInstance(),
-                            entry.getName());
+            if (osgiRegistration == null) {
+                osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(),
+                        newReadableConfigBean.getInstance(), entry.getName());
+            }
 
             RootRuntimeBeanRegistratorImpl runtimeBeanRegistrator = runtimeRegistrators
                     .get(entry.getName());
index e71aef4c04cd3b90d5bc4cf8002aa52b8a4d2da9..c4f40fbeeb42a6c05e08a6213fc2d928d2a912da 100644 (file)
@@ -36,6 +36,11 @@ public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdent
         this.transactionModuleJMXRegistration = transactionModuleJMXRegistration;
     }
 
+
+    /**
+     * Use {@link #getIdentifier()} instead.
+     */
+    @Deprecated
     public ModuleIdentifier getName() {
         return name;
     }
@@ -56,7 +61,7 @@ public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdent
                 maybeOldInternalInfo.getOrderingIdx());
     }
 
-    @Deprecated
+
     public Module getModule() {
         return module;
     }
index 0b84d905dfff907b82b88d287d5d70c94bdc43a0..18a22bb26fa91560dcc24be28a5e9c65877413c1 100644 (file)
@@ -51,6 +51,8 @@ public abstract class AbstractConfigTest extends
     protected ConfigRegistryJMXClient configRegistryClient;
     protected BaseJMXRegistrator baseJmxRegistrator;
     protected InternalJMXRegistrator internalJmxRegistrator;
+    protected BundleContext mockedContext;
+    protected ServiceRegistration<?> mockedServiceRegistration;
 
     // this method should be called in @Before
     protected void initConfigTransactionManagerImpl(
@@ -60,16 +62,16 @@ public abstract class AbstractConfigTest extends
 
         configRegistryJMXRegistrator = new ConfigRegistryJMXRegistrator(
                 platformMBeanServer);
-        BundleContext context = mock(BundleContext.class);
-        ServiceRegistration<?> mockedServiceRegistration = mock(ServiceRegistration.class);
+        this.mockedContext = mock(BundleContext.class);
+        this.mockedServiceRegistration = mock(ServiceRegistration.class);
         doNothing().when(mockedServiceRegistration).unregister();
-        doReturn(mockedServiceRegistration).when(context).registerService(
+        doReturn(mockedServiceRegistration).when(mockedContext).registerService(
                 Matchers.any(String[].class), any(Closeable.class),
                 any(Dictionary.class));
         internalJmxRegistrator = new InternalJMXRegistrator(platformMBeanServer);
         baseJmxRegistrator = new BaseJMXRegistrator(internalJmxRegistrator);
 
-        configRegistry = new ConfigRegistryImpl(resolver, context,
+        configRegistry = new ConfigRegistryImpl(resolver, mockedContext,
                 platformMBeanServer, baseJmxRegistrator);
         try {
             configRegistryJMXRegistrator.registerToJMX(configRegistry);
diff --git a/opendaylight/config/netty-config-api/pom.xml b/opendaylight/config/netty-config-api/pom.xml
new file mode 100644 (file)
index 0000000..9a2fe37
--- /dev/null
@@ -0,0 +1,54 @@
+<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>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-subsystem</artifactId>
+    <version>0.2.3-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>netty-config-api</artifactId>
+     <name>${project.artifactId}</name>
+   <packaging>bundle</packaging>
+   <prerequisites>
+      <maven>3.0.4</maven>
+   </prerequisites>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-transport</artifactId>
+        </dependency>
+    </dependencies>
+   <build>
+      <plugins>
+         <plugin>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>maven-bundle-plugin</artifactId>
+            <configuration>
+               <instructions>
+                  <Import-Package>
+                     org.opendaylight.controller.config.api.*,
+                     io.netty.channel,
+                     io.netty.util,
+                     io.netty.util.concurrent
+                  </Import-Package>
+                  <Export-Package>
+                     org.opendaylight.controller.config.yang.netty
+                  </Export-Package>
+               </instructions>
+            </configuration>
+         </plugin>
+         <plugin>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-maven-plugin</artifactId>
+         </plugin>
+      </plugins>
+   </build>
+</project>
\ No newline at end of file
diff --git a/opendaylight/config/netty-config-api/src/main/yang/netty.yang b/opendaylight/config/netty-config-api/src/main/yang/netty.yang
new file mode 100644 (file)
index 0000000..7f7a3ff
--- /dev/null
@@ -0,0 +1,52 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module netty {
+       yang-version 1;
+       namespace "urn:opendaylight:params:xml:ns:yang:controller:netty";
+       prefix "netty";
+
+       import config { prefix config; revision-date 2013-04-05; }
+
+       organization "Cisco Systems, Inc.";
+
+       contact "Milos Fabian <milfabia@cisco.com>";
+
+    description
+        "This module contains the base YANG definitions for
+         netty services.
+
+        Copyright (c)2013 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";
+
+    revision "2013-11-19" {
+        description
+            "Initial revision.";
+    }
+    
+    identity netty-threadgroup {
+        description
+            "Configuration wrapper around netty's threadgroup";
+
+        base "config:service-type";
+        config:java-class "io.netty.channel.EventLoopGroup";
+    }
+    
+    identity netty-event-executor {
+        description
+            "Configuration wrapper around netty's event executor";
+
+        base "config:service-type";
+        config:java-class "io.netty.util.concurrent.EventExecutor";
+    }
+    
+    identity netty-timer {
+        description
+            "Configuration wrapper around netty's timer";
+
+        base "config:service-type";
+        config:java-class "io.netty.util.Timer";       
+    }
+}
\ No newline at end of file
index a2ce94f340f073cfc447a46c5e971776bbe44fe9..3d5384d171774d053ca01ee39ca1a9e3c784401f 100644 (file)
       </dependency>
       <dependency>
          <groupId>org.opendaylight.controller</groupId>
-         <artifactId>threadpool-config-api</artifactId>
+         <artifactId>netty-config-api</artifactId>
          <version>${project.version}</version>
       </dependency>
       <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
       </dependency>
-      <dependency>
-         <groupId>com.google.guava</groupId>
-         <artifactId>guava</artifactId>
-      </dependency>
 
       <!--test dependencies -->
       <dependency>
@@ -80,7 +76,7 @@
                   </Export-Package>
                   <Import-Package>
                      com.google.common.base,
-                     org.opendaylight.controller.config.yang.threadpool,
+                     org.opendaylight.controller.config.yang.netty,
                      io.netty.util.concurrent,
                      org.opendaylight.controller.config.api,
                      org.opendaylight.controller.config.api.annotations,
index d45eccded8f7fd6b5c20c3f68f67898e559815a5..16e5c07356df97c6af8baf2f6e7eb80ac7d123f4 100644 (file)
@@ -2,18 +2,18 @@
 module netty-event-executor {
     yang-version 1;
        namespace "urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor";
-    prefix "netty-t";
+    prefix "netty-ee";
 
     import config { prefix config; revision-date 2013-04-05; }
-    import threadpool { prefix th; revision-date 2013-04-09; }
+    import netty { prefix netty; revision-date 2013-11-19; }
 
     organization "Cisco Systems, Inc.";
 
     contact "Milos Fabian <milfabia@cisco.com>";
 
     description
-        "This module contains the base YANG definitions for NS-OS
-         thread-related services.
+        "This module contains the base YANG definitions for
+         netty event executor implementation.
 
         Copyright (c)2013 Cisco Systems, Inc. All rights reserved.;
         
@@ -29,7 +29,7 @@ module netty-event-executor {
     
     identity netty-global-event-executor {
         base config:module-type;
-        config:provided-service th:netty-event-executor;
+        config:provided-service netty:netty-event-executor;
         config:java-name-prefix GlobalEventExecutor;
     }
 
@@ -39,6 +39,4 @@ module netty-event-executor {
 
         }
     }
-
-
 }
index ef63fce2ce66126f329d72eeb94aa0e69d33eb23..8dc989e7283751c1a91b4e57d789046724b1f5b3 100644 (file)
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
-            <artifactId>threadpool-config-api</artifactId>
+            <artifactId>netty-config-api</artifactId>
             <version>${project.version}</version>
         </dependency>
-
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
 
-
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-        </dependency>
-
         <!--test dependencies -->
         <dependency>
             <groupId>junit</groupId>
@@ -82,7 +75,6 @@
             <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
-                <version>2.3.7</version>
                 <extensions>true</extensions>
                 <configuration>
                     <instructions>
@@ -92,7 +84,7 @@
                         <Import-Package>
                             com.google.common.base,
                             io.netty.channel.nio,
-                            org.opendaylight.controller.config.yang.threadpool,
+                            org.opendaylight.controller.config.yang.netty,
                             io.netty.util.concurrent,
                             org.opendaylight.controller.config.api,
                             org.opendaylight.controller.config.api.annotations,
index fd6b216f53fa50c9cb956710d565140383bbf515..9ceef3116ac5603219c019eb2fd21d340e23dcca 100644 (file)
@@ -9,9 +9,10 @@
 */
 package org.opendaylight.controller.config.yang.netty.threadgroup;
 
-import com.google.common.base.Preconditions;
 import io.netty.channel.nio.NioEventLoopGroup;
 
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+
 /**
 *
 */
@@ -28,7 +29,8 @@ public final class NettyThreadgroupModule extends org.opendaylight.controller.co
     @Override
     public void validate(){
         if(getThreadCount()!=null) {
-            Preconditions.checkArgument(getThreadCount() > 0, "Thread count cannot be < 0");
+            JmxAttributeValidationException.checkCondition(getThreadCount() > 0, "value must be greater than 0",
+                    threadCountJmxAttribute);
         }
     }
 
similarity index 83%
rename from opendaylight/config/netty-threadgroup-config/src/main/yang/nsos-netty-threadgroup.yang
rename to opendaylight/config/netty-threadgroup-config/src/main/yang/netty-threadgroup.yang
index f13cf391bf3dbd042853dc65df2ef6a652150435..e648c5328a71349f9261efa82f8c8ef02a798a58 100644 (file)
@@ -1,19 +1,19 @@
 // vi: set smarttab et sw=4 tabstop=4:
-module nsos-threadpool {
+module threadgroup {
     yang-version 1;
        namespace "urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup";
-    prefix "netty-t";
+    prefix "netty-th";
 
     import config { prefix config; revision-date 2013-04-05; }
-    import threadpool { prefix th; revision-date 2013-04-09; }
+    import netty { prefix netty; revision-date 2013-11-19; }
 
     organization "Cisco Systems, Inc.";
 
     contact "Robert Varga <rovarga@cisco.com>";
 
     description
-        "This module contains the base YANG definitions for NS-OS
-         thread-related services.
+        "This module contains the base YANG definitions for
+         netty threadgroup implementation.
 
         Copyright (c)2013 Cisco Systems, Inc. All rights reserved.";
 
@@ -24,7 +24,7 @@ module nsos-threadpool {
 
     identity netty-threadgroup-fixed {
         base config:module-type;
-        config:provided-service th:netty-threadgroup;
+        config:provided-service netty:netty-threadgroup;
         config:java-name-prefix NettyThreadgroup;
     }
 
diff --git a/opendaylight/config/netty-timer-config/pom.xml b/opendaylight/config/netty-timer-config/pom.xml
new file mode 100644 (file)
index 0000000..095e71f
--- /dev/null
@@ -0,0 +1,114 @@
+<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>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-subsystem</artifactId>
+      <version>0.2.3-SNAPSHOT</version>
+   </parent>
+   <modelVersion>4.0.0</modelVersion>
+   <artifactId>netty-timer-config</artifactId>
+   <description>Configuration Wrapper around netty's timer</description>
+   <packaging>bundle</packaging>
+   <name>${project.artifactId}</name>
+   <prerequisites>
+      <maven>3.0.4</maven>
+   </prerequisites>
+
+   <dependencies>
+      <dependency>
+         <groupId>org.opendaylight.controller</groupId>
+         <artifactId>config-api</artifactId>
+      </dependency>
+      <dependency>
+         <groupId>org.opendaylight.controller</groupId>
+         <artifactId>netty-config-api</artifactId>
+         <version>${project.version}</version>
+      </dependency>
+      <dependency>
+         <groupId>org.opendaylight.controller</groupId>
+         <artifactId>threadpool-config-api</artifactId>
+         <version>${project.version}</version>
+      </dependency>
+      <dependency>
+         <groupId>org.slf4j</groupId>
+         <artifactId>slf4j-api</artifactId>
+      </dependency>
+
+      <!--test dependencies -->
+      <dependency>
+         <groupId>junit</groupId>
+         <artifactId>junit</artifactId>
+         <scope>test</scope>
+      </dependency>
+      <dependency>
+         <groupId>org.opendaylight.controller</groupId>
+         <artifactId>config-manager</artifactId>
+         <scope>test</scope>
+         <type>test-jar</type>
+      </dependency>
+      <dependency>
+         <groupId>org.opendaylight.controller</groupId>
+         <artifactId>config-manager</artifactId>
+         <scope>test</scope>
+      </dependency>
+      <dependency>
+         <groupId>org.opendaylight.controller</groupId>
+         <artifactId>config-util</artifactId>
+         <scope>test</scope>
+      </dependency>
+      <dependency>
+         <groupId>org.opendaylight.bgpcep</groupId>
+         <artifactId>mockito-configuration</artifactId>
+         <scope>test</scope>
+      </dependency>
+      <dependency>
+         <groupId>org.opendaylight.controller</groupId>
+         <artifactId>threadpool-config-impl</artifactId>
+         <version>${project.version}</version>
+         <scope>test</scope>
+      </dependency>
+
+   </dependencies>
+
+   <build>
+      <plugins>
+         <plugin>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-maven-plugin</artifactId>
+         </plugin>
+         <plugin>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>maven-bundle-plugin</artifactId>
+            <extensions>true</extensions>
+            <configuration>
+               <instructions>
+                  <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                  <Export-Package>
+                  </Export-Package>
+                  <Import-Package>
+                     javax.management,
+                     com.google.common.base,
+                     org.opendaylight.controller.config.yang.netty,
+                     org.opendaylight.controller.config.yang.threadpool,
+                     io.netty.util,
+                     org.opendaylight.controller.config.api,
+                     org.opendaylight.controller.config.api.annotations,
+                     org.opendaylight.controller.config.api.runtime,
+                     org.opendaylight.controller.config.spi,
+                     org.slf4j,
+                     org.osgi.framework
+                  </Import-Package>
+               </instructions>
+            </configuration>
+         </plugin>
+      </plugins>
+   </build>
+
+   <distributionManagement>
+      <site>
+         <id>${project.artifactId}</id>
+         <name>NETTY-TIMER-CONFIG Module site</name>
+         <url>${basedir}/target/site/${project.artifactId}</url>
+      </site>
+   </distributionManagement>
+</project>
\ No newline at end of file
diff --git a/opendaylight/config/netty-timer-config/src/main/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModule.java b/opendaylight/config/netty-timer-config/src/main/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModule.java
new file mode 100644 (file)
index 0000000..cc78124
--- /dev/null
@@ -0,0 +1,99 @@
+/**
+ * Generated file
+
+ * Generated from: yang module name: netty-event-executor  yang module local name: netty-hashed-wheel-timer
+ * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ * Generated at: Tue Nov 19 12:49:59 CET 2013
+ *
+ * Do not modify this file unless it is present under src/main directory
+ */
+package org.opendaylight.controller.config.yang.netty.timer;
+
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+
+/**
+*
+*/
+public final class HashedWheelTimerModule extends
+        org.opendaylight.controller.config.yang.netty.timer.AbstractHashedWheelTimerModule {
+
+    public HashedWheelTimerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public HashedWheelTimerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            HashedWheelTimerModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void validate() {
+        super.validate();
+        if (getTickDuration() != null) {
+            JmxAttributeValidationException.checkCondition(getTickDuration() > 0, "value must be greater than 0",
+                    tickDurationJmxAttribute);
+        }
+        if (getTicksPerWheel() != null) {
+            JmxAttributeValidationException.checkCondition(getTicksPerWheel() > 0, "value must be greater than 0",
+                    ticksPerWheelJmxAttribute);
+        }
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        TimeUnit unit = TimeUnit.MILLISECONDS;
+        if (getTickDuration() != null && getThreadFactoryDependency() == null && getTicksPerWheel() == null) {
+            return new HashedWheelTimerCloseable(new HashedWheelTimer(getTickDuration(), unit));
+        }
+        if (getTickDuration() != null && getThreadFactoryDependency() == null && getTicksPerWheel() != null) {
+            return new HashedWheelTimerCloseable(new HashedWheelTimer(getTickDuration(), unit, getTicksPerWheel()));
+        }
+        if (getTickDuration() == null && getThreadFactoryDependency() != null && getTicksPerWheel() == null) {
+            return new HashedWheelTimerCloseable(new HashedWheelTimer(getThreadFactoryDependency()));
+        }
+        if (getTickDuration() != null && getThreadFactoryDependency() != null && getTicksPerWheel() == null) {
+            return new HashedWheelTimerCloseable(new HashedWheelTimer(getThreadFactoryDependency(), getTickDuration(),
+                    unit));
+        }
+        if (getTickDuration() != null && getThreadFactoryDependency() != null && getTicksPerWheel() != null) {
+            return new HashedWheelTimerCloseable(new HashedWheelTimer(getThreadFactoryDependency(), getTickDuration(),
+                    unit, getTicksPerWheel()));
+        }
+        return new HashedWheelTimerCloseable(new HashedWheelTimer());
+    }
+
+    static final private class HashedWheelTimerCloseable implements AutoCloseable, Timer {
+
+        private final Timer timer;
+
+        public HashedWheelTimerCloseable(Timer timer) {
+            this.timer = timer;
+        }
+
+        @Override
+        public void close() throws Exception {
+            stop();
+        }
+
+        @Override
+        public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) {
+            return this.timer.newTimeout(task, delay, unit);
+        }
+
+        @Override
+        public Set<Timeout> stop() {
+            return this.timer.stop();
+        }
+
+    }
+}
diff --git a/opendaylight/config/netty-timer-config/src/main/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleFactory.java b/opendaylight/config/netty-timer-config/src/main/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleFactory.java
new file mode 100644 (file)
index 0000000..e291ab5
--- /dev/null
@@ -0,0 +1,18 @@
+/**
+ * Generated file
+
+ * Generated from: yang module name: netty-event-executor  yang module local name: netty-hashed-wheel-timer
+ * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ * Generated at: Tue Nov 19 12:49:59 CET 2013
+ *
+ * Do not modify this file unless it is present under src/main directory
+ */
+package org.opendaylight.controller.config.yang.netty.timer;
+
+/**
+*
+*/
+public class HashedWheelTimerModuleFactory extends
+        org.opendaylight.controller.config.yang.netty.timer.AbstractHashedWheelTimerModuleFactory {
+
+}
diff --git a/opendaylight/config/netty-timer-config/src/main/yang/netty-timer.yang b/opendaylight/config/netty-timer-config/src/main/yang/netty-timer.yang
new file mode 100644 (file)
index 0000000..b53b13f
--- /dev/null
@@ -0,0 +1,59 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module netty-timer {
+    yang-version 1;
+       namespace "urn:opendaylight:params:xml:ns:yang:controller:netty:timer";
+    prefix "netty-timer";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import netty { prefix netty; revision-date 2013-11-19; }
+    import threadpool { prefix th; revision-date 2013-04-09; }
+
+    organization "Cisco Systems, Inc.";
+
+    contact "Milos Fabian <milfabia@cisco.com>";
+
+    description
+        "This module contains the base YANG definitions for
+         netty timer implementation.
+
+        Copyright (c)2013 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";
+
+    revision "2013-11-19" {
+        description
+            "Initial revision";
+    }
+    
+    identity netty-hashed-wheel-timer {
+        base config:module-type;
+        config:provided-service netty:netty-timer;
+        config:java-name-prefix HashedWheelTimer;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netty-hashed-wheel-timer {
+            when "/config:modules/config:module/config:type = 'netty-hashed-wheel-timer'";
+            
+            leaf tick-duration {
+                type uint32;
+            }
+            
+            leaf ticks-per-wheel {
+                type uint16;
+            }
+            
+                       container thread-factory {
+                               uses config:service-ref {
+                                       refine type {
+                                               mandatory false;
+                                               config:required-identity th:threadfactory;
+                                       }
+                               }
+                       }
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/config/netty-timer-config/src/test/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java b/opendaylight/config/netty-timer-config/src/test/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java
new file mode 100644 (file)
index 0000000..8bc4d95
--- /dev/null
@@ -0,0 +1,131 @@
+package org.opendaylight.controller.config.yang.netty.timer;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+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.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+import org.opendaylight.controller.config.yang.threadpool.impl.NamingThreadFactoryModuleFactory;
+import org.opendaylight.controller.config.yang.threadpool.impl.NamingThreadFactoryModuleMXBean;
+
+public class HashedWheelTimerModuleTest extends AbstractConfigTest {
+
+    private HashedWheelTimerModuleFactory factory;
+    private NamingThreadFactoryModuleFactory threadFactory;
+    private final String instanceName = "hashed-wheel-timer1";
+
+    @Before
+    public void setUp() {
+        factory = new HashedWheelTimerModuleFactory();
+        threadFactory = new NamingThreadFactoryModuleFactory();
+        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(factory, threadFactory));
+    }
+
+    public void testValidationExceptionTickDuration() throws InstanceAlreadyExistsException {
+        ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+        try {
+            createInstance(transaction, instanceName, 0L, 10, true);
+            transaction.validateConfig();
+            Assert.fail();
+        } catch (ValidationException e) {
+            Assert.assertTrue(e.getMessage().contains("TickDuration value must be greater than 0"));
+        }
+    }
+
+    public void testValidationExceptionTicksPerWheel() throws InstanceAlreadyExistsException {
+        ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+        try {
+            createInstance(transaction, instanceName, 500L, 0, true);
+            transaction.validateConfig();
+            Assert.fail();
+        } catch (ValidationException e) {
+            Assert.assertTrue(e.getMessage().contains("TicksPerWheel value must be greater than 0"));
+        }
+    }
+
+    @Test
+    public void testCreateBean() throws InstanceAlreadyExistsException, ValidationException,
+            ConflictingVersionException {
+        ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+
+        createInstance(transaction, instanceName, 500L, 10, true);
+        createInstance(transaction, instanceName + 1, null, null, false);
+        createInstance(transaction, instanceName + 2, 500L, 10, false);
+        createInstance(transaction, instanceName + 3, 500L, null, false);
+        transaction.validateConfig();
+        CommitStatus status = transaction.commit();
+
+        assertBeanCount(4, factory.getImplementationName());
+        assertStatus(status, 5, 0, 0);
+    }
+
+    @Test
+    public void testReusingOldInstance() throws InstanceAlreadyExistsException, ConflictingVersionException,
+            ValidationException {
+
+        ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+        createInstance(transaction, instanceName, 500L, 10, true);
+
+        transaction.commit();
+
+        transaction = configRegistryClient.createTransaction();
+        assertBeanCount(1, factory.getImplementationName());
+        CommitStatus status = transaction.commit();
+
+        assertBeanCount(1, factory.getImplementationName());
+        assertStatus(status, 0, 0, 2);
+    }
+
+    @Test
+    public void testReconfigure() throws InstanceAlreadyExistsException, ConflictingVersionException,
+            ValidationException, InstanceNotFoundException {
+
+        ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+        createInstance(transaction, instanceName, 500L, 10, true);
+        transaction.commit();
+
+        transaction = configRegistryClient.createTransaction();
+        assertBeanCount(1, factory.getImplementationName());
+        HashedWheelTimerModuleMXBean mxBean = transaction.newMBeanProxy(
+                transaction.lookupConfigBean(factory.getImplementationName(), instanceName),
+                HashedWheelTimerModuleMXBean.class);
+        mxBean.setTicksPerWheel(20);
+        CommitStatus status = transaction.commit();
+
+        assertBeanCount(1, factory.getImplementationName());
+        assertStatus(status, 0, 1, 1);
+    }
+
+    private ObjectName createInstance(ConfigTransactionJMXClient transaction, String instanceName,
+            final Long tickDuration, final Integer ticksPerWheel, final boolean hasThreadfactory)
+            throws InstanceAlreadyExistsException {
+        ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), instanceName);
+        HashedWheelTimerModuleMXBean mxBean = transaction
+                .newMBeanProxy(nameCreated, HashedWheelTimerModuleMXBean.class);
+        mxBean.setTickDuration(tickDuration);
+        mxBean.setTicksPerWheel(ticksPerWheel);
+        if (hasThreadfactory) {
+            mxBean.setThreadFactory(createThreadfactoryInstance(transaction, "thread-factory1", "th"));
+        }
+        return nameCreated;
+    }
+
+    private ObjectName createThreadfactoryInstance(ConfigTransactionJMXClient transaction, String instanceName,
+            final String namePrefix) throws InstanceAlreadyExistsException {
+        ObjectName nameCreated = transaction.createModule(threadFactory.getImplementationName(), instanceName);
+        NamingThreadFactoryModuleMXBean mxBean = transaction.newMBeanProxy(nameCreated,
+                NamingThreadFactoryModuleMXBean.class);
+        mxBean.setNamePrefix(namePrefix);
+        return nameCreated;
+    }
+
+}
index 3f27ff1055882d1352e27f7208d4571919f06e71..22be6f162b23239cf4952ec6283ae0094d3e0e74 100755 (executable)
         <module>yang-test</module>
         <module>logback-config</module>
         <module>threadpool-config-api</module>
+        <module>netty-config-api</module>
         <module>threadpool-config-impl</module>
         <module>netty-threadgroup-config</module>
         <module>netty-event-executor-config</module>
+        <module>netty-timer-config</module>
     </modules>
 
     <profiles>
index cddfb6483099d3e8e4e5127484866d102ef86e2c..5c70ac7958fdd4a9af2803879bb598c2d2bee11f 100644 (file)
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>
-        <dependency>
-            <groupId>io.netty</groupId>
-            <artifactId>netty-transport</artifactId>
-        </dependency>
     </dependencies>
 
    <build>
@@ -38,8 +34,6 @@
                   <Import-Package>
                      org.opendaylight.controller.config.api.*,
                      com.google.common.eventbus,
-                     io.netty.channel,
-                     io.netty.util.concurrent
                   </Import-Package>
                   <Export-Package>
                      org.opendaylight.controller.config.threadpool,
index 9c73711c17bf98e0547b87674be96fd6451a64f1..8f3064822be319dfee6fd7c7061c8bee14db268f 100644 (file)
@@ -73,23 +73,4 @@ module threadpool {
                base "threadpool";
         config:java-class "org.opendaylight.controller.config.threadpool.ScheduledThreadPool";
        }
-
-
-    identity netty-threadgroup {
-        description
-            "Configuration wrapper around netty's threadgroup";
-
-        base "config:service-type";
-        config:java-class "io.netty.channel.EventLoopGroup";
-    }
-    
-    identity netty-event-executor {
-        description
-            "Configuration wrapper around netty's event executor";
-
-        base "config:service-type";
-        config:java-class "io.netty.util.concurrent.EventExecutor";
-    }
-
-
 }
index 00f2581ae14ff82ecd6ab29e9a51c72120ad8eef..a331e4e0c1ad95245f838ebee17192e2a7c61c81 100644 (file)
@@ -17,7 +17,12 @@ package ${packageName};
 
     @Override
     public final boolean isModuleImplementingServiceInterface(Class<? extends ${abstractServiceInterfaceType}> serviceInterface) {
-        return serviceIfcs.contains(serviceInterface);
+        for (Class<?> ifc: serviceIfcs) {
+            if (serviceInterface.isAssignableFrom(ifc)){
+                return true;
+            }
+        }
+        return false;
     }
 
     @Override
index 282dff0ec621a50e46ba107d73627ca4152e7aba..556abad7af2b9b80f4623cca42c4411f7191e974 100644 (file)
@@ -748,8 +748,10 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
                 // available if source level is 5.0
                 if (c.getID() == 1610613329)
                     continue;
+                if (c.getID() == 1610613328) // 'for each' statements are only available if source level is 5.0
+                    continue;
                 fail("Error in generated source code " + file + ":"
-                        + c.getSourceLineNumber() + " " + c.toString());
+                        + c.getSourceLineNumber() + " id: " + c.getID() + " message:"  + c.toString());
             }
 
             ASTVisitor visitor = verifiers.get(file.getName());
index 9b103df8d7f8900e7e474bf0e777ec30805670f4..382dced3e754b08e8f4c593b3fca2ae9bcb11eaf 100644 (file)
@@ -13,7 +13,7 @@
 
     <dependencies>
         <dependency>
-            <groupId>org.opendaylight.controller</groupId>
+            <groupId>${project.groupId}</groupId>
             <artifactId>yang-jmx-generator</artifactId>
         </dependency>
     </dependencies>
@@ -31,7 +31,6 @@
                         </Import-Package>
                         <Export-Package>
                             org.opendaylight.controller.config.yang.store.api,
-                            org.opendaylight.controller.config.yang.store.spi
                         </Export-Package>
                     </instructions>
                 </configuration>
index 3ac4b84fdb2e1b203d9508dfb01f16b0db76af08..15619a88cc41b3ac88e59469b3e72563de0e1b5c 100644 (file)
@@ -7,8 +7,6 @@
  */
 package org.opendaylight.controller.config.yang.store.api;
 
-import org.opendaylight.controller.config.yang.store.spi.YangStoreListener;
-
 /**
  * Yang store OSGi service
  */
@@ -21,10 +19,4 @@ public interface YangStoreService {
      */
     YangStoreSnapshot getYangStoreSnapshot() throws YangStoreException;
 
-
-    /**
-     * Allows for registering for change notifications.
-     */
-    YangStoreListenerRegistration registerListener(YangStoreListener listener);
-
 }
diff --git a/opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/spi/YangStoreListener.java b/opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/spi/YangStoreListener.java
deleted file mode 100644 (file)
index 72c3d34..0000000
+++ /dev/null
@@ -1,23 +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.yang.store.spi;
-
-import java.net.URL;
-import java.util.Collection;
-
-/**
- * Implementation of this interface gets notified when bundle containing yang files in META-INF/yang has been
- * added or removed. One notification is sent per one bundle.
- */
-public interface YangStoreListener {
-
-    void onAddedYangURL(Collection<URL> url);
-
-    void onRemovedYangURL(Collection<URL> url);
-
-}
index ae59dde26ca461ee844df5486ae50fd6367a76b9..7b79c831f84477253bdcf647303631ebdc8e2f13 100644 (file)
             <artifactId>mockito-configuration</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.google.code.findbugs</groupId>
+            <artifactId>jsr305</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-                        <Bundle-Activator>org.opendaylight.controller.config.yang.store.impl.YangStoreActivator
-                        </Bundle-Activator>
-                        <Private-Package>
-                            org.opendaylight.controller.config.yang.store.impl,
-                        </Private-Package>
-
+                        <Bundle-Activator>org.opendaylight.controller.config.yang.store.impl.YangStoreActivator</Bundle-Activator>
                         <Import-Package>
                             org.opendaylight.controller.config.yang.store.api,
-                            org.opendaylight.controller.config.yang.store.spi,
                             org.opendaylight.controller.config.yangjmxgenerator,
                             com.google.common.base,
                             com.google.common.collect,
@@ -76,7 +74,7 @@
                             org.opendaylight.yangtools.yang.common,
                             org.opendaylight.yangtools.yang.model.api,
                             org.opendaylight.yangtools.sal.binding.generator.spi,
-                            org.opendaylight.yangtools.yang.parser.impl
+                            org.opendaylight.yangtools.yang.parser.impl,
                         </Import-Package>
                         <Export-Package>
                         </Export-Package>
@@ -16,24 +16,27 @@ import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Sets;
 import org.opendaylight.controller.config.yang.store.api.YangStoreException;
-import org.opendaylight.controller.config.yang.store.api.YangStoreListenerRegistration;
 import org.opendaylight.controller.config.yang.store.api.YangStoreService;
 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
-import org.opendaylight.controller.config.yang.store.spi.YangStoreListener;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
-import org.osgi.util.tracker.BundleTrackerCustomizer;
+import org.osgi.util.tracker.BundleTracker;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.annotation.concurrent.GuardedBy;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.List;
 import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * Note on consistency:
@@ -41,10 +44,9 @@ import java.util.Set;
  * is not preserved. We thus maintain two maps, one containing consistent snapshot, other inconsistent. The
  * container should eventually send all events and thus making the inconsistent map redundant.
  */
-public class ExtenderYangTrackerCustomizer implements BundleTrackerCustomizer<Object>, YangStoreService {
+public class ExtenderYangTracker extends BundleTracker<Object> implements YangStoreService, AutoCloseable {
 
-    private static final Logger logger = LoggerFactory
-            .getLogger(ExtenderYangTrackerCustomizer.class);
+    private static final Logger logger = LoggerFactory.getLogger(ExtenderYangTracker.class);
 
     private final Multimap<Bundle, URL> consistentBundlesToYangURLs = HashMultimap.create();
 
@@ -55,20 +57,25 @@ public class ExtenderYangTrackerCustomizer implements BundleTrackerCustomizer<Ob
 
     private final YangStoreCache cache = new YangStoreCache();
     private final MbeParser mbeParser;
-    private final List<YangStoreListener> listeners = new ArrayList<>();
 
-    public ExtenderYangTrackerCustomizer() {
-        this(new MbeParser());
 
+    public ExtenderYangTracker(Optional<Pattern> maybeBlacklist, BundleContext bundleContext) {
+        this(new MbeParser(), maybeBlacklist, bundleContext);
     }
 
+    @GuardedBy("this")
+    private Optional<Pattern> maybeBlacklist;
+
     @VisibleForTesting
-    ExtenderYangTrackerCustomizer(MbeParser mbeParser) {
+    ExtenderYangTracker(MbeParser mbeParser, Optional<Pattern> maybeBlacklist, BundleContext bundleContext) {
+        super(bundleContext, BundleEvent.RESOLVED | BundleEvent.UNRESOLVED, null);
         this.mbeParser = mbeParser;
+        this.maybeBlacklist = maybeBlacklist;
+        open();
     }
 
     @Override
-    public Object addingBundle(Bundle bundle, BundleEvent event) {
+    public synchronized Object addingBundle(Bundle bundle, BundleEvent event) {
 
         // Ignore system bundle:
         // system bundle might have config-api on classpath &&
@@ -77,6 +84,14 @@ public class ExtenderYangTrackerCustomizer implements BundleTrackerCustomizer<Ob
         if (bundle.getBundleId() == 0)
             return bundle;
 
+        if (maybeBlacklist.isPresent()) {
+            Matcher m = maybeBlacklist.get().matcher(bundle.getSymbolicName());
+            if (m.matches()) {
+                logger.debug("Ignoring {} because it is in blacklist {}", bundle, maybeBlacklist);
+                return bundle;
+            }
+        }
+
         Enumeration<URL> enumeration = bundle.findEntries("META-INF/yang", "*.yang", false);
         if (enumeration != null && enumeration.hasMoreElements()) {
             synchronized (this) {
@@ -90,8 +105,32 @@ public class ExtenderYangTrackerCustomizer implements BundleTrackerCustomizer<Ob
                 Multimap<Bundle, URL> proposedNewState = HashMultimap.create(consistentBundlesToYangURLs);
                 proposedNewState.putAll(inconsistentBundlesToYangURLs);
                 proposedNewState.putAll(bundle, addedURLs);
-                boolean adding = true;
-                if (tryToUpdateState(addedURLs, proposedNewState, adding) == false) {
+
+                Preconditions.checkArgument(addedURLs.size() > 0, "No change can occur when no URLs are changed");
+                boolean success;
+                String failureReason = null;
+                try(YangStoreSnapshotImpl snapshot = createSnapshot(mbeParser, proposedNewState)) {
+                    updateCache(snapshot);
+                    success = true;
+                } catch(YangStoreException e) {
+                    failureReason = e.toString();
+                    success = false;
+                }
+                if (success){
+                    // consistent state
+                    // merge into
+                    consistentBundlesToYangURLs.clear();
+                    consistentBundlesToYangURLs.putAll(proposedNewState);
+                    inconsistentBundlesToYangURLs.clear();
+
+                    logger.info("Yang store updated to new consistent state containing {} yang files", consistentBundlesToYangURLs.size());
+                    logger.trace("Yang store updated to new consistent state containing {}", consistentBundlesToYangURLs);
+                } else {
+                    // inconsistent state
+                    logger.debug("Yang store is falling back on last consistent state containing {}, inconsistent yang files {}, reason {}",
+                            consistentBundlesToYangURLs, inconsistentBundlesToYangURLs, failureReason);
+                    logger.warn("Yang store is falling back on last consistent state containing {} files, inconsistent yang files size is {}, reason {}",
+                            consistentBundlesToYangURLs.size(), inconsistentBundlesToYangURLs.size(), failureReason);
                     inconsistentBundlesToYangURLs.putAll(bundle, addedURLs);
                 }
             }
@@ -99,30 +138,7 @@ public class ExtenderYangTrackerCustomizer implements BundleTrackerCustomizer<Ob
         return bundle;
     }
 
-    private synchronized boolean tryToUpdateState(Collection<URL> changedURLs, Multimap<Bundle, URL> proposedNewState, boolean adding) {
-        Preconditions.checkArgument(changedURLs.size() > 0, "No change can occur when no URLs are changed");
-        try(YangStoreSnapshot snapshot = createSnapshot(mbeParser, proposedNewState)) {
-            // consistent state
-            // merge into
-            consistentBundlesToYangURLs.clear();
-            consistentBundlesToYangURLs.putAll(proposedNewState);
-            inconsistentBundlesToYangURLs.clear();
-            // update cache
-            updateCache(snapshot);
-            logger.info("Yang store updated to new consistent state");
-            logger.trace("Yang store updated to new consistent state containing {}", consistentBundlesToYangURLs);
-
-            notifyListeners(changedURLs, adding);
-            return true;
-        } catch(YangStoreException e) {
-            // inconsistent state
-            logger.debug("Yang store is falling back on last consistent state containing {}, inconsistent yang files {}, reason {}",
-                    consistentBundlesToYangURLs, inconsistentBundlesToYangURLs, e.toString());
-            return false;
-        }
-    }
-
-    private void updateCache(YangStoreSnapshot snapshot) {
+    private void updateCache(YangStoreSnapshotImpl snapshot) {
         cache.cacheYangStore(consistentBundlesToYangURLs, snapshot);
     }
 
@@ -131,31 +147,6 @@ public class ExtenderYangTrackerCustomizer implements BundleTrackerCustomizer<Ob
         logger.debug("Modified bundle {} {} {}", bundle, event, object);
     }
 
-    /**
-     * Notifiers get only notified when consistent snapshot has changed.
-     */
-    private void notifyListeners(Collection<URL> changedURLs, boolean adding) {
-        Preconditions.checkArgument(changedURLs.size() > 0, "Cannot notify when no URLs changed");
-        if (changedURLs.size() > 0) {
-            RuntimeException potential = new RuntimeException("Error while notifying listeners");
-            for (YangStoreListener listener : listeners) {
-                try {
-                    if (adding) {
-                        listener.onAddedYangURL(changedURLs);
-                    } else {
-                        listener.onRemovedYangURL(changedURLs);
-                    }
-                } catch(RuntimeException e) {
-                    potential.addSuppressed(e);
-                }
-            }
-            if (potential.getSuppressed().length > 0) {
-                throw potential;
-            }
-        }
-    }
-
-
     /**
      * If removing YANG files makes yang store inconsistent, method {@link #getYangStoreSnapshot()}
      * will throw exception. There is no rollback.
@@ -163,31 +154,25 @@ public class ExtenderYangTrackerCustomizer implements BundleTrackerCustomizer<Ob
     @Override
     public synchronized void removedBundle(Bundle bundle, BundleEvent event, Object object) {
         inconsistentBundlesToYangURLs.removeAll(bundle);
-        Collection<URL> consistentURLsToBeRemoved = consistentBundlesToYangURLs.removeAll(bundle);
-
-        if (consistentURLsToBeRemoved.isEmpty()){
-            return; // no change
-        }
-        boolean adding = false;
-        notifyListeners(consistentURLsToBeRemoved, adding);
+        consistentBundlesToYangURLs.removeAll(bundle);
     }
 
     @Override
     public synchronized YangStoreSnapshot getYangStoreSnapshot()
             throws YangStoreException {
-        Optional<YangStoreSnapshot> yangStoreOpt = cache.getCachedYangStore(consistentBundlesToYangURLs);
+        Optional<YangStoreSnapshot> yangStoreOpt = cache.getSnapshotIfPossible(consistentBundlesToYangURLs);
         if (yangStoreOpt.isPresent()) {
             logger.trace("Returning cached yang store {}", yangStoreOpt.get());
             return yangStoreOpt.get();
         }
-        YangStoreSnapshot snapshot = createSnapshot(mbeParser, consistentBundlesToYangURLs);
+        YangStoreSnapshotImpl snapshot = createSnapshot(mbeParser, consistentBundlesToYangURLs);
         updateCache(snapshot);
         return snapshot;
     }
 
-    private static YangStoreSnapshot createSnapshot(MbeParser mbeParser, Multimap<Bundle, URL> multimap) throws YangStoreException {
+    private static YangStoreSnapshotImpl createSnapshot(MbeParser mbeParser, Multimap<Bundle, URL> multimap) throws YangStoreException {
         try {
-            YangStoreSnapshot yangStoreSnapshot = mbeParser.parseYangFiles(fromUrlsToInputStreams(multimap));
+            YangStoreSnapshotImpl yangStoreSnapshot = mbeParser.parseYangFiles(fromUrlsToInputStreams(multimap));
             logger.trace("{} module entries parsed successfully from {} yang files",
                     yangStoreSnapshot.countModuleMXBeanEntries(), multimap.values().size());
             return yangStoreSnapshot;
@@ -213,44 +198,46 @@ public class ExtenderYangTrackerCustomizer implements BundleTrackerCustomizer<Ob
                 });
     }
 
-    @Override
-    public synchronized YangStoreListenerRegistration registerListener(final YangStoreListener listener) {
-        listeners.add(listener);
-        return new YangStoreListenerRegistration() {
-            @Override
-            public void close() {
-                listeners.remove(listener);
-            }
-        };
+    public synchronized void setMaybeBlacklist(Optional<Pattern> maybeBlacklistPattern) {
+        maybeBlacklist = maybeBlacklistPattern;
+        cache.invalidate();
     }
+}
 
-    private static final class YangStoreCache {
-
-        Set<URL> cachedUrls;
-        YangStoreSnapshot cachedYangStoreSnapshot;
-
-        Optional<YangStoreSnapshot> getCachedYangStore(
-                Multimap<Bundle, URL> bundlesToYangURLs) {
-            Set<URL> urls = setFromMultimapValues(bundlesToYangURLs);
-            if (cachedUrls != null && cachedUrls.equals(urls)) {
-                Preconditions.checkState(cachedYangStoreSnapshot != null);
-                return Optional.of(cachedYangStoreSnapshot);
-            }
-            return Optional.absent();
+class YangStoreCache {
+    @GuardedBy("this")
+    private Set<URL> cachedUrls = Collections.emptySet();
+    @GuardedBy("this")
+    private Optional<YangStoreSnapshotImpl> cachedYangStoreSnapshot = Optional.absent();
+
+    synchronized Optional<YangStoreSnapshot> getSnapshotIfPossible(Multimap<Bundle, URL> bundlesToYangURLs) {
+        Set<URL> urls = setFromMultimapValues(bundlesToYangURLs);
+        if (cachedUrls != null && cachedUrls.equals(urls)) {
+            Preconditions.checkState(cachedYangStoreSnapshot.isPresent());
+            YangStoreSnapshot freshSnapshot = new YangStoreSnapshotImpl(cachedYangStoreSnapshot.get());
+            return Optional.of(freshSnapshot);
         }
+        return Optional.absent();
+    }
 
-        private static Set<URL> setFromMultimapValues(
-                Multimap<Bundle, URL> bundlesToYangURLs) {
-            Set<URL> urls = Sets.newHashSet(bundlesToYangURLs.values());
-            Preconditions.checkState(bundlesToYangURLs.size() == urls.size());
-            return urls;
-        }
+    private static Set<URL> setFromMultimapValues(
+            Multimap<Bundle, URL> bundlesToYangURLs) {
+        Set<URL> urls = Sets.newHashSet(bundlesToYangURLs.values());
+        Preconditions.checkState(bundlesToYangURLs.size() == urls.size());
+        return urls;
+    }
 
-        void cacheYangStore(Multimap<Bundle, URL> urls,
-                YangStoreSnapshot yangStoreSnapshot) {
-            this.cachedUrls = setFromMultimapValues(urls);
-            this.cachedYangStoreSnapshot = yangStoreSnapshot;
-        }
+    synchronized void cacheYangStore(Multimap<Bundle, URL> urls,
+                        YangStoreSnapshotImpl yangStoreSnapshot) {
+        this.cachedUrls = setFromMultimapValues(urls);
+        this.cachedYangStoreSnapshot = Optional.of(yangStoreSnapshot);
+    }
 
+    synchronized void invalidate() {
+        cachedUrls.clear();
+        if (cachedYangStoreSnapshot.isPresent()){
+            cachedYangStoreSnapshot.get().close();
+            cachedYangStoreSnapshot = Optional.absent();
+        }
     }
 }
index fc895eb51dcb25ba4e381ef3cac7d7b7d49d0479..211da6bfefdc62df10906eff27b30655e90eb790 100644 (file)
@@ -7,19 +7,11 @@
  */
 package org.opendaylight.controller.config.yang.store.impl;
 
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import org.apache.commons.io.IOUtils;
 import org.opendaylight.controller.config.yang.store.api.YangStoreException;
-import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.PackageTranslator;
 import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
@@ -30,13 +22,19 @@ import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 public class MbeParser {
 
-    public YangStoreSnapshot parseYangFiles(
+    public YangStoreSnapshotImpl parseYangFiles(
             Collection<? extends InputStream> allInput)
             throws YangStoreException {
         YangParserImpl parser = new YangParserImpl();
index a358e5f7c1e0bc7080fd674effe18d24ffc9703d..a25b05ab8aa92225df6d1ec1f7782a70efef640b 100644 (file)
@@ -7,50 +7,40 @@
  */
 package org.opendaylight.controller.config.yang.store.impl;
 
-import java.util.Dictionary;
-import java.util.Hashtable;
-
+import com.google.common.base.Optional;
 import org.opendaylight.controller.config.yang.store.api.YangStoreService;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.util.tracker.BundleTracker;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class YangStoreActivator implements BundleActivator {
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.regex.Pattern;
 
-    private BundleTracker bundleTracker;
-    private ServiceRegistration<YangStoreService> registration;
-    private static final Logger logger = LoggerFactory
-            .getLogger(YangStoreActivator.class);
+public class YangStoreActivator implements BundleActivator {
+    private static final Logger logger = LoggerFactory.getLogger(YangStoreActivator.class);
 
     @Override
     public void start(BundleContext context) throws Exception {
-        ExtenderYangTrackerCustomizer customizerAndService = new ExtenderYangTrackerCustomizer();
-        bundleTracker = new BundleTracker(context, BundleEvent.RESOLVED | BundleEvent.UNRESOLVED, customizerAndService);
-        bundleTracker.open();
-
+        // get blacklist
+        Optional<Pattern> maybeBlacklistPattern = Optional.absent();
+        String blacklist = context.getProperty("yangstore.blacklist");
+        if (blacklist != null) {
+            try {
+                maybeBlacklistPattern = Optional.of(Pattern.compile(blacklist));
+            } catch (RuntimeException e) {
+                logger.error("Cannot parse blacklist regex " + blacklist, e);
+                throw e;
+            }
+        }
+        ExtenderYangTracker extenderYangTracker = new ExtenderYangTracker(maybeBlacklistPattern, context);
         Dictionary<String, ?> properties = new Hashtable<>();
-        registration = context.registerService(YangStoreService.class,
-                customizerAndService, properties);
+        context.registerService(YangStoreService.class, extenderYangTracker, properties);
     }
 
     @Override
     public void stop(BundleContext context) throws Exception {
-        try {
-            bundleTracker.close();
-        } catch (Exception e) {
-            logger.warn("Exception while closing bundleTracker", e);
-        }
-        if (registration != null) {
-            try {
-                registration.unregister();
-            } catch (Exception e) {
-                logger.warn("Exception while unregistring yang store service",
-                        e);
-            }
-        }
+
     }
 }
index d5169eac38b2d97982ef6a9227933662450687c3..7a5ca7debe8c3d4379e1c03812afcabac3ee1390 100644 (file)
@@ -7,32 +7,31 @@
  */
 package org.opendaylight.controller.config.yang.store.impl;
 
-import java.util.Map;
-import java.util.Map.Entry;
-
 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.yangtools.yang.model.api.Module;
 
+import java.util.Collections;
+import java.util.Map;
+import java.util.Map.Entry;
+
 public class YangStoreSnapshotImpl implements YangStoreSnapshot {
 
-    private final Map<String /* Namespace from yang file */, Map<String /*
-                                                                         * Name
-                                                                         * of
-                                                                         * module
-                                                                         * entry
-                                                                         * from
-                                                                         * yang
-                                                                         * file
-                                                                         */, ModuleMXBeanEntry>> moduleMXBeanEntryMap;
+    private final Map<String /* Namespace from yang file */,
+            Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> moduleMXBeanEntryMap;
 
     private final Map<String, Entry<Module, String>> moduleMap;
 
     public YangStoreSnapshotImpl(
             Map<String, Map<String, ModuleMXBeanEntry>> moduleMXBeanEntryMap,
             Map<String, Entry<Module, String>> moduleMap) {
-        this.moduleMXBeanEntryMap = moduleMXBeanEntryMap;
-        this.moduleMap = moduleMap;
+        this.moduleMXBeanEntryMap = Collections.unmodifiableMap(moduleMXBeanEntryMap);
+        this.moduleMap = Collections.unmodifiableMap(moduleMap);
+    }
+
+    public YangStoreSnapshotImpl(YangStoreSnapshotImpl yangStoreSnapshot) {
+        this.moduleMXBeanEntryMap = yangStoreSnapshot.moduleMXBeanEntryMap;
+        this.moduleMap = yangStoreSnapshot.moduleMap;
     }
 
     @Override
index 427da1f634cd6c3ac657bf71b6ef4926f3b5b023..c4c523992f271391b33f6220b9f49fc28a4fc4ca 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.config.yang.store.impl;
 
+import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import org.junit.Before;
 import org.junit.Test;
@@ -15,14 +16,19 @@ import org.mockito.MockitoAnnotations;
 import org.opendaylight.controller.config.yang.store.api.YangStoreException;
 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleListener;
 
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.List;
+import java.util.regex.Pattern;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyCollectionOf;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -34,22 +40,26 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
 public class ExtenderYangTrackerCustomizerTest {
 
 
-    private ExtenderYangTrackerCustomizer tested;
+    private ExtenderYangTracker tested;
     @Mock
     private MbeParser parser;
     @Mock
-    private YangStoreSnapshot yangStoreSnapshot;
+    private YangStoreSnapshotImpl yangStoreSnapshot;
+    @Mock
+    private BundleContext bundleContext;
 
     @Before
     public void setUp() throws YangStoreException {
         MockitoAnnotations.initMocks(this);
-
-        tested = new ExtenderYangTrackerCustomizer(parser);
+        doNothing().when(bundleContext).addBundleListener(any(BundleListener.class));
+        doReturn(new Bundle[0]).when(bundleContext).getBundles();
+        tested = new ExtenderYangTracker(parser, Optional.<Pattern>absent(), bundleContext);
         doReturn(yangStoreSnapshot).when(parser).parseYangFiles(
                 anyCollectionOf(InputStream.class));
         doReturn(22).when(yangStoreSnapshot).countModuleMXBeanEntries();
         doReturn("mock yang store").when(yangStoreSnapshot).toString();
         doNothing().when(yangStoreSnapshot).close();
+        doReturn(Collections.emptyMap()).when(yangStoreSnapshot).getModuleMap();
     }
 
     @Test
@@ -73,17 +83,15 @@ public class ExtenderYangTrackerCustomizerTest {
         bundle = getMockedBundle(10, false);
         tested.addingBundle(bundle, null);
 
-        for(int i = 0; i< 10; i++){
+        for(int i = 0; i< 20; i++){
             tested.getYangStoreSnapshot();
         }
 
-        verify(parser, times(5)).parseYangFiles(
-                anyCollectionOf(InputStream.class));
+        verify(parser, times(7)).parseYangFiles(anyCollectionOf(InputStream.class));
 
         returnedStore = tested.getYangStoreSnapshot();
 
         verifyNoMoreInteractions(parser);
-        assertEquals(yangStoreSnapshot, returnedStore);
     }
 
     int bundleCounter = 1;
@@ -106,6 +114,7 @@ public class ExtenderYangTrackerCustomizerTest {
             doReturn(1L).when(mock).getBundleId();
 
         doReturn("mockedBundle").when(mock).toString();
+        doReturn("mockedBundle").when(mock).getSymbolicName();
 
         return mock;
     }
index 844f682b7a6348a2e86cecceb35e010772e5074e..6221682147e86eea464e3f25abb066d0bfa4d3aa 100644 (file)
@@ -7,7 +7,10 @@
  */
 package org.opendaylight.controller.config.yang.store.impl;
 
-import static org.junit.Assert.assertNotNull;
+import org.apache.commons.io.IOUtils;
+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 java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -15,12 +18,7 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collection;
 
-import org.apache.commons.io.IOUtils;
-import org.opendaylight.controller.config.yang.store.api.YangStoreException;
-import org.opendaylight.controller.config.yang.store.api.YangStoreListenerRegistration;
-import org.opendaylight.controller.config.yang.store.api.YangStoreService;
-import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
-import org.opendaylight.controller.config.yang.store.spi.YangStoreListener;
+import static org.junit.Assert.assertNotNull;
 
 public class HardcodedYangStoreService implements YangStoreService {
 
@@ -50,9 +48,4 @@ public class HardcodedYangStoreService implements YangStoreService {
         }
         return new MbeParser().parseYangFiles(byteArrayInputStreams);
     }
-
-    @Override
-    public YangStoreListenerRegistration registerListener(YangStoreListener listener){
-        throw new UnsupportedOperationException("Cannot register for changes on this service");
-    }
 }
index e5c8a975873d11fd25da0758762660cac0eafb43..74a133f9139261d9741183337034b4c9c791b4f5 100644 (file)
           <artifactId>inventory-manager</artifactId>
           <version>${mdsal.version}</version>
         </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller.md</groupId>
+          <artifactId>forwardingrules-manager</artifactId>
+          <version>${mdsal.version}</version>
+        </dependency>
 
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
             <version>1.2.0</version>
         </dependency>
 
+         <!-- threadpool -->
+          <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>threadpool-config-api</artifactId>
+              <version>${config.version}</version>
+          </dependency>
+          <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>netty-config-api</artifactId>
+              <version>${config.version}</version>
+          </dependency>
+          <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>threadpool-config-impl</artifactId>
+              <version>${config.version}</version>
+          </dependency>
+          <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>netty-threadgroup-config</artifactId>
+              <version>${config.version}</version>
+          </dependency>
+          <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>netty-event-executor-config</artifactId>
+              <version>${config.version}</version>
+          </dependency>
+          <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>netty-timer-config</artifactId>
+              <version>${config.version}</version>
+          </dependency>
+
+
           <!-- toaster example I'm pretty sure we should trim -->
          <dependency>
           <groupId>org.opendaylight.controller.samples</groupId>
index caf9d095914413477ef2888501e0dd53e473559e..dacdd2546ef235fda3453c10d522294b297348a0 100644 (file)
@@ -14,7 +14,7 @@ osgi.bundles=\
     reference\:file\:../lib/jersey-server-1.17.jar@2:start
 
 # Netconf startup configuration
-netconf.tcp.address=127.0.0.1
+netconf.tcp.address=0.0.0.0
 netconf.tcp.port=8383
 
 #netconf.tls.address=127.0.0.1
@@ -23,6 +23,7 @@ netconf.tcp.port=8383
 #netconf.tls.keystore.password=
 
 netconf.config.persister.storageAdapterClass=org.opendaylight.controller.netconf.persist.impl.NoOpStorageAdapter
+yangstore.blacklist=.*controller.model.*
 
 # Set Default start level for framework
 osgi.bundles.defaultStartLevel=4
diff --git a/opendaylight/forwardingrulesmanager_mdsal/openflow/pom.xml b/opendaylight/forwardingrulesmanager_mdsal/openflow/pom.xml
deleted file mode 100644 (file)
index 11f2305..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <parent>
-    <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
-    <version>1.4.1-SNAPSHOT</version>
-    <relativePath>../../commons/opendaylight</relativePath>
-  </parent>
-  <scm>
-    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
-    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
-    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
-    <tag>HEAD</tag>
-  </scm>
-
-  <artifactId>forwardingrulesmanager_mdsal</artifactId>
-  <version>1.0-SNAPSHOT</version>
-  <packaging>bundle</packaging>
-
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <version>${bundle.plugin.version}</version>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Embed-Transitive>
-              false
-            </Embed-Transitive>
-            <Bundle-Activator>
-              org.opendaylight.controller.forwardingrulesmanager_mdsal.consumer.impl.FRMConsumerImpl
-            </Bundle-Activator>
-          </instructions>
-          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>equinoxSDK381</groupId>
-      <artifactId>org.eclipse.osgi</artifactId>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>sal-binding-api</artifactId>
-      <version>1.0-SNAPSHOT</version>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>flow-management-compatibility</artifactId>
-      <version>1.0-SNAPSHOT</version>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller.model</groupId>
-      <artifactId>model-flow-service</artifactId>
-      <version>1.0-SNAPSHOT</version>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller.model</groupId>
-      <artifactId>model-flow-management</artifactId>
-      <version>1.0-SNAPSHOT</version>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>sal-binding-broker-impl</artifactId>
-      <version>1.0-SNAPSHOT</version>
-      <scope>provided</scope>
-    </dependency>
-  </dependencies>
-</project>
index d462251a9fb55b4d1aba050e200d31cf06071a84..bbad85b35f9b4b99a10c937d1fa2e833930c4ad2 100644 (file)
@@ -108,7 +108,7 @@ class ConfigurationReader implements FlowManagementReader {
     }
 
     override readFlow(FlowKey key) {
-        val flowCfg = manager.getStaticFlow(key.id,key.node.toADNode());
+        val flowCfg = manager.getStaticFlow(String.valueOf(key.id), key.node.toADNode());
         return flowCfg.toConfigurationFlow;
     }
 }
index e4d917337848967a0917e24538bcb28348f11184..ef806f33efbba82955e093bc47c035730800c586 100644 (file)
@@ -24,14 +24,14 @@ class FlowConfigMapping {
         idleTimeout = source.idleTimeout
         match = source.match
         node = source.node
-        key = new FlowKey(sourceCfg.name,node);
+        key = new FlowKey(Long.parseLong(sourceCfg.name),node);
         return it.build();
     }
 
     static def toFlowConfig(Flow sourceCfg) {
         val flow = toFlow(sourceCfg);
         val it = new FlowConfig;
-        name = sourceCfg.key.id
+        name = String.valueOf(sourceCfg.id);
         node = sourceCfg.node.toADNode();
 
         return it
@@ -40,7 +40,7 @@ class FlowConfigMapping {
     static def toFlowConfig(InstanceIdentifier<?> identifier) {
         val it = new FlowConfig()
         val FlowKey key = ((identifier.path.get(2) as IdentifiableItem<Flow,FlowKey>).key)
-        name = key.id;
+        name = String.valueOf(key.id);
         node = key.node.toADNode();
 
         return it;
index a82eedc3f95156c0980e7f5ce580faf6a16387c8..2fbe0a02025bbff6afc0eb020fa59fb6587dcc50 100644 (file)
@@ -31,7 +31,7 @@ public class SampleConsumer {
 
     Flow createSampleFlow(String name, NodeRef node) {
         FlowBuilder ret = new FlowBuilder();
-        FlowKey key = new FlowKey(name, node);
+        FlowKey key = new FlowKey(Long.parseLong(name), node);
         ret.setKey(key);
         return ret.build();
     }
diff --git a/opendaylight/md-sal/forwardingrules-manager/pom.xml b/opendaylight/md-sal/forwardingrules-manager/pom.xml
new file mode 100644 (file)
index 0000000..b5f5402
--- /dev/null
@@ -0,0 +1,73 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <groupId>org.opendaylight.controller.md</groupId>
+    <artifactId>forwardingrules-manager</artifactId>
+    <packaging>bundle</packaging>
+    
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+        <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+    </scm>
+  
+        <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>org.opendaylight.controller.forwardingrulesmanager.consumer.impl.FRMConsumerImpl</Bundle-Activator>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.eclipse.xtend</groupId>
+                <artifactId>xtend-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <artifactId>maven-clean-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+  
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>    
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-api</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>flow-management-compatibility</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-flow-service</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-flow-management</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-broker-impl</artifactId>
+      <version>1.0-SNAPSHOT</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+</project>
index 5bfe54e4c32a7132a0fe8e8e9c53908e0e4f6aa0..3850dd551fd42abd8725a7262952235efd13c980 100644 (file)
@@ -5,7 +5,7 @@ module opendaylight-action-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-l2-types {prefix l2t; revision-date "2013-08-27";}
-    import opendaylight-match-types {prefix match; revision-date 2013-10-26";}
+    import opendaylight-match-types {prefix match; revision-date "2013-10-26";}
     
     revision "2013-11-12" {
         description "Initial revision of action service";
index 8338d185cc36abbbbc34613fe1e3df84d805550a..f0b7e97a15ff5b2a221ed9e15212b7516459de7f 100644 (file)
@@ -8,7 +8,14 @@ module opendaylight-port-types {
     revision "2013-09-25" {
         description "Initial revision of Port Inventory model";
     }
-
+    
+    typedef port-reason {
+        type enumeration {
+            enum add;
+            enum delete;
+            enum update;
+        }
+    }
     
     typedef port-config {
         type bits {
@@ -26,7 +33,6 @@ module opendaylight-port-types {
             enum live;
         }
     }
-
     
     typedef port-features {
         type bits {
@@ -72,6 +78,14 @@ module opendaylight-port-types {
         }
     }
     
+    grouping flow-port-status {
+        leaf reason {
+            type port-reason;
+        }
+        
+        uses flow-capable-port;
+    }
+    
     grouping flow-capable-port {    
                 
         uses common-port;
@@ -114,7 +128,7 @@ module opendaylight-port-types {
         }
     }    
     
-    grouping ofp-port-mod {
+    grouping port-mod {
         container port {
             list port {
                 key "port-mod-order";
index 7361358aff2d65c18346db532e74ba9268a465e5..1c57142997f05279780d5931a058b4f5ed96f896 100644 (file)
@@ -23,7 +23,7 @@ module flow-management {
             key "node id"; 
 
             leaf id {
-                type string;
+                type uint32;
             }
             uses flow:flow-entry;
         }
index 48dda2edcd9435a40e9230caf68ea797912bd0a3..2fc051087d38c099af6e0189a86ef1b0711aecf2 100644 (file)
@@ -22,7 +22,7 @@ module group-management {
             key "id node"; 
                         
             leaf id {
-                type string;
+                type uint32;
             }                       
             
             uses group-entry;
index 111d3d60faaf29fcfff6e93f05be3bad10b089e5..35d4550ebf7a472cdd0b054f9f73cc181d9cb8fa 100644 (file)
@@ -22,7 +22,7 @@ module meter-management {
             key "id node"; 
                         
             leaf id {
-                type string;
+                type uint32;
             }                    
             
             uses meter-entry;
index 945cc32ab5d33bb194d10e9ff63d971d573495fb..50762b87ce821411583acffa86418e656539c99c 100644 (file)
@@ -14,7 +14,7 @@ module port-management {
         leaf node {
             type inv:node-ref;
         }
-        uses port:ofp-port-mod;
+        uses port:port-mod;
     }   
      
     container ports {
@@ -22,7 +22,7 @@ module port-management {
             key "id node"; 
                         
             leaf id {
-                type string;
+                type uint32;
             }                       
             
             uses port-entry;
index 88dcfce91c43c1f515e7067db045e7b2b6ee611b..512fb6528bbc6320ec1b6de699fa4c7c9e08b896 100644 (file)
@@ -23,7 +23,7 @@ module table-management {
             key "id node"; 
                         
             leaf id {
-                type string;
+                type uint32;
             }                    
             
             uses table-entry;
index 171f9563ee318c7c78c8c05f9e6ed701ef771457..369b279b95264a317ae51001f016290bbdac79cb 100644 (file)
@@ -16,13 +16,15 @@ module flow-errors {
             enum flow-mod-failed;
             enum group-mod-failed;
             enum port-mod-failed;
-            enum table-mod-failed;
-            enum meter-mod-failed;
+            enum table-mod-failed;            
             enum queue-op-failed;
             enum switch-config-failed;
             enum role-request-failed;
+            enum meter-mod-failed;
             enum table-features-failed;
-            enum experimenter;
+            enum experimenter {
+                value "65535";
+            }
         }
     }
     
index df0b2527b8731c4036d902d481d7adee1b1e7233..a32a45f2fdfea5cb5ce894c9c569942e0752d48e 100644 (file)
@@ -97,9 +97,11 @@ module sal-flow {
     
     notification node-error-notification {
         uses error:error-message;
+        uses tr:transaction-aware;
     }
     
     notification node-experimenter-error-notification {
         uses error:experimenter-error-message;
+        uses tr:transaction-aware;
     }
 }
\ No newline at end of file
index df527ef26778d41c18db40fdf08e452e6d728784..9588652a1c6cdb8fb63901f8cb4ccf72228c7b9c 100644 (file)
@@ -13,7 +13,7 @@ module sal-port {
     grouping node-port {
         uses "inv:node-context-ref";
         
-        uses port-type:ofp-port-mod;
+        uses port-type:flow-port-status;
     }
 
     /** Base configuration structure **/
@@ -21,10 +21,10 @@ module sal-port {
         uses "inv:node-context-ref";
 
         container original-port {
-            uses port-type:ofp-port-mod;
+            uses port-type:port-mod;
         }
         container updated-port {
-            uses port-type:ofp-port-mod;
+            uses port-type:port-mod;
         }
     }
 
index e6f166ac02d224f9ab57a2080851e5300e4d686c..5b565365a5894f9912fde799a5a8f1b56855094b 100644 (file)
@@ -18,7 +18,7 @@ module opendaylight-group-statistics {
     augment "/inv:nodes/inv:node" {
         ext:augment-identifier "node-group-statistics";
         container group-statistics {
-               config "false";
+               //config "false";
                uses group-types:group-statistics-reply;
         }
     }
@@ -26,7 +26,7 @@ module opendaylight-group-statistics {
        augment "/inv:nodes/inv:node" {
         ext:augment-identifier "node-group-desc-stats";
         container group-desc {
-               config "false";
+               //config "false";
                uses group-types:group-desc-stats-reply;
         }
     }
@@ -34,7 +34,7 @@ module opendaylight-group-statistics {
        augment "/inv:nodes/inv:node" {
         ext:augment-identifier "node-group-features";
         container group-features {
-               config "false";
+               //config "false";
                uses group-types:group-features-reply;
         }
     }
index b9a6c0d49b1568991dc2d9c4ccf9302112b6ed38..c22bdd3906bb801f1a2432329dff8ef9c9f40292 100644 (file)
@@ -18,7 +18,7 @@ module opendaylight-meter-statistics {
     augment "/inv:nodes/inv:node" {
         ext:augment-identifier "node-meter-statistics";
         container meter-statistics {
-               config "false";
+               //config "false";
                uses meter-types:meter-statistics-reply;
         }
     }
@@ -26,7 +26,7 @@ module opendaylight-meter-statistics {
        augment "/inv:nodes/inv:node" {
         ext:augment-identifier "node-meter-config-stats";
         container meter-config-stats {
-               config "false";
+               //config "false";
                uses meter-types:meter-config-stats-reply;
         }
     }
@@ -34,7 +34,7 @@ module opendaylight-meter-statistics {
        augment "/inv:nodes/inv:node" {
         ext:augment-identifier "node-meter-features";
         container meter-features {
-               config "false";
+               //config "false";
                uses meter-types:meter-features-reply;
         }
     }
index 3198109bc4f0d97268b3a79b559b5182ea4c7996..bdbcce0950fa449dbc43a7be562fa22bbb7f3ade 100644 (file)
 
         <module>inventory-manager</module>
         <module>statistics-manager</module>
+        <module>forwardingrules-manager</module>
+        
         <!-- Compability Packages -->
         <module>compatibility</module>
-
+        <module>zeromq-routingtable/implementation</module>
         <module>sal-zeromq-connector</module>
     </modules>
 
@@ -61,6 +63,7 @@
            </activation>
             <modules>
                 <module>sal-binding-it</module>
+                <module>zeromq-routingtable/integrationtest</module>
                 <module>clustered-data-store/integrationtest</module>
                 <module>test</module>
             </modules>
index fbd87d17beede977e4efa2b987f077352522481c..f0f92da18e5c3b2235eb77a9cf3d0e32b8df371c 100644 (file)
@@ -39,7 +39,7 @@ class RuntimeCodeHelper {
     public static def void setDelegate(RpcService proxy, RpcService delegate) {
         val field = proxy.class.getField(DELEGATE_FIELD)
         if (field == null) throw new UnsupportedOperationException("Unable to set delegate to proxy");
-        if (field.type.isAssignableFrom(delegate.class)) {
+        if (delegate == null || field.type.isAssignableFrom(delegate.class)) {
             field.set(proxy, delegate)
         } else
             throw new IllegalArgumentException("delegate class is not assignable to proxy");
@@ -55,7 +55,7 @@ class RuntimeCodeHelper {
     public static def void setDelegate(Object proxy, Object delegate) {
         val field = proxy.class.getField(DELEGATE_FIELD)
         if (field == null) throw new UnsupportedOperationException("Unable to set delegate to proxy");
-        if (field.type.isAssignableFrom(delegate.class)) {
+        if (delegate == null || field.type.isAssignableFrom(delegate.class)) {
             field.set(proxy, delegate)
         } else
             throw new IllegalArgumentException("delegate class is not assignable to proxy");
index 5b11ec72077876dbe6f2f95183977e30273b7d10..b6dcde19ee18a4ae3e05571b6c56e448d50c1794 100644 (file)
@@ -8,7 +8,6 @@ import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeC
 import java.util.Set
 import java.util.HashMap
 import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable
-import static org.opendaylight.controller.sal.binding.codegen.impl.XtendHelper.*
 import org.opendaylight.yangtools.yang.binding.DataContainer
 import org.opendaylight.yangtools.yang.binding.RpcImplementation
 
index 21b48bb47511699dfef265ed46c6c90dc2be52c6..83096514465a4814c86ad751493dec1d6e1fc156 100644 (file)
@@ -9,8 +9,4 @@ public class XtendHelper {
             Class<C> cls) {
         return new RpcRoutingTableImpl<>(cls);
     }
-    
-    public static String foo() {
-        return "Foo";
-    }
 }
index 19737b83c628caa531edb74d3fbb8bcc1531d2db..802e7acb5bb993976a8a5d04a1c1776a6c8a67c8 100644 (file)
@@ -10,10 +10,15 @@ import javassist.Modifier
 import javassist.NotFoundException
 import javassist.LoaderClassPath
 import javassist.ClassClassPath
+import java.util.concurrent.locks.Lock
+import java.util.concurrent.locks.ReentrantLock
 
 class JavassistUtils {
 
     ClassPool classPool
+    
+    @Property
+    val Lock lock = new ReentrantLock();
 
     new(ClassPool pool) {
         classPool = pool;
@@ -49,12 +54,14 @@ class JavassistUtils {
     }
 
     def CtClass createClass(String fqn, ClassGenerator cls) {
+        
         val target = classPool.makeClass(fqn);
         cls.process(target);
         return target;
     }
 
     def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) {
+        
         val target = classPool.makeClass(fqn);
         target.implementsType(superInterface);
         cls.process(target);
@@ -76,6 +83,13 @@ class JavassistUtils {
         addField(field);
         return field;
     }
+    
+    def CtField staticField(CtClass it, String name, Class<?> returnValue) {
+        val field = new CtField(returnValue.asCtClass, name, it);
+        field.modifiers = Modifier.PUBLIC + Modifier.STATIC
+        addField(field);
+        return field;
+    }
 
     def get(ClassPool pool, Class<?> cls) {
         try {
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/AugmentationCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/AugmentationCodec.java
new file mode 100644 (file)
index 0000000..cdddec7
--- /dev/null
@@ -0,0 +1,15 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public interface AugmentationCodec<A extends Augmentation<?>> extends DomCodec<A> {
+
+    
+    @Override
+    public CompositeNode serialize(ValueWithQName<A> input);
+    
+    @Override
+    public ValueWithQName<A> deserialize(Node<?> input);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCaseCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCaseCodec.java
new file mode 100644 (file)
index 0000000..d545b72
--- /dev/null
@@ -0,0 +1,16 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public interface ChoiceCaseCodec<C extends DataContainer> extends DataContainerCodec<C> {
+
+    @Override
+    public CompositeNode serialize(ValueWithQName<C> input);
+    
+    @Override
+    public ValueWithQName<C> deserialize(Node<?> input);
+    
+    public boolean isAcceptable(Node<?> input);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ChoiceCodec.java
new file mode 100644 (file)
index 0000000..21bb1cf
--- /dev/null
@@ -0,0 +1,12 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public interface ChoiceCodec<C> extends DomCodec<C> {
+
+    @Override
+    public Node<?> serialize(ValueWithQName<C> input);
+    
+    @Override
+    public ValueWithQName<C> deserialize(Node<?> input);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java
new file mode 100644 (file)
index 0000000..1a02ea1
--- /dev/null
@@ -0,0 +1,32 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec;
+
+
+public interface CodecRegistry {
+
+    InstanceIdentifierCodec getInstanceIdentifierCodec();
+
+    <T extends DataContainer> DataContainerCodec<T> getCodecForDataObject(Class<T> object);
+
+    <T extends Identifiable<?>> IdentifierCodec<?> getIdentifierCodecForIdentifiable(Class<T> object);
+
+    <T extends Identifier<?>> IdentifierCodec<T> getCodecForIdentifier(Class<T> object);
+
+    <T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object);
+
+    Class<?> getClassForPath(List<QName> names);
+
+    IdentifierCodec<?> getKeyCodecForPath(List<QName> names);
+    
+    
+    void bindingClassEncountered(Class<?> cls);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DataContainerCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DataContainerCodec.java
new file mode 100644 (file)
index 0000000..683faaf
--- /dev/null
@@ -0,0 +1,17 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public interface DataContainerCodec<T extends DataContainer> extends  DomCodec<T> {
+
+
+    @Override
+    public ValueWithQName<T> deserialize(Node<?> input);
+    
+    @Override
+    public CompositeNode serialize(ValueWithQName<T> input);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DomCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/DomCodec.java
new file mode 100644 (file)
index 0000000..76969ab
--- /dev/null
@@ -0,0 +1,17 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public interface DomCodec<I> extends BindingCodec<Node<?>, ValueWithQName<I>>{
+    
+    
+    @Override
+    public Node<?> serialize(ValueWithQName<I> input);
+    
+    
+    @Override
+    public ValueWithQName<I> deserialize(Node<?> input);
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentifierCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/IdentifierCodec.java
new file mode 100644 (file)
index 0000000..933b884
--- /dev/null
@@ -0,0 +1,14 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public interface IdentifierCodec<I extends Identifier<?>> extends DomCodec<I> {
+
+    @Override
+    public ValueWithQName<I> deserialize(Node<?> input);
+    
+    @Override
+    public CompositeNode serialize(ValueWithQName<I> input);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/InstanceIdentifierCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/InstanceIdentifierCodec.java
new file mode 100644 (file)
index 0000000..7fbb79d
--- /dev/null
@@ -0,0 +1,13 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface InstanceIdentifierCodec extends BindingCodec<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier,InstanceIdentifier<?>> {
+
+    @Override
+    public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier serialize(InstanceIdentifier<?> input);
+    
+    @Override
+    public InstanceIdentifier<?> deserialize(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier input);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ValueWithQName.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/ValueWithQName.java
new file mode 100644 (file)
index 0000000..442df01
--- /dev/null
@@ -0,0 +1,72 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.yangtools.yang.common.QName;
+
+public class ValueWithQName<V> implements Entry<QName, V>{
+    
+    final QName qname;
+    final V value;
+    
+    public ValueWithQName(QName qname, V value) {
+        super();
+        this.qname = qname;
+        this.value = value;
+    }
+
+    public QName getQname() {
+        return qname;
+    }
+
+    public V getValue() {
+        return value;
+    }
+    
+    @Override
+    public QName getKey() {
+        return qname;
+    }
+    
+    @Override
+    public V setValue(V value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+        result = prime * result + ((value == null) ? 0 : value.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        @SuppressWarnings("rawtypes")
+        ValueWithQName other = (ValueWithQName) obj;
+        if (qname == null) {
+            if (other.qname != null)
+                return false;
+        } else if (!qname.equals(other.qname))
+            return false;
+        if (value == null) {
+            if (other.value != null) {
+                return false;
+            }
+        } else if (!value.equals(other.value)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.java
new file mode 100644 (file)
index 0000000..c2b5635
--- /dev/null
@@ -0,0 +1,7 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+
+public interface BindingClassListener {
+
+    void onBindingClassCaptured(Class<?> cls);
+    
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java
new file mode 100644 (file)
index 0000000..19e9961
--- /dev/null
@@ -0,0 +1,79 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public class CodecMapping {
+
+    public static final String INSTANCE_IDENTIFIER_CODEC = "INSTANCE_IDENTIFIER_CODEC";
+    public static final String CLASS_TO_CASE_MAP = "CLASS_TO_CASE";
+    public static final String COMPOSITE_TO_CASE = "COMPOSITE_TO_CASE";
+    public static final String AUGMENTATION_CODEC = "AUGMENTATION_CODEC";
+    
+    public static void setIdentifierCodec(Class obj,InstanceIdentifierCodec codec) {
+        Field instanceIdField;
+        try {
+            instanceIdField = obj.getField(INSTANCE_IDENTIFIER_CODEC);
+            instanceIdField.set(null, codec);
+        } catch (NoSuchFieldException e) {
+           // NOOP
+        } catch (SecurityException e) {
+            // NOOP
+        } catch (IllegalAccessException e) {
+            // NOOp
+        }
+    }
+
+    public static void setClassToCaseMap(Class<? extends BindingCodec> codec,
+            Map<Class,BindingCodec> classToCaseRawCodec) {
+        Field instanceIdField;
+        try {
+            instanceIdField = codec.getField(CLASS_TO_CASE_MAP);
+            instanceIdField.set(null, classToCaseRawCodec);
+        } catch (NoSuchFieldException e) {
+           // NOOP
+        } catch (SecurityException e) {
+            // NOOP
+        } catch (IllegalAccessException e) {
+            // NOOp
+        }
+        
+        
+    }
+
+    public static void setCompositeNodeToCaseMap(Class<? extends BindingCodec> codec,
+            Map<CompositeNode,BindingCodec> compositeToCase) {
+        Field instanceIdField;
+        try {
+            instanceIdField = codec.getField(COMPOSITE_TO_CASE);
+            instanceIdField.set(null, compositeToCase);
+        } catch (NoSuchFieldException e) {
+           // NOOP
+        } catch (SecurityException e) {
+            // NOOP
+        } catch (IllegalAccessException e) {
+            // NOOp
+        }
+    }
+
+    public static void setAugmentationCodec(Class<? extends BindingCodec<Map<QName, Object>, Object>> dataCodec,
+            BindingCodec augmentableCodec) {
+            Field instanceIdField;
+            try {
+                instanceIdField = dataCodec.getField(AUGMENTATION_CODEC);
+                instanceIdField.set(null, augmentableCodec);
+            } catch (NoSuchFieldException e) {
+               // NOOP
+            } catch (SecurityException e) {
+                // NOOP
+            } catch (IllegalAccessException e) {
+                // NOOp
+            }
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecTypeUtils.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecTypeUtils.java
new file mode 100644 (file)
index 0000000..048dc3a
--- /dev/null
@@ -0,0 +1,17 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+
+public class CodecTypeUtils {
+
+    @SuppressWarnings({"unchecked","rawtypes"})
+    public static IdentifiableItem<?, ?> newIdentifiableItem(Class<?> type, Object key) {
+        Class<? extends Identifiable<?>> identifiableType = (Class<? extends Identifiable<?>>) type;
+        Identifier<? extends Identifiable<?>> identifier = (Identifier<? extends Identifiable<?>>) key;
+        return new IdentifiableItem(identifiableType,identifier);
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java
new file mode 100644 (file)
index 0000000..3f74c9e
--- /dev/null
@@ -0,0 +1,17 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public interface GeneratorListener {
+
+    
+    
+    void onCodecCreated(Class<?> codec);
+    void onValueCodecCreated(Class<?> valueClass,Class<?> valueCodec);
+    void onChoiceCodecCreated(Class<?> choiceClass,Class<? extends BindingCodec<Map<QName, Object>,Object>> choiceCodec);
+    void onCaseCodecCreated(Class<?> choiceClass,Class<? extends BindingCodec<Map<QName, Object>,Object>> choiceCodec);
+    public abstract void onDataContainerCodecCreated(Class<?> dataClass, Class<?  extends BindingCodec<Map<QName, Object>,Object>> dataCodec);
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend
new file mode 100644 (file)
index 0000000..fd02fde
--- /dev/null
@@ -0,0 +1,123 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl
+
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import org.opendaylight.controller.sal.binding.dom.serializer.api.CodecRegistry
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
+import org.opendaylight.yangtools.yang.common.QName
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item
+import java.util.Map
+import java.util.WeakHashMap
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import java.util.ArrayList
+import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec
+import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName
+import java.util.HashMap
+import org.slf4j.LoggerFactory
+import java.util.List
+import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+
+class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
+    
+    private static val LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl);
+    val CodecRegistry codecRegistry;
+    
+    val Map<Class<?>,QName> classToQName = new WeakHashMap;
+    
+    
+    public new(CodecRegistry registry) {
+        codecRegistry = registry;
+    }
+    
+    
+    override deserialize(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier input) {
+        var Class<?> baType = null
+        val biArgs = input.path
+        val scannedPath = new ArrayList<QName>(biArgs.size);
+        val baArgs = new ArrayList<org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument>(biArgs.size)
+        for(biArg : biArgs) {
+            scannedPath.add(biArg.nodeType);
+            val baArg = deserializePathArgument(biArg,scannedPath)
+            baArgs.add(baArg)
+            baType = baArg?.type
+        }
+        val ret = new InstanceIdentifier(baArgs,baType as Class<? extends DataObject>);
+        return ret;
+    }
+    
+    private def dispatch org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(NodeIdentifier argument,List<QName> processedPath) {
+        val Class cls = codecRegistry.getClassForPath(processedPath);
+        return new Item(cls);
+    }
+    
+    
+    private def dispatch org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(NodeIdentifierWithPredicates argument,List<QName> processedPath) {
+        val Class type = codecRegistry.getClassForPath(processedPath);
+        val IdentifierCodec codec = codecRegistry.getIdentifierCodecForIdentifiable(type);
+        val value = codec.deserialize(argument.toCompositeNode())?.value;
+        return CodecTypeUtils.newIdentifiableItem(type,value);
+    }
+    
+    def CompositeNode toCompositeNode(NodeIdentifierWithPredicates predicates) {
+        val keyValues = predicates.keyValues.entrySet;
+        val values = new ArrayList<Node<?>>(keyValues.size)
+        for(keyValue : keyValues) {
+            values.add(new SimpleNodeTOImpl(keyValue.key,null,keyValue.value))
+        }
+        return new CompositeNodeTOImpl(predicates.nodeType,null,values);
+    }
+    
+    override serialize(InstanceIdentifier input) {
+        val pathArgs = input.path as List<org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument>
+        var QName previousQName = null;
+        val components = new ArrayList<PathArgument>(pathArgs.size);
+        for(baArg : pathArgs) { 
+            codecRegistry.bindingClassEncountered(baArg.type);
+            val biArg = serializePathArgument(baArg,previousQName);
+            previousQName = biArg.nodeType;
+            components.add(biArg);
+        }
+        return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(components);
+    }
+    
+    private def dispatch PathArgument serializePathArgument(Item argument, QName previousQname) {
+        val type = argument.type;
+        val qname = resolveQname(type);
+        if(previousQname == null) {
+            return new NodeIdentifier(qname);
+        }
+        return new NodeIdentifier(QName.create(previousQname,qname.localName));
+    }
+    
+    private def dispatch PathArgument serializePathArgument(IdentifiableItem argument, QName previousQname) {
+        val Map<QName,Object> predicates = new HashMap();
+        val type = argument.type;
+        val keyCodec = codecRegistry.getIdentifierCodecForIdentifiable(type);
+        val qname = resolveQname(type);
+        val combinedInput =  new ValueWithQName(previousQname,argument.key)
+        val compositeOutput = keyCodec.serialize(combinedInput as ValueWithQName);
+        for(outputValue :compositeOutput.value) {
+            predicates.put(outputValue.nodeType,outputValue.value);
+        }
+        if(previousQname == null) {
+            return new NodeIdentifierWithPredicates(qname,predicates);
+        }
+        return new NodeIdentifierWithPredicates(QName.create(previousQname,qname.localName),predicates);
+    }
+    
+    def resolveQname(Class class1) {
+        val qname = classToQName.get(class1);
+        if(qname !== null) {
+            return qname;
+        }
+        val qnameField = class1.getField("QNAME");
+        val qnameValue = qnameField.get(null) as QName;
+        classToQName.put(class1,qnameValue);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/IntermediateMapping.xtend
new file mode 100644 (file)
index 0000000..d0b114e
--- /dev/null
@@ -0,0 +1,40 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl
+
+import org.opendaylight.yangtools.yang.data.api.Node
+import java.util.Map
+import org.opendaylight.yangtools.yang.common.QName
+import java.util.List
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import com.google.common.base.Preconditions
+
+class IntermediateMapping {
+    
+    
+    
+    static def Node<?> toNode(Map map) {
+        val nodeMap = map as Map<QName,Object>;
+        Preconditions.checkArgument(map.size == 1);
+        val elem = nodeMap.entrySet.iterator.next;
+        val qname = elem.key;
+        val value = elem.value;
+        toNodeImpl(qname, value);
+    }
+
+    static def dispatch Node<?> toNodeImpl(QName name, List<?> objects) {
+        val values = new ArrayList<Node<?>>(objects.size);
+        for (obj : objects) {
+            values.add(toNode(obj as Map));
+        }
+        return new CompositeNodeTOImpl(name, null, values);
+    }
+
+    static def dispatch Node<?> toNodeImpl(QName name, Map<QName, Object> object) {
+        throw new UnsupportedOperationException("Unsupported node hierarchy.");
+    }
+
+    static def dispatch Node<?> toNodeImpl(QName name, Object object) {
+        return new SimpleNodeTOImpl(name, null, object);
+    } 
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java
new file mode 100644 (file)
index 0000000..e8e4c43
--- /dev/null
@@ -0,0 +1,779 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCaseCodec;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCodec;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.CodecRegistry;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.DomCodec;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName;
+import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener;
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
+import org.opendaylight.yangtools.binding.generator.util.Types;
+import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.google.common.base.Preconditions.*;
+import static org.opendaylight.controller.sal.binding.dom.serializer.impl.IntermediateMapping.*;
+
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext;
+import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+
+public class LazyGeneratedCodecRegistry implements //
+        CodecRegistry, //
+        SchemaServiceListener, //
+        GeneratorListener {
+
+    private final static Logger LOG = LoggerFactory.getLogger(LazyGeneratedCodecRegistry.class);
+    private final static LateMixinCodec NOT_READY_CODEC = new LateMixinCodec();
+
+    private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this);
+
+    private TransformerGenerator generator;
+
+    // Concrete class to codecs
+    private Map<Class<?>, DataContainerCodec<?>> containerCodecs = new WeakHashMap<>();
+    private Map<Class<?>, IdentifierCodec<?>> identifierCodecs = new WeakHashMap<>();
+    private Map<Class<?>, ChoiceCodecImpl<?>> choiceCodecs = new WeakHashMap<>();
+    private Map<Class<?>, ChoiceCaseCodecImpl<?>> caseCodecs = new WeakHashMap<>();
+    private Map<Class<?>, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>();
+
+    /** Binding type to encountered classes mapping **/
+    @SuppressWarnings("rawtypes")
+    Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
+
+    @SuppressWarnings("rawtypes")
+    private ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseNodes = new ConcurrentHashMap<>();
+
+    private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
+
+    Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
+
+    private SchemaContext currentSchema;
+
+    public TransformerGenerator getGenerator() {
+        return generator;
+    }
+
+    public void setGenerator(TransformerGenerator generator) {
+        this.generator = generator;
+    }
+
+    @Override
+    public InstanceIdentifierCodec getInstanceIdentifierCodec() {
+        return instanceIdentifierCodec;
+    }
+
+    @Override
+    public <T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Class<?> getClassForPath(List<QName> names) {
+        DataSchemaNode node = getSchemaNode(names);
+        SchemaPath path = node.getPath();
+        GeneratedTypeBuilder type = pathToType.get(path);
+        ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+        @SuppressWarnings("rawtypes")
+        WeakReference<Class> weakRef = typeToClass.get(typeref);
+        return weakRef.get();
+    }
+
+    @Override
+    public IdentifierCodec<?> getKeyCodecForPath(List<QName> names) {
+        @SuppressWarnings("unchecked")
+        Class<? extends Identifiable<?>> cls = (Class<? extends Identifiable<?>>) getClassForPath(names);
+        return getIdentifierCodecForIdentifiable(cls);
+    }
+
+    @Override
+    public <T extends DataContainer> DataContainerCodec<T> getCodecForDataObject(Class<T> type) {
+        @SuppressWarnings("unchecked")
+        DataContainerCodec<T> ret = (DataContainerCodec<T>) containerCodecs.get(type);
+        if (ret != null) {
+            return ret;
+        }
+        Class<? extends BindingCodec<Map<QName, Object>, Object>> newType = generator.transformerFor(type);
+        BindingCodec<Map<QName, Object>, Object> rawCodec = newInstanceOf(newType);
+        DataContainerCodecImpl<T> newWrapper = new DataContainerCodecImpl<>(rawCodec);
+        containerCodecs.put(type, newWrapper);
+        return newWrapper;
+    }
+
+    @Override
+    @SuppressWarnings("rawtypes")
+    public void bindingClassEncountered(Class cls) {
+        ConcreteType typeRef = Types.typeForClass(cls);
+        WeakReference<Class> weakRef = new WeakReference<>(cls);
+        typeToClass.put(typeRef, weakRef);
+    }
+
+    private DataSchemaNode getSchemaNode(List<QName> path) {
+        QName firstNode = path.get(0);
+        DataNodeContainer previous = currentSchema.findModuleByNamespaceAndRevision(firstNode.getNamespace(),
+                firstNode.getRevision());
+        Iterator<QName> iterator = path.iterator();
+        while (iterator.hasNext()) {
+            QName arg = iterator.next();
+            DataSchemaNode currentNode = previous.getDataChildByName(arg);
+            if (currentNode == null && previous instanceof DataNodeContainer) {
+                currentNode = searchInChoices(previous, arg);
+            }
+            if (currentNode instanceof DataNodeContainer) {
+                previous = (DataNodeContainer) currentNode;
+            } else if (currentNode instanceof LeafSchemaNode || currentNode instanceof LeafListSchemaNode) {
+                checkState(!iterator.hasNext(), "Path tries to nest inside leaf node.");
+                return currentNode;
+            }
+        }
+        return (DataSchemaNode) previous;
+    }
+
+    private DataSchemaNode searchInChoices(DataNodeContainer node, QName arg) {
+        Set<DataSchemaNode> children = node.getChildNodes();
+        for (DataSchemaNode child : children) {
+            if (child instanceof ChoiceNode) {
+                ChoiceNode choiceNode = (ChoiceNode) child;
+                DataSchemaNode potential = searchInCases(choiceNode, arg);
+                if (potential != null) {
+                    return potential;
+                }
+            }
+        }
+        return null;
+    }
+
+    private DataSchemaNode searchInCases(ChoiceNode choiceNode, QName arg) {
+        Set<ChoiceCaseNode> cases = choiceNode.getCases();
+        for (ChoiceCaseNode caseNode : cases) {
+            DataSchemaNode node = caseNode.getDataChildByName(arg);
+            if (node != null) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    private <T> T newInstanceOf(Class<?> newType) {
+        try {
+            @SuppressWarnings("unchecked")
+            T ret = (T) newType.newInstance();
+            return ret;
+        } catch (InstantiationException e) {
+            throw new IllegalStateException(e);
+        } catch (IllegalAccessException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public <T extends Identifiable<?>> IdentifierCodec<?> getIdentifierCodecForIdentifiable(Class<T> type) {
+        IdentifierCodec<?> obj = identifierCodecs.get(type);
+        if (obj != null) {
+            return obj;
+        }
+        Class<? extends BindingCodec<Map<QName, Object>, Object>> newCodec = generator
+                .keyTransformerForIdentifiable(type);
+        BindingCodec<Map<QName, Object>, Object> newInstance;
+        newInstance = newInstanceOf(newCodec);
+        IdentifierCodecImpl<?> newWrapper = new IdentifierCodecImpl<>(newInstance);
+        identifierCodecs.put(type, newWrapper);
+        return newWrapper;
+    }
+
+    @Override
+    public void onCodecCreated(Class<?> cls) {
+        CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec);
+    }
+
+    @Override
+    public <T extends Identifier<?>> IdentifierCodec<T> getCodecForIdentifier(Class<T> object) {
+        @SuppressWarnings("unchecked")
+        IdentifierCodec<T> obj = (IdentifierCodec<T>) identifierCodecs.get(object);
+        if (obj != null) {
+            return obj;
+        }
+        Class<? extends BindingCodec<Map<QName, Object>, Object>> newCodec = generator
+                .keyTransformerForIdentifier(object);
+        BindingCodec<Map<QName, Object>, Object> newInstance;
+        newInstance = newInstanceOf(newCodec);
+        IdentifierCodecImpl<T> newWrapper = new IdentifierCodecImpl<>(newInstance);
+        identifierCodecs.put(object, newWrapper);
+        return newWrapper;
+    }
+
+    @SuppressWarnings("rawtypes")
+    public ChoiceCaseCodecImpl getCaseCodecFor(Class caseClass) {
+        ChoiceCaseCodecImpl<?> potential = caseCodecs.get(caseClass);
+        if (potential != null) {
+            return potential;
+        }
+        ConcreteType typeref = Types.typeForClass(caseClass);
+        ChoiceCaseCodecImpl caseCodec = typeToCaseNodes.get(typeref);
+
+        @SuppressWarnings("unchecked")
+        Class<? extends BindingCodec> newCodec = generator.caseCodecFor(caseClass, caseCodec.schema);
+        BindingCodec newInstance = newInstanceOf(newCodec);
+        caseCodec.setDelegate(newInstance);
+        caseCodecs.put(caseClass, caseCodec);
+
+        for (Entry<Class<?>, ChoiceCodecImpl<?>> choice : choiceCodecs.entrySet()) {
+            if (choice.getKey().isAssignableFrom(caseClass)) {
+                choice.getValue().cases.put(caseClass, caseCodec);
+            }
+        }
+        return caseCodec;
+    }
+
+    public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) {
+        pathToType.putAll(context.getChildNodes());
+
+        captureCases(context.getCases(), schemaContext);
+    }
+
+    private void captureCases(Map<SchemaPath, GeneratedTypeBuilder> cases, SchemaContext module) {
+        for (Entry<SchemaPath, GeneratedTypeBuilder> caseNode : cases.entrySet()) {
+            ReferencedTypeImpl typeref = new ReferencedTypeImpl(caseNode.getValue().getPackageName(), caseNode
+                    .getValue().getName());
+            ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey());
+            @SuppressWarnings("rawtypes")
+            ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(node);
+            typeToCaseNodes.putIfAbsent(typeref, value);
+        }
+    }
+
+    @Override
+    public void onGlobalContextUpdated(SchemaContext context) {
+        currentSchema = context;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public void onChoiceCodecCreated(Class<?> choiceClass,
+            Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec) {
+        ChoiceCodec<?> oldCodec = choiceCodecs.get(choiceClass);
+        checkState(oldCodec == null);
+        BindingCodec<Map<QName, Object>, Object> delegate = newInstanceOf(choiceCodec);
+        ChoiceCodecImpl<?> newCodec = new ChoiceCodecImpl(delegate);
+        choiceCodecs.put(choiceClass, newCodec);
+        CodecMapping.setClassToCaseMap(choiceCodec, (Map<Class, BindingCodec>) classToCaseRawCodec);
+        CodecMapping.setCompositeNodeToCaseMap(choiceCodec, newCodec.getCompositeToCase());
+
+    }
+
+    @Override
+    public void onValueCodecCreated(Class<?> valueClass, Class<?> valueCodec) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onCaseCodecCreated(Class<?> choiceClass,
+            Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onDataContainerCodecCreated(Class<?> dataClass,
+            Class<? extends BindingCodec<Map<QName, Object>, Object>> dataCodec) {
+        if (Augmentable.class.isAssignableFrom(dataClass)) {
+            AugmentableCompositeCodec augmentableCodec = getAugmentableCodec(dataClass);
+            CodecMapping.setAugmentationCodec(dataCodec, augmentableCodec);
+        }
+
+    }
+
+    private AugmentableCompositeCodec getAugmentableCodec(Class<?> dataClass) {
+        AugmentableCompositeCodec ret = augmentableCodecs.get(dataClass);
+        if (ret != null) {
+            return ret;
+        }
+        ret = new AugmentableCompositeCodec(dataClass);
+        augmentableCodecs.put(dataClass, ret);
+        return ret;
+    }
+
+    private static abstract class IntermediateCodec<T> implements //
+            DomCodec<T>, Delegator<BindingCodec<Map<QName, Object>, Object>> {
+
+        private final BindingCodec<Map<QName, Object>, Object> delegate;
+
+        @Override
+        public BindingCodec<Map<QName, Object>, Object> getDelegate() {
+            return delegate;
+        }
+
+        public IntermediateCodec(BindingCodec<Map<QName, Object>, Object> delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public Node<?> serialize(ValueWithQName<T> input) {
+            Map<QName, Object> intermediateOutput = delegate.serialize(input);
+            return toNode(intermediateOutput);
+        }
+    }
+
+    private static class IdentifierCodecImpl<T extends Identifier<?>> //
+            extends IntermediateCodec<T> //
+            implements IdentifierCodec<T> {
+
+        public IdentifierCodecImpl(BindingCodec<Map<QName, Object>, Object> delegate) {
+            super(delegate);
+        }
+
+        @Override
+        public ValueWithQName<T> deserialize(Node<?> input) {
+            QName qname = input.getNodeType();
+            @SuppressWarnings("unchecked")
+            T value = (T) getDelegate().deserialize((Map<QName, Object>) input);
+            return new ValueWithQName<T>(qname, value);
+        }
+
+        @Override
+        public CompositeNode serialize(ValueWithQName<T> input) {
+            return (CompositeNode) super.serialize(input);
+        }
+    }
+
+    private static class DataContainerCodecImpl<T extends DataContainer> //
+            extends IntermediateCodec<T> //
+            implements DataContainerCodec<T> {
+
+        public DataContainerCodecImpl(BindingCodec<Map<QName, Object>, Object> delegate) {
+            super(delegate);
+        }
+
+        @Override
+        public ValueWithQName<T> deserialize(Node<?> input) {
+            if (input == null) {
+                return null;
+            }
+            QName qname = input.getNodeType();
+            @SuppressWarnings("unchecked")
+            T value = (T) getDelegate().deserialize((Map<QName, Object>) input);
+            return new ValueWithQName<T>(qname, value);
+        }
+
+        @Override
+        public CompositeNode serialize(ValueWithQName<T> input) {
+            return (CompositeNode) super.serialize(input);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static class ChoiceCaseCodecImpl<T extends DataContainer> implements ChoiceCaseCodec<T>, //
+            Delegator<BindingCodec> {
+        private final boolean augmenting;
+        private BindingCodec delegate;
+
+        private final Set<String> validNames;
+        private final Set<QName> validQNames;
+        private ChoiceCaseNode schema;
+
+        public ChoiceCaseCodecImpl(ChoiceCaseNode caseNode) {
+            this.delegate = NOT_READY_CODEC;
+            this.schema = caseNode;
+            validNames = new HashSet<>();
+            validQNames = new HashSet<>();
+            for (DataSchemaNode node : caseNode.getChildNodes()) {
+                QName qname = node.getQName();
+                validQNames.add(qname);
+                validNames.add(qname.getLocalName());
+            }
+            augmenting = caseNode.isAugmenting();
+        }
+
+        @Override
+        public ValueWithQName<T> deserialize(Node<?> input) {
+            throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
+        }
+
+        @Override
+        public CompositeNode serialize(ValueWithQName<T> input) {
+            throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
+        }
+
+        public BindingCodec getDelegate() {
+            return delegate;
+        }
+
+        public void setDelegate(BindingCodec delegate) {
+            this.delegate = delegate;
+        }
+
+        public ChoiceCaseNode getSchema() {
+            return schema;
+        }
+
+        @Override
+        public boolean isAcceptable(Node<?> input) {
+            if (false == (input instanceof CompositeNode)) {
+                if (augmenting) {
+                    return checkAugmenting((CompositeNode) input);
+                } else {
+                    return checkLocal((CompositeNode) input);
+                }
+            }
+            return false;
+        }
+
+        private boolean checkLocal(CompositeNode input) {
+            QName parent = input.getNodeType();
+            for (Node<?> childNode : input.getChildren()) {
+                QName child = childNode.getNodeType();
+                if (false == Objects.equals(parent.getNamespace(), child.getNamespace())) {
+                    continue;
+                }
+                if (false == Objects.equals(parent.getRevision(), child.getRevision())) {
+                    continue;
+                }
+                if (validNames.contains(child.getLocalName())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private boolean checkAugmenting(CompositeNode input) {
+            for (Node<?> child : input.getChildren()) {
+                if (validQNames.contains(child.getNodeType())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private static class ChoiceCodecImpl<T> implements ChoiceCodec<T> {
+
+        private final BindingCodec<Map<QName, Object>, Object> delegate;
+
+        @SuppressWarnings("rawtypes")
+        private final Map<Class, ChoiceCaseCodecImpl<?>> cases = new WeakHashMap<>();
+
+        private final CaseCompositeNodeMapFacade CompositeToCase;
+
+        public ChoiceCodecImpl(BindingCodec<Map<QName, Object>, Object> delegate) {
+            this.delegate = delegate;
+            this.CompositeToCase = new CaseCompositeNodeMapFacade(cases);
+        }
+
+        @Override
+        public ValueWithQName<T> deserialize(Node<?> input) {
+            throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
+        }
+
+        @Override
+        public Node<?> serialize(ValueWithQName<T> input) {
+            throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
+        }
+
+        public CaseCompositeNodeMapFacade getCompositeToCase() {
+            return CompositeToCase;
+        }
+
+        public Map<Class, ChoiceCaseCodecImpl<?>> getCases() {
+            return cases;
+        }
+
+        public BindingCodec<Map<QName, Object>, Object> getDelegate() {
+            return delegate;
+        }
+
+    }
+
+    @SuppressWarnings("rawtypes")
+    private class CaseClassMapFacade extends MapFacadeBase {
+
+        @Override
+        public Set<java.util.Map.Entry<Class, BindingCodec<Object, Object>>> entrySet() {
+            return null;
+        }
+
+        @Override
+        public BindingCodec get(Object key) {
+            if (key instanceof Class) {
+                Class cls = (Class) key;
+                bindingClassEncountered(cls);
+                ChoiceCaseCodecImpl caseCodec = getCaseCodecFor(cls);
+                return caseCodec.getDelegate();
+            }
+            return null;
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static class CaseCompositeNodeMapFacade extends MapFacadeBase<CompositeNode> {
+
+        final Map<Class, ChoiceCaseCodecImpl<?>> choiceCases;
+
+        public CaseCompositeNodeMapFacade(Map<Class, ChoiceCaseCodecImpl<?>> choiceCases) {
+            this.choiceCases = choiceCases;
+        }
+
+        @Override
+        public Set<java.util.Map.Entry<CompositeNode, BindingCodec>> entrySet() {
+            return null;
+        }
+
+        @Override
+        public BindingCodec get(Object key) {
+            if (false == (key instanceof CompositeNode)) {
+                return null;
+            }
+            for (java.util.Map.Entry<Class, ChoiceCaseCodecImpl<?>> entry : choiceCases.entrySet()) {
+                ChoiceCaseCodecImpl<?> codec = entry.getValue();
+                if (codec.isAcceptable((CompositeNode) key)) {
+                    return codec.getDelegate();
+                }
+            }
+            return null;
+        }
+    }
+
+    /**
+     * This map is used as only facade for {@link BindingCodec} in different
+     * classloaders to retrieve codec dynamicly based on provided key.
+     * 
+     * @param <T>
+     *            Key type
+     */
+    @SuppressWarnings("rawtypes")
+    private static abstract class MapFacadeBase<T> implements Map<T, BindingCodec> {
+
+        @Override
+        public boolean containsKey(Object key) {
+            return get(key) != null;
+        }
+
+        @Override
+        public void clear() {
+            throw notModifiable();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return super.equals(obj);
+        }
+
+        @Override
+        public BindingCodec remove(Object key) {
+            return null;
+        }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public Collection<BindingCodec> values() {
+            return null;
+        }
+
+        private UnsupportedOperationException notModifiable() {
+            return new UnsupportedOperationException("Not externally modifiable.");
+        }
+
+        @Override
+        public BindingCodec<Map<QName, Object>, Object> put(T key, BindingCodec value) {
+            throw notModifiable();
+        }
+
+        @Override
+        public void putAll(Map<? extends T, ? extends BindingCodec> m) {
+            throw notModifiable();
+        }
+
+        @Override
+        public int hashCode() {
+            return super.hashCode();
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return false;
+        }
+
+        @Override
+        public Set<T> keySet() {
+            return null;
+        }
+
+        @Override
+        public Set<java.util.Map.Entry<T, BindingCodec>> entrySet() {
+            return null;
+        }
+
+        @Override
+        public boolean containsValue(Object value) {
+            return false;
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private class AugmentableCompositeCodec implements BindingCodec {
+
+        private final Class augmentableType;
+
+        Map<Class, BindingCodec> rawAugmentationCodecs = new WeakHashMap<>();
+
+        public AugmentableCompositeCodec(Class type) {
+            checkArgument(Augmentable.class.isAssignableFrom(type));
+            augmentableType = type;
+        }
+
+        @Override
+        public Object serialize(Object input) {
+            if (input instanceof Augmentable<?>) {
+
+                Map<Class, Augmentation> augmentations = getAugmentations(input);
+                return serializeImpl(augmentations);
+            }
+            return null;
+        }
+
+        private Map<Class, Augmentation> getAugmentations(Object input) {
+            Field augmentationField;
+            try {
+                augmentationField = input.getClass().getDeclaredField("augmentation");
+                augmentationField.setAccessible(true);
+                Map<Class, Augmentation> augMap = (Map<Class, Augmentation>) augmentationField.get(input);
+                return augMap;
+            } catch (NoSuchFieldException e) {
+
+            } catch (SecurityException e) {
+
+            } catch (IllegalArgumentException e) {
+
+            } catch (IllegalAccessException e) {
+
+            }
+            return Collections.emptyMap();
+        }
+
+        private List serializeImpl(Map<Class, Augmentation> input) {
+            List ret = new ArrayList<>();
+            for (Entry<Class, Augmentation> entry : input.entrySet()) {
+                BindingCodec codec = getRawCodecForAugmentation(entry.getKey());
+                List output = (List) codec.serialize(new ValueWithQName(null, entry.getValue()));
+                ret.addAll(output);
+            }
+            return ret;
+        }
+
+        private BindingCodec getRawCodecForAugmentation(Class key) {
+            BindingCodec ret = rawAugmentationCodecs.get(key);
+            if (ret != null) {
+                return ret;
+            }
+            try {
+                Class<? extends BindingCodec> retClass = generator.augmentationTransformerFor(key);
+                ret = retClass.newInstance();
+                rawAugmentationCodecs.put(key, ret);
+                return ret;
+            } catch (InstantiationException e) {
+
+            } catch (IllegalAccessException e) {
+
+            }
+            return null;
+        }
+
+        @Override
+        public Map<Class, Augmentation> deserialize(Object input) {
+            Map<Class, Augmentation> ret = new HashMap<>();
+            if (input instanceof CompositeNode) {
+                for (Entry<Class, BindingCodec> codec : rawAugmentationCodecs.entrySet()) {
+                    Augmentation value = (Augmentation) codec.getValue().deserialize(input);
+                    if (value != null) {
+                        ret.put(codec.getKey(), value);
+                    }
+                }
+            }
+            return ret;
+        }
+
+        public Map<Class, BindingCodec> getRawAugmentationCodecs() {
+            return rawAugmentationCodecs;
+        }
+
+        public void setRawAugmentationCodecs(Map<Class, BindingCodec> rawAugmentationCodecs) {
+            this.rawAugmentationCodecs = rawAugmentationCodecs;
+        }
+
+        public Class getAugmentableType() {
+            return augmentableType;
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private static class LateMixinCodec implements BindingCodec, Delegator<BindingCodec> {
+
+        private BindingCodec delegate;
+
+        @Override
+        public BindingCodec getDelegate() {
+            if (delegate == null) {
+                throw new IllegalStateException("Codec not initialized yet.");
+            }
+            return delegate;
+        }
+
+        @Override
+        public Object deserialize(Object input) {
+            return getDelegate().deserialize(input);
+        }
+
+        @Override
+        public Object serialize(Object input) {
+            return getDelegate().serialize(input);
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend
new file mode 100644 (file)
index 0000000..4614c60
--- /dev/null
@@ -0,0 +1,218 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl
+
+import org.opendaylight.controller.sal.binding.dom.serializer.impl.TransformerGenerator
+import javassist.ClassPool
+import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
+import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
+import java.util.Map
+import org.opendaylight.yangtools.sal.binding.model.api.Type
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
+import org.opendaylight.yangtools.yang.model.api.SchemaNode
+import java.util.concurrent.ConcurrentHashMap
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import java.util.Map.Entry
+import java.util.AbstractMap.SimpleEntry
+import org.opendaylight.yangtools.yang.model.api.SchemaPath
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.common.QName
+import org.opendaylight.yangtools.yang.binding.DataContainer
+import static com.google.common.base.Preconditions.*;
+import java.util.List
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.concepts.Delegator
+import java.util.concurrent.ConcurrentMap
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
+import org.opendaylight.yangtools.yang.binding.BindingCodec
+import com.google.common.collect.HashMultimap
+import com.google.common.util.concurrent.SettableFuture
+import java.util.concurrent.Future
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
+import org.opendaylight.controller.sal.binding.dom.serializer.impl.LazyGeneratedCodecRegistry
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService
+import org.slf4j.LoggerFactory
+import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName
+import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec
+import org.opendaylight.yangtools.binding.generator.util.Types
+
+class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener {
+
+    @Property
+    ClassPool pool;
+
+    private static val LOG = LoggerFactory.getLogger(RuntimeGeneratedMappingServiceImpl);
+
+    @Property
+    extension TransformerGenerator binding;
+
+    @Property
+    extension LazyGeneratedCodecRegistry registry;
+
+    @Property
+    val ConcurrentMap<Type, Type> typeDefinitions = new ConcurrentHashMap();
+
+    @Property
+    val ConcurrentMap<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
+
+    @Property
+    val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
+
+    val promisedTypeDefinitions = HashMultimap.<Type, SettableFuture<GeneratedTypeBuilder>>create;
+
+    val promisedSchemas = HashMultimap.<Type, SettableFuture<SchemaNode>>create;
+
+    override onGlobalContextUpdated(SchemaContext arg0) {
+        recreateBindingContext(arg0);
+        registry.onGlobalContextUpdated(arg0);
+    }
+
+    def recreateBindingContext(SchemaContext schemaContext) {
+        val newBinding = new BindingGeneratorImpl();
+        newBinding.generateTypes(schemaContext);
+
+        for (entry : newBinding.moduleContexts.entrySet) {
+
+            registry.onModuleContextAdded(schemaContext, entry.key, entry.value);
+
+            //val module = entry.key;
+            val context = entry.value;
+            updateBindingFor(context.childNodes, schemaContext);
+            updateBindingFor(context.cases, schemaContext);
+            
+
+            val typedefs = context.typedefs;
+            for (typedef : typedefs.values) {
+                binding.typeDefinitions.put(typedef, typedef as GeneratedType);
+            }
+            val augmentations = context.augmentations;
+            for (augmentation : augmentations) {
+                binding.typeToDefinition.put(augmentation, augmentation);
+            }
+            
+            binding.typeToAugmentation.putAll(context.typeToAugmentation);
+        }
+    }
+
+    override CompositeNode toDataDom(DataObject data) {
+        toCompositeNodeImpl(data);
+    }
+
+    override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
+        Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
+        val key = toDataDom(entry.key)
+        val data = toCompositeNodeImpl(entry.value);
+        return new SimpleEntry(key, data);
+    }
+
+    private def CompositeNode toCompositeNodeImpl(DataObject object) {
+        val cls = object.implementedInterface;
+        waitForSchema(cls);
+        val codec = registry.getCodecForDataObject(cls) as DataContainerCodec<DataObject>;
+        val ret = codec.serialize(new ValueWithQName(null, object));
+        return ret as CompositeNode;
+    }
+
+    private def waitForSchema(Class<? extends DataContainer> class1) {
+        val ref = Types.typeForClass(class1);
+        getSchemaWithRetry(ref);
+    }
+
+    override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
+        InstanceIdentifier<? extends DataObject> path) {
+        for (arg : path.path) {
+            waitForSchema(arg.type);
+        }
+        return registry.instanceIdentifierCodec.serialize(path);
+    }
+
+    override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode node) {
+        if (node == null) {
+            return null;
+        }
+        val targetType = path.targetType
+        val transformer = registry.getCodecForDataObject(targetType);
+        val ret = transformer.deserialize(node)?.value as DataObject;
+        return ret;
+    }
+
+    private def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
+        for (entry : map.entrySet) {
+            val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
+            //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName)
+            if (schemaNode != null) {
+                typeToSchemaNode.put(entry.value, schemaNode);
+                typeToDefinition.put(entry.value, entry.value);
+                updatePromisedSchemas(entry.value, schemaNode);
+            }
+        }
+    }
+
+    public def void start() {
+        binding = new TransformerGenerator(pool);
+        registry = new LazyGeneratedCodecRegistry()
+        registry.generator = binding
+
+        //binding.staticFieldsInitializer = registry
+        binding.listener = registry
+        binding.typeToDefinition = typeToDefinition
+        binding.typeToSchemaNode = typeToSchemaNode
+        binding.typeDefinitions = typeDefinitions
+
+    }
+
+    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);
+    }
+
+    private def getSchemaWithRetry(Type type) {
+        val typeDef = typeToSchemaNode.get(type);
+        if (typeDef !== null) {
+            return typeDef;
+        }
+        return type.getSchemaInFuture.get();
+    }
+
+    private def Future<SchemaNode> getSchemaInFuture(Type type) {
+        val future = SettableFuture.<SchemaNode>create()
+        promisedSchemas.put(type, future);
+        return future;
+    }
+
+    private def void updatePromisedSchemas(Type builder, SchemaNode schema) {
+        val ref = new ReferencedTypeImpl(builder.packageName, builder.name);
+        val futures = promisedSchemas.get(ref);
+        if (futures === null || futures.empty) {
+            return;
+        }
+        for (future : futures) {
+            future.set(schema);
+        }
+        promisedSchemas.removeAll(builder);
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/StaticFieldInitializer.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/StaticFieldInitializer.java
new file mode 100644 (file)
index 0000000..e5b36e1
--- /dev/null
@@ -0,0 +1,6 @@
+package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+
+public interface StaticFieldInitializer {
+
+    void initializeStaticFields(Class<?> cls);
+}
index 2136572aa3240117ced443e180acc8b6c26d68be..8e059aa22ed4e8ec1946afc18154b5fe9a38ded6 100644 (file)
@@ -9,9 +9,9 @@ import java.util.Map
 import org.opendaylight.yangtools.yang.common.QName
 import javassist.CtField
 import static javassist.Modifier.*
+import static org.opendaylight.controller.sal.binding.dom.serializer.impl.CodecMapping.*
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
-import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
 import org.opendaylight.yangtools.sal.binding.model.api.Type
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
@@ -22,7 +22,6 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
-import java.util.WeakHashMap
 import java.util.List
 import java.util.TreeSet
 import com.google.common.base.Joiner
@@ -31,13 +30,21 @@ import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
 import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.*;
 import org.opendaylight.yangtools.yang.binding.BindingDeserializer
-import org.opendaylight.yangtools.yang.binding.BindingSerializer
 import org.opendaylight.yangtools.yang.binding.BindingCodec
 import org.slf4j.LoggerFactory
 import org.opendaylight.controller.sal.binding.codegen.CodeGenerationException
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode
 import java.security.ProtectionDomain
 import java.io.File
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
+import java.util.Map.Entry
+import java.util.AbstractMap.SimpleEntry
+import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.yangtools.yang.binding.Augmentation
+import java.util.Iterator
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
+import java.util.concurrent.ConcurrentHashMap
 
 class TransformerGenerator {
 
@@ -46,6 +53,7 @@ class TransformerGenerator {
     public static val STRING = Types.typeForClass(String);
     public static val BOOLEAN = Types.typeForClass(Boolean);
     public static val INTEGER = Types.typeForClass(Integer);
+    public static val INSTANCE_IDENTIFIER = Types.typeForClass(InstanceIdentifier)
 
     //public static val DECIMAL = Types.typeForClass(Decimal);
     public static val LONG = Types.typeForClass(Long);
@@ -53,36 +61,39 @@ class TransformerGenerator {
     val ClassPool classPool
     val extension JavassistUtils utils;
 
-    CtClass ctTransformator
+    CtClass BINDING_CODEC
 
     CtClass ctQName
 
     @Property
     var File classFileCapturePath;
 
+    @Property
+    var Map<Type, Type> typeDefinitions = new ConcurrentHashMap();
 
     @Property
-    var Map<Type, Type> typeDefinitions;
+    var Map<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
 
     @Property
-    var Map<Type, GeneratedTypeBuilder> typeToDefinition
+    var Map<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
 
     @Property
-    var Map<Type, SchemaNode> typeToSchemaNode
+    var Map<Type, AugmentationSchema> typeToAugmentation = new ConcurrentHashMap();
 
-    val Map<Class<?>, Class<?>> generatedClasses = new WeakHashMap();
+    @Property
+    var GeneratorListener listener;
 
     public new(ClassPool pool) {
         classPool = pool;
         utils = new JavassistUtils(pool)
 
-        ctTransformator = BindingCodec.asCtClass;
+        BINDING_CODEC = BindingCodec.asCtClass;
         ctQName = QName.asCtClass
     }
 
     def Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(Class<?> inputType) {
-        return withClassLoader(inputType.classLoader) [ |
-            val ret = generatedClasses.get(inputType);
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val ret = getGeneratedClass(inputType)
             if (ret !== null) {
                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
@@ -90,60 +101,148 @@ class TransformerGenerator {
             val node = typeToSchemaNode.get(ref)
             val typeSpecBuilder = typeToDefinition.get(ref)
             val typeSpec = typeSpecBuilder.toInstance();
-            val newret = generateTransformerFor(inputType, typeSpec, node)
-            generatedClasses.put(inputType, newret);
+            val newret = generateTransformerFor(inputType, typeSpec, node);
+            return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+        ]
+    }
+
+    def Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentationTransformerFor(Class<?> inputType) {
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val ret = getGeneratedClass(inputType)
+            if (ret !== null) {
+                return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            }
+            val ref = Types.typeForClass(inputType)
+            val node = typeToAugmentation.get(ref)
+            val typeSpecBuilder = typeToDefinition.get(ref)
+            val typeSpec = typeSpecBuilder.toInstance();
+            val newret = generateAugmentationTransformerFor(inputType, typeSpec, node);
+            return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+        ]
+    }
+
+    def Class<? extends BindingCodec<Object, Object>> caseCodecFor(Class<?> inputType, ChoiceCaseNode node) {
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val ret = getGeneratedClass(inputType)
+            if (ret !== null) {
+                return ret as Class<? extends BindingCodec<Object, Object>>;
+            }
+            val ref = Types.typeForClass(inputType)
+            val typeSpecBuilder = typeToDefinition.get(ref)
+            val typeSpec = typeSpecBuilder.toInstance();
+            val newret = generateCaseCodec(inputType, typeSpec, node);
+            return newret as Class<? extends BindingCodec<Object, Object>>;
+        ]
+    }
+
+    def Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifiable(Class<?> parentType) {
+        return withClassLoaderAndLock(parentType.classLoader, lock) [ |
+            val inputName = parentType.name + "Key";
+            val inputType = loadClassWithTCCL(inputName);
+            val ret = getGeneratedClass(inputType)
+            if (ret !== null) {
+                return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            }
+            val ref = Types.typeForClass(parentType)
+            val node = typeToSchemaNode.get(ref) as ListSchemaNode
+            val typeSpecBuilder = typeToDefinition.get(ref)
+            val typeSpec = typeSpecBuilder.identifierDefinition;
+            val newret = generateKeyTransformerFor(inputType, typeSpec, node);
+            return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+        ]
+    }
+
+    def getIdentifierDefinition(GeneratedTypeBuilder builder) {
+        val inst = builder.toInstance
+        val keyMethod = inst.methodDefinitions.findFirst[name == "getKey"]
+        return keyMethod.returnType as GeneratedTransferObject
+    }
+
+    def Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifier(Class<?> inputType) {
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val ret = getGeneratedClass(inputType)
+            if (ret !== null) {
+                return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            }
+            val ref = Types.typeForClass(inputType)
+            val node = typeToSchemaNode.get(ref) as ListSchemaNode
+            val typeSpecBuilder = typeToDefinition.get(ref)
+            val typeSpec = typeSpecBuilder.toInstance();
+            val newret = generateKeyTransformerFor(inputType, typeSpec, node);
             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         ]
     }
 
     private def Class<?> keyTransformerFor(Class<?> inputType, GeneratedType type, ListSchemaNode schema) {
-        return withClassLoader(inputType.classLoader) [ |
-            val transformer = generatedClasses.get(inputType);
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val transformer = getGeneratedClass(inputType)
             if (transformer != null) {
                 return transformer;
             }
             val newret = generateKeyTransformerFor(inputType, type, schema);
-            generatedClasses.put(inputType, newret);
             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         ]
     }
 
-    def Class<?> keyTransformer(GeneratedType type, ListSchemaNode node) {
+    private def Class getGeneratedClass(Class<? extends Object> cls) {
+
+        try {
+            return loadClassWithTCCL(cls.codecClassName)
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+
+    private def Class<?> keyTransformer(GeneratedType type, ListSchemaNode node) {
         val cls = loadClassWithTCCL(type.resolvedName + "Key");
         keyTransformerFor(cls, type, node);
     }
 
     private def serializer(Type type) {
         val cls = loadClassWithTCCL(type.resolvedName);
+
         transformerFor(cls);
 
     }
 
     private def Class<?> getValueSerializer(GeneratedTransferObject type) {
         val cls = loadClassWithTCCL(type.resolvedName);
-        val transformer = generatedClasses.get(cls);
+        val transformer = cls.generatedClass;
         if (transformer !== null) {
             return transformer;
         }
         val valueTransformer = generateValueTransformer(cls, type);
-        generatedClasses.put(cls, valueTransformer);
         return valueTransformer;
     }
 
     private def generateKeyTransformerFor(Class<? extends Object> inputType, GeneratedType typeSpec, ListSchemaNode node) {
         try {
-            log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
+            log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
             val properties = typeSpec.allProperties;
-            val ctCls = createClass(inputType.transformatorFqn) [
+            val ctCls = createClass(inputType.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
                 staticQNameField(node.QName);
-                implementsType(ctTransformator)
+                implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
                         {
-                        
-                            return null;
+                            Â«QName.name» _resultName;
+                            if($1 != null) {
+                                _resultName = Â«QName.name».create($1,QNAME.getLocalName());
+                            } else {
+                                _resultName = QNAME;
+                            }
+                            java.util.List _childNodes = new java.util.ArrayList();
+                            Â«inputType.name» value = («inputType.name») $2;
+                            Â«FOR key : node.keyDefinition»
+                                Â«val propertyName = key.getterName»
+                                Â«val keyDef = node.getDataChildByName(key)»
+                                Â«val property = properties.get(propertyName)»
+                                Â«serializeProperty(keyDef, property, propertyName)»;
+                            Â«ENDFOR»
+                            return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
                         }
                     '''
                 ]
@@ -160,7 +259,7 @@ class TransformerGenerator {
                                 Â«val propertyName = key.getterName»
                                 Â«val keyDef = node.getDataChildByName(key)»
                                 Â«val property = properties.get(propertyName)»
-                                Â«deserializeProperty(keyDef, property.returnType, property)»;
+                                Â«deserializeProperty(keyDef, property, propertyName)»;
                             Â«ENDFOR»
                             Â«inputType.name» _value = new Â«inputType.name»(«node.keyDefinition.keyConstructorList»);
                             return _value;
@@ -169,7 +268,12 @@ class TransformerGenerator {
                 ]
                 method(Object, "serialize", Object) [
                     body = '''
-                        return toDomStatic(QNAME,$1);
+                        {
+                            java.util.Map.Entry _input =  (java.util.Map.Entry) $1;
+                            Â«QName.name» _localQName = («QName.name») _input.getKey();
+                            Â«inputType.name» _keyValue = («inputType.name») _input.getValue();
+                            return toDomStatic(_localQName,_keyValue);
+                        }
                     '''
                 ]
                 method(Object, "deserialize", Object) [
@@ -179,29 +283,95 @@ class TransformerGenerator {
                 ]
             ]
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
-            log.info("DOM Codec for {} was generated {}",inputType,ret)
+            log.info("DOM Codec for {} was generated {}", inputType, ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, ?>>;
         } catch (Exception e) {
-            processException(inputType,e);
+            processException(inputType, e);
             return null;
         }
     }
 
-    private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(Class inputType,
-        GeneratedType typeSpec, SchemaNode node) {
+    private def Class<? extends BindingCodec<Object, Object>> generateCaseCodec(Class inputType, GeneratedType type,
+        ChoiceCaseNode node) {
         try {
-            log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
-            val ctCls = createClass(typeSpec.transformatorFqn) [
+            log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
+            val ctCls = createClass(type.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                implementsType(BINDING_CODEC)
                 staticQNameField(inputType);
-                implementsType(ctTransformator)
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                method(Object, "toDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    body = '''
+                        {
+                            Â«QName.name» _resultName = Â«QName.name».create($1,QNAME.getLocalName());
+                            java.util.List _childNodes = new java.util.ArrayList();
+                            Â«type.resolvedName» value = («type.resolvedName») $2;
+                            Â«transformDataContainerBody(type.allProperties, node)»
+                            return ($r) _childNodes;
+                        }
+                    '''
+                ]
+                method(Object, "serialize", Object) [
+                    body = '''
+                        {
+                            java.util.Map.Entry _input = (java.util.Map.Entry) $1;
+                            Â«QName.name» _localName = QNAME;
+                            if(_input.getKey() != null) {
+                                _localName = («QName.name») _input.getKey();
+                            }
+                            return toDomStatic(_localName,_input.getValue());
+                        }
+                    '''
+                ]
+                method(Object, "fromDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    body = deserializeBody(type, node)
+                ]
+                method(Object, "deserialize", Object) [
+                    body = '''
+                        {
+                            
+                            return fromDomStatic(QNAME,$1);
+                        }
+                    '''
+                ]
+            ]
+
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            log.info("DOM Codec for {} was generated {}", inputType, ret)
+            return ret as Class<? extends BindingCodec<Object, Object>>;
+        } catch (Exception e) {
+            processException(inputType, e);
+            return null;
+        }
+    }
+
+    private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(
+        Class inputType, GeneratedType typeSpec, SchemaNode node) {
+        try {
+            log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
+            val ctCls = createClass(typeSpec.codecClassName) [
+                //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                staticQNameField(inputType);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = serializeBodyFacade(typeSpec, node)
                 ]
                 method(Object, "serialize", Object) [
                     body = '''
-                        return toDomStatic(QNAME,$1);
+                        {
+                            java.util.Map.Entry _input = (java.util.Map.Entry) $1;
+                            Â«QName.name» _localName = QNAME;
+                            if(_input.getKey() != null) {
+                                _localName = («QName.name») _input.getKey();
+                            }
+                            return toDomStatic(_localName,_input.getValue());
+                        }
                     '''
                 ]
                 method(Object, "fromDomStatic", QName, Object) [
@@ -215,55 +385,159 @@ class TransformerGenerator {
                 ]
             ]
 
-            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
-            return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Map<QName,Object>, Object>>
+            listener?.onDataContainerCodecCreated(inputType, ret);
+            log.info("DOM Codec for {} was generated {}", inputType, ret)
+            return ret;
         } catch (Exception e) {
-            processException(inputType,e);
+            processException(inputType, e);
             return null;
         }
     }
-    
-    
-    private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(Class inputType,
-        GeneratedType typeSpec, ChoiceNode node) {
+
+    private def Class<? extends BindingCodec<Map<QName, Object>, Object>> generateAugmentationTransformerFor(
+        Class inputType, GeneratedType type, AugmentationSchema node) {
         try {
-            log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
-            val ctCls = createClass(typeSpec.transformatorFqn) [
+            log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
+            val properties = type.allProperties
+            val ctCls = createClass(type.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
-                //staticQNameField(inputType);
-                implementsType(ctTransformator)
+                staticQNameField(inputType);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, AUGMENTATION_CODEC, BindingCodec)
+                implementsType(BINDING_CODEC)
                 method(Object, "toDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
-                        return null;
+                        {
+                            //System.out.println("Qname " + $1);
+                            //System.out.println("Value " + $2);
+                            Â«QName.name» _resultName = Â«QName.name».create($1,QNAME.getLocalName());
+                            java.util.List _childNodes = new java.util.ArrayList();
+                            Â«type.resolvedName» value = («type.resolvedName») $2;
+                            Â«FOR child : node.childNodes»
+                                Â«var signature = properties.getFor(child)»
+                                //System.out.println("«signature.key»" + value.«signature.key»());
+                                Â«serializeProperty(child, signature.value, signature.key)»
+                            Â«ENDFOR»
+                            return ($r) _childNodes;
+                        }
                     '''
                 ]
                 method(Object, "serialize", Object) [
                     body = '''
-                        return null;
+                        {
+                        java.util.Map.Entry _input = (java.util.Map.Entry) $1;
+                        Â«QName.name» _localName = QNAME;
+                        if(_input.getKey() != null) {
+                            _localName = («QName.name») _input.getKey();
+                        }
+                        return toDomStatic(_localName,_input.getValue());
+                        }
                     '''
                 ]
                 method(Object, "fromDomStatic", QName, Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
-                        return null;
+                        {
+                            Â«QName.name» _localQName = QNAME;
+                            
+                            if($2 == null) {
+                            return null;
+                            }
+                            java.util.Map _compositeNode = (java.util.Map) $2;
+                            ////System.out.println(_localQName + " " + _compositeNode);
+                            Â«type.builderName» _builder = new Â«type.builderName»();
+                            Â«FOR child : node.childNodes»
+                                Â«val signature = properties.getFor(child)»
+                                Â«deserializeProperty(child, signature.value, signature.key)»
+                                
+                                _builder.«signature.key.toSetter»(«signature.key»);
+                            Â«ENDFOR»
+                            return _builder.build();
+                        }
                     '''
                 ]
                 method(Object, "deserialize", Object) [
                     body = '''
-                        return null;
+                        return fromDomStatic(QNAME,$1);
                     '''
                 ]
             ]
 
-            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
-            return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Map<QName,Object>, Object>>
+            listener?.onDataContainerCodecCreated(inputType, ret);
+            return ret;
         } catch (Exception e) {
-            processException(inputType,e);
+            processException(inputType, e);
+            return null;
+        }
+    }
+
+    private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(
+        Class inputType, GeneratedType typeSpec, ChoiceNode node) {
+        try {
+            log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
+            val ctCls = createClass(typeSpec.codecClassName) [
+                //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                //staticQNameField(inputType);
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+                staticField(it, CLASS_TO_CASE_MAP, Map)
+                staticField(it, COMPOSITE_TO_CASE, Map)
+                //staticField(it,QNAME_TO_CASE_MAP,BindingCodec)
+                implementsType(BINDING_CODEC)
+                method(List, "toDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    body = '''
+                        {
+                            if($2 == null) {
+                                return null;
+                            }
+                            Â«DataObject.name» _baValue = («DataObject.name») $2;
+                            Class _baClass = _baValue.getImplementedInterface();
+                            Â«BINDING_CODEC.name» _codec =  Â«CLASS_TO_CASE_MAP».get(_baClass);
+                            if(_codec == null) {
+                                return null;
+                            }
+                            java.util.Map.Entry _input = new Â«SimpleEntry.name»($1,_baValue);
+                            return (java.util.List) _codec.serialize(_input);
+                        }
+                    '''
+                ]
+                method(Object, "serialize", Object) [
+                    body = '''
+                        throw new Â«UnsupportedOperationException.name»("Direct invocation not supported.");
+                    '''
+                ]
+                method(Object, "fromDomStatic", QName, Map) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    body = '''
+                        {
+                            Â«BINDING_CODEC.name» _codec = («BINDING_CODEC.name») Â«COMPOSITE_TO_CASE».get($2);
+                            if(_codec != null) {
+                                return _codec.deserialize(new Â«SimpleEntry.name»($1,$2));
+                            }
+                            return null;
+                        }
+                    '''
+                ]
+                method(Object, "deserialize", Object) [
+                    body = '''
+                        throw new Â«UnsupportedOperationException.name»("Direct invocation not supported.");
+                    '''
+                ]
+            ]
+
+            val rawRet = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            val ret = rawRet as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            listener?.onChoiceCodecCreated(inputType, ret);
+            log.info("DOM Codec for {} was generated {}", inputType, ret)
+            return ret;
+        } catch (Exception e) {
+            processException(inputType, e);
             return null;
         }
     }
-    
 
     private def keyConstructorList(List<QName> qnames) {
         val names = new TreeSet<String>()
@@ -302,7 +576,6 @@ class TransformerGenerator {
             }
             java.util.Map _compositeNode = (java.util.Map) $2;
             Â«type.builderName» _builder = new Â«type.builderName»();
-            
             return _builder.build();
         }
     '''
@@ -317,6 +590,7 @@ class TransformerGenerator {
             Â«type.builderName» _builder = new Â«type.builderName»();
             Â«deserializeKey(type, node)»
             Â«deserializeDataNodeContainerBody(type, node)»
+            Â«deserializeAugmentations»
             return _builder.build();
         }
     '''
@@ -330,6 +604,7 @@ class TransformerGenerator {
             java.util.Map _compositeNode = (java.util.Map) $2;
             Â«type.builderName» _builder = new Â«type.builderName»();
             Â«deserializeDataNodeContainerBody(type, node)»
+            Â«deserializeAugmentations»
             return _builder.build();
         }
     '''
@@ -337,12 +612,15 @@ class TransformerGenerator {
     private def dispatch String deserializeBodyImpl(GeneratedType type, ChoiceCaseNode node) '''
         {
             Â«QName.name» _localQName = Â«QName.name».create($1,QNAME.getLocalName());
+            
             if($2 == null) {
                 return null;
             }
             java.util.Map _compositeNode = (java.util.Map) $2;
+            ////System.out.println(_localQName + " " + _compositeNode);
             Â«type.builderName» _builder = new Â«type.builderName»();
             Â«deserializeDataNodeContainerBody(type, node)»
+            Â«deserializeAugmentations»
             return _builder.build();
         }
     '''
@@ -351,87 +629,106 @@ class TransformerGenerator {
         deserializeNodeContainerBodyImpl(type, type.allProperties, node);
     }
 
-    private def deserializeNodeContainerBodyImpl(GeneratedType type, HashMap<String, MethodSignature> properties,
+    private def deserializeNodeContainerBodyImpl(GeneratedType type, HashMap<String, Type> properties,
         DataNodeContainer node) {
         val ret = '''
             Â«FOR child : node.childNodes.filter[!augmenting]»
                 Â«val signature = properties.getFor(child)»
-                Â«deserializeProperty(child, signature.returnType, signature)»
-                _builder.«signature.name.toSetter»(«signature.name»);
+                Â«deserializeProperty(child, signature.value, signature.key)»
+                
+                _builder.«signature.key.toSetter»(«signature.key»);
             Â«ENDFOR»
         '''
         return ret;
     }
 
+    def deserializeAugmentations() '''
+        java.util.Map _augmentation = (java.util.Map) Â«AUGMENTATION_CODEC».deserialize(_compositeNode);
+        if(_augmentation != null) {
+            Â«Iterator.name» _entries = _augmentation.entrySet().iterator();
+            while(_entries.hasNext()) {
+                java.util.Map.Entry _entry = (java.util.Map.Entry) _entries.next();
+                //System.out.println("Aug. key:" + _entry.getKey());
+                Class _type = (Class) _entry.getKey();
+                Â«Augmentation.resolvedName» _value = («Augmentation.name») _entry.getValue();
+                _builder.addAugmentation(_type,_value);
+            }
+        }
+    '''
+
     private def dispatch CharSequence deserializeProperty(ListSchemaNode schema, ParameterizedType type,
-        MethodSignature property) '''
-        java.util.List _dom_«property.name» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
+        String propertyName) '''
+        java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
             localName»"));
-        //System.out.println("«property.name»#deCode"+_dom_«property.name»);
-        java.util.List Â«property.name» = new java.util.ArrayList();
-        if(_dom_«property.name» != null) {
+        ////System.out.println("«propertyName»#deCode"+_dom_«propertyName»);
+        java.util.List Â«propertyName» = new java.util.ArrayList();
+        if(_dom_«propertyName» != null) {
             java.util.List _serialized = new java.util.ArrayList();
-            java.util.Iterator _iterator = _dom_«property.name».iterator();
+            java.util.Iterator _iterator = _dom_«propertyName».iterator();
             boolean _hasNext = _iterator.hasNext();
             while(_hasNext) {
                 Object _listItem = _iterator.next();
-                //System.out.println("  item" + _listItem);
-                Object _value = Â«type.actualTypeArguments.get(0).serializer.name».fromDomStatic(_localQName,_listItem);
-                //System.out.println("  value" + _value);
-                Â«property.name».add(_value);
+                ////System.out.println("  item" + _listItem);
+                Object _value = Â«type.actualTypeArguments.get(0).serializer.resolvedName».fromDomStatic(_localQName,_listItem);
+                ////System.out.println("  value" + _value);
+                Â«propertyName».add(_value);
                 _hasNext = _iterator.hasNext();
             }
         }
         
-        //System.out.println(" list" + Â«property.name»);
+        ////System.out.println(" list" + Â«propertyName»);
     '''
 
     private def dispatch CharSequence deserializeProperty(LeafListSchemaNode schema, ParameterizedType type,
-        MethodSignature property) '''
-        java.util.List _dom_«property.name» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
+        String propertyName) '''
+        java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
             localName»"));
-        java.util.List Â«property.name» = new java.util.ArrayList();
-        if(_dom_«property.name» != null) {
+        java.util.List Â«propertyName» = new java.util.ArrayList();
+        if(_dom_«propertyName» != null) {
             java.util.List _serialized = new java.util.ArrayList();
-            java.util.Iterator _iterator = _dom_«property.name».iterator();
+            java.util.Iterator _iterator = _dom_«propertyName».iterator();
             boolean _hasNext = _iterator.hasNext();
             while(_hasNext) {
                 Object _listItem = _iterator.next();
                 if(_listItem instanceof java.util.Map.Entry) {
                     Object _innerValue = ((java.util.Map.Entry) _listItem).getValue();
                     Object _value = Â«deserializeValue(type.actualTypeArguments.get(0), "_innerValue")»;
-                    Â«property.name».add(_value);
+                    Â«propertyName».add(_value);
                 }
                 _hasNext = _iterator.hasNext();
             }
         }
     '''
 
-    private def dispatch CharSequence deserializeProperty(LeafSchemaNode schema, Type type, MethodSignature property) '''
-        java.util.List _dom_«property.name»_list = 
+    private def dispatch CharSequence deserializeProperty(LeafSchemaNode schema, Type type, String propertyName) '''
+        java.util.List _dom_«propertyName»_list = 
             _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»"));
-        Â«type.resolvedName» Â«property.name» = null;
-        if(_dom_«property.name»_list != null && _dom_«property.name»_list.size() > 0) {
-            java.util.Map.Entry _dom_«property.name» = (java.util.Map.Entry) _dom_«property.name»_list.get(0);
-            Object _inner_value = _dom_«property.name».getValue();
-            Â«property.name» = Â«deserializeValue(type, "_inner_value")»;
+        Â«type.resolvedName» Â«propertyName» = null;
+        if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) {
+            java.util.Map.Entry _dom_«propertyName» = (java.util.Map.Entry) _dom_«propertyName»_list.get(0);
+            Object _inner_value = _dom_«propertyName».getValue();
+            Â«propertyName» = Â«deserializeValue(type, "_inner_value")»;
         }
     '''
 
     private def dispatch CharSequence deserializeProperty(ContainerSchemaNode schema, Type type,
-        MethodSignature property) '''
-        java.util.List _dom_«property.name»_list = 
+        String propertyName) '''
+        java.util.List _dom_«propertyName»_list = 
             _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»"));
-        Â«type.resolvedName» Â«property.name» = null;
-        if(_dom_«property.name»_list != null && _dom_«property.name»_list.size() > 0) {
+        Â«type.resolvedName» Â«propertyName» = null;
+        if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) {
             
-            java.util.Map _dom_«property.name» = (java.util.Map) _dom_«property.name»_list.get(0);
-            Â«type.resolvedName» Â«property.name» =  Â«type.serializer.name».fromDomStatic(_localQName,_dom_«property.name»);
+            java.util.Map _dom_«propertyName» = (java.util.Map) _dom_«propertyName»_list.get(0);
+            Â«propertyName» =  Â«type.serializer.resolvedName».fromDomStatic(_localQName,_dom_«propertyName»);
         }
     '''
 
+    private def dispatch CharSequence deserializeProperty(ChoiceNode schema, Type type, String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = Â«type.serializer.resolvedName».fromDomStatic(_localQName,_compositeNode);
+    '''
+
     private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter) '''
-        («type.resolvedName») Â«type.valueSerializer.name».fromDomValue(«domParameter»);
+        («type.resolvedName») Â«type.valueSerializer.resolvedName».fromDomValue(«domParameter»);
     '''
 
     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
@@ -445,9 +742,10 @@ class TransformerGenerator {
                 val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
-            val ctCls = createClass(typeSpec.transformatorFqn) [
+            val ctCls = createClass(typeSpec.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
-                implementsType(ctTransformator)
+                implementsType(BINDING_CODEC)
+                staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
                 implementsType(BindingDeserializer.asCtClass)
                 method(Object, "toDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
@@ -459,10 +757,11 @@ class TransformerGenerator {
                                 return null;
                             }
                             Â«typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1;
-                            //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
+                            ////System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
                             Â«returnType.resolvedName» _value =  _encapsulatedValue.getValue();
-                            //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value);
-                            return _value;
+                            ////System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value);
+                            Object _domValue = Â«serializeValue(returnType, "_value")»;
+                            return _domValue;
                         }
                     '''
                 ]
@@ -477,7 +776,7 @@ class TransformerGenerator {
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
                         {
-                            //System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
+                            ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
                             
                             if($1 == null) {
                                 return null;
@@ -497,10 +796,10 @@ class TransformerGenerator {
             ]
 
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
-            log.info("DOM Codec for {} was generated {}",inputType,ret)
+            log.info("DOM Codec for {} was generated {}", inputType, ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         } catch (Exception e) {
-            log.error("Cannot compile DOM Codec for {}",inputType,e);
+            log.error("Cannot compile DOM Codec for {}", inputType, e);
             val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
             exception.addSuppressed(e);
             throw exception;
@@ -509,10 +808,10 @@ class TransformerGenerator {
     }
 
     private def createDummyImplementation(Class<?> object, GeneratedTransferObject typeSpec) {
-        log.info("Generating Dummy DOM Codec for {} with {}",object,object.classLoader)
-        return createClass(typeSpec.transformatorFqn) [
+        log.info("Generating Dummy DOM Codec for {} with {}", object, object.classLoader)
+        return createClass(typeSpec.codecClassName) [
             //staticField(Map,"AUGMENTATION_SERIALIZERS");
-            implementsType(ctTransformator)
+            implementsType(BINDING_CODEC)
             implementsType(BindingDeserializer.asCtClass)
             method(Object, "toDomValue", Object) [
                 modifiers = PUBLIC + FINAL + STATIC
@@ -553,10 +852,10 @@ class TransformerGenerator {
     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
         Class<?> inputType, Enumeration typeSpec) {
         try {
-            log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
-            val ctCls = createClass(typeSpec.transformatorFqn) [
+            log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
+            val ctCls = createClass(typeSpec.codecClassName) [
                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
-                implementsType(ctTransformator)
+                implementsType(BINDING_CODEC)
                 method(Object, "toDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
@@ -591,49 +890,57 @@ class TransformerGenerator {
             ]
 
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
-            log.info("DOM Codec for {} was generated {}",inputType,ret)
+            log.info("DOM Codec for {} was generated {}", inputType, ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         } catch (CodeGenerationException e) {
-            throw new CodeGenerationException("Cannot compile Transformator for " + inputType,e);
+            throw new CodeGenerationException("Cannot compile Transformator for " + inputType, e);
         } catch (Exception e) {
-            log.error("Cannot compile DOM Codec for {}",inputType,e);
+            log.error("Cannot compile DOM Codec for {}", inputType, e);
             val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
             exception.addSuppressed(e);
             throw exception;
         }
 
     }
-    
+
     def Class<?> toClassImpl(CtClass newClass, ClassLoader loader, ProtectionDomain domain) {
-        val cls = newClass.toClass(loader,domain);
-        if(classFileCapturePath !== null) {
+        val cls = newClass.toClass(loader, domain);
+        if (classFileCapturePath !== null) {
             newClass.writeFile(classFileCapturePath.absolutePath);
         }
+        listener?.onCodecCreated(cls);
         return cls;
     }
-    
+
     def debugWriteClass(CtClass class1) {
-        val path = class1.name.replace(".","/")+".class"
-        
-        val captureFile = new File(classFileCapturePath,path);
+        val path = class1.name.replace(".", "/") + ".class"
+
+        val captureFile = new File(classFileCapturePath, path);
         captureFile.createNewFile
-        
-        
+
     }
 
-    private def dispatch String deserializeValue(Type type, String domParameter) '''(«type.resolvedName») Â«domParameter»'''
+    private def dispatch String deserializeValue(Type type, String domParameter) {
+        if (INSTANCE_IDENTIFIER.equals(type)) {
+
+            return '''(«InstanceIdentifier.name») Â«INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)'''
+        }
+
+        return '''(«type.resolvedName») Â«domParameter»'''
+
+    }
 
     /** 
      * Default catch all
      * 
      **/
-    private def dispatch CharSequence deserializeProperty(DataSchemaNode container, Type type, MethodSignature property) '''
-        Â«type.resolvedName» Â«property.name» = null;
+    private def dispatch CharSequence deserializeProperty(DataSchemaNode container, Type type, String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = null;
     '''
 
     private def dispatch CharSequence deserializeProperty(DataSchemaNode container, GeneratedTypeBuilder type,
-        MethodSignature property) {
-        _deserializeProperty(container, type.toInstance, property)
+        String propertyName) {
+        _deserializeProperty(container, type.toInstance, propertyName)
     }
 
     public static def toSetter(String it) {
@@ -647,84 +954,96 @@ class TransformerGenerator {
     }
 
     /* 
-    private def dispatch CharSequence deserializeProperty(DataSchemaNode container,GeneratedType type, MethodSignature property) '''
-        Â«property.returnType.resolvedName» Â«property.name» = value.«property.name»();
-        if(«property.name» != null) {
-            Object domValue = Â«type.serializer».toDomStatic(QNAME,«property.name»);
-            childNodes.add(domValue);
+    private def dispatch CharSequence deserializeProperty(DataSchemaNode container,GeneratedType type, String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            Object domValue = Â«type.serializer».toDomStatic(QNAME,«propertyName»);
+            _childNodes.add(domValue);
         }
     '''
     */
     private def getBuilderName(GeneratedType type) '''«type.resolvedName»Builder'''
 
-    private def staticQNameField(CtClass it, Class node) {
+    private def staticQNameField(CtClass it, Class<?> node) {
         val field = new CtField(ctQName, "QNAME", it);
         field.modifiers = PUBLIC + FINAL + STATIC;
         addField(field, '''«node.name».QNAME''')
     }
-    
+
     private def staticQNameField(CtClass it, QName node) {
         val field = new CtField(ctQName, "QNAME", it);
         field.modifiers = PUBLIC + FINAL + STATIC;
-        addField(field, '''«QName.asCtClass.name».create("«node.namespace»","«node.formattedRevision»","«node.localName»")''')
+        addField(field,
+            '''«QName.asCtClass.name».create("«node.namespace»","«node.formattedRevision»","«node.localName»")''')
     }
 
     private def dispatch String serializeBody(GeneratedType type, ListSchemaNode node) '''
         {
-            Â«QName.name» resultName = Â«QName.name».create($1,QNAME.getLocalName());
-            java.util.List childNodes = new java.util.ArrayList();
+            Â«QName.name» _resultName = Â«QName.name».create($1,QNAME.getLocalName());
+            java.util.List _childNodes = new java.util.ArrayList();
             Â«type.resolvedName» value = («type.resolvedName») $2;
             Â«transformDataContainerBody(type.allProperties, node)»
-            return ($r) java.util.Collections.singletonMap(resultName,childNodes);
+            Â«serializeAugmentations»
+            return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
         }
     '''
 
     private def dispatch String serializeBody(GeneratedType type, ContainerSchemaNode node) '''
         {
-            Â«QName.name» resultName = Â«QName.name».create($1,QNAME.getLocalName());
-            java.util.List childNodes = new java.util.ArrayList();
+            Â«QName.name» _resultName = Â«QName.name».create($1,QNAME.getLocalName());
+            java.util.List _childNodes = new java.util.ArrayList();
             Â«type.resolvedName» value = («type.resolvedName») $2;
             Â«transformDataContainerBody(type.allProperties, node)»
-            return ($r) java.util.Collections.singletonMap(resultName,childNodes);
+            Â«serializeAugmentations»
+            return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
         }
     '''
 
     private def dispatch String serializeBody(GeneratedType type, ChoiceCaseNode node) '''
         {
-        Â«QName.name» resultName = Â«QName.name».create($1,QNAME.getLocalName());
-            java.util.List childNodes = new java.util.ArrayList();
+        Â«QName.name» _resultName = Â«QName.name».create($1,QNAME.getLocalName());
+            java.util.List _childNodes = new java.util.ArrayList();
             Â«type.resolvedName» value = («type.resolvedName») $2;
             Â«transformDataContainerBody(type.allProperties, node)»
-            return ($r) java.util.Collections.singletonMap(resultName,childNodes);
+            Â«serializeAugmentations»
+            return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
         }
     '''
 
     private def dispatch String serializeBody(GeneratedType type, SchemaNode node) '''
         {
-        Â«QName.name» resultName = Â«QName.name».create($1,QNAME.getLocalName());
-            java.util.List childNodes = new java.util.ArrayList();
+        Â«QName.name» _resultName = Â«QName.name».create($1,QNAME.getLocalName());
+            java.util.List _childNodes = new java.util.ArrayList();
             Â«type.resolvedName» value = («type.resolvedName») $2;
-            return ($r) java.util.Collections.singletonMap(resultName,childNodes);
+            return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
         }
     '''
 
-
-    private def transformDataContainerBody(Map<String, MethodSignature> properties, DataNodeContainer node) {
+    private def transformDataContainerBody(Map<String, Type> properties, DataNodeContainer node) {
         val ret = '''
             Â«FOR child : node.childNodes.filter[!augmenting]»
                 Â«var signature = properties.getFor(child)»
-                Â«serializeProperty(child, signature.returnType, signature)»
+                //System.out.println("«signature.key»" + value.«signature.key»());
+                Â«serializeProperty(child, signature.value, signature.key)»
             Â«ENDFOR»
         '''
         return ret;
     }
-    
-    def MethodSignature getFor(Map<String,MethodSignature> map, DataSchemaNode node) {
+
+    def serializeAugmentations() '''
+        java.util.List _augmentations = (java.util.List) Â«AUGMENTATION_CODEC».serialize(value);
+        if(_augmentations != null) {
+            _childNodes.addAll(_augmentations);
+        }
+    '''
+
+    def Entry<String, Type> getFor(Map<String, Type> map, DataSchemaNode node) {
         val sig = map.get(node.getterName);
-        if(sig == null) {
-            return map.get(node.booleanGetterName);
+        if (sig == null) {
+
+            return new SimpleEntry(node.booleanGetterName, map.get(node.booleanGetterName));
         }
-        return sig;
+        return new SimpleEntry(node.getterName, sig);
     }
 
     private static def String getBooleanGetterName(DataSchemaNode node) {
@@ -740,106 +1059,126 @@ class TransformerGenerator {
     }
 
     private def dispatch CharSequence serializeProperty(ListSchemaNode schema, ParameterizedType type,
-        MethodSignature property) '''
-        Â«property.returnType.resolvedName» Â«property.name» = value.«property.name»();
-        if(«property.name» != null) {
-            java.util.Iterator _iterator = Â«property.name».iterator();
+        String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            java.util.Iterator _iterator = Â«propertyName».iterator();
             boolean _hasNext = _iterator.hasNext();
             while(_hasNext) {
                 Object _listItem = _iterator.next();
-                Object _domValue = Â«type.actualTypeArguments.get(0).serializer.name».toDomStatic(QNAME,_listItem);
-                childNodes.add(_domValue);
+                Object _domValue = Â«type.actualTypeArguments.get(0).serializer.resolvedName».toDomStatic(_resultName,_listItem);
+                _childNodes.add(_domValue);
                 _hasNext = _iterator.hasNext();
             }
         }
     '''
 
-    private def dispatch CharSequence serializeProperty(LeafSchemaNode schema, Type type, MethodSignature property) '''
-        Â«property.returnType.resolvedName» Â«property.name» = value.«property.name»();
+    private def dispatch CharSequence serializeProperty(LeafSchemaNode schema, Type type, String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = value.«propertyName»();
         
-        if(«property.name» != null) {
-            Â«QName.name» _qname = Â«QName.name».create(resultName,"«schema.QName.localName»");
-            Object _propValue = Â«serializeValue(type, property.name)»;
+        if(«propertyName» != null) {
+            Â«QName.name» _qname = Â«QName.name».create(_resultName,"«schema.QName.localName»");
+            Object _propValue = Â«serializeValue(type, propertyName)»;
             if(_propValue != null) {
                 Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
-                childNodes.add(_domValue);
+                _childNodes.add(_domValue);
             }
         }
     '''
 
-    private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer.name».toDomValue(«parameter»)'''
+    private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer.
+        resolvedName».toDomValue(«parameter»)'''
 
-    private def dispatch serializeValue(Type signature, String property) '''«property»'''
+    private def dispatch serializeValue(Type signature, String property) {
+        if (INSTANCE_IDENTIFIER == signature) {
+            return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)'''
+        }
+        return '''«property»''';
+    }
 
-    private def dispatch CharSequence serializeProperty(LeafListSchemaNode schema, Type type, MethodSignature property) '''
-        Â«property.returnType.resolvedName» Â«property.name» = value.«property.name»();
-        if(«property.name» != null) {
-            Â«QName.name» _qname = Â«QName.name».create(resultName,"«schema.QName.localName»");
-            java.util.Iterator _iterator = Â«property.name».iterator();
+    private def dispatch CharSequence serializeProperty(LeafListSchemaNode schema, ParameterizedType type,
+        String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            Â«QName.name» _qname = Â«QName.name».create(_resultName,"«schema.QName.localName»");
+            java.util.Iterator _iterator = Â«propertyName».iterator();
             boolean _hasNext = _iterator.hasNext();
             while(_hasNext) {
                 Object _listItem = _iterator.next();
-                Object _propValue = Â«property.name»;
+                Object _propValue = Â«serializeValue(type.actualTypeArguments.get(0), "_listItem")»;
                 Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
-                childNodes.add(_domValue);
+                _childNodes.add(_domValue);
                 _hasNext = _iterator.hasNext();
             }
         }
     '''
 
+    private def dispatch CharSequence serializeProperty(ChoiceNode container, GeneratedType type,
+        String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            java.util.List domValue = Â«type.serializer.resolvedName».toDomStatic(_resultName,«propertyName»);
+            _childNodes.addAll(domValue);
+        }
+    '''
+
     /** 
      * Default catch all
      * 
      **/
-    private def dispatch CharSequence serializeProperty(DataSchemaNode container, Type type, MethodSignature property) '''
-        Â«property.returnType.resolvedName» Â«property.name» = value.«property.name»();
-        if(«property.name» != null) {
-            Object domValue = Â«property.name»;
-            childNodes.add(domValue);
+    private def dispatch CharSequence serializeProperty(DataSchemaNode container, Type type, String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            Object domValue = Â«propertyName»;
+            _childNodes.add(domValue);
         }
     '''
 
     private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedTypeBuilder type,
-        MethodSignature property) {
-        serializeProperty(container, type.toInstance, property)
+        String propertyName) {
+        serializeProperty(container, type.toInstance, propertyName)
     }
 
     private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedType type,
-        MethodSignature property) '''
-        Â«property.returnType.resolvedName» Â«property.name» = value.«property.name»();
-        if(«property.name» != null) {
-            Object domValue = Â«type.serializer.name».toDomStatic(QNAME,«property.name»);
-            childNodes.add(domValue);
+        String propertyName) '''
+        Â«type.resolvedName» Â«propertyName» = value.«propertyName»();
+        if(«propertyName» != null) {
+            Object domValue = Â«type.serializer.resolvedName».toDomStatic(_resultName,«propertyName»);
+            _childNodes.add(domValue);
         }
     '''
 
-
-
-    private def transformatorFqn(GeneratedType typeSpec) {
+    private def codecClassName(GeneratedType typeSpec) {
         return '''«typeSpec.resolvedName»$Broker$Codec$DOM'''
     }
 
-    private def transformatorFqn(Class typeSpec) {
+    private def codecClassName(Class typeSpec) {
         return '''«typeSpec.name»$Broker$Codec$DOM'''
     }
 
-    private def HashMap<String, MethodSignature> getAllProperties(GeneratedType type) {
-        val ret = new HashMap<String, MethodSignature>();
+    private def dispatch HashMap<String, Type> getAllProperties(GeneratedType type) {
+        val ret = new HashMap<String, Type>();
         type.collectAllProperties(ret);
         return ret;
     }
 
-    private def dispatch void collectAllProperties(GeneratedType type, Map<String, MethodSignature> set) {
+    private def dispatch void collectAllProperties(GeneratedType type, Map<String, Type> set) {
         for (definition : type.methodDefinitions) {
-            set.put(definition.name, definition);
+            set.put(definition.name, definition.returnType);
+        }
+        for (property : type.properties) {
+            set.put(property.getterName, property.returnType);
         }
-
         for (parent : type.implements) {
             parent.collectAllProperties(set);
         }
     }
 
-    private def dispatch void collectAllProperties(Type type, Map<String, MethodSignature> set) {
+    def String getGetterName(GeneratedProperty property) {
+        return "get" + property.name.toFirstUpper
+    }
+
+    private def dispatch void collectAllProperties(Type type, Map<String, Type> set) {
         // NOOP for generic type.
     }
 
@@ -847,22 +1186,24 @@ class TransformerGenerator {
         return type.asCtClass.name;
     }
 
+    def String getResolvedName(Class type) {
+        return type.asCtClass.name;
+    }
+
     def CtClass asCtClass(Type type) {
         val name = type.fullyQualifiedName
         val cls = loadClassWithTCCL(type.fullyQualifiedName)
         return cls.asCtClass;
     }
-    
-    
-    
-    private def dispatch processException(Class<?> inputType,CodeGenerationException e){
-        log.error("Cannot compile DOM Codec for {}. One of it's prerequisites was not generated.",inputType);
+
+    private def dispatch processException(Class<?> inputType, CodeGenerationException e) {
+        log.error("Cannot compile DOM Codec for {}. One of it's prerequisites was not generated.", inputType);
         throw e;
     }
-    
-    private def dispatch processException(Class<?> inputType,Exception e){
-        log.error("Cannot compile DOM Codec for {}",inputType,e);
-        val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType,e);
+
+    private def dispatch processException(Class<?> inputType, Exception e) {
+        log.error("Cannot compile DOM Codec for {}", inputType, e);
+        val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType, e);
         throw exception;
     }
 
@@ -876,7 +1217,7 @@ class PropertyPair {
     Type type;
 
     @Property
-    MethodSignature signature;
+    Type returnType;
     @Property
     SchemaNode schemaNode;
 }
index 6e493057b240e2f7bcce4c2ebad267afbf9fb4c6..887ef82ca90c459d6ed4e8d12bc7c52903442919 100644 (file)
@@ -179,7 +179,7 @@ class NotifyTask implements Callable<Object> {
         try {
             listener.onNotification(notification);
         } catch (Exception e) {
-            log.error("Unhandled exception {} thrown by listener: {} Notification: {}", e, listener, notification);
+            log.error("Unhandled exception thrown by listener: {}", listener, e);
         }
         return null;
     }
index d8fbc70f8e26d70a1320688c1051cc9c20b74c0a..8e61c9b3eeb8c131d81d30c8446b460c297eda95 100644 (file)
@@ -2,6 +2,7 @@ package org.opendaylight.controller.sal.binding.impl.connect.dom;
 
 import java.util.Map.Entry;
 
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@@ -16,4 +17,6 @@ public interface BindingIndependentMappingService {
     org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(InstanceIdentifier<? extends DataObject> path);
 
     DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result);
+    
+    
 }
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend
deleted file mode 100644 (file)
index a0e1c98..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-package org.opendaylight.controller.sal.binding.impl.connect.dom
-
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext
-import java.util.List
-import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
-import org.opendaylight.yangtools.sal.binding.model.api.Type
-import org.opendaylight.yangtools.yang.model.api.SchemaNode
-import java.util.Map
-import org.opendaylight.yangtools.yang.model.api.SchemaPath
-import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
-import org.opendaylight.yangtools.binding.generator.util.Types
-import java.util.HashMap
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.binding.DataContainer
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
-import java.util.Collections
-import java.util.ArrayList
-import org.opendaylight.yangtools.yang.data.api.Node
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
-import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
-import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
-import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition
-import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition
-import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
-import org.opendaylight.yangtools.yang.model.util.ExtendedType
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
-import com.google.common.collect.FluentIterable
-import org.opendaylight.yangtools.yang.data.api.SimpleNode
-import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
-import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils
-import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition
-import com.google.common.collect.HashMultimap
-import com.google.common.collect.ArrayListMultimap
-import com.google.common.collect.Multimap
-import java.util.Collection
-import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
-
-class BindingMapping {
-
-    @Property
-    val Map<Type, GeneratedTypeBuilder> typeToDefinition = new HashMap();
-    
-    @Property
-    val Map<Type, SchemaNode> typeToSchemaNode = new HashMap();
-
-    def QName getSchemaNode(Class<?> cls) {
-        val ref = Types.typeForClass(cls);
-        return typeToSchemaNode.get(ref)?.QName;
-    }
-
-    def void updateBinding(SchemaContext schemaContext, ModuleContext moduleBindingContext) {
-        updateBindingFor(moduleBindingContext.childNodes, schemaContext);
-
-    }
-
-    def org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
-        InstanceIdentifier<? extends DataObject> obj) {
-        val pathArguments = obj.path;
-        var Class<? extends DataObject> parent;
-        val dataDomArgs = new ArrayList<PathArgument>();
-        for (pathArgument : pathArguments) {
-            dataDomArgs.add(pathArgument.toDataDomPathArgument(parent));
-            parent = pathArgument.type;
-        }
-
-        return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(dataDomArgs);
-    }
-
-    
-
-    def DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> identifier, CompositeNode node) {
-        if (node == null) {
-            return null;
-        }
-        val targetClass = identifier.targetType;
-        val classLoader = targetClass.classLoader;
-        val ref = Types.typeForClass(targetClass);
-        val targetType = typeToDefinition.get(ref);
-        val targetSchema = typeToSchemaNode.get(ref);
-        return node.toDataObject(classLoader, targetType.toInstance, targetSchema);
-
-    }
-
-    private def dispatch PathArgument toDataDomPathArgument(IdentifiableItem argument, Class<? extends DataObject> parent) {
-        val Class rawType = argument.type;
-        val ref = Types.typeForClass(rawType);
-        val schemaType = typeToSchemaNode.get(ref);
-        val qname = schemaType.QName
-
-        val Object key = argument.key;
-        val predicates = key.toPredicates(schemaType as ListSchemaNode);
-
-        return new NodeIdentifierWithPredicates(qname, predicates);
-    }
-    
-    private def dispatch PathArgument toDataDomPathArgument(Item<?> argument, Class<? extends DataObject> parent) {
-        val ref = Types.typeForClass(argument.type);
-        val qname = typeToSchemaNode.get(ref).QName
-        return new NodeIdentifier(qname);
-    }
-
-    private def Map<QName, Object> toPredicates(Object identifier, ListSchemaNode node) {
-        val keyDefinitions = node.keyDefinition;
-        val map = new HashMap<QName, Object>();
-        for (keydef : keyDefinitions) {
-            val keyNode = node.getDataChildByName(keydef) as LeafSchemaNode;
-            val value = identifier.getSimpleValue(keydef, keyNode.type);
-            map.put(keydef, value.value);
-        }
-        return map;
-    }
-
-    def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
-        for (entry : map.entrySet) {
-            val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
-            typeToDefinition.put(entry.value, entry.value);
-            typeToSchemaNode.put(entry.value, schemaNode)
-        }
-    }
-
-    def CompositeNode toCompositeNode(DataContainer data) {
-        val type = data.implementedInterface;
-        val typeRef = Types.typeForClass(type);
-        val schemaNode = typeToSchemaNode.get(typeRef);
-        val generatedType = typeToDefinition.get(typeRef);
-
-        return data.toDataDom(schemaNode, generatedType);
-    }
-
-    private def dispatch CompositeNode toDataDom(DataContainer data, ContainerSchemaNode node,
-        GeneratedTypeBuilder builder) {
-        val subnodes = data.toDataDomComponents(node);
-        return new CompositeNodeTOImpl(node.QName, null, subnodes);
-    }
-
-    private def dispatch CompositeNode toDataDom(DataContainer data, NotificationDefinition node,
-        GeneratedTypeBuilder builder) {
-        val subnodes = data.toDataDomComponents(node);
-        return new CompositeNodeTOImpl(node.QName, null, subnodes);
-    }
-
-    private def dispatch CompositeNode toDataDom(DataContainer data, ListSchemaNode node,
-        GeneratedTypeBuilder builder) {
-        val subnodes = data.toDataDomComponents(node);
-        return new CompositeNodeTOImpl(node.QName, null, subnodes);
-    }
-
-    private def List<Node<?>> toDataDomComponents(DataContainer data, DataNodeContainer node) {
-        val subnodes = new ArrayList<Node<?>>();
-        for (childNode : node.childNodes) {
-            val value = childNode.dataDomFromParent(data);
-            if (value !== null) {
-                subnodes.addAll(value);
-            }
-        }
-        return subnodes;
-    }
-
-    private def List<Node<?>> dataDomFromParent(DataSchemaNode node, DataContainer container) {
-        if (node.augmenting) {
-            return Collections.emptyList();
-        }
-        return dataDomFromParentImpl(node, container);
-    }
-
-    private def dispatch List<Node<?>> dataDomFromParentImpl(LeafSchemaNode node, DataContainer container) {
-        val value = container.getSimpleValue(node.QName, node.type);
-        if (value !== null) {
-            return Collections.<Node<?>>singletonList(value);
-        }
-        return Collections.emptyList();
-    }
-
-    private def dispatch List<Node<?>> dataDomFromParentImpl(LeafListSchemaNode node, DataContainer container) {
-        val values = container.getSimpleValues(node);
-        if (values !== null) {
-            //val it = new ArrayList<Node<?>>();
-            //for (value : values) {
-            //}
-
-        }
-        return Collections.emptyList();
-    }
-
-    private def getSimpleValues(DataContainer container, LeafListSchemaNode node) {
-        return Collections.emptyList();
-    }
-
-    private def dispatch List<Node<?>> dataDomFromParentImpl(ListSchemaNode node, DataContainer container) {
-        val qname = node.QName;
-        val values = container.<List>getValue(qname, List) as List<? extends DataContainer>;
-        if (values === null) {
-            return Collections.emptyList;
-        }
-        val it = new ArrayList<Node<?>>();
-        for (value : values) {
-            add(value.toCompositeNode());
-        }
-
-        return it;
-    }
-
-    private def dispatch List<Node<?>> dataDomFromParentImpl(ChoiceNode node, DataContainer container) {
-    }
-
-    private def dispatch List<Node<?>> serializeValueImpl(List<?> list, GeneratedTypeBuilder builder,
-        ListSchemaNode node) {
-        val it = new ArrayList<Node<?>>();
-        for (value : list) {
-
-            val serVal = value.serializeValueImpl(builder, node);
-            if (serVal !== null) {
-                addAll(serVal);
-            }
-        }
-        return it;
-    }
-
-    public static def dispatch Node<?> getSimpleValue(Object container, QName name, ExtendedType type) {
-        getSimpleValue(container, name, type.baseType);
-    }
-
-    public static def dispatch Node<?> getSimpleValue(Object container, QName name, StringTypeDefinition type) {
-        val value = container.getValue(name, String);
-        if(value === null) return null;
-        return new SimpleNodeTOImpl(name, null, value);
-    }
-
-    public static def dispatch Node<?> getSimpleValue(Object container, QName name, TypeDefinition<?> type) {
-        val value = container.getValue(name, Object);
-        if(value === null) return null;
-        return new SimpleNodeTOImpl(name, null, value);
-    }
-
-    public static def dispatch Node<?> getSimpleValue(Object container, QName name, BooleanTypeDefinition type) {
-        val value = container.getValue(name, Boolean);
-        if(value === null) return null;
-        return new SimpleNodeTOImpl(name, null, value);
-    }
-
-    public static def dispatch Node<?> getSimpleValue(Object container, QName name, BinaryTypeDefinition type) {
-        val Object value = container.getValue(name, Object); //Constants.BYTES_CLASS);
-        if(value === null) return null;
-        return new SimpleNodeTOImpl(name, null, value);
-    }
-
-    public static def <T> T getValue(Object object, QName node, Class<T> type) {
-        val methodName = BindingGeneratorImpl.getterMethodName(node.localName, Types.typeForClass(type));
-        var clz = object.class;
-        if (object instanceof DataContainer) {
-            clz = (object as DataContainer).implementedInterface;
-        }
-        val method = clz.getMethod(methodName);
-        if (method === null) {
-            return null;
-        }
-        val value = method.invoke(object);
-        if (value === null) {
-            return null;
-        }
-        if (type.isAssignableFrom(value.class)) {
-            return value  as T;
-        }
-        return value.getEncapsulatedValue(type);
-    }
-
-    public static def <T> T getEncapsulatedValue(Object value, Class<T> type) {
-        val method = value.class.getMethod("getValue");
-        if (method !== null && type.isAssignableFrom(method.returnType)) {
-            return method.invoke(value) as T;
-        }
-        return null;
-    }
-
-    private def dispatch List<Node<?>> serializeValueImpl(DataContainer data, GeneratedTypeBuilder builder,
-        SchemaNode node) {
-        return Collections.<Node<?>>singletonList(data.toDataDom(node, builder));
-    }
-
-    private def dispatch List<Node<?>> serializeValueImpl(Object object, GeneratedTypeBuilder builder,
-        SchemaNode node) {
-    }
-
-    def DataObject toDataObject(CompositeNode node, ClassLoader loader, GeneratedType type, SchemaNode schema) {
-
-        // Nasty reflection hack (for now)
-        val builderClass = loader.loadClass(type.builderFQN);
-        val builder = builderClass.newInstance;
-        val buildMethod = builderClass.getMethod("build");
-
-        node.fillDataObject(builder, loader, type, schema);
-
-        return buildMethod.invoke(builder) as DataObject;
-    }
-
-    private def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type,
-        ListSchemaNode schema) {
-
-        if (schema.keyDefinition !== null && !schema.keyDefinition.empty) {
-
-            val value = node.keyToBindingKey(loader, type, schema);
-            builder.setProperty("key", value);
-        }
-        node.fillBuilderFromContainer(builder,loader,type,schema);
-    }
-    
-    
-
-    private def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type,
-        ContainerSchemaNode schema) {
-        node.fillBuilderFromContainer(builder,loader,type,schema);
-    }
-
-    
-    private def void fillBuilderFromContainer(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type, DataNodeContainer schema) {
-        val Multimap<QName,Node<?>> dataMap = ArrayListMultimap.create();
-        for(child :node.children) {
-            dataMap.put(child.nodeType,node);
-        }
-        for(entry : dataMap.asMap.entrySet) {
-            val entrySchema = schema.getDataChildByName(entry.key);
-            val entryType = type.methodDefinitions.byQName(entry.key);
-            entry.value.addValueToBuilder(builder,loader,entryType,entrySchema);
-        }
-    }
-    
-    private def Type byQName(List<MethodSignature> signatures, QName name) {
-      
-    }
-    
-    private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, LeafSchemaNode container) {
-        
-    }
-    
-    
-    
-    private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, ContainerSchemaNode container) {
-        
-    }
-    
-    
-    private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, ListSchemaNode container) {
-        
-    }
-    
-    private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, LeafListSchemaNode container) {
-        
-    }
-    
-    
-    
-    
-    private def Object keyToBindingKey(CompositeNode node, ClassLoader loader, GeneratedType type, ListSchemaNode schema) {
-        val keyClass = loader.loadClass(type.keyFQN);
-        val constructor = keyClass.constructors.get(0);
-        val keyType = type.keyTypeProperties;
-        val args = new ArrayList();
-        for (key : schema.keyDefinition) {
-            var keyProperty = keyType.get(BindingGeneratorUtil.parseToClassName(key.localName));
-            if (keyProperty == null) {
-                keyProperty = keyType.get(BindingGeneratorUtil.parseToValidParamName(key.localName));
-            }
-            val domKeyValue = node.getFirstSimpleByName(key);
-            val keyValue = domKeyValue.deserializeSimpleValue(loader, keyProperty.returnType,
-                schema.getDataChildByName(key));
-            args.add(keyValue);
-        }
-        return ClassLoaderUtils.construct(constructor, args);
-    }
-
-    private def dispatch Object deserializeSimpleValue(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
-        LeafSchemaNode node2) {
-        deserializeSimpleValueImpl(node, loader, type, node2.type);
-    }
-
-    private def dispatch Object deserializeSimpleValue(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
-        LeafListSchemaNode node2) {
-        deserializeSimpleValueImpl(node, loader, type, node2.type);
-    }
-
-    private def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
-        ExtendedType definition) {
-        deserializeSimpleValueImpl(node, loader, type, definition.baseType);
-    }
-
-    private def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
-        StringTypeDefinition definition) {
-        if (type instanceof GeneratedTransferObject) {
-            val cls = loader.getClassForType(type);
-            val const = cls.getConstructor(String);
-            val str = String.valueOf(node.value);
-            return const.newInstance(str);
-        }
-        return node.value;
-    }
-
-    private def Class<?> getClassForType(ClassLoader loader, Type type) {
-        loader.loadClass(type.fullyQualifiedName);
-    }
-
-    private def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
-        TypeDefinition definition) {
-        throw new UnsupportedOperationException("TODO: auto-generated method stub")
-    }
-
-    private def Map<String, GeneratedProperty> getKeyTypeProperties(GeneratedType type) {
-        val method = FluentIterable.from(type.methodDefinitions).findFirst[name == "getKey"]
-        val key = method.returnType as GeneratedTransferObject;
-        val ret = new HashMap<String, GeneratedProperty>();
-        for (prop : key.properties) {
-            ret.put(prop.name, prop);
-        }
-        return ret;
-    }
-
-    private def void setProperty(Object object, String property, Object value) {
-        val cls = object.class;
-        val valMethod = cls.getMethod("set" + property.toFirstUpper, value.class);
-        if (valMethod != null)
-            valMethod.invoke(object, value);
-    }
-
-    private def String getBuilderFQN(Type type) '''«type.fullyQualifiedName»Builder'''
-
-    private def String getKeyFQN(Type type) '''«type.fullyQualifiedName»Key'''
-
-}
-
-@Data
-class PropertyCapture {
-
-    @Property
-    val Type returnType;
-    @Property
-    val String name;
-
-}
index af18e9c0cb184a7d7060fd34e37c674fce1d28c9..f69e664ee8c764d3eb8be718ed88932ff1474f50 100644 (file)
@@ -6,6 +6,7 @@ import java.util.Collections;
 import javassist.ClassPool;
 
 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.dom.serializer.impl.TransformerGenerator;
 import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.controller.sal.core.api.Provider;
@@ -42,6 +43,7 @@ public class ConnectorActivator implements Provider, ServiceTrackerCustomizer<Br
     public void onSessionInitiated(ProviderSession session) {
 
         RuntimeGeneratedMappingServiceImpl mappingImpl = new RuntimeGeneratedMappingServiceImpl();
+        mappingImpl.setPool(new ClassPool());
         SchemaService schemaService = (session.getService(SchemaService.class));
         ClassPool pool = new ClassPool();
         mappingImpl.setBinding(new TransformerGenerator(pool));
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/MappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/MappingServiceImpl.xtend
deleted file mode 100644 (file)
index 84a0065..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.opendaylight.controller.sal.binding.impl.connect.dom
-
-import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
-import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import org.opendaylight.yangtools.sal.binding.model.api.CodeGenerator
-import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
-import org.opendaylight.yangtools.sal.binding.generator.api.BindingGenerator
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
-import java.util.Collections
-import java.util.Map.Entry
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import java.util.AbstractMap.SimpleEntry
-import org.opendaylight.controller.sal.core.api.model.SchemaService
-
-class MappingServiceImpl implements SchemaServiceListener, BindingIndependentMappingService {
-
-    var extension BindingMapping mapping = new BindingMapping;
-
-    @Property
-    BindingGeneratorImpl binding;
-
-    @Property
-    SchemaService schemaService;
-
-    override onGlobalContextUpdated(SchemaContext arg0) {
-        recreateBindingContext(arg0);
-    }
-
-    def recreateBindingContext(SchemaContext schemaContext) {
-        val newBinding = new BindingGeneratorImpl();
-        newBinding.generateTypes(schemaContext);
-        val newMapping = new BindingMapping();
-        for (entry : newBinding.moduleContexts.entrySet) {
-            val module = entry.key;
-            val context = entry.value;
-            
-            newMapping.updateBinding(schemaContext, context);
-        }
-        mapping = newMapping
-    }
-
-    override CompositeNode toDataDom(DataObject data) {
-        mapping.toCompositeNode(data);
-    }
-
-    override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
-        Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
-        val key = mapping.toDataDom(entry.key);
-        val data = mapping.toCompositeNode(entry.value);
-        return new SimpleEntry(key, data);
-    }
-
-    override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
-        InstanceIdentifier<? extends DataObject> path) {
-        return mapping.toDataDom(path);
-    }
-    
-    override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result) {
-        return mapping.dataObjectFromDataDom(path,result);
-    }
-    
-    public def void start() {
-        schemaService.registerSchemaServiceListener(this);
-        recreateBindingContext(schemaService.globalContext);
-    }
-}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/RuntimeGeneratedMappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/RuntimeGeneratedMappingServiceImpl.xtend
deleted file mode 100644 (file)
index c1efd11..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-package org.opendaylight.controller.sal.binding.impl.connect.dom
-
-import org.opendaylight.controller.sal.binding.dom.serializer.impl.TransformerGenerator
-import javassist.ClassPool
-import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
-import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
-import java.util.Map
-import org.opendaylight.yangtools.sal.binding.model.api.Type
-import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
-import org.opendaylight.yangtools.yang.model.api.SchemaNode
-import java.util.HashMap
-import java.util.concurrent.ConcurrentHashMap
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import java.util.Map.Entry
-import java.util.AbstractMap.SimpleEntry
-import org.opendaylight.yangtools.yang.model.api.SchemaPath
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
-import java.util.ArrayList
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
-import org.opendaylight.yangtools.binding.generator.util.Types
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
-import org.opendaylight.yangtools.yang.binding.DataContainer
-import static com.google.common.base.Preconditions.*;
-import java.util.List
-import org.opendaylight.yangtools.yang.data.api.Node
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
-import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
-import org.opendaylight.yangtools.concepts.Delegator
-import java.util.concurrent.ConcurrentMap
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
-import org.opendaylight.yangtools.yang.binding.BindingCodec
-
-class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener {
-
-    ClassPool pool;
-
-    @Property
-    extension TransformerGenerator binding;
-    
-    val ConcurrentMap<Type, Type> typeDefinitions = new ConcurrentHashMap();
-
-    val ConcurrentMap<Class<? extends DataContainer>, TransformerWrapper> domSerializers = new ConcurrentHashMap();
-
-    @Property
-    val ConcurrentMap<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
-
-    @Property
-    val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
-
-    override onGlobalContextUpdated(SchemaContext arg0) {
-        recreateBindingContext(arg0);
-    }
-
-    def recreateBindingContext(SchemaContext schemaContext) {
-        val newBinding = new BindingGeneratorImpl();
-        newBinding.generateTypes(schemaContext);
-
-        for (entry : newBinding.moduleContexts.entrySet) {
-
-            //val module = entry.key;
-            val context = entry.value;
-            updateBindingFor(context.childNodes, schemaContext);
-            
-            val typedefs = context.typedefs;
-            for(typedef : typedefs.values) {
-                binding.typeDefinitions.put(typedef,typedef as GeneratedType);
-            }
-        }
-    }
-
-    override CompositeNode toDataDom(DataObject data) {
-        toCompositeNodeImpl(data);
-    }
-
-    override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
-        Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
-        val key = toDataDomImpl(entry.key);
-        val data = toCompositeNodeImpl(entry.value);
-        return new SimpleEntry(key, data);
-    }
-
-    private def CompositeNode toCompositeNodeImpl(DataObject object) {
-        val cls = object.implementedInterface;
-        val transformator = resolveTransformator(cls);
-        val ret = transformator.transform(object);
-        return ret;
-    }
-
-    private def resolveTransformator(Class<? extends DataContainer> cls) {
-        val serializer = domSerializers.get(cls);
-        if (serializer !== null) {
-            return serializer;
-        }
-        val transformerClass = binding.transformerFor(cls).newInstance;
-        val wrapper = new TransformerWrapper(transformerClass);
-        domSerializers.putIfAbsent(cls, wrapper);
-        return wrapper;
-    }
-
-    private def org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDomImpl(
-        InstanceIdentifier<? extends DataObject> object) {
-        val pathArguments = object.path;
-        var Class<? extends DataObject> parent;
-        val dataDomArgs = new ArrayList<PathArgument>();
-        for (pathArgument : pathArguments) {
-            dataDomArgs.add(pathArgument.toDataDomPathArgument(parent));
-            parent = pathArgument.type;
-        }
-
-        return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(dataDomArgs);
-    }
-
-    override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
-        InstanceIdentifier<? extends DataObject> path) {
-        return toDataDomImpl(path);
-    }
-
-    override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result) {
-        return dataObjectFromDataDomImpl(path, result);
-    }
-
-    def DataObject dataObjectFromDataDomImpl(InstanceIdentifier<? extends DataObject> identifier, CompositeNode node) {
-        val targetType = identifier.targetType
-        val transformer = resolveTransformator(targetType);
-        val ret = transformer.deserialize(node) as DataObject;
-        return ret;
-    }
-
-    def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
-        for (entry : map.entrySet) {
-            val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
-            typeToDefinition.put(entry.value, entry.value);
-            typeToSchemaNode.put(entry.value, schemaNode)
-        }
-    }
-
-    private def dispatch PathArgument toDataDomPathArgument(IdentifiableItem argument,
-        Class<? extends DataObject> parent) {
-        val Class<?> rawType = argument.type;
-        val ref = Types.typeForClass(rawType);
-        val schemaType = typeToSchemaNode.get(ref);
-        val qname = schemaType.QName
-
-        val Object key = argument.key;
-        val predicates = key.toPredicates(schemaType as ListSchemaNode);
-
-        return new NodeIdentifierWithPredicates(qname, predicates);
-    }
-
-    private def Map<QName, Object> toPredicates(Object identifier, ListSchemaNode node) {
-        val keyDefinitions = node.keyDefinition;
-        val map = new HashMap<QName, Object>();
-        for (keydef : keyDefinitions) {
-            val keyNode = node.getDataChildByName(keydef) as LeafSchemaNode;
-            val value = BindingMapping.getSimpleValue(identifier, keydef, keyNode.type);
-            map.put(keydef, value.value);
-        }
-        return map;
-    }
-
-    private def dispatch PathArgument toDataDomPathArgument(Item<?> argument, Class<? extends DataObject> parent) {
-        val ref = Types.typeForClass(argument.type);
-        val qname = typeToSchemaNode.get(ref).QName
-        return new NodeIdentifier(qname);
-    }
-
-    public def void start() {
-        pool = new ClassPool()
-        binding = new TransformerGenerator(pool);
-
-        binding.typeToDefinition = typeToDefinition
-        binding.typeToSchemaNode = typeToSchemaNode
-        binding.typeDefinitions = typeDefinitions
-
-    }
-}
-
-class TransformerWrapper implements // //
-Delegator<BindingCodec<Map<QName, Object>, Object>> {
-
-    @Property
-    val BindingCodec<Map<QName, Object>, Object> delegate;
-
-    new(BindingCodec<Map<QName, Object>, Object> delegate) {
-        _delegate = delegate;
-    }
-
-    def CompositeNode transform(DataObject input) {
-        val ret = delegate.serialize(input);
-        val node = toNode(ret)
-        return node as CompositeNode;
-    }
-
-    def deserialize(CompositeNode node) {
-        if (node === null) {
-            return null;
-        }
-        val Map mapCapture = node
-        return delegate.deserialize(mapCapture as Map<QName,Object>);
-    }
-
-    static def Node<?> toNode(Map map) {
-        val nodeMap = map as Map<QName,Object>;
-        checkArgument(map.size == 1);
-        val elem = nodeMap.entrySet.iterator.next;
-        val qname = elem.key;
-        val value = elem.value;
-        toNodeImpl(qname, value);
-    }
-
-    static def dispatch Node<?> toNodeImpl(QName name, List objects) {
-        val values = new ArrayList<Node<?>>(objects.size);
-        for (obj : objects) {
-            values.add(toNode(obj as Map));
-        }
-        return new CompositeNodeTOImpl(name, null, values);
-    }
-
-    static def dispatch Node<?> toNodeImpl(QName name, Map<QName, Object> object) {
-        throw new UnsupportedOperationException("Unsupported node hierarchy.");
-    }
-
-    static def dispatch Node<?> toNodeImpl(QName name, Object object) {
-        return new SimpleNodeTOImpl(name, null, object);
-    }
-}
index 87f31ac5c435820c5ddb5ec505e3dabbab94eba8..6478a03bbc025f8a7fa1f6ec937270a80d807797 100644 (file)
@@ -3,6 +3,7 @@ package org.opendaylight.controller.sal.binding.impl.util;
 
 
 import java.util.concurrent.Callable;
+import java.util.concurrent.locks.Lock;
 
 import static com.google.common.base.Preconditions.*;
 
@@ -10,20 +11,35 @@ import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 
+import com.google.common.base.Optional;
+
 public class ClassLoaderUtils {
     
     public static <V> V withClassLoader(ClassLoader cls,Callable<V> function) throws Exception {
-        checkNotNull(cls);
-        checkNotNull(function);
+        return withClassLoaderAndLock(cls, Optional.<Lock>absent(), function);
+    }
+    
+    public static <V> V withClassLoaderAndLock(ClassLoader cls,Lock lock,Callable<V> function) throws Exception {
+        checkNotNull(lock,"Lock should not be null");
+        return withClassLoaderAndLock(cls, Optional.of(lock), function);
+    }
+    
+    public static <V> V withClassLoaderAndLock(ClassLoader cls,Optional<Lock> lock,Callable<V> function) throws Exception {
+        checkNotNull(cls, "Classloader should not be null");
+        checkNotNull(function,"Function should not be null");
+        if(lock.isPresent()) {
+            lock.get().lock();
+        }
         ClassLoader oldCls = Thread.currentThread().getContextClassLoader();
         try {
             Thread.currentThread().setContextClassLoader(cls);
             V result = function.call();
-            Thread.currentThread().setContextClassLoader(oldCls);
             return result;
-        } catch (Exception e) {
+        }  finally {
             Thread.currentThread().setContextClassLoader(oldCls);
-            throw new Exception(e);
+            if(lock.isPresent()) {
+                lock.get().unlock();
+            }
         }
     }
 
index 27d985b2d26c0a260c8801fa7a5bbaea6f80021f..7d8a8f1fffa7703c2d1b567cbc372f694e4cdba0 100644 (file)
@@ -6,13 +6,14 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
+import javassist.ClassPool;
+
 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.BindingIndependentMappingService;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.RuntimeGeneratedMappingServiceImpl;
-import org.opendaylight.controller.sal.binding.test.connect.dom.MappingServiceTest;
+import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl;
 import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
 import org.opendaylight.yangtools.yang.model.api.Module;
@@ -29,6 +30,12 @@ public  abstract class AbstractDataServiceTest {
     protected DataBrokerService biDataService;
     protected DataProviderService baDataService;
     
+    /**
+     * Workaround for JUNIT sharing classloaders
+     * 
+     */
+    protected static final ClassPool POOL = new ClassPool();
+    
     protected RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
     protected BindingIndependentMappingService mappingService;
     protected DataBrokerImpl baDataImpl;
@@ -56,6 +63,7 @@ public  abstract class AbstractDataServiceTest {
         biDataImpl.registerCommitHandler(treeRoot, dataStore);
         
         mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl();
+        mappingServiceImpl.setPool(POOL);
         mappingService = mappingServiceImpl;
         File pathname = new File("target/gen-classes-debug");
         //System.out.println("Generated classes are captured in " + pathname.getAbsolutePath());
@@ -69,15 +77,17 @@ public  abstract class AbstractDataServiceTest {
         connectorServiceImpl.start();
         
         String[] yangFiles= getModelFilenames();
-        mappingServiceImpl.onGlobalContextUpdated(getContext(yangFiles));
+        if(yangFiles != null && yangFiles.length > 0) {
+            mappingServiceImpl.onGlobalContextUpdated(getContext(yangFiles));
+        }
     }
 
 
     protected  String[] getModelFilenames() {
-        return getModelFilenamesImpl();
+        return getAllModelFilenames();
     }
     
-    public static String[] getModelFilenamesImpl() {
+    public static String[] getAllModelFilenames() {
         Predicate<String> predicate = new Predicate<String>() {
             @Override
             public boolean apply(String input) {
index 70be175598b591428d6a9386ae7c9a58315f6769..4e7628fd06cc87254c2ce2df71a7b844070678d6 100644 (file)
@@ -1,22 +1,41 @@
 package org.opendaylight.controller.sal.binding.test.bugfix;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 
 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.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 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.NodesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
@@ -27,78 +46,130 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
 
 import static org.junit.Assert.*;
 
-/**
- * 
- * Testcase for https://bugs.opendaylight.org/show_bug.cgi?id=144
- * 
- * Cannot compile CoDec for org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow
- * 
- * @author ttkacik
- *
- */
 public class DOMCodecBug01Test extends AbstractDataServiceTest {
 
     private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
     private static final QName FLOW_ID_QNAME = QName.create(Flow.QNAME, "id");
     private static final QName FLOW_NODE_QNAME = QName.create(Flow.QNAME, "node");
-    
-    private static final String FLOW_ID = "foo";
+    private static final long FLOW_ID = 1234;
     private static final String NODE_ID = "node:1";
 
     private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
-    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder().node(Nodes.class)
-            .node(Node.class, NODE_KEY).toInstance();
-    
-    
+
     private static final Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
             NODE_ID);
-    
+
+    private static final InstanceIdentifier<Nodes> NODES_INSTANCE_ID_BA = InstanceIdentifier.builder() //
+            .node(Nodes.class) //
+            .toInstance();
+
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODES_INSTANCE_ID_BI = //
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .toInstance();
+
+    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder() //
+            .node(Nodes.class) //
+            .child(Node.class, NODE_KEY).toInstance();
+
     private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = //
-            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
-                    .node(Nodes.QNAME) //
-                    .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
-                    .toInstance();
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+            .toInstance();
     private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA);
-    
+
     private static final FlowKey FLOW_KEY = new FlowKey(FLOW_ID, NODE_REF);
 
     private static final Map<QName, Object> FLOW_KEY_BI = //
-            ImmutableMap.<QName,Object>of(FLOW_ID_QNAME, FLOW_ID, FLOW_NODE_QNAME, NODE_REF);
-
-
-    
+    ImmutableMap.<QName, Object> of(FLOW_ID_QNAME, FLOW_ID, FLOW_NODE_QNAME, NODE_INSTANCE_ID_BI);
 
     private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier FLOW_INSTANCE_ID_BI = //
-            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
-                    .node(Flows.QNAME) //
-                    .nodeWithKey(Flow.QNAME, FLOW_KEY_BI) //
-                    .toInstance();
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Flows.QNAME) //
+            .nodeWithKey(Flow.QNAME, FLOW_KEY_BI) //
+            .toInstance();
     private static final InstanceIdentifier<? extends DataObject> FLOW_INSTANCE_ID_BA = //
-            InstanceIdentifier.builder() //
-                .node(Flows.class) //
-                .node(Flow.class, FLOW_KEY) //
-                .toInstance();
+    InstanceIdentifier.builder() //
+            .node(Flows.class) //
+            .node(Flow.class, FLOW_KEY) //
+            .toInstance();
+
+
+
     /**
-     * 
+     *
+     * Testcase for https://bugs.opendaylight.org/show_bug.cgi?id=
+     *
+     * Cannot compile CoDec for
+     * org.opendaylight.yang.gen.v1.urn.opendaylight.flow
+     * .config.rev130819.flows.Flow
+     *
      * When invoking following code in the consumer, user got an
      * IllegalStateException during creation of mapping between Java DTOs and
      * data-dom.
-     * 
+     *
      * Exception was compilation error which was caused by incorect generation
      * of code.
-     * 
-     * 
+     *
+     * Reported by Depthi V V
+     *
      */
     @Test
     public void testIndirectGeneration() throws Exception {
 
+        ExecutorService basePool = Executors.newFixedThreadPool(2);
+        ListeningExecutorService listenablePool = MoreExecutors.listeningDecorator(basePool);
+
+        createFlow();
+
+        Object lock = new Object();
+        CreateFlowTask task1 = new CreateFlowTask(lock);
+        CreateFlowTask task2 = new CreateFlowTask(lock);
+        CreateFlowTask task3 = new CreateFlowTask(lock);
+
+        ListenableFuture<Void> task1Future = listenablePool.submit(task1);
+        ListenableFuture<Void> task2Future = listenablePool.submit(task2);
+        ListenableFuture<Void> task3Future = listenablePool.submit(task3);
+
+
+        ListenableFuture<List<Void>> compositeFuture = Futures.allAsList(task1Future,task2Future,task3Future);
+
+        Thread.sleep(500);
+        //lock.notifyAll();
+        compositeFuture.get();
+
+        verifyDataAreStoredProperly();
+
+        DataModificationTransaction modification2 = baDataService.beginTransaction();
+        modification2.removeConfigurationData(FLOW_INSTANCE_ID_BA);
+
+        DataObject originalData = modification2.getOriginalConfigurationData().get(FLOW_INSTANCE_ID_BA);
+        assertNotNull(originalData);
+        RpcResult<TransactionStatus> ret2 = modification2.commit().get();
+
+        assertNotNull(ret2);
+        assertEquals(TransactionStatus.COMMITED, ret2.getResult());
+
+        // Data are not in the store.
+        assertNull(baDataService.readOperationalData(FLOW_INSTANCE_ID_BA));
+
+    }
+
+    private void createFlow() throws Exception {
+
         DataModificationTransaction modification = baDataService.beginTransaction();
 
-       FlowBuilder flow = new FlowBuilder();
+        FlowBuilder flow = new FlowBuilder();
         MatchBuilder match = new MatchBuilder();
         VlanMatchBuilder vlanBuilder = new VlanMatchBuilder();
         VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
@@ -110,35 +181,58 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest {
         flow.setMatch(match.build());
         flow.setNode(NODE_REF);
 
+
+        InstructionsBuilder instructions = new InstructionsBuilder();
+        InstructionBuilder instruction = new InstructionBuilder();
+        ApplyActionsBuilder applyActions = new ApplyActionsBuilder();
+        List<Action> actionList = new ArrayList<>();
+        PopMplsActionBuilder popMplsAction = new PopMplsActionBuilder();
+        popMplsAction.setEthernetType(34);
+        actionList.add(new ActionBuilder().setAction(popMplsAction.build()).build());
+
+        applyActions.setAction(actionList );
+
+
+        instruction.setInstruction(applyActions.build());
+
+
+        List<Instruction> instructionList = Collections.<Instruction>singletonList(instruction.build());
+        instructions.setInstruction(instructionList );
+
+        flow.setInstructions(instructions.build());
         modification.putConfigurationData(FLOW_INSTANCE_ID_BA, flow.build());
         RpcResult<TransactionStatus> ret = modification.commit().get();
         assertNotNull(ret);
         assertEquals(TransactionStatus.COMMITED, ret.getResult());
-        
-        verifyDataAreStoredProperly();
-        
-        
-        DataModificationTransaction modification2 = baDataService.beginTransaction();
-        modification2.removeConfigurationData(FLOW_INSTANCE_ID_BA);
-        
-        DataObject originalData = modification2.getOriginalConfigurationData().get(FLOW_INSTANCE_ID_BA);
-        assertNotNull(originalData);
-        RpcResult<TransactionStatus> ret2 = modification2.commit().get();
-        
-        assertNotNull(ret2);
-        assertEquals(TransactionStatus.COMMITED, ret2.getResult());
-        
-        
-        // Data are not in the store.
-        assertNull(baDataService.readOperationalData(FLOW_INSTANCE_ID_BA));
-        
-        
+    }
+
+    private class CreateFlowTask implements Callable<Void> {
+
+        final Object startSyncObject;
+
+        public CreateFlowTask(Object startSync) {
+            startSyncObject = startSync;
+        }
+
+        @Override
+        public Void call() {
+            try {
+                //startSyncObject.wait();
+                //Thread.sleep(500);
+                createFlow();
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+            return null;
+        }
     }
 
     private void verifyDataAreStoredProperly() {
         CompositeNode biFlow = biDataService.readConfigurationData(FLOW_INSTANCE_ID_BI);
         assertNotNull(biFlow);
-        CompositeNode biMatch = biFlow.getFirstCompositeByName(QName.create(Flow.QNAME,Match.QNAME.getLocalName()));
+        CompositeNode biMatch = biFlow.getFirstCompositeByName(QName.create(Flow.QNAME, Match.QNAME.getLocalName()));
         assertNotNull(biMatch);
     }
+
+
 }
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java
new file mode 100644 (file)
index 0000000..773bab8
--- /dev/null
@@ -0,0 +1,121 @@
+package org.opendaylight.controller.sal.binding.test.bugfix;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+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.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+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.NodesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+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.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import static org.junit.Assert.*;
+
+public class DOMCodecBug02Test extends AbstractDataServiceTest {
+
+    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+    private static final QName FLOW_ID_QNAME = QName.create(Flow.QNAME, "id");
+    private static final QName FLOW_NODE_QNAME = QName.create(Flow.QNAME, "node");
+
+    private static final String FLOW_ID = "foo";
+    private static final String NODE_ID = "node:1";
+
+    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+
+    private static final Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
+            NODE_ID);
+
+    private static final InstanceIdentifier<Nodes> NODES_INSTANCE_ID_BA = InstanceIdentifier.builder() //
+            .node(Nodes.class) //
+            .toInstance();
+
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODES_INSTANCE_ID_BI = //
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .toInstance();
+
+    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder() //
+            .node(Nodes.class) //
+            .child(Node.class, NODE_KEY).toInstance();
+
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = //
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+            .toInstance();
+    private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA);
+
+    @Override
+    protected String[] getModelFilenames() {
+        return null;
+    }
+
+    /**
+     * 
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testSchemaContextNotAvailable() throws Exception {
+
+        ExecutorService testExecutor = Executors.newFixedThreadPool(1);
+        
+        Future<Future<RpcResult<TransactionStatus>>> future = testExecutor.submit(new Callable<Future<RpcResult<TransactionStatus>>>() {
+            @Override
+            public Future<RpcResult<TransactionStatus>> call() throws Exception {
+                NodesBuilder nodesBuilder = new NodesBuilder();
+                nodesBuilder.setNode(Collections.<Node> emptyList());
+                DataModificationTransaction transaction = baDataService.beginTransaction();
+                transaction.putOperationalData(NODES_INSTANCE_ID_BA, nodesBuilder.build());
+                return transaction.commit();
+            }
+        });
+        mappingServiceImpl.onGlobalContextUpdated(getContext(getAllModelFilenames()));
+        
+        RpcResult<TransactionStatus> result = future.get().get();
+        assertEquals(TransactionStatus.COMMITED, result.getResult());
+        
+        
+        Nodes nodes = checkForNodes();
+        assertNotNull(nodes);
+
+    }
+
+    private Nodes checkForNodes() {
+        return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
+
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java
new file mode 100644 (file)
index 0000000..ae54591
--- /dev/null
@@ -0,0 +1,156 @@
+package org.opendaylight.controller.sal.binding.test.bugfix;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+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.NodesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+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.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import static org.junit.Assert.*;
+
+public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataChangeListener {
+
+    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+    private static final String NODE_ID = "openflow:1";
+
+    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+
+    private static final Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
+            NODE_ID);
+
+    private static final InstanceIdentifier<Nodes> NODES_INSTANCE_ID_BA = InstanceIdentifier.builder() //
+            .node(Nodes.class) //
+            .toInstance();
+
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODES_INSTANCE_ID_BI = //
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .toInstance();
+
+    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder() //
+            .node(Nodes.class) //
+            .child(Node.class, NODE_KEY).toInstance();
+
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = //
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+            .toInstance();
+    private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA);
+    private DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedChangeEvent;
+
+    
+    
+    /**
+     * Test for Bug 148
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testAugmentSerialization() throws Exception {
+
+        
+        baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
+        
+        NodeBuilder nodeBuilder = new NodeBuilder();
+        nodeBuilder.setId(new NodeId(NODE_ID));
+        nodeBuilder.setKey(NODE_KEY);
+        DataModificationTransaction transaction = baDataService.beginTransaction();
+        
+        
+        FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder();
+        fnub.setHardware("Hardware Foo");
+        fnub.setManufacturer("Manufacturer Foo");
+        fnub.setSerialNumber("Serial Foo");
+        fnub.setDescription("Description Foo");
+        fnub.setSoftware("JUnit emulated");
+        FlowCapableNode fnu = fnub.build();
+        nodeBuilder.addAugmentation(FlowCapableNode.class, fnu);
+        Node original = nodeBuilder.build();
+        transaction.putOperationalData(NODE_INSTANCE_ID_BA, original);
+        
+        RpcResult<TransactionStatus> result = transaction.commit().get();
+        assertEquals(TransactionStatus.COMMITED, result.getResult());
+        
+        assertNotNull(receivedChangeEvent);
+        
+        verifyNodes((Nodes) receivedChangeEvent.getUpdatedOperationalSubtree(),original);
+        assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
+        Nodes nodes = checkForNodes();
+        verifyNodes(nodes,original);
+        
+        
+    }
+
+    private void verifyNodes(Nodes nodes,Node original) {
+        assertNotNull(nodes);
+        assertNotNull(nodes.getNode());
+        assertEquals(1, nodes.getNode().size());
+        Node readedNode = nodes.getNode().get(0);
+        assertEquals(original.getId(), readedNode.getId());
+        assertEquals(original.getKey(), readedNode.getKey());
+        
+        FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class);
+        FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class);
+        assertNotNull(fnu);
+        assertEquals(fnu.getDescription(), readedAugment.getDescription());
+        assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber());
+        
+    }
+
+    private void assertBindingIndependentVersion(
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) {
+        CompositeNode node = biDataService.readOperationalData(nodeId);
+        assertNotNull(node);
+    }
+
+    private Nodes checkForNodes() {
+        return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
+    }
+    
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        receivedChangeEvent = change;
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java
deleted file mode 100644 (file)
index e26273e..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-package org.opendaylight.controller.sal.binding.test.connect.dom;
-
-import static org.junit.Assert.*;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.MappingServiceImpl;
-import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext;
-import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-
-public class MappingServiceTest {
-
-    private static final QName NODES = QName.create("urn:opendaylight:inventory", "2013-08-19", "nodes");
-    private static final QName NODE = QName.create(NODES,"node");
-    private static final QName ID = QName.create(NODES,"id");
-    
-    BindingIndependentMappingService service;
-    private MappingServiceImpl impl;
-
-    @Before
-    public void setUp() {
-        impl = new MappingServiceImpl();
-        service = impl;
-    }
-
-    @Test
-    public void baDataToBiData() throws Exception {
-
-        String[] yangFiles = AbstractDataServiceTest.getModelFilenamesImpl();
-
-        SchemaContext ctx = AbstractDataServiceTest.getContext(yangFiles);
-
-        impl.onGlobalContextUpdated(ctx);
-
-        NodesBuilder nodes = new NodesBuilder();
-
-        List<Node> nodeList = new ArrayList<>();
-        nodeList.add(createChildNode("foo"));
-        nodeList.add(createChildNode("bar"));
-
-        nodes.setNode(nodeList);
-        Nodes nodesTO = nodes.build();
-        CompositeNode xmlNodes = service.toDataDom(nodesTO);
-        assertNotNull(xmlNodes);
-        List<CompositeNode> invNodes = xmlNodes.getCompositesByName(NODE);
-        assertNotNull(invNodes);
-        assertEquals(2, invNodes.size());
-    }
-
-    @Test
-    public void instanceIdentifierTest() throws Exception {
-
-        String[] yangFiles = AbstractDataServiceTest.getModelFilenamesImpl();
-        SchemaContext ctx = AbstractDataServiceTest.getContext(yangFiles);
-        impl.onGlobalContextUpdated(ctx);
-
-        NodeKey nodeKey = new NodeKey(new NodeId("foo"));
-        InstanceIdentifier<Node> path = InstanceIdentifier.builder().node(Nodes.class).child(Node.class, nodeKey).toInstance();
-        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier result = service.toDataDom(path);
-        assertNotNull(result);
-        assertEquals(2, result.getPath().size());
-    }
-
-    private Node createChildNode(String id) {
-        NodeBuilder node = new NodeBuilder();
-        NodeId nodeId = new NodeId(id);
-
-        node.setId(nodeId);
-        node.setKey(new NodeKey(nodeId));
-
-        FlowCapableNodeBuilder aug = new FlowCapableNodeBuilder();
-        aug.setManufacturer(id);
-        node.addAugmentation(FlowCapableNode.class, aug.build());
-
-        return node.build();
-    }
-
-}
index 8fb6c897d5d3500454cbcfa16f8f108c3a2cc47e..bf3d7abd1ed0433c3f6c334ec8f2de595def2bb1 100644 (file)
@@ -17,4 +17,20 @@ module opendaylight-md-sal-binding {
         base "config:service-type";
         config:java-class "org.opendaylight.controller.sal.binding.api.BindingAwareBroker";
     }
+
+    identity binding-data-broker {
+        base "config:service-type";
+        config:java-class "org.opendaylight.controller.sal.binding.api.data.DataProviderService";
+    }
+
+    identity binding-rpc-registry {
+        base "config:service-type";
+        config:java-class "org.opendaylight.controller.sal.binding.api.RpcProviderRegistry";
+    }
+
+    identity binding-notification-service {
+        base "config:service-type";
+        config:java-class "org.opendaylight.controller.sal.binding.api.NotificationProviderService";
+    }
+
 }
\ No newline at end of file
index b878071183e14937a63a1ce8981bcfaa5785566d..74c4e0a148640a2278deee8a87bf67c4c27eb334 100644 (file)
@@ -27,25 +27,37 @@ import java.util.concurrent.Future
 import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter
 import org.opendaylight.yangtools.concepts.Path
 import org.slf4j.LoggerFactory
-
-abstract class AbstractDataBroker<P extends Path<P>,D,DCL extends DataChangeListener<P,D>> implements 
-DataModificationTransactionFactory<P, D>, //
+import java.util.HashSet
+import java.util.Map.Entry
+import java.util.Iterator
+import java.util.Collection
+import com.google.common.collect.FluentIterable;
+import java.util.Set
+import com.google.common.collect.ImmutableList
+
+abstract class AbstractDataBroker<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> implements DataModificationTransactionFactory<P, D>, //
 DataReader<P, D>, //
 DataChangePublisher<P, D, DCL>, //
-DataProvisionService<P,D> {
+DataProvisionService<P, D> {
 
     @Property
     var ExecutorService executor;
 
     @Property
-    var AbstractDataReadRouter<P,D> dataReadRouter;
-
-    Multimap<P, DataChangeListenerRegistration<P,D,DCL>> listeners = HashMultimap.create();
-    Multimap<P, DataCommitHandlerRegistration<P,D>> commitHandlers = HashMultimap.create();
+    var AbstractDataReadRouter<P, D> dataReadRouter;
 
+    Multimap<P, DataChangeListenerRegistration<P, D, DCL>> listeners = HashMultimap.create();
+    Multimap<P, DataCommitHandlerRegistration<P, D>> commitHandlers = HashMultimap.create();
 
     public new() {
-        
+    }
+
+    protected def /*Iterator<Entry<Collection<DataChangeListenerRegistration<P,D,DCL>>,D>>*/ affectedCommitHandlers(
+        HashSet<P> paths) {
+        return FluentIterable.from(commitHandlers.asMap.entrySet)
+            .filter[key.isAffectedBy(paths)] //
+            .transformAndConcat [value] //
+            .transform[instance].toList()
     }
 
     override final readConfigurationData(P path) {
@@ -56,11 +68,10 @@ DataProvisionService<P,D> {
         return dataReadRouter.readOperationalData(path);
     }
 
-    override final registerCommitHandler(P path,
-        DataCommitHandler<P, D> commitHandler) {
-            val registration = new DataCommitHandlerRegistration(path,commitHandler,this);
-            commitHandlers.put(path,registration)
-            return registration;
+    override final registerCommitHandler(P path, DataCommitHandler<P, D> commitHandler) {
+        val registration = new DataCommitHandlerRegistration(path, commitHandler, this);
+        commitHandlers.put(path, registration)
+        return registration;
     }
 
     override final def registerDataChangeListener(P path, DCL listener) {
@@ -69,27 +80,49 @@ DataProvisionService<P,D> {
         return reg;
     }
 
-     final def registerDataReader(P path,DataReader<P,D> reader) {
-        
-        val confReg = dataReadRouter.registerConfigurationReader(path,reader);
-        val dataReg = dataReadRouter.registerOperationalReader(path,reader);
-        
-        return new CompositeObjectRegistration(reader,Arrays.asList(confReg,dataReg));
+    final def registerDataReader(P path, DataReader<P, D> reader) {
+
+        val confReg = dataReadRouter.registerConfigurationReader(path, reader);
+        val dataReg = dataReadRouter.registerOperationalReader(path, reader);
+
+        return new CompositeObjectRegistration(reader, Arrays.asList(confReg, dataReg));
     }
 
-    protected  final def removeListener(DataChangeListenerRegistration<P,D,DCL> registration) {
+    protected final def removeListener(DataChangeListenerRegistration<P, D, DCL> registration) {
         listeners.remove(registration.path, registration);
     }
 
-    protected  final def removeCommitHandler(DataCommitHandlerRegistration<P,D> registration) {
+    protected final def removeCommitHandler(DataCommitHandlerRegistration<P, D> registration) {
         commitHandlers.remove(registration.path, registration);
     }
-    
-    protected  final def getActiveCommitHandlers() {
-        return commitHandlers.entries.map[ value.instance].toSet
+
+    protected final def getActiveCommitHandlers() {
+        return commitHandlers.entries;
     }
 
-    package final def Future<RpcResult<TransactionStatus>>  commit(AbstractDataTransaction<P,D> transaction) {
+    protected def /*Iterator<Entry<Collection<DataChangeListenerRegistration<P,D,DCL>>,D>>*/ affectedListenersWithInitialState(
+        HashSet<P> paths) {
+        return FluentIterable.from(listeners.asMap.entrySet).filter[key.isAffectedBy(paths)].transform [
+            val operationalState = readOperationalData(key)
+            val configurationState = readConfigurationData(key)
+            return new ListenerStateCapture(key, value, operationalState, configurationState)
+        ].toList()
+    }
+
+    protected def boolean isAffectedBy(P key, Set<P> paths) {
+        if (paths.contains(key)) {
+            return true;
+        }
+        for (path : paths) {
+            if (key.contains(path)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    package final def Future<RpcResult<TransactionStatus>> commit(AbstractDataTransaction<P, D> transaction) {
         checkNotNull(transaction);
         transaction.changeStatus(TransactionStatus.SUBMITED);
         val task = new TwoPhaseCommit(transaction, this);
@@ -98,14 +131,30 @@ DataProvisionService<P,D> {
 
 }
 
-package class DataChangeListenerRegistration<P extends Path<P>,D,DCL extends DataChangeListener<P,D>> extends AbstractObjectRegistration<DCL> implements ListenerRegistration<DCL> {
+@Data
+package class ListenerStateCapture<P extends Path<P>, D,DCL extends DataChangeListener<P, D>> {
 
-    AbstractDataBroker<P,D,DCL> dataBroker;
+    @Property
+    P path;
+
+    @Property
+    Collection<DataChangeListenerRegistration<P, D, DCL>> listeners;
+
+    @Property
+    D initialOperationalState;
+
+    @Property
+    D initialConfigurationState;
+}
+
+package class DataChangeListenerRegistration<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> extends AbstractObjectRegistration<DCL> implements ListenerRegistration<DCL> {
+
+    AbstractDataBroker<P, D, DCL> dataBroker;
 
     @Property
     val P path;
 
-    new(P path, DCL instance, AbstractDataBroker<P,D,DCL> broker) {
+    new(P path, DCL instance, AbstractDataBroker<P, D, DCL> broker) {
         super(instance)
         dataBroker = broker;
         _path = path;
@@ -118,16 +167,14 @@ package class DataChangeListenerRegistration<P extends Path<P>,D,DCL extends Dat
 
 }
 
-package class DataCommitHandlerRegistration<P extends Path<P>,D>
-extends AbstractObjectRegistration<DataCommitHandler<P, D>> {
+package class DataCommitHandlerRegistration<P extends Path<P>, D> extends AbstractObjectRegistration<DataCommitHandler<P, D>> {
 
-    AbstractDataBroker<P,D,?> dataBroker;
+    AbstractDataBroker<P, D, ?> dataBroker;
 
     @Property
     val P path;
 
-    new(P path, DataCommitHandler<P, D> instance,
-        AbstractDataBroker<P,D,?> broker) {
+    new(P path, DataCommitHandler<P, D> instance, AbstractDataBroker<P, D, ?> broker) {
         super(instance)
         dataBroker = broker;
         _path = path;
@@ -140,74 +187,105 @@ extends AbstractObjectRegistration<DataCommitHandler<P, D>> {
 
 }
 
-package class TwoPhaseCommit<P extends Path<P>,D> implements Callable<RpcResult<TransactionStatus>> {
-    
+package class TwoPhaseCommit<P extends Path<P>, D,DCL extends DataChangeListener<P, D>> implements Callable<RpcResult<TransactionStatus>> {
+
     private static val log = LoggerFactory.getLogger(TwoPhaseCommit);
 
-    val AbstractDataTransaction<P,D> transaction;
-    val AbstractDataBroker<P,D,?> dataBroker;
+    val AbstractDataTransaction<P, D> transaction;
+    val AbstractDataBroker<P, D, DCL> dataBroker;
 
-    new(AbstractDataTransaction<P,D> transaction, AbstractDataBroker<P,D,?> broker) {
+    new(AbstractDataTransaction<P, D> transaction, AbstractDataBroker<P, D, DCL> broker) {
         this.transaction = transaction;
         this.dataBroker = broker;
     }
 
     override call() throws Exception {
 
-        val Iterable<DataCommitHandler<P, D>> commitHandlers = dataBroker.activeCommitHandlers;
+        // get affected paths
+        val affectedPaths = new HashSet<P>();
+
+        affectedPaths.addAll(transaction.createdConfigurationData.keySet);
+        affectedPaths.addAll(transaction.updatedConfigurationData.keySet);
+        affectedPaths.addAll(transaction.removedConfigurationData);
+
+        affectedPaths.addAll(transaction.createdOperationalData.keySet);
+        affectedPaths.addAll(transaction.updatedOperationalData.keySet);
+        affectedPaths.addAll(transaction.removedOperationalData);
+
+        val listeners = dataBroker.affectedListenersWithInitialState(affectedPaths);
 
         // requesting commits
+        val Iterable<DataCommitHandler<P, D>> commitHandlers =   dataBroker.affectedCommitHandlers(affectedPaths);
         val List<DataCommitTransaction<P, D>> handlerTransactions = new ArrayList();
         try {
             for (handler : commitHandlers) {
                 handlerTransactions.add(handler.requestCommit(transaction));
             }
         } catch (Exception e) {
-            log.error("Request Commit failded",e);
-            return rollback(handlerTransactions,e);
+            log.error("Request Commit failded", e);
+            return rollback(handlerTransactions, e);
         }
         val List<RpcResult<Void>> results = new ArrayList();
         try {
             for (subtransaction : handlerTransactions) {
                 results.add(subtransaction.finish());
             }
+            listeners.publishDataChangeEvent();
         } catch (Exception e) {
-            log.error("Finish Commit failed",e);
-            return rollback(handlerTransactions,e);
+            log.error("Finish Commit failed", e);
+            return rollback(handlerTransactions, e);
         }
 
+        
         return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet());
+
+    }
+    
+    def void publishDataChangeEvent(ImmutableList<ListenerStateCapture<P, D,DCL>> listeners) {
+        for(listenerSet : listeners) {
+            val updatedConfiguration = dataBroker.readConfigurationData(listenerSet.path);
+            val updatedOperational = dataBroker.readOperationalData(listenerSet.path);
+            
+            val changeEvent = new DataChangeEventImpl(transaction,listenerSet.initialConfigurationState,listenerSet.initialOperationalState,updatedOperational,updatedConfiguration);
+            for(listener : listenerSet.listeners) {
+                try {
+                    listener.instance.onDataChanged(changeEvent);
+                    
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
     }
 
-    def rollback(List<DataCommitTransaction<P, D>> transactions,Exception e) {
+    def rollback(List<DataCommitTransaction<P, D>> transactions, Exception e) {
         for (transaction : transactions) {
             transaction.rollback()
         }
+
         // FIXME return encountered error.
         return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.emptySet());
     }
 }
-
 public abstract class AbstractDataTransaction<P extends Path<P>, D> extends AbstractDataModification<P, D> {
 
     @Property
     private val Object identifier;
 
-    
     var TransactionStatus status;
-    
-    
+
     var AbstractDataBroker<P, D, ?> broker;
 
-    protected new (AbstractDataBroker<P,D,?> dataBroker) {
+    protected new(AbstractDataBroker<P, D, ?> dataBroker) {
         super(dataBroker);
         _identifier = new Object();
         broker = dataBroker;
         status = TransactionStatus.NEW;
-        //listeners = new ListenerRegistry<>();
+
+    //listeners = new ListenerRegistry<>();
     }
 
-    override  commit() {
+    override commit() {
         return broker.commit(this);
     }
 
@@ -230,7 +308,7 @@ public abstract class AbstractDataTransaction<P extends Path<P>, D> extends Abst
             return false;
         if (getClass() != obj.getClass())
             return false;
-        val other = (obj as AbstractDataTransaction<P,D>) ;
+        val other = (obj as AbstractDataTransaction<P,D>);
         if (broker == null) {
             if (other.broker != null)
                 return false;
@@ -248,12 +326,11 @@ public abstract class AbstractDataTransaction<P extends Path<P>, D> extends Abst
         return status;
     }
 
-    
     protected abstract def void onStatusChange(TransactionStatus status);
-    
+
     public def changeStatus(TransactionStatus status) {
         this.status = status;
         onStatusChange(status);
     }
-    
+
 }
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java
new file mode 100644 (file)
index 0000000..4eb9586
--- /dev/null
@@ -0,0 +1,73 @@
+package org.opendaylight.controller.md.sal.common.impl.service;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChange;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+
+public class DataChangeEventImpl<P, D> implements DataChangeEvent<P, D> {
+
+    private final DataChange<P, D> dataChange;
+
+    private final D originalConfigurationSubtree;
+    private final D originalOperationalSubtree;
+    private final D updatedOperationalSubtree;
+    private final D updatedConfigurationSubtree;
+
+    
+    
+    
+    public DataChangeEventImpl(DataChange<P, D> dataChange, D originalConfigurationSubtree,
+            D originalOperationalSubtree, D updatedOperationalSubtree, D updatedConfigurationSubtree) {
+        super();
+        this.dataChange = dataChange;
+        this.originalConfigurationSubtree = originalConfigurationSubtree;
+        this.originalOperationalSubtree = originalOperationalSubtree;
+        this.updatedOperationalSubtree = updatedOperationalSubtree;
+        this.updatedConfigurationSubtree = updatedConfigurationSubtree;
+    }
+
+    @Override
+    public D getUpdatedOperationalSubtree() {
+        return updatedOperationalSubtree;
+    }
+
+    @Override
+    public D getUpdatedConfigurationSubtree() {
+        return updatedConfigurationSubtree;
+    }
+
+    public Map<P, D> getCreatedOperationalData() {
+        return dataChange.getCreatedOperationalData();
+    }
+
+    public Map<P, D> getCreatedConfigurationData() {
+        return dataChange.getCreatedConfigurationData();
+    }
+
+    public Map<P, D> getUpdatedOperationalData() {
+        return dataChange.getUpdatedOperationalData();
+    }
+
+    public Map<P, D> getUpdatedConfigurationData() {
+        return dataChange.getUpdatedConfigurationData();
+    }
+
+    public Set<P> getRemovedConfigurationData() {
+        return dataChange.getRemovedConfigurationData();
+    }
+
+    public Set<P> getRemovedOperationalData() {
+        return dataChange.getRemovedOperationalData();
+    }
+
+    public Map<P, D> getOriginalConfigurationData() {
+        return dataChange.getOriginalConfigurationData();
+    }
+
+    public Map<P, D> getOriginalOperationalData() {
+        return dataChange.getOriginalOperationalData();
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connector/netconf/test/MountTest.java b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connector/netconf/test/MountTest.java
deleted file mode 100644 (file)
index 4abf0e1..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-package org.opendaylight.controller.sal.connector.netconf.test;
-
-import static junit.framework.Assert.assertEquals;
-import static org.junit.Assert.*;
-import io.netty.channel.ChannelFuture;
-import io.netty.util.HashedWheelTimer;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import javax.net.ssl.SSLContext;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
-import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
-import org.opendaylight.controller.config.spi.ModuleFactory;
-import org.opendaylight.controller.config.yang.store.api.YangStoreException;
-import org.opendaylight.controller.config.yang.store.impl.HardcodedYangStoreService;
-import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
-import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
-import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
-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.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
-import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
-import org.opendaylight.controller.netconf.impl.NetconfServerSessionListenerFactory;
-import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
-import org.opendaylight.controller.netconf.impl.SessionIdProvider;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.sal.connect.netconf.InventoryUtils;
-import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
-import org.opendaylight.controller.sal.connect.netconf.NetconfDeviceManager;
-import org.opendaylight.controller.sal.connect.netconf.NetconfInventoryUtils;
-import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
-import org.opendaylight.controller.sal.core.api.data.DataProviderService;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
-import org.opendaylight.controller.sal.dom.broker.DataBrokerImpl;
-import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.Node;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-
-public class MountTest extends AbstractConfigTest {
-
-    private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
-    private static final InetSocketAddress tlsAddress = new InetSocketAddress("127.0.0.1", 12024);
-    private static final URI NETCONF_MONITORING_NS = URI.create("urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring");
-    
-    private static final QName NETCONF_MONITORING = new QName(NETCONF_MONITORING_NS, new Date(2010,10,04), "ietf-netconf-monitoring");
-    private static final QName NETCONF_MONITORING_STATE = new QName(NETCONF_MONITORING,"netconf-state");
-    
-
-    private NetconfMessage getConfig, getConfigCandidate, editConfig, closeSession;
-    private DefaultCommitNotificationProducer commitNot;
-    private NetconfServerDispatcher dispatch;
-    private DataProviderService dataBroker;
-    private MountPointManagerImpl mountManager;
-    private NetconfDeviceManager netconfManager;
-
-    private static QName CONFIG_MODULES = new QName(
-            URI.create("urn:opendaylight:params:xml:ns:yang:controller:config"), null, "modules");
-    private static QName CONFIG_SERVICES = new QName(
-            URI.create("urn:opendaylight:params:xml:ns:yang:controller:config"), null, "modules");
-
-    private NetconfClient createSession(final InetSocketAddress address, NetconfClientDispatcher dispatcher) throws InterruptedException {
-        final NetconfClient netconfClient = new NetconfClient("test " + address.toString(), address, 5000, dispatcher);
-        return netconfClient;
-    }
-    
-    @Before
-    public void setUp() throws Exception {
-        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(getModuleFactories().toArray(
-                new ModuleFactory[0])));
-
-        loadMessages();
-
-        NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
-        factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
-
-        commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
-
-        dispatch = createDispatcher(Optional.<SSLContext> absent(), factoriesListener);
-        ChannelFuture s = dispatch.createServer(tcpAddress);
-        s.await();
-
-        dataBroker = new DataBrokerImpl();
-        mountManager = new MountPointManagerImpl();
-        mountManager.setDataBroker(dataBroker);
-        netconfManager = new NetconfDeviceManager();
-
-        netconfManager.setMountService(mountManager);
-        netconfManager.setDataService(dataBroker);
-        netconfManager.start();
-
-        try (NetconfClient netconfClient = createSession(tcpAddress, netconfManager.getDispatcher())) {
-            // send edit_config.xml
-            final Document rpcReply = netconfClient.sendMessage(this.editConfig).getDocument();
-            assertNotNull(rpcReply);
-        }
-    }
-
-
-    protected List<ModuleFactory> getModuleFactories() {
-        return getModuleFactoriesS();
-    }
-
-    static List<ModuleFactory> getModuleFactoriesS() {
-        return Lists.newArrayList(new TestImplModuleFactory(), new DepTestImplModuleFactory(),
-                new NetconfTestImplModuleFactory());
-    }
-
-    private void loadMessages() throws IOException, SAXException, ParserConfigurationException {
-        this.editConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/edit_config.xml");
-        this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
-        this.getConfigCandidate = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig_candidate.xml");
-        this.closeSession = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/closeSession.xml");
-    }
-
-    private NetconfServerDispatcher createDispatcher(Optional<SSLContext> sslC,
-            NetconfOperationServiceFactoryListenerImpl factoriesListener) {
-        SessionIdProvider idProvider = new SessionIdProvider();
-        NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
-                new HashedWheelTimer(5000, TimeUnit.MILLISECONDS), factoriesListener, idProvider);
-
-        NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
-                factoriesListener, commitNot, idProvider);
-
-        return new NetconfServerDispatcher(sslC, serverNegotiatorFactory, listenerFactory);
-    }
-
-    private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
-        final Collection<InputStream> yangDependencies = getBasicYangs();
-        return new HardcodedYangStoreService(yangDependencies);
-    }
-
-    private Collection<InputStream> getBasicYangs() throws IOException {
-        List<String> paths = Arrays.asList("/META-INF/yang/config.yang", "/META-INF/yang/rpc-context.yang",
-                "/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang",
-                "/META-INF/yang/ietf-inet-types.yang");
-        final Collection<InputStream> yangDependencies = new ArrayList<>();
-        for (String path : paths) {
-            final InputStream is = Preconditions
-                    .checkNotNull(getClass().getResourceAsStream(path), path + " not found");
-            yangDependencies.add(is);
-        }
-        return yangDependencies;
-    }
-
-    @Test
-    public void test() {
-        // MountProvisionInstance mount =
-        // Mockito.mock(MountProvisionInstance.class);
-        InstanceIdentifier path = InstanceIdentifier.builder(InventoryUtils.INVENTORY_PATH)
-                .node(InventoryUtils.INVENTORY_NODE).toInstance();
-        netconfManager.netconfNodeAdded(path, tcpAddress);
-        InstanceIdentifier mountPointPath = path;
-        MountProvisionInstance mountPoint = mountManager.getMountPoint(mountPointPath);
-
-        CompositeNode data = mountPoint.readOperationalData(InstanceIdentifier.builder().node(CONFIG_MODULES)
-                .toInstance());
-        assertNotNull(data);
-        assertEquals(CONFIG_MODULES, data.getNodeType());
-
-        CompositeNode data2 = mountPoint.readOperationalData(InstanceIdentifier.builder().toInstance());
-        assertNotNull(data2);
-
-        InstanceIdentifier fullPath = InstanceIdentifier.builder(mountPointPath).node(CONFIG_MODULES).toInstance();
-
-        CompositeNode data3 = dataBroker.readOperationalData(fullPath);
-        assertNotNull(data3);
-        assertEquals(CONFIG_MODULES, data.getNodeType());
-    }
-
-}
index c36a79c5d901093ad3bf79d1a4a354ebcf161209..a22ea623975049cd3bd37c8af3103fecce4317e4 100644 (file)
@@ -15,10 +15,9 @@ import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
 
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.sal.restconf.impl.StructuredData;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 /**
@@ -57,7 +56,6 @@ public interface RestconfService extends RestconfServiceLegacy {
     @GET
     public Object getRoot();
 
-
     @GET
     @Path("/modules")
     @Produces({API+JSON,API+XML})
@@ -68,23 +66,20 @@ public interface RestconfService extends RestconfServiceLegacy {
     @Produces({Draft02.MediaTypes.API+JSON,Draft02.MediaTypes.API+XML,API+JSON,API+XML})
     public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload);
     
-    
     @GET
     @Path("/config/{identifier:.+}")
     @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML})
     public StructuredData readConfigurationData(@PathParam("identifier") String identifier);
-
-    
     
     @PUT
     @Path("/config/{identifier:.+}")
     @Produces({API+JSON,API+XML})
-    public RpcResult<TransactionStatus> createConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload);
+    public Response createConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload);
 
     @POST
     @Path("/config/{identifier:.+}")
     @Produces({API+JSON,API+XML})
-    public RpcResult<TransactionStatus> updateConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload);
+    public Response updateConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload);
 
     @GET
     @Path("/operational/{identifier:.+}")
@@ -94,12 +89,11 @@ public interface RestconfService extends RestconfServiceLegacy {
     @PUT
     @Path("/operational/{identifier:.+}")
     @Produces({API+JSON,API+XML})
-    public RpcResult<TransactionStatus> createOperationalData(@PathParam("identifier") String identifier, CompositeNode payload);
+    public Response createOperationalData(@PathParam("identifier") String identifier, CompositeNode payload);
 
     @POST
     @Path("/operational/{identifier:.+}")
     @Produces({API+JSON,API+XML})
-    public RpcResult<TransactionStatus> updateOperationalData(@PathParam("identifier") String identifier, CompositeNode payload);
+    public Response updateOperationalData(@PathParam("identifier") String identifier, CompositeNode payload);
 
-    
 }
index 6683fd1835942f2af4bd23d42dc16220f3bb6872..242e7f3150d4b775ce56d957ae62ba947a080eba 100644 (file)
@@ -8,10 +8,9 @@ import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
 
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.sal.restconf.impl.StructuredData;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 public interface RestconfServiceLegacy {
@@ -35,12 +34,12 @@ public interface RestconfServiceLegacy {
     @PUT
     @Path("/datastore/{identifier:.+}")
     @Produces({API+JSON,API+XML})
-    public RpcResult<TransactionStatus> createConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload);
+    public Response createConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload);
 
     @Deprecated
     @POST
     @Path("/datastore/{identifier:.+}")
     @Produces({API+JSON,API+XML})
-    public RpcResult<TransactionStatus> updateConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload);
+    public Response updateConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload);
 
 }
index 3115994e01575a57661db4bbc73bc81927e9713d..a2ae1c9f7f248e81218f9862e4247376ae47dc75 100644 (file)
@@ -17,17 +17,17 @@ import com.google.gson.JsonPrimitive;
 
 class JsonReader {
 
-    public CompositeNodeWrapper read(InputStream entityStream) throws UnsupportedJsonFormatException {
+    public CompositeNodeWrapper read(InputStream entityStream) throws UnsupportedFormatException {
         JsonParser parser = new JsonParser();
-        
+
         JsonElement rootElement = parser.parse(new InputStreamReader(entityStream));
         if (!rootElement.isJsonObject()) {
-            throw new UnsupportedJsonFormatException("Root element of Json has to be Object");
+            throw new UnsupportedFormatException("Root element of Json has to be Object");
         }
-        
+
         Set<Entry<String, JsonElement>> entrySetsOfRootJsonObject = rootElement.getAsJsonObject().entrySet();
         if (entrySetsOfRootJsonObject.size() != 1) {
-            throw new UnsupportedJsonFormatException("Json Object should contain one element");
+            throw new UnsupportedFormatException("Json Object should contain one element");
         } else {
             Entry<String, JsonElement> childEntry = Lists.newArrayList(entrySetsOfRootJsonObject).get(0);
             String firstElementName = childEntry.getKey();
@@ -41,13 +41,15 @@ class JsonReader {
                     if (firstElementInArray.isJsonObject()) {
                         return createStructureWithRoot(firstElementName, firstElementInArray.getAsJsonObject());
                     }
-                    throw new UnsupportedJsonFormatException("Array as the first element in Json Object can have only Object element");
+                    throw new UnsupportedFormatException(
+                            "Array as the first element in Json Object can have only Object element");
                 }
             }
-            throw new UnsupportedJsonFormatException("First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet.");
+            throw new UnsupportedFormatException(
+                    "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet.");
         }
     }
-    
+
     private CompositeNodeWrapper createStructureWithRoot(String rootObjectName, JsonObject rootObject) {
         CompositeNodeWrapper firstNode = new CompositeNodeWrapper(getNamespaceFrom(rootObjectName),
                 getLocalNameFrom(rootObjectName));
@@ -56,7 +58,7 @@ class JsonReader {
         }
         return firstNode;
     }
-    
+
     private void addChildToParent(String childName, JsonElement childType, CompositeNodeWrapper parent) {
         if (childType.isJsonObject()) {
             CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFrom(childName),
@@ -66,19 +68,18 @@ class JsonReader {
                 addChildToParent(childOfChild.getKey(), childOfChild.getValue(), child);
             }
         } else if (childType.isJsonArray()) {
-            for (JsonElement childOfChildType : childType.getAsJsonArray()) {
-                addChildToParent(childName, childOfChildType, parent);
+            if (childType.getAsJsonArray().size() == 1 && childType.getAsJsonArray().get(0).isJsonNull()) {
+                parent.addValue(new SimpleNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName), null));
+
+            } else {
+                for (JsonElement childOfChildType : childType.getAsJsonArray()) {
+                    addChildToParent(childName, childOfChildType, parent);
+                }
             }
         } else if (childType.isJsonPrimitive()) {
             JsonPrimitive childPrimitive = childType.getAsJsonPrimitive();
             String value = childPrimitive.getAsString();
-            SimpleNodeWrapper child = null;
-            if (value.equals("[null]")) {
-                child = new SimpleNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName), null);
-            } else {
-                child = new SimpleNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName), value);
-            }
-            parent.addValue(child);
+            parent.addValue(new SimpleNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName), value));
         }
     }
 
index daaedd92b8d6c85f05f26365b90f6bbe68f7d5d6..dea4a73cd17d23f53f7c88d9b2ace669b285a2a6 100644 (file)
@@ -35,8 +35,8 @@ public enum JsonToCompositeNodeProvider implements MessageBodyReader<CompositeNo
         JsonReader jsonReader = new JsonReader();
         try {
             return jsonReader.read(entityStream);
-        } catch (UnsupportedJsonFormatException e) {
-            throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
+        } catch (UnsupportedFormatException e) {
+            throw new WebApplicationException(e,Response.status(Response.Status.BAD_REQUEST)
                     .entity(e.getMessage()).build());
         }
     }
index 6dc74840810a195d7e8a1bd8771a947530ce307a..bede249c943a08bc40bb97ccc39aebac9d2abe58 100644 (file)
@@ -24,6 +24,8 @@ public class RestconfApplication extends Application {
         singletons.add(restconfImpl);
         singletons.add(XmlToCompositeNodeProvider.INSTANCE);
         singletons.add(StructuredDataToXmlProvider.INSTANCE);
+        singletons.add(JsonToCompositeNodeProvider.INSTANCE);
+        singletons.add(StructuredDataToJsonProvider.INSTANCE);
         return singletons;
     }
 
index 35b751c73fcf1f007f3a9d419b63fbea2c7727d2..53b401e4a2c55856dc215c4fc5b62987ebaa71f0 100644 (file)
@@ -1,19 +1,31 @@
 package org.opendaylight.controller.sal.rest.impl;
 
-import org.opendaylight.controller.sal.core.api.AbstractProvider;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.Provider;
 import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
-import org.opendaylight.controller.sal.core.api.data.DataProviderService;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener;
 import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
 
-public class RestconfProvider extends AbstractProvider {
+public class RestconfProvider implements BundleActivator, Provider, ServiceTrackerCustomizer<Broker, Broker> {
 
+    public final static String NOT_INITALIZED_MSG = "Restcof is not initialized yet. Please try again later";
+    
     private ListenerRegistration<SchemaServiceListener> listenerRegistration;
+    private ServiceTracker<Broker, Broker> brokerServiceTrancker;
+    private BundleContext bundleContext;
+    private ProviderSession session;
 
     @Override
     public void onSessionInitiated(ProviderSession session) {
@@ -28,8 +40,14 @@ public class RestconfProvider extends AbstractProvider {
     }
 
     @Override
-    protected void stopImpl(BundleContext context) {
-        super.stopImpl(context);
+    public void start(BundleContext context) throws Exception {
+        bundleContext = context;
+        brokerServiceTrancker = new ServiceTracker<>(context, Broker.class, this);
+        brokerServiceTrancker.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) {
         if (listenerRegistration != null) {
             try {
                 listenerRegistration.close();
@@ -37,5 +55,32 @@ public class RestconfProvider extends AbstractProvider {
                 e.printStackTrace();
             }
         }
+        session.close();
+        brokerServiceTrancker.close();
+    }
+
+    @Override
+    public Collection<ProviderFunctionality> getProviderFunctionality() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Broker addingService(ServiceReference<Broker> reference) {
+        Broker broker = bundleContext.getService(reference);
+        broker.registerProvider(this, bundleContext);
+        return broker;
+    }
+
+    @Override
+    public void modifiedService(ServiceReference<Broker> reference, Broker service) {
+        // NOOP
+    }
+
+    @Override
+    public void removedService(ServiceReference<Broker> reference, Broker service) {
+        bundleContext.ungetService(reference);
+        BrokerFacade.getInstance().setContext(null);
+        BrokerFacade.getInstance().setDataService(null);
+        ControllerContext.getInstance().setSchemas(null);
     }
 }
index 4a851a3f6ca531f6042b9d20df7f4d9ba3cd3517..90e6d2affc5cde925d4adc941b24d42005aad117 100644 (file)
@@ -24,7 +24,7 @@ import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import com.google.gson.stream.JsonWriter;
 
 @Provider
-@Produces({ API + RestconfService.JSON })
+@Produces({API+RestconfService.JSON})
 public enum StructuredDataToJsonProvider implements MessageBodyWriter<StructuredData> {
     INSTANCE;
     
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/UnsupportedFormatException.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/UnsupportedFormatException.java
new file mode 100644 (file)
index 0000000..615f209
--- /dev/null
@@ -0,0 +1,23 @@
+package org.opendaylight.controller.sal.rest.impl;
+
+public class UnsupportedFormatException extends Exception {
+
+    private static final long serialVersionUID = -1741388894406313402L;
+
+    public UnsupportedFormatException() {
+        super();
+    }
+
+    public UnsupportedFormatException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public UnsupportedFormatException(String message) {
+        super(message);
+    }
+
+    public UnsupportedFormatException(Throwable cause) {
+        super(cause);
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/UnsupportedJsonFormatException.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/UnsupportedJsonFormatException.java
deleted file mode 100644 (file)
index dccf29b..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.opendaylight.controller.sal.rest.impl;
-
-public class UnsupportedJsonFormatException extends Exception {
-
-    private static final long serialVersionUID = -1741388894406313402L;
-
-    public UnsupportedJsonFormatException() {
-        super();
-    }
-
-    public UnsupportedJsonFormatException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-    public UnsupportedJsonFormatException(String message) {
-        super(message);
-    }
-
-    public UnsupportedJsonFormatException(Throwable cause) {
-        super(cause);
-    }
-
-}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java
new file mode 100644 (file)
index 0000000..9f31eb4
--- /dev/null
@@ -0,0 +1,157 @@
+package org.opendaylight.controller.sal.rest.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Stack;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Characters;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.NodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
+
+public class XmlReader {
+    
+    private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
+    private XMLEventReader eventReader;
+
+    public CompositeNodeWrapper read(InputStream entityStream) throws XMLStreamException, UnsupportedFormatException {
+        eventReader = xmlInputFactory.createXMLEventReader(entityStream);
+        
+        if (eventReader.hasNext()) {
+            XMLEvent element = eventReader.peek();
+            if (element.isStartDocument()) {
+                eventReader.nextEvent();
+            }
+        }
+
+        if (eventReader.hasNext() && !isCompositeNodeEvent(eventReader.peek())) {
+            throw new UnsupportedFormatException("Root element of XML has to be composite element.");
+        }
+        
+        final Stack<NodeWrapper<?>> processingQueue = new Stack<>();
+        CompositeNodeWrapper root = null;
+        NodeWrapper<?> element = null;
+        while (eventReader.hasNext()) {
+            final XMLEvent event = eventReader.nextEvent();
+
+            if (event.isStartElement()) {
+                final StartElement startElement = event.asStartElement();
+                CompositeNodeWrapper compParentNode = null;
+                if (!processingQueue.isEmpty() && processingQueue.peek() instanceof CompositeNodeWrapper) {
+                    compParentNode = (CompositeNodeWrapper) processingQueue.peek();
+                }
+                NodeWrapper<?> newNode = null;
+                if (isCompositeNodeEvent(event)) {
+                    if (root == null) {
+                        root = resolveCompositeNodeFromStartElement(startElement);
+                        newNode = root;
+                    } else {
+                        newNode = resolveCompositeNodeFromStartElement(startElement);
+                    }
+                } else if (isSimpleNodeEvent(event)) {
+                    if (root == null) {
+                        throw new UnsupportedFormatException("Root element of XML has to be composite element.");
+                    }
+                    newNode = resolveSimpleNodeFromStartElement(startElement);
+                }
+
+                if (newNode != null) {
+                    processingQueue.push(newNode);
+                    if (compParentNode != null) {
+                        compParentNode.addValue(newNode);
+                    }
+                }
+            } else if (event.isEndElement()) {
+                element = processingQueue.pop();
+            }
+        }
+        
+        if (!root.getLocalName().equals(element.getLocalName())) {
+            throw new UnsupportedFormatException("XML should contain only one root element");
+        }
+        
+        return root;
+    }
+    
+    private boolean isSimpleNodeEvent(final XMLEvent event) throws XMLStreamException {
+        checkArgument(event != null, "XML Event cannot be NULL!");
+        if (event.isStartElement()) {
+            if (eventReader.hasNext()) {
+                final XMLEvent innerEvent;
+                innerEvent = eventReader.peek();
+                if (innerEvent.isCharacters()) {
+                    final Characters chars = innerEvent.asCharacters();
+                    if (!chars.isWhiteSpace()) {
+                        return true;
+                    }
+                } else if (innerEvent.isEndElement()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    
+    private boolean isCompositeNodeEvent(final XMLEvent event) throws XMLStreamException {
+        checkArgument(event != null, "XML Event cannot be NULL!");
+        if (event.isStartElement()) {
+            if (eventReader.hasNext()) {
+                XMLEvent innerEvent;
+                innerEvent = eventReader.peek();
+                if (innerEvent.isCharacters()) {
+                    Characters chars = innerEvent.asCharacters();
+                    if (chars.isWhiteSpace()) {
+                        eventReader.nextEvent();
+                        innerEvent = eventReader.peek();
+                    }
+                }
+                if (innerEvent.isStartElement()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    
+    private SimpleNodeWrapper resolveSimpleNodeFromStartElement(final StartElement startElement) throws XMLStreamException {
+        checkArgument(startElement != null, "Start Element cannot be NULL!");
+        String data = null;
+
+        if (eventReader.hasNext()) {
+            final XMLEvent innerEvent = eventReader.peek();
+            if (innerEvent.isCharacters()) {
+                final Characters chars = innerEvent.asCharacters();
+                if (!chars.isWhiteSpace()) {
+                    data = innerEvent.asCharacters().getData();
+                }
+            } else if (innerEvent.isEndElement()) {
+                data = "";
+            }
+        }
+        
+        return new SimpleNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement), data);
+    }
+    
+    private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final StartElement startElement) {
+        checkArgument(startElement != null, "Start Element cannot be NULL!");
+        return new CompositeNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement));
+    }
+    
+    private String getLocalNameFrom(StartElement startElement) {
+        return startElement.getName().getLocalPart();
+    }
+    
+    private URI getNamespaceFrom(StartElement startElement) {
+        String namespaceURI = startElement.getName().getNamespaceURI();
+        return namespaceURI.isEmpty() ? null : URI.create(namespaceURI);
+    }
+    
+}
index 09733f5e907faa533167be5211b39cf2839b6345..19720107d3b2e12a63e10cedec8ec173b7ea52e8 100644 (file)
@@ -18,18 +18,11 @@ import javax.xml.stream.XMLStreamException;
 
 import org.opendaylight.controller.sal.rest.api.RestconfService;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.Node;
-import org.opendaylight.yangtools.yang.data.api.SimpleNode;
-import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 @Provider
-@Consumes({API+RestconfService.XML})
+@Consumes({ API + RestconfService.XML })
 public enum XmlToCompositeNodeProvider implements MessageBodyReader<CompositeNode> {
     INSTANCE;
-    
-    private final static Logger logger = LoggerFactory.getLogger(XmlToCompositeNodeProvider.class);
 
     @Override
     public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
@@ -40,18 +33,12 @@ public enum XmlToCompositeNodeProvider implements MessageBodyReader<CompositeNod
     public CompositeNode readFrom(Class<CompositeNode> type, Type genericType, Annotation[] annotations,
             MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
             throws IOException, WebApplicationException {
+        XmlReader xmlReader = new XmlReader();
         try {
-            Node<?> node = XmlTreeBuilder.buildDataTree(entityStream);
-            if (node instanceof SimpleNode) {
-                logger.info("Node is SimpleNode");
-                throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
-                        .entity("XML should start with XML element that contains 1..N XML child elements.").build());
-            }
-            return (CompositeNode) node;
-        } catch (XMLStreamException e) {
-            logger.info("Error during translation of InputStream to Node\n" + e.getMessage());
-            throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
-                    .entity(e.getMessage()).build());
+            return xmlReader.read(entityStream);
+        } catch (XMLStreamException | UnsupportedFormatException e) {
+            throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage())
+                    .build());
         }
     }
 
index 3c31c5a313ec0b45a9a8390729638331d4a7a7a0..f5b913253201ee3d045bfbc00d3af994fdf8cba0 100644 (file)
@@ -1,13 +1,15 @@
 package org.opendaylight.controller.sal.restconf.impl
 
+import javax.ws.rs.WebApplicationException
+import javax.ws.rs.core.Response
 import org.opendaylight.controller.md.sal.common.api.data.DataReader
 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession
 import org.opendaylight.controller.sal.core.api.data.DataBrokerService
+import org.opendaylight.controller.sal.rest.impl.RestconfProvider
 import org.opendaylight.yangtools.yang.common.QName
 import org.opendaylight.yangtools.yang.common.RpcResult
 import org.opendaylight.yangtools.yang.data.api.CompositeNode
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import static org.opendaylight.controller.sal.restconf.impl.BrokerFacade.*
 
 class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
 
@@ -24,31 +26,43 @@ class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
             throw new IllegalStateException("Already instantiated");
         }
     }
-    
+
     def static BrokerFacade getInstance() {
         return INSTANCE
     }
 
+    private def void checkPreconditions() {
+        if (context == null || dataService == null) {
+            throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE)
+                    .entity(RestconfProvider::NOT_INITALIZED_MSG).build())
+        }
+    }
+
     override readConfigurationData(InstanceIdentifier path) {
+        checkPreconditions
         return dataService.readConfigurationData(path);
     }
 
     override readOperationalData(InstanceIdentifier path) {
+        checkPreconditions
         return dataService.readOperationalData(path);
     }
 
     def RpcResult<CompositeNode> invokeRpc(QName type, CompositeNode payload) {
+        checkPreconditions
         val future = context.rpc(type, payload);
         return future.get;
     }
 
     def commitConfigurationDataPut(InstanceIdentifier path, CompositeNode payload) {
+        checkPreconditions
         val transaction = dataService.beginTransaction;
         transaction.putConfigurationData(path, payload);
         return transaction.commit()
     }
 
     def commitOperationalDataPut(InstanceIdentifier path, CompositeNode payload) {
+        checkPreconditions
         val transaction = dataService.beginTransaction;
         transaction.putOperationalData(path, payload);
         return transaction.commit()
index 624178569d4e71551507f7733cec7c93bf4b032c..c1ee611e07c77241b1346f0683387d503111e1e9 100644 (file)
@@ -8,6 +8,11 @@ import java.net.URLEncoder
 import java.util.HashMap
 import java.util.List
 import java.util.Map
+import java.util.concurrent.ConcurrentHashMap
+import javax.ws.rs.WebApplicationException
+import javax.ws.rs.core.Response
+import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
+import org.opendaylight.controller.sal.rest.impl.RestconfProvider
 import org.opendaylight.yangtools.yang.common.QName
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder
@@ -21,12 +26,10 @@ import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition
 import org.opendaylight.yangtools.yang.model.api.SchemaContext
 
 import static com.google.common.base.Preconditions.*
-import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
-import org.opendaylight.yangtools.yang.model.api.RpcDefinition
-import java.util.concurrent.ConcurrentHashMap
 
 class ControllerContext implements SchemaServiceListener {
 
@@ -51,6 +54,13 @@ class ControllerContext implements SchemaServiceListener {
     static def getInstance() {
         return INSTANCE
     }
+    
+    private def void checkPreconditions() {
+        if (schemas == null) {
+            throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE)
+                    .entity(RestconfProvider::NOT_INITALIZED_MSG).build())
+        }
+    }
 
     public def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) {
         val ret = InstanceIdentifier.builder();
@@ -69,6 +79,7 @@ class ControllerContext implements SchemaServiceListener {
     }
 
     private def findModule(String restconfInstance) {
+        checkPreconditions
         checkNotNull(restconfInstance);
         val pathArgs = restconfInstance.split("/");
         if (pathArgs.empty) {
@@ -93,6 +104,7 @@ class ControllerContext implements SchemaServiceListener {
     }
 
     def String toFullRestconfIdentifier(InstanceIdentifier path) {
+        checkPreconditions
         val elements = path.path;
         val ret = new StringBuilder();
         val startQName = elements.get(0).nodeType;
@@ -120,6 +132,7 @@ class ControllerContext implements SchemaServiceListener {
     }
 
     def CharSequence toRestconfIdentifier(QName qname) {
+        checkPreconditions
         var module = uriToModuleName.get(qname.namespace)
         if (module == null) {
             val moduleSchema = schemas.findModuleByNamespaceAndRevision(qname.namespace, qname.revision);
index ea3a4fbcfcbae90e848c39e505008dd701613b26..d9ac53589fa5415bcba3e59467576fcbb98d069e 100644 (file)
@@ -1,10 +1,12 @@
 package org.opendaylight.controller.sal.restconf.impl
 
 import java.util.List
+import javax.ws.rs.core.Response
 import org.opendaylight.controller.sal.rest.api.RestconfService
 import org.opendaylight.yangtools.yang.data.api.CompositeNode
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus
 
 class RestconfImpl implements RestconfService {
     
@@ -48,13 +50,21 @@ class RestconfImpl implements RestconfService {
     override createConfigurationData(String identifier, CompositeNode payload) {
         val identifierWithSchemaNode = identifier.toInstanceIdentifier
         val value = resolveNodeNamespaceBySchema(payload, identifierWithSchemaNode.schemaNode)
-        return broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
+        val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
+        switch status.result {
+            case TransactionStatus.COMMITED: Response.status(Response.Status.OK).build
+            default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build
+        }
     }
 
     override updateConfigurationData(String identifier, CompositeNode payload) {
         val identifierWithSchemaNode = identifier.toInstanceIdentifier
         val value = resolveNodeNamespaceBySchema(payload, identifierWithSchemaNode.schemaNode)
-        return broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
+        val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
+        switch status.result {
+            case TransactionStatus.COMMITED: Response.status(Response.Status.NO_CONTENT).build
+            default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build
+        }
     }
 
     override invokeRpc(String identifier, CompositeNode payload) {
@@ -88,13 +98,21 @@ class RestconfImpl implements RestconfService {
     override createOperationalData(String identifier, CompositeNode payload) {
         val identifierWithSchemaNode = identifier.toInstanceIdentifier
         val value = resolveNodeNamespaceBySchema(payload, identifierWithSchemaNode.schemaNode)
-        return broker.commitOperationalDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
+        val status = broker.commitOperationalDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
+        switch status.result {
+            case TransactionStatus.COMMITED: Response.status(Response.Status.OK).build
+            default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build
+        }
     }
     
     override updateOperationalData(String identifier, CompositeNode payload) {
         val identifierWithSchemaNode = identifier.toInstanceIdentifier
         val value = resolveNodeNamespaceBySchema(payload, identifierWithSchemaNode.schemaNode)
-        return broker.commitOperationalDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
+        val status = broker.commitOperationalDataPut(identifierWithSchemaNode.instanceIdentifier,value).get();
+        switch status.result {
+            case TransactionStatus.COMMITED: Response.status(Response.Status.NO_CONTENT).build
+            default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build
+        }
     }
     
     private def CompositeNode resolveNodeNamespaceBySchema(CompositeNode node, DataSchemaNode schema) {
@@ -113,7 +131,7 @@ class RestconfImpl implements RestconfService {
             val List<NodeWrapper<?>> children = (nodeBuilder as CompositeNodeWrapper).getValues
             for (child : children) {
                 addNamespaceToNodeFromSchemaRecursively(child,
-                    (schema as DataNodeContainer).childNodes.findFirst[n|n.QName.localName === child.localName])
+                    (schema as DataNodeContainer).childNodes.findFirst[n|n.QName.localName.equals(child.localName)])
             }
         }
     }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java
new file mode 100644 (file)
index 0000000..251b212
--- /dev/null
@@ -0,0 +1,90 @@
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.util.concurrent.*;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class DummyFuture implements Future<RpcResult<TransactionStatus>> {
+    
+    private final boolean cancel;
+    private final boolean isCancelled;
+    private final boolean isDone;
+    private final RpcResult<TransactionStatus> result;
+    
+    public DummyFuture() {
+        cancel = false;
+        isCancelled = false;
+        isDone = false;
+        result = null;
+    }
+    
+    private DummyFuture(Builder builder) {
+        cancel = builder.cancel;
+        isCancelled = builder.isCancelled;
+        isDone = builder.isDone;
+        result = builder.result;
+    }
+    
+    public static Builder builder() {
+        return new DummyFuture.Builder();
+    }
+
+    @Override
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        return cancel;
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return isCancelled;
+    }
+
+    @Override
+    public boolean isDone() {
+        return isDone;
+    }
+
+    @Override
+    public RpcResult<TransactionStatus> get() throws InterruptedException, ExecutionException {
+        return result;
+    }
+
+    @Override
+    public RpcResult<TransactionStatus> get(long timeout, TimeUnit unit) throws InterruptedException,
+            ExecutionException, TimeoutException {
+        return result;
+    }
+    
+    public static class Builder {
+        
+        private boolean cancel;
+        private boolean isCancelled;
+        private boolean isDone;
+        private RpcResult<TransactionStatus> result;
+
+        public Builder cancel(boolean cancel) {
+            this.cancel = cancel;
+            return this;
+        }
+        
+        public Builder isCancelled(boolean isCancelled) {
+            this.isCancelled = isCancelled;
+            return this;
+        }
+        
+        public Builder isDone(boolean isDone) {
+            this.isDone = isDone;
+            return this;
+        }
+        
+        public Builder rpcResult(RpcResult<TransactionStatus> result) {
+            this.result = result;
+            return this;
+        }
+        
+        public Future<RpcResult<TransactionStatus>> build() {
+            return new DummyFuture(this);
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java
new file mode 100644 (file)
index 0000000..5ab4f99
--- /dev/null
@@ -0,0 +1,72 @@
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class DummyRpcResult implements RpcResult<TransactionStatus> {
+    
+    private final boolean isSuccessful;
+    private final TransactionStatus result;
+    private final Collection<RpcError> errors;
+    
+    public DummyRpcResult() {
+        isSuccessful = false;
+        result = null;
+        errors = null;
+    }
+    
+    private DummyRpcResult(Builder builder) {
+        isSuccessful = builder.isSuccessful;
+        result = builder.result;
+        errors = builder.errors;
+    }
+    
+    public static Builder builder() {
+        return new DummyRpcResult.Builder();
+    }
+
+    @Override
+    public boolean isSuccessful() {
+        return isSuccessful;
+    }
+
+    @Override
+    public TransactionStatus getResult() {
+        return result;
+    }
+
+    @Override
+    public Collection<RpcError> getErrors() {
+        return errors;
+    }
+    
+    public static class Builder {
+        private boolean isSuccessful;
+        private TransactionStatus result;
+        private Collection<RpcError> errors;
+        
+        public Builder isSuccessful(boolean isSuccessful) {
+            this.isSuccessful = isSuccessful;
+            return this;
+        }
+        
+        public Builder result(TransactionStatus result) {
+            this.result = result;
+            return this;
+        }
+        
+        public Builder errors(Collection<RpcError> errors) {
+            this.errors = errors;
+            return this;
+        }
+        
+        public RpcResult<TransactionStatus> build() {
+            return new DummyRpcResult(this);
+        }
+        
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNodeTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNodeTest.java
new file mode 100644 (file)
index 0000000..ede225c
--- /dev/null
@@ -0,0 +1,351 @@
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import javax.ws.rs.WebApplicationException;
+
+import org.junit.*;
+import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
+import org.opendaylight.controller.sal.restconf.impl.*;
+import org.opendaylight.yangtools.yang.data.api.*;
+import org.slf4j.*;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.model.api.*;
+
+import com.google.gson.JsonSyntaxException;
+
+public class FromJsonToCompositeNodeTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FromJsonToCompositeNodeTest.class);
+
+    @Test
+    public void simpleListTest() {
+        simpleTest("/json-to-composite-node/simple-list.json", "/json-to-composite-node/simple-list-yang", "lst",
+                "simple:list:yang1", "simple-list-yang1");
+    }
+
+    @Test
+    public void simpleContainerTest() {
+        simpleTest("/json-to-composite-node/simple-container.json", "/json-to-composite-node/simple-container-yang",
+                "cont", "simple:container:yang", "simple-container-yang");
+    }
+
+    /**
+     * test if for every leaf list item is simple node instance created
+     */
+    @Test
+    public void multipleItemsInLeafList() {
+        CompositeNode compositeNode = compositeContainerFromJson(
+                "/json-to-composite-node/multiple-leaflist-items.json", true);
+        assertNotNull(compositeNode);
+        assertEquals(3, compositeNode.getChildren().size());
+
+        boolean lflst1_1 = false;
+        boolean lflst1_2 = false;
+        boolean lflst1_3 = false;
+
+        for (Node<?> node : compositeNode.getChildren()) {
+            assertEquals("lflst1", node.getNodeType().getLocalName());
+            assertTrue(node instanceof SimpleNode<?>);
+            SimpleNode<?> simpleNode = (SimpleNode<?>) node;
+            if (simpleNode.getValue().equals("45")) {
+                lflst1_1 = true;
+            } else if (simpleNode.getValue().equals("55")) {
+                lflst1_2 = true;
+            } else if (simpleNode.getValue().equals("66")) {
+                lflst1_3 = true;
+            }
+        }
+
+        assertTrue(lflst1_1);
+        assertTrue(lflst1_2);
+        assertTrue(lflst1_3);
+
+    }
+
+    /**
+     * List contains 4 items and in every item are other elements. It is
+     * supposed that there should be: lf11, lflst11, cont11, lst11
+     */
+    @Test
+    public void multipleItemsInListTest() {
+        CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/multiple-items-in-list.json",
+                true);
+        assertNotNull(compositeNode);
+
+        assertEquals("lst", compositeNode.getNodeType().getLocalName());
+
+        verityMultipleItemsInList(compositeNode);
+    }
+
+    @Test
+    public void nullArrayToCompositeNodeWithNullValueTest() {
+        CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/array-with-null.json", true);
+        assertNotNull(compositeNode);
+        assertEquals("cont", compositeNode.getNodeType().getLocalName());
+
+        assertNotNull(compositeNode.getChildren());
+        assertEquals(1, compositeNode.getChildren().size());
+        Node<?> lfNode = compositeNode.getChildren().iterator().next();
+
+        assertTrue(lfNode instanceof SimpleNode<?>);
+        assertEquals(null, ((SimpleNode<?>) lfNode).getValue());
+
+    }
+
+    @Test
+    public void incorrectTopLevelElementsTest() {
+        Throwable cause1 = null;
+        try {
+            compositeContainerFromJson("/json-to-composite-node/wrong-top-level1.json", true);
+        } catch (WebApplicationException e) {
+            cause1 = e;
+        }
+
+        assertNotNull(cause1);
+        assertTrue(cause1
+                .getCause()
+                .getMessage()
+                .contains(
+                        "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet."));
+
+        Throwable cause2 = null;
+        try {
+            compositeContainerFromJson("/json-to-composite-node/wrong-top-level2.json", true);
+        } catch (WebApplicationException e) {
+            cause2 = e;
+        }
+        assertNotNull(cause2);
+        assertTrue(cause2.getCause().getMessage().contains("Json Object should contain one element"));
+
+        Throwable cause3 = null;
+        try {
+            compositeContainerFromJson("/json-to-composite-node/wrong-top-level3.json", true);
+        } catch (WebApplicationException e) {
+            cause3 = e;
+        }
+        assertNotNull(cause3);
+        assertTrue(cause3
+                .getCause()
+                .getMessage()
+                .contains(
+                        "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet."));
+
+    }
+
+    /**
+     * if leaf list with no data is in json then no corresponding data is
+     * created in composite node. if leaf with no data then exception is raised
+     */
+    @Test
+    public void emptyDataReadTest() {
+        CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/empty-data.json", true);
+
+        assertNotNull(compositeNode);
+
+        assertEquals("cont", compositeNode.getNodeType().getLocalName());
+        assertTrue(compositeNode instanceof CompositeNode);
+        List<Node<?>> children = ((CompositeNode) compositeNode).getChildren();
+        assertEquals(1, children.size());
+        assertEquals("lflst2", children.get(0).getNodeType().getLocalName());
+        assertEquals("45", children.get(0).getValue());
+
+        String reason = null;
+        try {
+            compositeContainerFromJson("/json-to-composite-node/empty-data1.json", true);
+        } catch (JsonSyntaxException e) {
+            reason = e.getMessage();
+        }
+
+        assertTrue(reason.contains("Expected value at line"));
+
+    }
+
+    /**
+     * Tests whether namespace <b>stay unchanged</b> if concrete values are
+     * present in composite or simple node and if the method for update is
+     * called.
+     * 
+     */
+    @Test
+    public void notSupplyNamespaceIfAlreadySupplied() {
+
+        CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/simple-list.json");
+        assertNotNull(compositeNode);
+
+        DataSchemaNode dataSchemaNode1 = null;
+        DataSchemaNode dataSchemaNode2 = null;
+        try {
+            dataSchemaNode1 = TestUtils.obtainSchemaFromYang("/json-to-composite-node/simple-list-yang",
+                    "simple-list-yang1");
+            dataSchemaNode2 = TestUtils.obtainSchemaFromYang("/json-to-composite-node/simple-list-yang",
+                    "simple-list-yang2");
+        } catch (FileNotFoundException e) {
+            LOG.error(e.getMessage());
+            assertTrue(false);
+        }
+        assertNotNull(dataSchemaNode1);
+        assertNotNull(dataSchemaNode2);
+
+        // supplement namespaces according to first data schema -
+        // "simple:data:types1"
+        TestUtils.supplementNamespace(dataSchemaNode1, compositeNode);
+
+        assertTrue(compositeNode instanceof CompositeNodeWrapper);
+        CompositeNode compNode = ((CompositeNodeWrapper) compositeNode).unwrap(null);
+
+        assertEquals("lst", compNode.getNodeType().getLocalName());
+        verifyCompositeNode(compNode, "simple:list:yang1");
+
+        // dataSchemaNode2 should't be taken into account, because compNode
+        // isn't CompositeNodeWrapper
+        TestUtils.supplementNamespace(dataSchemaNode2, compNode);
+        verifyCompositeNode(compNode, "simple:list:yang1");
+
+    }
+
+    private void simpleTest(String jsonPath, String yangPath, String topLevelElementName, String namespace,
+            String moduleName) {
+        CompositeNode compositeNode = compositeContainerFromJson(jsonPath);
+        assertNotNull(compositeNode);
+
+        DataSchemaNode dataSchemaNode = null;
+        try {
+            dataSchemaNode = TestUtils.obtainSchemaFromYang(yangPath, moduleName);
+        } catch (FileNotFoundException e) {
+            LOG.error(e.getMessage());
+            assertTrue(false);
+        }
+        assertNotNull(dataSchemaNode);
+
+        TestUtils.supplementNamespace(dataSchemaNode, compositeNode);
+
+        assertTrue(compositeNode instanceof CompositeNodeWrapper);
+        CompositeNode compNode = ((CompositeNodeWrapper) compositeNode).unwrap(null);
+
+        assertEquals(topLevelElementName, compNode.getNodeType().getLocalName());
+        verifyCompositeNode(compNode, namespace);
+    }
+
+    private void verityMultipleItemsInList(CompositeNode compositeNode) {
+        List<Node<?>> childrenNodes = compositeNode.getChildren();
+        assertEquals(4, childrenNodes.size());
+        boolean lf11Found = false;
+        boolean cont11Found = false;
+        boolean lst11Found = false;
+        for (Node<?> lst1Item : childrenNodes) {
+            assertEquals("lst1", lst1Item.getNodeType().getLocalName());
+            assertTrue(lst1Item instanceof CompositeNode);
+
+            List<Node<?>> childrenLst1 = ((CompositeNode) lst1Item).getChildren();
+            assertEquals(1, childrenLst1.size());
+            String localName = childrenLst1.get(0).getNodeType().getLocalName();
+            if (localName.equals("lf11")) {
+                assertTrue(childrenLst1.get(0) instanceof SimpleNode);
+                lf11Found = true;
+            } else if (localName.equals("lflst11")) {
+                assertTrue(childrenLst1.get(0) instanceof SimpleNode);
+                assertEquals("45", ((SimpleNode<?>) childrenLst1.get(0)).getValue());
+                lf11Found = true;
+            } else if (localName.equals("cont11")) {
+                assertTrue(childrenLst1.get(0) instanceof CompositeNode);
+                cont11Found = true;
+            } else if (localName.equals("lst11")) {
+                lst11Found = true;
+                assertTrue(childrenLst1.get(0) instanceof CompositeNode);
+                assertEquals(0, ((CompositeNode) childrenLst1.get(0)).getChildren().size());
+            }
+
+        }
+        assertTrue(lf11Found);
+        assertTrue(cont11Found);
+        assertTrue(lst11Found);
+    }
+
+    private void verifyCompositeNode(CompositeNode compositeNode, String namespace) {
+        boolean cont1Found = false;
+        boolean lst1Found = false;
+        boolean lflst1_1Found = false;
+        boolean lflst1_2Found = false;
+        boolean lf1Found = false;
+
+        assertEquals(namespace, compositeNode.getNodeType().getNamespace().toString());
+
+        for (Node<?> node : compositeNode.getChildren()) {
+            if (node.getNodeType().getLocalName().equals("cont1")) {
+                if (node instanceof CompositeNode) {
+                    cont1Found = true;
+                    assertEquals(0, ((CompositeNode) node).getChildren().size());
+                }
+            } else if (node.getNodeType().getLocalName().equals("lst1")) {
+                if (node instanceof CompositeNode) {
+                    lst1Found = true;
+                    assertEquals(0, ((CompositeNode) node).getChildren().size());
+                }
+            } else if (node.getNodeType().getLocalName().equals("lflst1")) {
+                if (node instanceof SimpleNode) {
+                    if (((SimpleNode<?>) node).getValue().equals("lflst1_1")) {
+                        lflst1_1Found = true;
+                    } else if (((SimpleNode<?>) node).getValue().equals("lflst1_2")) {
+                        lflst1_2Found = true;
+                    }
+                }
+
+            } else if (node.getNodeType().getLocalName().equals("lf1")) {
+                if (node instanceof SimpleNode) {
+                    if (((SimpleNode<?>) node).getValue().equals("lf1")) {
+                        lf1Found = true;
+                    }
+                }
+            }
+            assertEquals(namespace, node.getNodeType().getNamespace().toString());
+        }
+        assertTrue(cont1Found);
+        assertTrue(lst1Found);
+        assertTrue(lflst1_1Found);
+        assertTrue(lflst1_2Found);
+        assertTrue(lf1Found);
+    }
+
+    private CompositeNode compositeContainerFromJson(String jsonPath) {
+        return compositeContainerFromJson(jsonPath, false);
+    }
+
+    private CompositeNode compositeContainerFromJson(String jsonPath, boolean dummyNamespaces)
+            throws WebApplicationException {
+
+        JsonToCompositeNodeProvider jsonToCompositeNodeProvider = JsonToCompositeNodeProvider.INSTANCE;
+        InputStream jsonStream = FromJsonToCompositeNodeTest.class.getResourceAsStream(jsonPath);
+        try {
+            CompositeNode compositeNode = jsonToCompositeNodeProvider
+                    .readFrom(null, null, null, null, null, jsonStream);
+            assertTrue(compositeNode instanceof CompositeNodeWrapper);
+            if (dummyNamespaces) {
+                try {
+                    TestUtils.addDummyNamespaceToAllNodes((CompositeNodeWrapper) compositeNode);
+                    return ((CompositeNodeWrapper) compositeNode).unwrap(null);
+                } catch (URISyntaxException e) {
+                    LOG.error(e.getMessage());
+                    assertTrue(e.getMessage(), false);
+                }
+            }
+            return compositeNode;
+        } catch (IOException e) {
+            LOG.error(e.getMessage());
+            assertTrue(e.getMessage(), false);
+        }
+        return null;
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNodeTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNodeTest.java
new file mode 100644 (file)
index 0000000..6249d2a
--- /dev/null
@@ -0,0 +1,253 @@
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.*;
+import java.net.URISyntaxException;
+
+import javax.ws.rs.WebApplicationException;
+
+import org.junit.*;
+import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
+import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
+import org.opendaylight.yangtools.yang.data.api.*;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.slf4j.*;
+
+public class FromXmlToCompositeNodeTest {
+    private static final Logger LOG = LoggerFactory.getLogger(FromXmlToCompositeNodeTest.class);
+
+    /**
+     * top level element represents container. second level element is list with
+     * two elements.
+     */
+    @Test
+    public void testXmlDataContainer() {
+        CompositeNode compNode = compositeContainerFromXml("/xml-to-composite-node/data-container.xml", false);
+        assertNotNull(compNode);
+        DataSchemaNode dataSchemaNode = null;
+        try {
+            dataSchemaNode = TestUtils.obtainSchemaFromYang("/xml-to-composite-node/data-container-yang");
+        } catch (FileNotFoundException e) {
+            LOG.error(e.getMessage());
+            assertTrue(false);
+        }
+
+        assertNotNull(dataSchemaNode);
+        TestUtils.supplementNamespace(dataSchemaNode, compNode);
+
+        String nameSpace = "data:container:yang";
+        assertEquals(nameSpace, compNode.getNodeType().getNamespace().toString());
+
+        verifyCommonPartAOfXml(compNode, "", nameSpace);
+    }
+
+    @Test
+    public void testXmlDataList() {
+        CompositeNode compNode = compositeContainerFromXml("/xml-to-composite-node/data-list.xml", false);
+        assertNotNull(compNode);
+
+        DataSchemaNode dataSchemaNode = null;
+        try {
+            dataSchemaNode = TestUtils.obtainSchemaFromYang("/xml-to-composite-node/data-list-yang",
+                    "data-container-yang");
+        } catch (FileNotFoundException e) {
+            LOG.error(e.getMessage());
+        }
+        assertNotNull(dataSchemaNode);
+        TestUtils.supplementNamespace(dataSchemaNode, compNode);
+
+        String nameSpaceList = "data:list:yang";
+        String nameSpaceCont = "data:container:yang";
+        assertEquals(nameSpaceCont, compNode.getNodeType().getNamespace().toString());
+        assertEquals("cont", compNode.getNodeType().getLocalName());
+        assertEquals(3, compNode.getChildren().size());
+        CompositeNode lst1_1 = null;
+        CompositeNode lst1_2 = null;
+        int loopCount = 0;
+        for (Node<?> node : compNode.getChildren()) {
+            if (node.getNodeType().getLocalName().equals("lf1")) {
+                assertEquals(nameSpaceList, node.getNodeType().getNamespace().toString());
+                assertTrue(node instanceof SimpleNode<?>);
+                assertEquals("lf1", node.getValue());
+            } else {
+                assertTrue(node instanceof CompositeNode);
+                switch (loopCount++) {
+                case 0:
+                    lst1_1 = (CompositeNode) node;
+                    break;
+                case 1:
+                    lst1_2 = (CompositeNode) node;
+                    break;
+                }
+                assertEquals(nameSpaceCont, node.getNodeType().getNamespace().toString());
+            }
+        }
+        // lst1_1
+        verifyCommonPartAOfXml(lst1_1, "1", nameSpaceCont);
+        // :lst1_1
+
+        // lst1_2
+        SimpleNode<?> lflst11 = null;
+        CompositeNode cont11 = null;
+        for (Node<?> node : lst1_2.getChildren()) {
+            String nodeName = node.getNodeType().getLocalName();
+            if (nodeName.equals("lflst11")) {
+                assertTrue(node instanceof SimpleNode<?>);
+                lflst11 = (SimpleNode<?>) node;
+
+            } else if (nodeName.equals("cont11")) {
+                assertTrue(node instanceof CompositeNode);
+                cont11 = (CompositeNode) node;
+            }
+            assertEquals(nameSpaceCont, compNode.getNodeType().getNamespace().toString());
+        }
+        assertEquals("221", lflst11.getValue());
+
+        assertEquals(1, cont11.getChildren().size());
+        assertTrue(cont11.getChildren().get(0) instanceof SimpleNode<?>);
+        SimpleNode<?> cont11_lf111 = (SimpleNode<?>) cont11.getChildren().get(0);
+        assertEquals(nameSpaceCont, cont11_lf111.getNodeType().getNamespace().toString());
+        assertEquals("lf111", cont11_lf111.getNodeType().getLocalName());
+        assertEquals("100", cont11_lf111.getValue());
+        // :lst1_2
+
+    }
+
+    @Test
+    public void testXmlEmptyData() {
+        CompositeNode compNode = compositeContainerFromXml("/xml-to-composite-node/empty-data.xml", true);
+        assertEquals("cont", compNode.getNodeType().getLocalName());
+        SimpleNode<?> lf1 = null;
+        SimpleNode<?> lflst1_1 = null;
+        SimpleNode<?> lflst1_2 = null;
+        CompositeNode lst1 = null;
+        int lflst1Count = 0;
+        for (Node<?> node : compNode.getChildren()) {
+            if (node.getNodeType().getLocalName().equals("lf1")) {
+                assertTrue(node instanceof SimpleNode<?>);
+                lf1 = (SimpleNode<?>) node;
+            } else if (node.getNodeType().getLocalName().equals("lflst1")) {
+                assertTrue(node instanceof SimpleNode<?>);
+
+                switch (lflst1Count++) {
+                case 0:
+                    lflst1_1 = (SimpleNode<?>) node;
+                    break;
+                case 1:
+                    lflst1_2 = (SimpleNode<?>) node;
+                    break;
+                }
+            } else if (node.getNodeType().getLocalName().equals("lst1")) {
+                assertTrue(node instanceof CompositeNode);
+                lst1 = (CompositeNode) node;
+            }
+        }
+
+        assertNotNull(lf1);
+        assertNotNull(lflst1_1);
+        assertNotNull(lflst1_2);
+        assertNotNull(lst1);
+
+        assertEquals("", lf1.getValue());
+        assertEquals("", lflst1_1.getValue());
+        assertEquals("", lflst1_2.getValue());
+        assertEquals(1, lst1.getChildren().size());
+        assertEquals("lf11", lst1.getChildren().get(0).getNodeType().getLocalName());
+
+        assertTrue(lst1.getChildren().get(0) instanceof SimpleNode<?>);
+        assertEquals("", lst1.getChildren().get(0).getValue());
+
+    }
+
+    private void verifyCommonPartAOfXml(CompositeNode compNode, String suf, String nameSpace) {
+        SimpleNode<?> lf1suf = null;
+        SimpleNode<?> lflst1suf_1 = null;
+        SimpleNode<?> lflst1suf_2 = null;
+        SimpleNode<?> lflst1suf_3 = null;
+        CompositeNode cont1suf = null;
+        CompositeNode lst1suf = null;
+
+        int lflstCount = 0;
+
+        for (Node<?> node : compNode.getChildren()) {
+            String localName = node.getNodeType().getLocalName();
+            if (localName.equals("lf1" + suf)) {
+                assertTrue(node instanceof SimpleNode<?>);
+                lf1suf = (SimpleNode<?>) node;
+            } else if (localName.equals("lflst1" + suf)) {
+                assertTrue(node instanceof SimpleNode<?>);
+                switch (lflstCount++) {
+                case 0:
+                    lflst1suf_1 = (SimpleNode<?>) node;
+                    break;
+                case 1:
+                    lflst1suf_2 = (SimpleNode<?>) node;
+                    break;
+                case 2:
+                    lflst1suf_3 = (SimpleNode<?>) node;
+                    break;
+                }
+            } else if (localName.equals("lst1" + suf)) {
+                assertTrue(node instanceof CompositeNode);
+                lst1suf = (CompositeNode) node;
+            } else if (localName.equals("cont1" + suf)) {
+                assertTrue(node instanceof CompositeNode);
+                cont1suf = (CompositeNode) node;
+            }
+            assertEquals(nameSpace, node.getNodeType().getNamespace().toString());
+        }
+
+        assertNotNull(lf1suf);
+        assertNotNull(lflst1suf_1);
+        assertNotNull(lflst1suf_2);
+        assertNotNull(lflst1suf_3);
+        assertNotNull(lst1suf);
+        assertNotNull(cont1suf);
+
+        assertEquals("str0", lf1suf.getValue());
+        assertEquals("121", lflst1suf_1.getValue());
+        assertEquals("131", lflst1suf_2.getValue());
+        assertEquals("str1", lflst1suf_3.getValue());
+
+        assertEquals(1, lst1suf.getChildren().size());
+
+        assertTrue(lst1suf.getChildren().get(0) instanceof SimpleNode<?>);
+        SimpleNode<?> lst11_lf11 = (SimpleNode<?>) lst1suf.getChildren().get(0);
+        assertEquals(nameSpace, lst11_lf11.getNodeType().getNamespace().toString());
+        assertEquals("lf11" + suf, lst11_lf11.getNodeType().getLocalName());
+        assertEquals("str2", lst11_lf11.getValue());
+
+        assertTrue(cont1suf.getChildren().get(0) instanceof SimpleNode<?>);
+        SimpleNode<?> cont1_lf11 = (SimpleNode<?>) cont1suf.getChildren().get(0);
+        assertEquals(nameSpace, cont1_lf11.getNodeType().getNamespace().toString());
+        assertEquals("lf11" + suf, cont1_lf11.getNodeType().getLocalName());
+        assertEquals("100", cont1_lf11.getValue());
+    }
+
+    private CompositeNode compositeContainerFromXml(String xmlPath, boolean dummyNamespaces) {
+        XmlToCompositeNodeProvider xmlToCompositeNodeProvider = XmlToCompositeNodeProvider.INSTANCE;
+        try {
+            InputStream xmlStream = FromXmlToCompositeNodeTest.class.getResourceAsStream(xmlPath);
+            CompositeNode compositeNode = xmlToCompositeNodeProvider.readFrom(null, null, null, null, null, xmlStream);
+            if (dummyNamespaces) {
+                try {
+                    TestUtils.addDummyNamespaceToAllNodes((CompositeNodeWrapper) compositeNode);
+                    return ((CompositeNodeWrapper) compositeNode).unwrap(null);
+                } catch (URISyntaxException e) {
+                    LOG.error(e.getMessage());
+                    assertTrue(e.getMessage(), false);
+                }
+            }
+            return compositeNode;
+
+        } catch (WebApplicationException | IOException e) {
+            LOG.error(e.getMessage());
+            assertTrue(false);
+        }
+        return null;
+    }
+
+}
index 532e29df66dbe5962ab246e56b674710fede7622..1d8d7495f9dfabae21bdddb737401032af34724b 100644 (file)
@@ -2,34 +2,40 @@ package org.opendaylight.controller.sal.restconf.impl.test;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import java.io.*;
 import java.net.*;
 import java.sql.Date;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
+import java.util.concurrent.Future;
 
 import javax.ws.rs.WebApplicationException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.stream.XMLStreamException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.*;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
-import org.opendaylight.controller.sal.rest.impl.*;
-import org.opendaylight.controller.sal.restconf.impl.StructuredData;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
+import org.opendaylight.controller.sal.restconf.impl.*;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.*;
-import org.opendaylight.yangtools.yang.data.impl.*;
+import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder;
 import org.opendaylight.yangtools.yang.model.api.*;
 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.slf4j.*;
 import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import com.google.common.base.Preconditions;
 
 final class TestUtils {
 
@@ -93,8 +99,20 @@ final class TestUtils {
         }
         return (CompositeNode) dataTree;
     }
+    
+    public static Document loadDocumentFrom(InputStream inputStream) {
+        try {
+            DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
+            DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
+            return docBuilder.parse(inputStream);
+        } catch (SAXException | IOException | ParserConfigurationException e) {
+            logger.error("Error during loading Document from XML", e);
+            return null;
+        }
+    }
 
     public static String getDocumentInPrintableForm(Document doc) {
+        Preconditions.checkNotNull(doc);
         try {
             ByteArrayOutputStream out = new ByteArrayOutputStream();
             TransformerFactory tf = TransformerFactory.newInstance();
@@ -265,4 +283,81 @@ final class TestUtils {
     static QName buildQName(String name) {
         return buildQName(name, "", null);
     }
+
+    static void supplementNamespace(DataSchemaNode dataSchemaNode, CompositeNode compositeNode) {
+        RestconfImpl restconf = RestconfImpl.getInstance();
+
+        InstanceIdWithSchemaNode instIdAndSchema = new InstanceIdWithSchemaNode(mock(InstanceIdentifier.class),
+                dataSchemaNode);
+
+        ControllerContext controllerContext = mock(ControllerContext.class);
+        BrokerFacade broker = mock(BrokerFacade.class);
+
+        RpcResult<TransactionStatus> rpcResult = DummyRpcResult.builder().result(TransactionStatus.COMMITED).build();
+        Future<RpcResult<TransactionStatus>> future = DummyFuture.builder().rpcResult(rpcResult).build();
+        when(controllerContext.toInstanceIdentifier(any(String.class))).thenReturn(instIdAndSchema);
+        when(broker.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(future);
+
+        restconf.setControllerContext(controllerContext);
+        restconf.setBroker(broker);
+
+        // method is called only because it contains call of method which
+        // supplement namespaces to compositeNode
+        restconf.createConfigurationData("something", compositeNode);
+    }
+
+    static DataSchemaNode obtainSchemaFromYang(String yangFolder) throws FileNotFoundException {
+        return obtainSchemaFromYang(yangFolder, null);
+    }
+
+    static DataSchemaNode obtainSchemaFromYang(String yangFolder, String moduleName) throws FileNotFoundException {
+        Set<Module> modules = null;
+        modules = TestUtils.loadModules(ToJsonBasicDataTypesTest.class.getResource(yangFolder).getPath());
+
+        if (modules == null) {
+            return null;
+        }
+        if (modules.size() < 1) {
+            return null;
+        }
+        
+        Module moduleRes = null;        
+        if (modules.size() > 1) {
+            if (moduleName == null) {
+                return null;
+            } else {
+                for (Module module: modules) {
+                    if (module.getName().equals(moduleName)) {
+                        moduleRes = module; 
+                    }
+                }
+                if (moduleRes == null) {
+                    return null;
+                }
+            }
+        } else {
+            moduleRes = modules.iterator().next();
+        }
+        
+        if (moduleRes.getChildNodes() == null) {
+            return null;
+        }
+
+        if (moduleRes.getChildNodes().size() != 1) {
+            return null;
+        }
+        DataSchemaNode dataSchemaNode = moduleRes.getChildNodes().iterator().next();
+        return dataSchemaNode;
+
+    }
+
+    static void addDummyNamespaceToAllNodes(NodeWrapper<?> wrappedNode) throws URISyntaxException {
+        wrappedNode.setNamespace(new URI(""));
+        if (wrappedNode instanceof CompositeNodeWrapper) {
+            for (NodeWrapper<?> childNodeWrapper : ((CompositeNodeWrapper) wrappedNode).getValues()) {
+                addDummyNamespaceToAllNodes(childNodeWrapper);
+            }
+        }
+    }
+
 }
index 8cdbf78db9a52fffee9255d330b471605f4ec25b..f88a335f18c9ac37927f34e973ab469ebaa0315c 100644 (file)
@@ -72,7 +72,8 @@ public class ToJsonBasicDataTypesTest {
         boolean lfbinaryChecked = false;
         // boolean lfref1Checked = false;
         boolean lfemptyChecked = false;
-
+        boolean lfstr1Checked = false;
+        
         while (jReader.hasNext()) {
             String keyName = jReader.nextName();
             JsonToken peek = null;
@@ -98,6 +99,10 @@ public class ToJsonBasicDataTypesTest {
                 assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
                 assertEquals("lfstr", jReader.nextString());
                 lfstrChecked = true;
+            } else if (keyName.equals("lfstr1")) {
+                assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+                assertEquals("", jReader.nextString());
+                lfstr1Checked = true;
             } else if (keyName.equals("lfbool1")) {
                 assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek);
                 assertEquals(true, jReader.nextBoolean());
@@ -167,6 +172,7 @@ public class ToJsonBasicDataTypesTest {
         assertTrue("lfbool1 wasn't checked", lfbool1Checked);
         assertTrue("lfbool2 wasn't checked", lfbool2Checked);
         assertTrue("lfstr wasn't checked", lfstrChecked);
+        assertTrue("lfstr1 wasn't checked", lfstr1Checked);
         assertTrue("lfbinary wasn't checked", lfbinaryChecked);
         assertTrue("lfempty wasn't checked", lfemptyChecked);
         // assertTrue("lfref1 wasn't checked", lfref1Checked);
index 9d004362d29d0b64b9a8636f51430ccfa46d8ca3..7b63c5fd9422e5bb3abd0060be1ba57dc9643389 100644 (file)
@@ -1,18 +1,19 @@
 package org.opendaylight.controller.sal.restconf.impl.test;
 
-import static org.mockito.Mockito.*;
-import static org.junit.Assert.*;
+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.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URLEncoder;
-import java.util.Collection;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Future;
 import java.util.logging.Level;
 import java.util.logging.LogRecord;
 
@@ -20,17 +21,14 @@ 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 javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
 
-import org.glassfish.jersey.client.ClientConfig;
 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.api.RestconfService;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
 import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
@@ -38,15 +36,11 @@ import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
 import org.opendaylight.controller.sal.restconf.impl.MediaTypes;
 import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
 
 import com.google.common.base.Charsets;
 
@@ -55,15 +49,11 @@ public class XmlProvidersTest extends JerseyTest {
     private static ControllerContext controllerContext;
     private static BrokerFacade brokerFacade;
     private static RestconfImpl restconfImpl;
+    private static final MediaType MEDIA_TYPE = new MediaType("application", "vnd.yang.api+xml");
 
     @BeforeClass
-    public static void init() {
-        Set<Module> allModules = null;
-        try {
-            allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs").getPath());
-        } catch (FileNotFoundException e) {
-            e.printStackTrace();
-        }
+    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);
@@ -73,7 +63,7 @@ public class XmlProvidersTest extends JerseyTest {
         restconfImpl.setControllerContext(controllerContext);
     }
 
-//    @Before
+    @Before
     public void logs() {
         List<LogRecord> loggedRecords = getLoggedRecords();
         for (LogRecord l : loggedRecords) {
@@ -82,90 +72,100 @@ public class XmlProvidersTest extends JerseyTest {
     }
 
     @Test
-    public void testStructuredDataToXmlProvider() throws FileNotFoundException {
-        URI uri = null;
-        try {
-            uri = new URI("/datastore/" + URLEncoder.encode("ietf-interfaces:interfaces/interface/eth0", Charsets.US_ASCII.name()).toString());
-        } catch (UnsupportedEncodingException | URISyntaxException e) {
-            e.printStackTrace();
-        }
+    public void testStructuredDataToXmlProvider() throws FileNotFoundException, UnsupportedEncodingException {
+        String uri = createUri("/datastore/", "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.toASCIIString()).request(MediaTypes.API+RestconfService.XML).get();
+        Response response = target(uri).request(MEDIA_TYPE).get();
         assertEquals(200, response.getStatus());
     }
 
     @Test
-    public void testXmlToCompositeNodeProvider() throws ParserConfigurationException, SAXException, IOException {
-        URI uri = null;
-        try {
-            uri = new URI("/operations/" + URLEncoder.encode("ietf-interfaces:interfaces/interface/eth0", Charsets.US_ASCII.name()).toString());
-        } catch (UnsupportedEncodingException | URISyntaxException e) {
-            e.printStackTrace();
-        }
-        InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
-        final CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream);
-        when(brokerFacade.invokeRpc(any(QName.class), any(CompositeNode.class))).thenReturn(new RpcResult<CompositeNode>() {
-            
-            @Override
-            public boolean isSuccessful() {
-                return true;
-            }
-            
-            @Override
-            public CompositeNode getResult() {
-                return loadedCompositeNode;
-            }
-            
-            @Override
-            public Collection<RpcError> getErrors() {
-                return null;
-            }
-        });
+    public void testBadFormatXmlToCompositeNodeProvider() throws UnsupportedEncodingException, URISyntaxException {
+        String uri = createUri("/operations/", "ietf-interfaces:interfaces/interface/eth0");
         
-        DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
-        DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
-        xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
-        Document doc = docBuilder.parse(xmlStream);
+        Response response = target(uri).request(MediaTypes.API + RestconfService.XML).post(
+                Entity.entity("<SimpleNode/>", MEDIA_TYPE));
+        assertEquals(400, response.getStatus());
         
-        Response response = target(uri.toASCIIString()).request(MediaTypes.API+RestconfService.XML).post(Entity.entity(TestUtils.getDocumentInPrintableForm(doc), new MediaType("application","vnd.yang.api+xml")));
-        assertEquals(200, response.getStatus());
+        response = target(uri).request(MediaTypes.API + RestconfService.XML).post(
+                Entity.entity("<SimpleNode>", MEDIA_TYPE));
+        assertEquals(400, response.getStatus());
     }
     
     @Test
-    public void testXmlToCompositeNodeProviderExceptions() {
-        URI uri = null;
-        try {
-            uri = new URI("/operations/" + URLEncoder.encode("ietf-interfaces:interfaces/interface/eth0", Charsets.US_ASCII.name()).toString());
-        } catch (UnsupportedEncodingException | URISyntaxException e) {
-            e.printStackTrace();
-        }
+    public void testXmlToCompositeNode404NotFound() throws UnsupportedEncodingException, URISyntaxException {
+        String uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0");
         
-        Response response = target(uri.toASCIIString()).request(MediaTypes.API + RestconfService.XML).post(
-                Entity.entity("<SimpleNode/>", new MediaType("application", "vnd.yang.api+xml")));
-        assertEquals(400, response.getStatus());
+        when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(null);
         
-        response = target(uri.toASCIIString()).request(MediaTypes.API + RestconfService.XML).post(
-                Entity.entity("<SimpleNode>", new MediaType("application", "vnd.yang.api+xml")));
-        assertEquals(400, response.getStatus());
+        Response response = target(uri).request(MediaTypes.API+RestconfService.XML).get();
+        assertEquals(404, response.getStatus());
     }
     
     @Test
-    public void testXmlToCompositeNode404NotFound() {
-        URI uri = null;
-        try {
-            uri = new URI("/datastore/" + URLEncoder.encode("ietf-interfaces:interfaces/interface/eth0", Charsets.US_ASCII.name()).toString());
-        } catch (UnsupportedEncodingException | URISyntaxException e) {
-            e.printStackTrace();
-        }
+    public void testRpcResultCommitedToStatusCodes() throws UnsupportedEncodingException {
+        InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+        String xml = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream));
+        Entity<String> entity = Entity.entity(xml, MEDIA_TYPE);
+        RpcResult<TransactionStatus> rpcResult = DummyRpcResult.builder().result(TransactionStatus.COMMITED).build();
+        Future<RpcResult<TransactionStatus>> dummyFuture = DummyFuture.builder().rpcResult(rpcResult).build();
+        when(brokerFacade.commitOperationalDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture);
+        when(brokerFacade.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture);
         
-        when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(null);
+        String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0");
+        Response response = target(uri).request(MEDIA_TYPE).put(entity);
+        assertEquals(200, response.getStatus());
+        response = target(uri).request(MEDIA_TYPE).post(entity);
+        assertEquals(204, response.getStatus());
         
-        Response response = target(uri.toASCIIString()).request(MediaTypes.API+RestconfService.XML).get();
-        assertEquals(404, response.getStatus());
+        uri = createUri("/operational/", "ietf-interfaces:interfaces/interface/eth0");
+        response = target(uri).request(MEDIA_TYPE).put(entity);
+        assertEquals(200, response.getStatus());
+        response = target(uri).request(MEDIA_TYPE).post(entity);
+        assertEquals(204, response.getStatus());
+        
+        uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0");
+        response = target(uri).request(MEDIA_TYPE).put(entity);
+        assertEquals(200, response.getStatus());
+        response = target(uri).request(MEDIA_TYPE).post(entity);
+        assertEquals(204, response.getStatus());
+    }
+    
+    @Test
+    public void testRpcResultOtherToStatusCodes() throws UnsupportedEncodingException {
+        InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+        String xml = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream));
+        Entity<String> entity = Entity.entity(xml, MEDIA_TYPE);
+        RpcResult<TransactionStatus> rpcResult = DummyRpcResult.builder().result(TransactionStatus.FAILED).build();
+        Future<RpcResult<TransactionStatus>> dummyFuture = DummyFuture.builder().rpcResult(rpcResult).build();
+        when(brokerFacade.commitOperationalDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture);
+        when(brokerFacade.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture);
+        
+        String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0");
+        Response response = target(uri).request(MEDIA_TYPE).put(entity);
+        assertEquals(500, response.getStatus());
+        response = target(uri).request(MEDIA_TYPE).post(entity);
+        assertEquals(500, response.getStatus());
+        
+        uri = createUri("/operational/", "ietf-interfaces:interfaces/interface/eth0");
+        response = target(uri).request(MEDIA_TYPE).put(entity);
+        assertEquals(500, response.getStatus());
+        response = target(uri).request(MEDIA_TYPE).post(entity);
+        assertEquals(500, response.getStatus());
+        
+        uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0");
+        response = target(uri).request(MEDIA_TYPE).put(entity);
+        assertEquals(500, response.getStatus());
+        response = target(uri).request(MEDIA_TYPE).post(entity);
+        assertEquals(500, 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
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/array-with-null.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/array-with-null.json
new file mode 100644 (file)
index 0000000..a19d948
--- /dev/null
@@ -0,0 +1,5 @@
+{
+       "cont": {
+               "lf":[null]
+       }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/empty-data.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/empty-data.json
new file mode 100644 (file)
index 0000000..a6ad7f6
--- /dev/null
@@ -0,0 +1,6 @@
+{
+       "cont": {       
+               "lflst1":[],
+               "lflst2":[45]           
+       }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/empty-data1.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/empty-data1.json
new file mode 100644 (file)
index 0000000..10d964d
--- /dev/null
@@ -0,0 +1,5 @@
+{
+       "cont": {       
+               "lf":                           
+       }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-items-in-list.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-items-in-list.json
new file mode 100644 (file)
index 0000000..8e88266
--- /dev/null
@@ -0,0 +1,26 @@
+{
+       "lst":[
+               {
+                       "lst1": [
+                               {
+                                       "lf11":"lf11_1"
+                               },
+                               {
+                                       "lflst11":[
+                                               45
+                                       ]
+                               },
+                               {
+                                       "cont11":{
+                                       }
+                               },
+                               {
+                                       "lst11":[
+                                       {
+                                               }
+                                       ]
+                               }
+                       ]
+               }
+       ]
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-leaflist-items.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-leaflist-items.json
new file mode 100644 (file)
index 0000000..b61a8a8
--- /dev/null
@@ -0,0 +1,5 @@
+{
+       "cont": {
+               "lflst1":[45,55,66]
+       }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container-yang/simple-container.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container-yang/simple-container.yang
new file mode 100644 (file)
index 0000000..493101c
--- /dev/null
@@ -0,0 +1,20 @@
+module simple-container-yang {
+  namespace "simple:container:yang";  
+
+  prefix "smpdtp";
+  revision 2013-11-12 {    
+  }
+  
+  container cont {
+       container cont1 {
+       }
+       list lst1 {
+       }
+       leaf-list lflst1 {
+               type string;
+       }
+       leaf lf1 {
+               type string;
+       }
+  }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container.json
new file mode 100644 (file)
index 0000000..1be4149
--- /dev/null
@@ -0,0 +1,15 @@
+{
+       "cont":{
+               "cont1":{
+               },
+               "lst1": [
+                       {
+                       }
+               ],
+               "lflst1":[
+                       "lflst1_1",
+                       "lflst1_2"
+               ],
+               "lf1":"lf1"
+       }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list1.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list1.yang
new file mode 100644 (file)
index 0000000..0ce8ea4
--- /dev/null
@@ -0,0 +1,20 @@
+module simple-list-yang1 {
+  namespace "simple:list:yang1";  
+
+  prefix "smplstyg";
+  revision 2013-11-12 {    
+  }
+  
+  list lst {
+       container cont1 {
+       }
+       list lst1 {
+       }
+       leaf-list lflst1 {
+               type string;
+       }
+       leaf lf1 {
+               type string;
+       }
+  }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list2.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list2.yang
new file mode 100644 (file)
index 0000000..0872a47
--- /dev/null
@@ -0,0 +1,20 @@
+module simple-list-yang2 {
+  namespace "simple:list:yang2";  
+
+  prefix "smplstyg";
+  revision 2013-11-12 {    
+  }
+  
+  list lst {
+       container cont1 {
+       }
+       list lst1 {
+       }
+       leaf-list lflst1 {
+               type string;
+       }
+       leaf lf1 {
+               type string;
+       }
+  }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list.json
new file mode 100644 (file)
index 0000000..fee6baa
--- /dev/null
@@ -0,0 +1,17 @@
+{
+       "lst":[
+               {
+                       "cont1":{
+                       },
+                       "lst1": [
+                               {
+                               }
+                       ],
+                       "lflst1":[
+                               "lflst1_1",
+                               "lflst1_2"
+                       ],
+                       "lf1":"lf1"
+               }
+       ]
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level1.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level1.json
new file mode 100644 (file)
index 0000000..3ae3a72
--- /dev/null
@@ -0,0 +1,9 @@
+{
+
+       "lst":[
+               {
+               },
+               {
+               }
+       ]
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level2.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level2.json
new file mode 100644 (file)
index 0000000..f0f5540
--- /dev/null
@@ -0,0 +1,9 @@
+{
+
+       "cont": {
+       },
+       "lst":[
+               {
+               }
+       ]
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level3.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level3.json
new file mode 100644 (file)
index 0000000..7288969
--- /dev/null
@@ -0,0 +1,3 @@
+{
+       "lf":"hello"
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container-yang/data-container.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container-yang/data-container.yang
new file mode 100644 (file)
index 0000000..7c17bf9
--- /dev/null
@@ -0,0 +1,26 @@
+module data-container-yang {
+  namespace "data:container:yang";  
+
+  prefix "dtconyg";
+  revision 2013-11-19 {    
+  }
+  
+  container cont {
+       leaf lf1 {
+               type string;
+       }
+       leaf-list lflst1 {
+               type string;
+       }
+       list lst1 {
+               leaf lf11 {
+                       type string;
+               } 
+       }
+       container cont1 {
+               leaf lf11 {
+                       type uint8;
+               }
+       }
+  }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container.xml
new file mode 100644 (file)
index 0000000..0c60fbc
--- /dev/null
@@ -0,0 +1,12 @@
+<cont>
+       <lf1>str0</lf1>
+       <lflst1>121</lflst1>
+       <lflst1>131</lflst1>
+       <lflst1>str1</lflst1>
+       <lst1>
+               <lf11>str2</lf11>
+       </lst1>                 
+       <cont1>
+               <lf11>100</lf11>
+       </cont1>
+</cont>
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list-yang/data-container.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list-yang/data-container.yang
new file mode 100644 (file)
index 0000000..3df3413
--- /dev/null
@@ -0,0 +1,28 @@
+module data-container-yang {
+  namespace "data:container:yang";  
+
+  prefix "dtconyg";
+  revision 2013-11-19 {    
+  }
+  
+  container cont {     
+         list lst1 {
+               leaf lf11 {
+                       type string;
+               }
+               leaf-list lflst11 {
+                       type string;
+               }
+               list lst11 {
+                       leaf lf111 {
+                               type string;
+                       } 
+               }
+               container cont11 {
+                       leaf lf111 {
+                               type uint8;
+                       }
+               }
+         }  
+  }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list-yang/data-list.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list-yang/data-list.yang
new file mode 100644 (file)
index 0000000..47e2a45
--- /dev/null
@@ -0,0 +1,22 @@
+module data-list-yang {
+  namespace "data:list:yang"; 
+  
+  prefix "dtlstyg";
+
+  import data-container-yang {
+       prefix "dtconyg";
+       revision-date 2013-11-19;
+  }
+  
+  
+  revision 2013-11-19 {    
+  }
+       
+
+
+  augment "/dtconyg:cont" {
+       leaf lf1 {
+               type string;
+       }
+  }    
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list.xml
new file mode 100644 (file)
index 0000000..cab23c6
--- /dev/null
@@ -0,0 +1,21 @@
+<cont>
+       <lst1>
+               <lf11>str0</lf11>
+               <lflst11>121</lflst11>
+               <lflst11>131</lflst11>
+               <lflst11>str1</lflst11>
+               <lst11>
+                       <lf111>str2</lf111>
+               </lst11>                        
+               <cont11>
+                       <lf111>100</lf111>
+               </cont11>
+       </lst1>
+       <lst1>
+               <lflst11>221</lflst11>
+               <cont11>
+                       <lf111>100</lf111>
+               </cont11>
+       </lst1> 
+       <lf1>lf1</lf1>
+</cont>
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/empty-data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/empty-data.xml
new file mode 100644 (file)
index 0000000..162a556
--- /dev/null
@@ -0,0 +1,8 @@
+<cont>
+       <lf1></lf1>
+       <lflst1></lflst1>
+       <lflst1></lflst1>
+       <lst1>          
+               <lf11></lf11>
+       </lst1>                 
+</cont>
index 4ad0983e0422ffe7523e408c2337ff634ac91679..010d3b1c2b374c1a9002877700bac6787ea6b676 100644 (file)
@@ -46,6 +46,9 @@ module simple-data-types {
          leaf lfstr {
                type string;
          }       
+         leaf lfstr1 {
+               type string;
+         }       
          leaf lfbool1 {
                type boolean;
          }       
index 1e83cb4f699d517c999eb8fb68bd98bc80afe49f..df00ca917e7d16f1e5f8a65bdaec9f10671cecc8 100644 (file)
@@ -11,6 +11,7 @@
        <lfnuint16Max>65535</lfnuint16Max>
        <lfnuint32Max>4294967295</lfnuint32Max>
        <lfstr>lfstr</lfstr>
+       <lfstr1></lfstr1>
        <lfbool1>true</lfbool1>
        <lfbool2>false</lfbool2>
        <lfbool3>bla</lfbool3>
index 72e49be4de49899f111aeb55ffe65426b0eb3d1e..78599087685f9ffcb5b7566c7b0da067e065ab0b 100644 (file)
@@ -20,7 +20,6 @@
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
-        <version>${bundle.plugin.version}</version>
         <extensions>true</extensions>
         <configuration>
           <instructions>
diff --git a/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChangeListener.java b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChangeListener.java
deleted file mode 100644 (file)
index 701cfaf..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.connector.remoterpc.api;
-
-import org.opendaylight.controller.sal.connector.api.RpcRouter;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-
-import java.util.EventListener;
-
-public interface RouteChangeListener extends EventListener {
-
-  public void onRouteChanged(RouteChange<RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>, String>  change);
-}
diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/pom.xml b/opendaylight/md-sal/zeromq-routingtable/implementation/pom.xml
new file mode 100644 (file)
index 0000000..37c973e
--- /dev/null
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <relativePath>../..</relativePath>
+    </parent>
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+        <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+        <tag>HEAD</tag>
+    </scm>
+
+    <artifactId>zeromq-routingtable.implementation</artifactId>
+    <version>0.4.1-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${bundle.plugin.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+
+                        <Import-Package>
+                            javax.xml.bind.annotation,
+                            org.opendaylight.controller.sal.core,
+                            org.opendaylight.controller.sal.utils,
+                            org.opendaylight.controller.sal.packet,
+                            org.opendaylight.controller.sal.topology,
+                            org.opendaylight.controller.clustering.services,
+                            org.opendaylight.controller.md.sal.common.api.data,
+                            org.opendaylight.yangtools.yang.binding,
+                            org.osgi.service.component,
+                            org.slf4j,
+                            org.apache.felix.dm,
+                            org.apache.commons.lang3.builder,
+                            org.apache.commons.lang3.tuple,
+                            org.eclipse.osgi.framework.console,
+                            org.osgi.framework,
+                            javax.transaction,
+                            com.google.common.base
+                        </Import-Package>
+                        <Bundle-Activator>
+                            org.opendaylight.controller.sal.connector.remoterpc.impl.Activator
+                        </Bundle-Activator>
+                    </instructions>
+                    <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <dependencies>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal</artifactId>
+            <version>0.5.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-connector-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>clustering.services</artifactId>
+            <version>0.4.1-SNAPSHOT</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+
+
+    </dependencies>
+</project>
@@ -5,10 +5,14 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.controller.config.yang.store.api;
+package org.opendaylight.controller.sal.connector.remoterpc.api;
 
-public interface YangStoreListenerRegistration extends AutoCloseable {
+import java.util.EventListener;
 
-    @Override
-    void close();
+public interface RouteChangeListener<I,R> extends EventListener {
+
+
+   void onRouteUpdated(I key, R new_value);
+
+   void onRouteDeleted(I key);
 }
@@ -11,6 +11,8 @@ import java.util.Set;
 
 public interface RoutingTable<I,R> {
 
+
+
   /**
    * Adds a network address for the route. If address for route
    * exists, appends the address to the list
@@ -18,17 +20,22 @@ public interface RoutingTable<I,R> {
    * @param routeId route identifier
    * @param route network address
    */
-  public void addRoute(I routeId, R route);
+  public void addRoute(I routeId, R route) throws SystemException,  RoutingTableException;
 
   /**
    * Adds a network address for the route. If the route already exists,
-   * it throws. This method would be used when registering a global service.
+   * it throws <code>DuplicateRouteException</code>.
+   * This method would be used when registering a global service.
+   *
    *
    * @param routeId route identifier
    * @param route network address
    * @throws DuplicateRouteException
    */
-  public void addGlobalRoute(I routeId, R route) throws DuplicateRouteException;
+  public void addGlobalRoute(I routeId, R route) throws  RoutingTableException, SystemException;
+
+
+
 
   /**
    * Removes the network address for the route from routing table. If only
@@ -38,6 +45,14 @@ public interface RoutingTable<I,R> {
    */
   public void removeRoute(I routeId, R route);
 
+
+    /**
+     * Remove the route.
+     * This method would be used when registering a global service.
+     * @param routeId
+     */
+    public void removeGlobalRoute(I routeId);
+
   /**
    * Returns a set of network addresses associated with this route
    * @param routeId
@@ -49,12 +64,18 @@ public interface RoutingTable<I,R> {
    * Returns only one address from the list of network addresses
    * associated with the route. The algorithm to determine that
    * one address is upto the implementer
-   * @param route
+   * @param routeId
    * @return
    */
   public R getARoute(I routeId);
 
   public void registerRouteChangeListener(RouteChangeListener listener);
 
-  public class DuplicateRouteException extends Exception {}
+  public class DuplicateRouteException extends RoutingTableException {
+      public DuplicateRouteException(String message) {
+          super(message);
+      }
+
+  }
+
 }
diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTableException.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTableException.java
new file mode 100644 (file)
index 0000000..fc7f6f1
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.connector.remoterpc.api;
+
+/**
+ * @author: syedbahm
+ */
+public class RoutingTableException extends Exception {
+
+    /**
+     * Constructs a new exception with {@code null} as its detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     */
+    public RoutingTableException() {
+        super();
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public RoutingTableException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * {@code cause} is <i>not</i> automatically incorporated in
+     * this exception's detail message.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *                by the {@link #getMessage()} method).
+     * @param cause   the cause (which is saved for later retrieval by the
+     *                {@link #getCause()} method).  (A <tt>null</tt> value is
+     *                permitted, and indicates that the cause is nonexistent or
+     *                unknown.)
+     */
+    public RoutingTableException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/SystemException.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/SystemException.java
new file mode 100644 (file)
index 0000000..491858e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+
+
+package org.opendaylight.controller.sal.connector.remoterpc.api;
+
+/**
+ * @author: syedbahm
+ *
+ */
+public class SystemException extends  Exception {
+    /**
+     * Constructs a new exception with {@code null} as its detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     */
+    public SystemException() {
+        super();
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public SystemException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * {@code cause} is <i>not</i> automatically incorporated in
+     * this exception's detail message.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *                by the {@link #getMessage()} method).
+     * @param cause   the cause (which is saved for later retrieval by the
+     *                {@link #getCause()} method).  (A <tt>null</tt> value is
+     *                permitted, and indicates that the cause is nonexistent or
+     *                unknown.)
+     * @since 1.4
+     */
+    public SystemException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java
new file mode 100644 (file)
index 0000000..4541443
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc.impl;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+/**
+ * @author: syedbahm
+ */
+public class Activator extends ComponentActivatorAbstractBase {
+
+    protected static final Logger logger = LoggerFactory
+            .getLogger(Activator.class);
+    private static final String CACHE_UPDATE_AWARE_REGISTRY_KEY = "cachenames" ;
+
+
+    /**
+     * Method which tells how many Global implementations are
+     * supported by the bundle. This way we can tune the number of
+     * components created. This components will be created ONLY at the
+     * time of bundle startup and will be destroyed only at time of
+     * bundle destruction, this is the major difference with the
+     * implementation retrieved via getImplementations where all of
+     * them are assumed to be in a container!
+     *
+     *
+     * @return The list of implementations the bundle will support,
+     * in Global version
+     */
+
+    @Override
+    protected Object[] getGlobalImplementations(){
+        logger.debug("Calling getGlobalImplementations to return:", RoutingTableImpl.class);
+        return new Object[] {
+                RoutingTableImpl.class
+        };
+    }
+
+    /**
+     * Configure the dependency for a given instance Global
+     *
+     * @param c Component assigned for this instance, this will be
+     * what will be used for configuration
+     * @param imp implementation to be configured
+     *
+     */
+    @Override
+    protected void configureGlobalInstance(Component c, Object imp){
+        if (imp.equals(RoutingTableImpl.class)) {
+            Dictionary<String, Set<String>> props = new Hashtable<String, Set<String>>();
+            Set<String> propSet = new HashSet<String>();
+            propSet.add(RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE);
+            props.put(CACHE_UPDATE_AWARE_REGISTRY_KEY, propSet);
+
+            c.setInterface(new String[] { RoutingTable.class.getName(),ICacheUpdateAware.class.getName()  }, props);
+            logger.debug("configureGlobalInstance adding dependency:", IClusterGlobalServices.class);
+
+            c.add(createServiceDependency().setService(
+                    IClusterGlobalServices.class).setCallbacks(
+                    "setClusterGlobalServices",
+                    "unsetClusterGlobalServices").setRequired(true));
+
+        }
+    }
+
+
+}
diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java
new file mode 100644 (file)
index 0000000..558c8a8
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc.impl;
+
+import com.google.common.base.Preconditions;
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.*;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import java.util.*;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * @author: syedbahm
+ */
+public class RoutingTableImpl<I, R> implements RoutingTable<I, R>,ICacheUpdateAware<I,R> {
+    public static final String ROUTING_TABLE_GLOBAL_CACHE = "routing_table_global_cache";
+
+  private Logger log = LoggerFactory
+            .getLogger(RoutingTableImpl.class);
+
+  private IClusterGlobalServices clusterGlobalServices = null;
+  private RoutingTableImpl routingTableInstance = null;
+  private ConcurrentMap routingTableCache = null;
+  private List<RouteChangeListener>  routeChangeListeners = new ArrayList<RouteChangeListener>();
+  private ServiceRegistration cacheAwareRegistration = null;
+                                                      
+ public RoutingTableImpl() {
+  }
+
+  @Override
+  public void addRoute(I routeId, R route) throws RoutingTableException {
+       throw new UnsupportedOperationException(" Not implemented yet!");
+  }
+
+  @Override
+  public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!");
+    Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!");
+    try {
+
+      Set<R> existingRoute = null;
+      // ok does the global route is already registered ?
+      if ((existingRoute = getRoutes(routeId)) == null) {
+
+          if(log.isDebugEnabled()){
+              log.debug("addGlobalRoute: adding  a new route with id"+ routeId + " and value = "+route);
+          }
+        // lets start a transaction
+        clusterGlobalServices.tbegin();
+        Set<R> routes  = new HashSet<R>();
+        routes.add(route);
+        routingTableCache.put(routeId, routes);
+        clusterGlobalServices.tcommit();
+      } else {
+        throw new DuplicateRouteException(" There is already existing route " + existingRoute);
+      }
+
+    } catch (NotSupportedException e) {
+      throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e);
+    } catch (HeuristicRollbackException e) {
+      throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e);
+    } catch (RollbackException e) {
+      throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e);
+    } catch (HeuristicMixedException e) {
+      throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e);
+    } catch (javax.transaction.SystemException e){
+        throw new SystemException ( "System error occurred - while trying to create with value",e);
+    }
+
+  }
+
+  @Override
+  public void removeRoute(I routeId, R route) {
+         throw new UnsupportedOperationException("Not implemented yet!");
+  }
+    @Override
+    public void removeGlobalRoute(I routeId) {
+        routingTableCache.remove(routeId);
+    }
+
+  @Override
+  public Set<R> getRoutes(I routeId) {
+
+      //Note: currently works for global routes only wherein there is just single route
+      Preconditions.checkNotNull(routeId, "getARoute: routeId cannot be null!");
+      return (Set<R>) routingTableCache.get(routeId);
+  }
+
+  @Override
+  public R getARoute(I routeId) {
+       throw new UnsupportedOperationException("Not implemented yet!");
+  }
+
+  /**
+   * Registers listener for sending any change notification
+   * 
+   * @param listener
+   */
+  @Override
+  public void registerRouteChangeListener(RouteChangeListener listener) {
+      routeChangeListeners.add(listener);
+  }
+
+
+    /**
+     * Returning the list of route change listeners for Unit testing
+     * Note: the package scope is default
+     * @return   List of registered RouteChangeListener<I,R> listeners
+     */
+  List<RouteChangeListener> getRegisteredRouteChangeListeners(){
+      return routeChangeListeners;
+  }
+
+  public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
+    this.clusterGlobalServices = clusterGlobalServices;
+  }
+
+  public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
+    if(cacheAwareRegistration != null) {
+        cacheAwareRegistration.unregister();
+    }
+    this.clusterGlobalServices = null;
+  }
+
+    /**
+     * Creates the Routing Table clustered global services cache
+     * @throws CacheExistException  -- cluster global services exception when cache exist
+     * @throws CacheConfigException -- cluster global services exception during cache config
+     * @throws CacheListenerAddException  -- cluster global services exception during adding of listener
+     */
+
+  void createRoutingTableCache() throws CacheExistException, CacheConfigException, CacheListenerAddException {
+    // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it
+    // should be caching?
+
+    // let us check here if the cache already exists -- if so don't create
+    if (!clusterGlobalServices.existCache(
+        ROUTING_TABLE_GLOBAL_CACHE)) {
+
+        if(log.isDebugEnabled()){
+            log.debug("createRoutingTableCache: creating a new routing table cache "+ROUTING_TABLE_GLOBAL_CACHE );
+        }
+      routingTableCache = clusterGlobalServices.createCache(
+          ROUTING_TABLE_GLOBAL_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+    } else {
+        if(log.isDebugEnabled()){
+            log.debug("createRoutingTableCache: found existing routing table cache "+ROUTING_TABLE_GLOBAL_CACHE );
+        }
+      routingTableCache = clusterGlobalServices.getCache(
+          ROUTING_TABLE_GLOBAL_CACHE);
+    }
+
+  }
+
+  /**
+   * Function called by the dependency manager when all the required
+   * dependencies are satisfied
+   * 
+   */
+  void init(Component c) {
+    try {
+
+      createRoutingTableCache();
+    } catch (CacheExistException e) {
+      throw new IllegalStateException("could not construct routing table cache");
+    } catch (CacheConfigException e) {
+      throw new IllegalStateException("could not construct routing table cache");
+    } catch (CacheListenerAddException e) {
+        throw new IllegalStateException("could not construct routing table cache");
+    }
+  }
+
+
+    /**
+     * Get routing table method is useful for unit testing
+     * <note>It has package scope</note>
+     */
+    ConcurrentMap getRoutingTableCache(){
+        return this.routingTableCache;
+    }
+
+
+      /**
+       * Invoked when a new entry is available in the cache, the key is
+       * only provided, the value will come as an entryUpdate invocation
+       *
+       * @param key         Key for the entry just created
+       * @param cacheName   name of the cache for which update has been
+       *                    received
+       * @param originLocal true if the event is generated from this
+       *                    node
+       */
+      @Override
+      public void entryCreated(I key, String cacheName, boolean originLocal) {
+          //TBD: do we require this.
+          if(log.isDebugEnabled()){
+              log.debug("RoutingTableUpdates: entryCreated  routeId = "+key
+                      + " cacheName="+cacheName
+                      );
+          }
+      }
+
+      /**
+       * Called anytime a given entry is updated
+       *
+       * @param key         Key for the entry modified
+       * @param new_value   the new value the key will have
+       * @param cacheName   name of the cache for which update has been
+       *                    received
+       * @param originLocal true if the event is generated from this
+       *                    node
+       */
+      @Override
+      public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) {
+          if(log.isDebugEnabled()){
+              log.debug("RoutingTableUpdates: entryUpdated  routeId = "+key
+                      + ",value = "+ new_value
+                      + " ,cacheName="+cacheName
+                      );
+          }
+          for(RouteChangeListener rcl:routeChangeListeners){
+              rcl.onRouteUpdated(key, new_value);
+          }
+      }
+
+      /**
+       * Called anytime a given key is removed from the
+       * ConcurrentHashMap we are listening to.
+       *
+       * @param key         Key of the entry removed
+       * @param cacheName   name of the cache for which update has been
+       *                    received
+       * @param originLocal true if the event is generated from this
+       *                    node
+       */
+      @Override
+      public void entryDeleted(I key, String cacheName, boolean originLocal) {
+          if(log.isDebugEnabled()){
+              log.debug("RoutingTableUpdates: entryUpdated  routeId = "+key
+                      + " local = "+ originLocal
+                      + " cacheName="+cacheName
+                       );
+          }
+          for(RouteChangeListener rcl:routeChangeListeners){
+              rcl.onRouteDeleted(key);
+          }
+      }
+  }
\ No newline at end of file
diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java
new file mode 100644 (file)
index 0000000..75cc6f5
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.connector.remoterpc.impl;
+
+import junit.framework.Assert;
+import org.apache.felix.dm.Component;
+import org.junit.Test;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+import java.net.URI;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author: syedbahm
+ */
+public class RoutingTableImplTest {
+
+    private IClusterGlobalServices ics =  mock(IClusterGlobalServices.class);
+    private RoutingTableImpl rti = new RoutingTableImpl();
+
+    private final URI namespace = URI.create("http://cisco.com/example");
+    private final QName QNAME = new QName(namespace,"global");
+
+    ConcurrentMap concurrentMapMock = mock(ConcurrentMap.class);
+
+
+    @Test
+    public void testAddGlobalRoute() throws Exception {
+        ConcurrentMap concurrentMap = createRoutingTableCache();
+
+        Assert.assertNotNull(concurrentMap);
+        RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier =  mock(RpcRouter.RouteIdentifier.class);
+        InstanceIdentifier identifier = mock(InstanceIdentifier.class);
+        when(routeIdentifier.getType()).thenReturn(QNAME);
+        when(routeIdentifier.getRoute()).thenReturn(identifier);
+
+        rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+
+        Set<String> globalService = new HashSet<String>();
+        globalService.add("172.27.12.1:5000");
+
+        when(concurrentMap.get(routeIdentifier)).thenReturn(globalService);
+        ConcurrentMap latestCache = rti.getRoutingTableCache();
+
+        Assert.assertEquals(concurrentMap,latestCache);
+
+        Set<String> servicesGlobal = (Set<String>)latestCache.get(routeIdentifier);
+        Assert.assertEquals(servicesGlobal.size(),1);
+
+        Assert.assertEquals(servicesGlobal.iterator().next(),"172.27.12.1:5000");
+
+    }
+
+    @Test
+    public void testGetRoutes() throws Exception {
+        ConcurrentMap concurrentMap = createRoutingTableCache();
+
+        Assert.assertNotNull(concurrentMap);
+        RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier =  mock(RpcRouter.RouteIdentifier.class);
+        InstanceIdentifier identifier = mock(InstanceIdentifier.class);
+        when(routeIdentifier.getContext()).thenReturn(QNAME);
+        when(routeIdentifier.getRoute()).thenReturn(identifier);
+
+        rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+
+        Set<String> globalService = new HashSet<String>();
+        globalService.add("172.27.12.1:5000");
+
+        when(concurrentMap.get(routeIdentifier)).thenReturn(globalService);
+        ConcurrentMap latestCache = rti.getRoutingTableCache();
+
+        Assert.assertEquals(concurrentMap,latestCache);
+
+        Set<String> servicesGlobal =  rti.getRoutes(routeIdentifier);
+
+
+        Assert.assertEquals(servicesGlobal.size(),1);
+
+        Assert.assertEquals(servicesGlobal.iterator().next(),"172.27.12.1:5000");
+
+
+
+    }
+    @Test
+    public void testRegisterRouteChangeListener() throws Exception {
+        Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),0);
+        rti.registerRouteChangeListener(new RouteChangeListenerImpl());
+
+        Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),1);
+
+    }
+    @Test
+    public void testRemoveGlobalRoute()throws Exception {
+
+        ConcurrentMap concurrentMap = createRoutingTableCache();
+
+        Assert.assertNotNull(concurrentMap);
+        RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier =  mock(RpcRouter.RouteIdentifier.class);
+        InstanceIdentifier identifier = mock(InstanceIdentifier.class);
+        when(routeIdentifier.getContext()).thenReturn(QNAME);
+        when(routeIdentifier.getRoute()).thenReturn(identifier);
+
+        rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+
+        Set<String> globalService = new HashSet<String>();
+        globalService.add("172.27.12.1:5000");
+
+        when(concurrentMap.get(routeIdentifier)).thenReturn(globalService);
+        ConcurrentMap latestCache = rti.getRoutingTableCache();
+
+        Assert.assertEquals(concurrentMap,latestCache);
+
+        Set<String> servicesGlobal =  rti.getRoutes(routeIdentifier);
+
+
+        Assert.assertEquals(servicesGlobal.size(),1);
+
+        Assert.assertEquals(servicesGlobal.iterator().next(),"172.27.12.1:5000");
+
+        rti.removeGlobalRoute(routeIdentifier);
+
+        Assert.assertNotNull(rti.getRoutes(routeIdentifier));
+
+
+    }
+
+    private ConcurrentMap createRoutingTableCache() throws Exception {
+
+        //here init
+        Component c = mock(Component.class);
+
+        when(ics.existCache(
+                RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(false);
+
+        when(ics.createCache(RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(concurrentMapMock);
+         rti.setClusterGlobalServices(this.ics);
+        rti.init(c);
+
+        Assert.assertEquals(concurrentMapMock,rti.getRoutingTableCache() );
+        return concurrentMapMock;
+
+    }
+
+
+    @Test
+    public void testCreateRoutingTableCacheReturnExistingCache() throws Exception {
+        ConcurrentMap concurrentMap = createRoutingTableCache();
+
+        //OK here we should try creating again the cache but this time it should return the existing one
+        when(ics.existCache(
+                RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(true);
+
+        when(ics.getCache(
+                RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(concurrentMap);
+
+
+        //here init
+        Component c = mock(Component.class);
+
+        rti.init(c);
+
+        Assert.assertEquals(concurrentMap,rti.getRoutingTableCache());
+
+
+
+
+
+    }
+
+    private class RouteChangeListenerImpl<I,R> implements RouteChangeListener<I,R>{
+
+        @Override
+        public void onRouteUpdated(I key, R new_value) {
+            //To change body of implemented methods use File | Settings | File Templates.
+        }
+
+        @Override
+        public void onRouteDeleted(I key) {
+            //To change body of implemented methods use File | Settings | File Templates.
+        }
+    }
+
+}
diff --git a/opendaylight/md-sal/zeromq-routingtable/integrationtest/pom.xml b/opendaylight/md-sal/zeromq-routingtable/integrationtest/pom.xml
new file mode 100644 (file)
index 0000000..308d5a9
--- /dev/null
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.integrationtest</artifactId>
+    <version>0.5.1-SNAPSHOT</version>
+    <relativePath>../../../commons/integrationtest</relativePath>
+  </parent>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+    <tag>HEAD</tag>
+  </scm>
+
+  <artifactId>zeromq-routingtable.integrationtest</artifactId>
+  <version>0.4.1-SNAPSHOT</version>
+
+  <dependencies>
+    <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>zeromq-routingtable.implementation</artifactId>
+        <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>clustering.services</artifactId>
+      <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.5.1-SNAPSHOT</version>
+    </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal.implementation</artifactId>
+          <version>0.4.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>containermanager</artifactId>
+          <version>0.5.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>containermanager.it.implementation</artifactId>
+          <version>0.5.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>clustering.stub</artifactId>
+          <version>0.4.0-SNAPSHOT</version>
+      </dependency>
+        <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <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>
+       <scope>test</scope>
+     </dependency>
+     <dependency>
+        <groupId>org.ops4j.pax.exam</groupId>
+        <artifactId>pax-exam-link-mvn</artifactId>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.ops4j.pax.url</groupId>
+        <artifactId>pax-url-aether</artifactId>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>log4j-over-slf4j</artifactId>
+      </dependency>
+      <dependency>
+        <groupId>ch.qos.logback</groupId>
+        <artifactId>logback-core</artifactId>
+      </dependency>
+      <dependency>
+        <groupId>ch.qos.logback</groupId>
+        <artifactId>logback-classic</artifactId>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>org.apache.felix.dependencymanager.shell</artifactId>
+      </dependency>
+      <dependency>
+        <groupId>eclipselink</groupId>
+        <artifactId>javax.resource</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>com.google.guava</groupId>
+          <artifactId>guava</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal</artifactId>
+          <version>0.5.1-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.yangtools</groupId>
+          <artifactId>yang-binding</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.yangtools</groupId>
+          <artifactId>yang-common</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-connector-api</artifactId>
+          <version>1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-common-util</artifactId>
+          <version>1.0-SNAPSHOT</version>
+      </dependency>
+
+      <dependency>
+          <groupId>junit</groupId>
+          <artifactId>junit</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-common-api</artifactId>
+          <version>1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-common-util</artifactId>
+          <version>1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-binding-broker-impl</artifactId>
+          <version>1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-binding-broker-impl</artifactId>
+          <version>1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-container-native</artifactId>
+          <version>${exam.version}</version>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-junit4</artifactId>
+          <version>${exam.version}</version>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-link-mvn</artifactId>
+          <version>${exam.version}</version>
+          <scope>test</scope>
+      </dependency>
+
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>config-manager</artifactId>
+          <version>0.2.3-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>equinoxSDK381</groupId>
+          <artifactId>org.eclipse.osgi</artifactId>
+          <version>3.8.1.v20120830-144521</version>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>log4j-over-slf4j</artifactId>
+          <version>1.7.2</version>
+      </dependency>
+      <dependency>
+          <groupId>ch.qos.logback</groupId>
+          <artifactId>logback-core</artifactId>
+          <version>1.0.9</version>
+      </dependency>
+      <dependency>
+          <groupId>ch.qos.logback</groupId>
+          <artifactId>logback-classic</artifactId>
+          <version>1.0.9</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+          <artifactId>antlr4-runtime-osgi-nohead</artifactId>
+          <version>4.0</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+          <artifactId>xtend-lib-osgi</artifactId>
+          <version>2.4.3</version>
+      </dependency>
+
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>clustering.services</artifactId>
+          <version>0.4.1-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>junit</groupId>
+          <artifactId>junit</artifactId>
+          <scope>test</scope>
+      </dependency>
+
+      <dependency>
+          <groupId>equinoxSDK381</groupId>
+          <artifactId>org.eclipse.osgi</artifactId>
+          <version>3.8.1.v20120830-144521</version>
+      </dependency>
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-junit4</artifactId>
+          <version>3.0.0</version>
+      </dependency>
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-junit4</artifactId>
+          <version>3.0.0</version>
+      </dependency>
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam</artifactId>
+          <version>3.0.0</version>
+      </dependency>
+  </dependencies>
+  <properties>
+    <!-- Sonar jacoco plugin to get integration test coverage info -->
+    <sonar.jacoco.reportPath>../implementation/target/jacoco.exec</sonar.jacoco.reportPath>
+    <sonar.jacoco.itReportPath>../implementation/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+  </properties>
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.jacoco</groupId>
+          <artifactId>jacoco-maven-plugin</artifactId>
+          <version>0.5.3.201107060350</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <version>${jacoco.version}</version>
+        <configuration>
+          <destFile>../implementation/target/jacoco-it.exec</destFile>
+          <includes>org.opendaylight.controller.*</includes>
+        </configuration>
+        <executions>
+          <execution>
+            <id>pre-test</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>post-test</id>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java b/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java
new file mode 100644 (file)
index 0000000..3b6d398
--- /dev/null
@@ -0,0 +1,290 @@
+package org.opendaylight.controller.sal.connector.remoterpc.impl;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.util.PathUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Set;
+
+
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemPackages;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
+
+
+
+@RunWith(PaxExam.class)
+public class
+        ZeroMQRoutingTableTestIT {
+    private Logger log = LoggerFactory
+            .getLogger(ZeroMQRoutingTableTestIT.class);
+
+    public static final String ODL = "org.opendaylight.controller";
+    public static final String YANG = "org.opendaylight.yangtools";
+    public static final String CONTROLLER = "org.opendaylight.controller";
+    public static final String YANGTOOLS = "org.opendaylight.yangtools";
+    // get the OSGI bundle context
+    @Inject
+    private BundleContext bc;
+    @Inject
+    private RoutingTable routingTable = null;
+
+    // Configure the OSGi container
+    @Configuration
+    public Option[] config() {
+        return options(
+                //
+                systemProperty("logback.configurationFile").value(
+                        "file:" + PathUtils.getBaseDir()
+                                + "/src/test/resources/logback.xml"),
+                // To start OSGi console for inspection remotely
+                systemProperty("osgi.console").value("2401"),
+                // Set the systemPackages (used by clustering)
+                systemPackages("sun.reflect", "sun.reflect.misc", "sun.misc"),
+                // List framework bundles
+
+                mavenBundle("equinoxSDK381",
+                        "org.eclipse.equinox.console").versionAsInProject(),
+                mavenBundle("equinoxSDK381",
+                        "org.eclipse.equinox.util").versionAsInProject(),
+                mavenBundle("equinoxSDK381",
+                        "org.eclipse.osgi.services").versionAsInProject(),
+                mavenBundle("equinoxSDK381",
+                        "org.eclipse.equinox.ds").versionAsInProject(),
+                mavenBundle("equinoxSDK381",
+                        "org.apache.felix.gogo.command").versionAsInProject(),
+                mavenBundle("equinoxSDK381",
+                        "org.apache.felix.gogo.runtime").versionAsInProject(),
+                mavenBundle("equinoxSDK381",
+                        "org.apache.felix.gogo.shell").versionAsInProject(),
+                // List logger bundles
+                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),
+                mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(),
+                mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(),
+                mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(),
+                // List all the bundles on which the test case depends
+                mavenBundle(ODL,
+                        "clustering.services").versionAsInProject(),
+
+                mavenBundle(ODL, "sal").versionAsInProject(),
+                mavenBundle(ODL,
+                        "sal.implementation").versionAsInProject(),
+                mavenBundle(ODL, "containermanager").versionAsInProject(),
+                mavenBundle(ODL,
+                        "containermanager.it.implementation").versionAsInProject(),
+                mavenBundle("org.jboss.spec.javax.transaction",
+                        "jboss-transaction-api_1.1_spec").versionAsInProject(),
+                mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(),
+                mavenBundle("org.apache.felix",
+                        "org.apache.felix.dependencymanager").versionAsInProject(),
+                mavenBundle("org.apache.felix",
+                        "org.apache.felix.dependencymanager.shell").versionAsInProject(),
+                mavenBundle("eclipselink", "javax.resource").versionAsInProject(),
+
+                mavenBundle("com.google.guava","guava").versionAsInProject(),
+                // List logger bundles
+                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),
+                mavenBundle("org.slf4j", "log4j-over-slf4j")
+                        .versionAsInProject(),
+                mavenBundle("ch.qos.logback", "logback-core")
+                        .versionAsInProject(),
+                mavenBundle("ch.qos.logback", "logback-classic")
+                        .versionAsInProject(),
+
+                mavenBundle(ODL, "clustering.services")
+                        .versionAsInProject(),
+                mavenBundle(ODL, "clustering.stub")
+                        .versionAsInProject(),
+
+
+                // List all the bundles on which the test case depends
+                mavenBundle(ODL, "sal")
+                        .versionAsInProject(),
+                mavenBundle(ODL, "sal-connector-api")
+                        .versionAsInProject(),
+                mavenBundle(ODL, "zeromq-routingtable.implementation")
+                        .versionAsInProject(),
+
+                mavenBundle("org.jboss.spec.javax.transaction",
+                        "jboss-transaction-api_1.1_spec").versionAsInProject(),
+                mavenBundle("org.apache.commons", "commons-lang3")
+                        .versionAsInProject(),
+                mavenBundle("org.apache.felix",
+                        "org.apache.felix.dependencymanager")
+                        .versionAsInProject(),
+
+                mavenBundle(ODL,
+                        "sal-core-api")
+                        .versionAsInProject(),
+                mavenBundle("org.opendaylight.yangtools","yang-data-api")
+                        .versionAsInProject(),
+                mavenBundle("org.opendaylight.yangtools","yang-model-api")
+                        .versionAsInProject(),
+                mavenBundle("org.opendaylight.yangtools","yang-binding")
+                        .versionAsInProject(),
+
+                mavenBundle(CONTROLLER, "sal-binding-api").versionAsInProject(), //
+                mavenBundle(CONTROLLER, "sal-binding-config").versionAsInProject(),
+                mavenBundle(CONTROLLER, "sal-binding-broker-impl").versionAsInProject(), //
+                mavenBundle("org.javassist", "javassist").versionAsInProject(), //
+                mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject(), //
+
+                mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), //
+                mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), //
+                mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), //
+                mavenBundle(YANGTOOLS, "yang-model-util").versionAsInProject(), //
+                mavenBundle(YANGTOOLS, "yang-parser-api").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(),
+
+
+                mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(), //
+                mavenBundle(YANGTOOLS, "binding-model-api").versionAsInProject(), //
+                mavenBundle(YANGTOOLS, "binding-generator-util").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "binding-type-provider").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "binding-generator-api").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(),
+
+
+                mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), //
+                mavenBundle(CONTROLLER, "sal-broker-impl").versionAsInProject(), //
+                mavenBundle(CONTROLLER, "sal-core-spi").versionAsInProject().update(), //
+
+                mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), //
+
+                mavenBundle(YANG, "concepts").versionAsInProject(),
+                mavenBundle(YANG, "yang-binding").versionAsInProject(), //
+                mavenBundle(YANG, "yang-common").versionAsInProject(), //
+                mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(),
+                mavenBundle("com.google.guava", "guava").versionAsInProject(), //
+                mavenBundle("org.javassist", "javassist").versionAsInProject(),
+                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), //
+                mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
+                mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
+                mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
+
+                mavenBundle(ODL, "sal-common").versionAsInProject(), //
+                mavenBundle(ODL, "sal-common-api").versionAsInProject(),//
+                mavenBundle(ODL, "sal-common-impl").versionAsInProject(), //
+                mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
+
+                mavenBundle(ODL, "config-api").versionAsInProject(), //
+                mavenBundle(ODL, "config-manager").versionAsInProject(), //
+                mavenBundle("commons-io", "commons-io").versionAsInProject(),
+                mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(),
+
+                mavenBundle(ODL, "sal-binding-api").versionAsInProject(), //
+                mavenBundle(ODL, "sal-binding-config").versionAsInProject(),
+                mavenBundle("org.javassist", "javassist").versionAsInProject(), //
+                mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
+
+                mavenBundle(YANG, "yang-data-api").versionAsInProject(), //
+                mavenBundle(YANG, "yang-data-impl").versionAsInProject(), //
+                mavenBundle(YANG, "yang-model-api").versionAsInProject(), //
+                mavenBundle(YANG, "yang-model-util").versionAsInProject(), //
+                mavenBundle(YANG, "yang-parser-api").versionAsInProject(),
+                mavenBundle(YANG, "yang-parser-impl").versionAsInProject(),
+
+
+                mavenBundle(YANG, "binding-generator-spi").versionAsInProject(), //
+                mavenBundle(YANG, "binding-model-api").versionAsInProject(), //
+                mavenBundle(YANG, "binding-generator-util").versionAsInProject(),
+                mavenBundle(YANG, "yang-parser-impl").versionAsInProject(),
+                mavenBundle(YANG, "binding-type-provider").versionAsInProject(),
+                mavenBundle(YANG, "binding-generator-api").versionAsInProject(),
+                mavenBundle(YANG, "binding-generator-spi").versionAsInProject(),
+                mavenBundle(YANG, "binding-generator-impl").versionAsInProject(),
+
+
+                mavenBundle(ODL, "sal-core-api").versionAsInProject().update(), //
+                mavenBundle(ODL, "sal-broker-impl").versionAsInProject(), //
+                mavenBundle(ODL, "sal-core-spi").versionAsInProject().update(), //
+
+                mavenBundle(YANG + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), //
+
+                mavenBundle(YANG, "concepts").versionAsInProject(),
+                mavenBundle(YANG, "yang-binding").versionAsInProject(), //
+                mavenBundle(YANG, "yang-common").versionAsInProject(), //
+                mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(),
+                mavenBundle("com.google.guava", "guava").versionAsInProject(), //
+                mavenBundle("org.javassist", "javassist").versionAsInProject(),
+
+                junitBundles());
+    }
+
+    private String stateToString(int state) {
+        switch (state) {
+            case Bundle.ACTIVE:
+                return "ACTIVE";
+            case Bundle.INSTALLED:
+                return "INSTALLED";
+            case Bundle.RESOLVED:
+                return "RESOLVED";
+            case Bundle.UNINSTALLED:
+                return "UNINSTALLED";
+            default:
+                return "Not CONVERTED";
+        }
+    }
+
+    @Test
+  public  void testAddGlobalRoute () throws Exception{
+       RoutingIdentifierImpl rii  = new RoutingIdentifierImpl();
+       routingTable.addGlobalRoute(rii,"172.27.12.1:5000");
+
+       Set<String> routes = routingTable.getRoutes(rii);
+
+       for(String route:routes){
+           Assert.assertEquals(route,"172.27.12.1:5000");
+       }
+
+
+    }
+
+
+   class RoutingIdentifierImpl implements RpcRouter.RouteIdentifier,Serializable {
+
+       private final URI namespace = URI.create("http://cisco.com/example");
+       private final QName QNAME = new QName(namespace,"global");
+       private final QName instance = new QName(URI.create("127.0.0.1"),"local");
+
+       @Override
+       public QName getContext() {
+           return QNAME;
+       }
+
+       @Override
+       public QName getType() {
+           return QNAME;
+       }
+
+       @Override
+       public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier getRoute() {
+           return InstanceIdentifier.of(instance);
+       }
+   }
+
+
+
+
+
+}
diff --git a/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/resources/logback.xml b/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/resources/logback.xml
new file mode 100644 (file)
index 0000000..6d9dfda
--- /dev/null
@@ -0,0 +1,12 @@
+<configuration scan="true">
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <encoder>
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+      </pattern>
+    </encoder>
+  </appender>
+
+  <root level="error">
+    <appender-ref ref="STDOUT" />
+  </root>
+</configuration>
index b3483a737a5d66653b0441faba5592909ddd519f..b8113a090313d270c4b1a391777d0d6e2e7d759e 100644 (file)
@@ -41,12 +41,12 @@ public class TransactionProvider implements AutoCloseable {
     @Override
     public synchronized void close() {
         for (ObjectName tx : allOpenedTransactions) {
-            if (isStillOpenTransaction(tx)) {
-                try {
+            try {
+                if (isStillOpenTransaction(tx)) {
                     configRegistryClient.getConfigTransactionClient(tx).abortConfig();
-                } catch (Exception e) {
-                    logger.debug("Ignoring {} while closing transaction {}", e.toString(), tx, e);
                 }
+            } catch (Exception e) {
+                logger.debug("Ignoring exception while closing transaction {}", tx, e);
             }
         }
         allOpenedTransactions.clear();
index a20e00bcffcc114ab9849b821898280bc743b4b2..0d68e25f67071b1505b2ab4a54e836e6cfe78e2d 100644 (file)
@@ -54,9 +54,9 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
     private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
 
     private final InetSocketAddress address;
-    private final NetconfClientDispatcher dispatcher;
     private final EventLoopGroup nettyThreadgroup;
 
+    private NetconfClientDispatcher netconfClientDispatcher;
     private NetconfClient netconfClient;
 
     private final Persister persister;
@@ -81,7 +81,6 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
         this.timeout = timeout;
 
         this.nettyThreadgroup = new NioEventLoopGroup();
-        this.dispatcher = new NetconfClientDispatcher(Optional.<SSLContext>absent(), nettyThreadgroup, nettyThreadgroup);
     }
 
     public void init() throws InterruptedException {
@@ -125,11 +124,12 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
         while (true) {
             attempt++;
 
+            netconfClientDispatcher = new NetconfClientDispatcher(Optional.<SSLContext>absent(), nettyThreadgroup, nettyThreadgroup);
             try {
-                netconfClient = new NetconfClient(this.toString(), address, delay, dispatcher);
-                // TODO is this correct ex to catch ?
+                netconfClient = new NetconfClient(this.toString(), address, delay, netconfClientDispatcher);
             } catch (IllegalStateException e) {
                 logger.debug("Netconf {} was not initialized or is not stable, attempt {}", address, attempt, e);
+                netconfClientDispatcher.close();
                 Thread.sleep(delay);
                 continue;
             }
@@ -148,11 +148,7 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
 
             logger.debug("Polling hello from netconf, attempt {}, capabilities {}", attempt, currentCapabilities);
 
-            try {
-                netconfClient.close();
-            } catch (IOException e) {
-                throw new RuntimeException("Error closing temporary client " + netconfClient);
-            }
+            closeClientAndDispatcher(netconfClient, netconfClientDispatcher);
 
             Thread.sleep(delay);
         }
@@ -162,6 +158,25 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
 
     }
 
+    private static void closeClientAndDispatcher(Closeable client, Closeable dispatcher) {
+        Exception fromClient = null;
+        try {
+            client.close();
+        } catch (Exception e) {
+            fromClient = e;
+        } finally {
+            try {
+                dispatcher.close();
+            } catch (Exception e) {
+                if (fromClient != null) {
+                    e.addSuppressed(fromClient);
+                }
+
+                throw new RuntimeException("Error closing temporary client ", e);
+            }
+        }
+    }
+
     private boolean isSubset(Set<String> currentCapabilities, Set<String> expectedCaps) {
         for (String exCap : expectedCaps) {
             if (currentCapabilities.contains(exCap) == false)
@@ -318,10 +333,18 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
             }
         }
 
+        if (netconfClientDispatcher != null) {
+            try {
+                netconfClientDispatcher.close();
+            } catch (Exception e) {
+                logger.warn("Unable to close connection to netconf {}", netconfClientDispatcher, e);
+            }
+        }
+
         try {
             nettyThreadgroup.shutdownGracefully();
         } catch (Exception e) {
-            logger.warn("Unable to close netconf client thread group {}", dispatcher, e);
+            logger.warn("Unable to close netconf client thread group {}", netconfClientDispatcher, e);
         }
 
         // unregister from JMX
index 6fc4da026f38acc3add7538f3c172e2c6ee01a0f..62c2113056afa1611300fce0c363ce293314fb49 100644 (file)
@@ -23,20 +23,27 @@ import org.opendaylight.protocol.framework.AbstractDispatcher;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
 import org.opendaylight.protocol.framework.SessionListener;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
+import java.io.Closeable;
 import java.net.InetSocketAddress;
 
-public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener> {
+public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener> implements Closeable {
+
+    private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
 
     private final Optional<SSLContext> maybeContext;
     private final NetconfClientSessionNegotiatorFactory negotatorFactory;
+    private final HashedWheelTimer timer;
 
     public NetconfClientDispatcher(final Optional<SSLContext> maybeContext, EventLoopGroup bossGroup, EventLoopGroup workerGroup) {
         super(bossGroup, workerGroup);
         this.maybeContext = Preconditions.checkNotNull(maybeContext);
-        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(new HashedWheelTimer());
+        timer = new HashedWheelTimer();
+        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer);
     }
 
     public Future<NetconfClientSession> createClient(InetSocketAddress address,
@@ -83,4 +90,12 @@ public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSes
         }
     }
 
+    @Override
+    public void close() {
+        try {
+            timer.stop();
+        } catch (Exception e) {
+            logger.debug("Ignoring exception while closing {}", timer, e);
+        }
+    }
 }
index 1a4888ba93b69081ab0d584a1730c7b74d84ed37..890bbe728804e469f0d2989253e6815ec1b85d06 100644 (file)
@@ -37,6 +37,7 @@ public class NetconfImplActivator implements BundleActivator {
     private DefaultCommitNotificationProducer commitNot;
     private NetconfServerDispatcher dispatch;
     private NioEventLoopGroup eventLoopGroup;
+    private HashedWheelTimer timer;
 
     @Override
     public void start(final BundleContext context) throws Exception {
@@ -50,8 +51,9 @@ public class NetconfImplActivator implements BundleActivator {
         factoriesTracker.open();
 
         SessionIdProvider idProvider = new SessionIdProvider();
+        timer = new HashedWheelTimer();
         NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
-                new HashedWheelTimer(), factoriesListener, idProvider);
+                timer, factoriesListener, idProvider);
 
         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
@@ -88,5 +90,6 @@ public class NetconfImplActivator implements BundleActivator {
 
         commitNot.close();
         eventLoopGroup.shutdownGracefully();
+        timer.stop();
     }
 }
index 403ba3d0fc090ea06e9ce73c4ff4acc2b7fc32c5..5f6e046929b4a5183f3e4cce1932db9f61c538bd 100644 (file)
@@ -134,6 +134,7 @@ public class NetconfITTest extends AbstractConfigTest {
     public void tearDown() throws Exception {
         commitNot.close();
         nettyThreadgroup.shutdownGracefully();
+        clientDispatcher.close();
     }
 
     private void loadMessages() throws IOException, SAXException, ParserConfigurationException {
diff --git a/third-party/ganymed/src/main/java/ch/ethz/ssh2/channel/ChannelManager.java b/third-party/ganymed/src/main/java/ch/ethz/ssh2/channel/ChannelManager.java
new file mode 100644 (file)
index 0000000..8fec9a0
--- /dev/null
@@ -0,0 +1,1845 @@
+/*
+ * Copyright (c) 2006-2013 Christian Plattner. All rights reserved.
+ * Please refer to the LICENSE.txt for licensing details.
+ */
+
+package ch.ethz.ssh2.channel;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Vector;
+
+import ch.ethz.ssh2.ChannelCondition;
+import ch.ethz.ssh2.PtySettings;
+import ch.ethz.ssh2.ServerConnectionCallback;
+import ch.ethz.ssh2.ServerSessionCallback;
+import ch.ethz.ssh2.log.Logger;
+import ch.ethz.ssh2.packets.PacketChannelFailure;
+import ch.ethz.ssh2.packets.PacketChannelOpenConfirmation;
+import ch.ethz.ssh2.packets.PacketChannelOpenFailure;
+import ch.ethz.ssh2.packets.PacketChannelSuccess;
+import ch.ethz.ssh2.packets.PacketGlobalCancelForwardRequest;
+import ch.ethz.ssh2.packets.PacketGlobalForwardRequest;
+import ch.ethz.ssh2.packets.PacketOpenDirectTCPIPChannel;
+import ch.ethz.ssh2.packets.PacketOpenSessionChannel;
+import ch.ethz.ssh2.packets.PacketSessionExecCommand;
+import ch.ethz.ssh2.packets.PacketSessionPtyRequest;
+import ch.ethz.ssh2.packets.PacketSessionStartShell;
+import ch.ethz.ssh2.packets.PacketSessionSubsystemRequest;
+import ch.ethz.ssh2.packets.PacketSessionX11Request;
+import ch.ethz.ssh2.packets.Packets;
+import ch.ethz.ssh2.packets.TypesReader;
+import ch.ethz.ssh2.server.ServerConnectionState;
+import ch.ethz.ssh2.transport.MessageHandler;
+import ch.ethz.ssh2.transport.TransportManager;
+
+/**
+ * ChannelManager. Please read the comments in Channel.java.
+ * <p/>
+ * Besides the crypto part, this is the core of the library.
+ *
+ * @author Christian Plattner
+ * @version $Id: ChannelManager.java 48 2013-08-01 12:22:33Z cleondris@gmail.com $
+ */
+public class ChannelManager implements MessageHandler
+{
+    private static final Logger log = Logger.getLogger(ChannelManager.class);
+
+    private final ServerConnectionState server_state;
+    private final TransportManager tm;
+
+    private final HashMap<String, X11ServerData> x11_magic_cookies = new HashMap<String, X11ServerData>();
+
+    private final List<Channel> channels = new Vector<Channel>();
+    private int nextLocalChannel = 100;
+    private boolean shutdown = false;
+    private int globalSuccessCounter = 0;
+    private int globalFailedCounter = 0;
+
+    private final HashMap<Integer, RemoteForwardingData> remoteForwardings = new HashMap<Integer, RemoteForwardingData>();
+
+    private final List<IChannelWorkerThread> listenerThreads = new Vector<IChannelWorkerThread>();
+
+    private boolean listenerThreadsAllowed = true;
+
+    /**
+     * Constructor for client-mode.
+     * @param tm
+     */
+    public ChannelManager(TransportManager tm)
+    {
+        this.server_state = null;
+        this.tm = tm;
+        tm.registerMessageHandler(this, 80, 100);
+    }
+
+    /**
+     * Constructor for server-mode.
+     * @param state
+     */
+    public ChannelManager(ServerConnectionState state)
+    {
+        this.server_state = state;
+        this.tm = state.tm;
+        tm.registerMessageHandler(this, 80, 100);
+    }
+
+    private Channel getChannel(int id)
+    {
+        synchronized (channels)
+        {
+            for (Channel c : channels)
+            {
+                if (c.localID == id)
+                    return c;
+            }
+        }
+        return null;
+    }
+
+    private void removeChannel(int id)
+    {
+        synchronized (channels)
+        {
+            for (Channel c : channels)
+            {
+                if (c.localID == id)
+                {
+                    channels.remove(c);
+                    break;
+                }
+            }
+        }
+    }
+
+    private int addChannel(Channel c)
+    {
+        synchronized (channels)
+        {
+            channels.add(c);
+            return nextLocalChannel++;
+        }
+    }
+
+    private void waitUntilChannelOpen(Channel c) throws IOException
+    {
+        boolean wasInterrupted = false;
+
+        synchronized (c)
+        {
+            while (c.state == Channel.STATE_OPENING)
+            {
+                try
+                {
+                    c.wait();
+                }
+                catch (InterruptedException ignore)
+                {
+                    wasInterrupted = true;
+                }
+            }
+
+            if (c.state != Channel.STATE_OPEN)
+            {
+                removeChannel(c.localID);
+
+                String detail = c.getReasonClosed();
+
+                if (detail == null)
+                    detail = "state: " + c.state;
+
+                throw new IOException("Could not open channel (" + detail + ")");
+            }
+        }
+
+        if (wasInterrupted)
+            Thread.currentThread().interrupt();
+    }
+
+    private void waitForGlobalSuccessOrFailure() throws IOException
+    {
+        boolean wasInterrupted = false;
+
+        try
+        {
+            synchronized (channels)
+            {
+                while ((globalSuccessCounter == 0) && (globalFailedCounter == 0))
+                {
+                    if (shutdown)
+                    {
+                        throw new IOException("The connection is being shutdown");
+                    }
+
+                    try
+                    {
+                        channels.wait();
+                    }
+                    catch (InterruptedException ignore)
+                    {
+                        wasInterrupted = true;
+                    }
+                }
+
+                if (globalFailedCounter != 0)
+                {
+                    throw new IOException("The server denied the request (did you enable port forwarding?)");
+                }
+
+                if (globalSuccessCounter == 0)
+                {
+                    throw new IOException("Illegal state.");
+                }
+            }
+        }
+        finally
+        {
+            if (wasInterrupted)
+                Thread.currentThread().interrupt();
+        }
+    }
+
+    private void waitForChannelSuccessOrFailure(Channel c) throws IOException
+    {
+        boolean wasInterrupted = false;
+
+        try
+        {
+            synchronized (c)
+            {
+                while ((c.successCounter == 0) && (c.failedCounter == 0))
+                {
+                    if (c.state != Channel.STATE_OPEN)
+                    {
+                        String detail = c.getReasonClosed();
+
+                        if (detail == null)
+                            detail = "state: " + c.state;
+
+                        throw new IOException("This SSH2 channel is not open (" + detail + ")");
+                    }
+
+                    try
+                    {
+                        c.wait();
+                    }
+                    catch (InterruptedException ignore)
+                    {
+                        wasInterrupted = true;
+                    }
+                }
+
+                if (c.failedCounter != 0)
+                {
+                    throw new IOException("The server denied the request.");
+                }
+            }
+        }
+        finally
+        {
+            if (wasInterrupted)
+                Thread.currentThread().interrupt();
+        }
+    }
+
+    public void registerX11Cookie(String hexFakeCookie, X11ServerData data)
+    {
+        synchronized (x11_magic_cookies)
+        {
+            x11_magic_cookies.put(hexFakeCookie, data);
+        }
+    }
+
+    public void unRegisterX11Cookie(String hexFakeCookie, boolean killChannels)
+    {
+        if (hexFakeCookie == null)
+            throw new IllegalStateException("hexFakeCookie may not be null");
+
+        synchronized (x11_magic_cookies)
+        {
+            x11_magic_cookies.remove(hexFakeCookie);
+        }
+
+        if (killChannels == false)
+            return;
+
+        log.debug("Closing all X11 channels for the given fake cookie");
+
+        List<Channel> channel_copy = new Vector<Channel>();
+
+        synchronized (channels)
+        {
+            channel_copy.addAll(channels);
+        }
+
+        for (Channel c : channel_copy)
+        {
+            synchronized (c)
+            {
+                if (hexFakeCookie.equals(c.hexX11FakeCookie) == false)
+                    continue;
+            }
+
+            try
+            {
+                closeChannel(c, "Closing X11 channel since the corresponding session is closing", true);
+            }
+            catch (IOException ignored)
+            {
+            }
+        }
+    }
+
+    public X11ServerData checkX11Cookie(String hexFakeCookie)
+    {
+        synchronized (x11_magic_cookies)
+        {
+            if (hexFakeCookie != null)
+                return x11_magic_cookies.get(hexFakeCookie);
+        }
+        return null;
+    }
+
+    public void closeAllChannels()
+    {
+        log.debug("Closing all channels");
+
+        List<Channel> channel_copy = new Vector<Channel>();
+
+        synchronized (channels)
+        {
+            channel_copy.addAll(channels);
+        }
+
+        for (Channel c : channel_copy)
+        {
+            try
+            {
+                closeChannel(c, "Closing all channels", true);
+            }
+            catch (IOException ignored)
+            {
+            }
+        }
+    }
+
+    public void closeChannel(Channel c, String reason, boolean force) throws IOException
+    {
+        byte msg[] = new byte[5];
+
+        synchronized (c)
+        {
+            if (force)
+            {
+                c.state = Channel.STATE_CLOSED;
+                c.EOF = true;
+            }
+
+            c.setReasonClosed(reason);
+
+            msg[0] = Packets.SSH_MSG_CHANNEL_CLOSE;
+            msg[1] = (byte) (c.remoteID >> 24);
+            msg[2] = (byte) (c.remoteID >> 16);
+            msg[3] = (byte) (c.remoteID >> 8);
+            msg[4] = (byte) (c.remoteID);
+
+            c.notifyAll();
+        }
+
+        synchronized (c.channelSendLock)
+        {
+            if (c.closeMessageSent == true)
+                return;
+            tm.sendMessage(msg);
+            c.closeMessageSent = true;
+        }
+
+        log.debug("Sent SSH_MSG_CHANNEL_CLOSE (channel " + c.localID + ")");
+    }
+
+    public void sendEOF(Channel c) throws IOException
+    {
+        byte[] msg = new byte[5];
+
+        synchronized (c)
+        {
+            if (c.state != Channel.STATE_OPEN)
+                return;
+
+            msg[0] = Packets.SSH_MSG_CHANNEL_EOF;
+            msg[1] = (byte) (c.remoteID >> 24);
+            msg[2] = (byte) (c.remoteID >> 16);
+            msg[3] = (byte) (c.remoteID >> 8);
+            msg[4] = (byte) (c.remoteID);
+        }
+
+        synchronized (c.channelSendLock)
+        {
+            if (c.closeMessageSent == true)
+                return;
+            tm.sendMessage(msg);
+        }
+
+
+        log.debug("Sent EOF (Channel " + c.localID + "/" + c.remoteID + ")");
+    }
+
+    public void sendOpenConfirmation(Channel c) throws IOException
+    {
+        PacketChannelOpenConfirmation pcoc = null;
+
+        synchronized (c)
+        {
+            if (c.state != Channel.STATE_OPENING)
+                return;
+
+            c.state = Channel.STATE_OPEN;
+
+            pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, c.localWindow, c.localMaxPacketSize);
+        }
+
+        synchronized (c.channelSendLock)
+        {
+            if (c.closeMessageSent == true)
+                return;
+            tm.sendMessage(pcoc.getPayload());
+        }
+    }
+
+    public void sendData(Channel c, byte[] buffer, int pos, int len) throws IOException
+    {
+        boolean wasInterrupted = false;
+
+        try
+        {
+            while (len > 0)
+            {
+                int thislen = 0;
+                byte[] msg;
+
+                synchronized (c)
+                {
+                    while (true)
+                    {
+                        if (c.state == Channel.STATE_CLOSED)
+                            throw new ChannelClosedException("SSH channel is closed. (" + c.getReasonClosed() + ")");
+
+                        if (c.state != Channel.STATE_OPEN)
+                            throw new ChannelClosedException("SSH channel in strange state. (" + c.state + ")");
+
+                        if (c.remoteWindow != 0)
+                            break;
+
+                        try
+                        {
+                            c.wait();
+                        }
+                        catch (InterruptedException ignore)
+                        {
+                            wasInterrupted = true;
+                        }
+                    }
+
+                    /* len > 0, no sign extension can happen when comparing */
+
+                    thislen = (c.remoteWindow >= len) ? len : (int) c.remoteWindow;
+
+                    int estimatedMaxDataLen = c.remoteMaxPacketSize - (tm.getPacketOverheadEstimate() + 9);
+
+                    /* The worst case scenario =) a true bottleneck */
+
+                    if (estimatedMaxDataLen <= 0)
+                    {
+                        estimatedMaxDataLen = 1;
+                    }
+
+                    if (thislen > estimatedMaxDataLen)
+                        thislen = estimatedMaxDataLen;
+
+                    c.remoteWindow -= thislen;
+
+                    msg = new byte[1 + 8 + thislen];
+
+                    msg[0] = Packets.SSH_MSG_CHANNEL_DATA;
+                    msg[1] = (byte) (c.remoteID >> 24);
+                    msg[2] = (byte) (c.remoteID >> 16);
+                    msg[3] = (byte) (c.remoteID >> 8);
+                    msg[4] = (byte) (c.remoteID);
+                    msg[5] = (byte) (thislen >> 24);
+                    msg[6] = (byte) (thislen >> 16);
+                    msg[7] = (byte) (thislen >> 8);
+                    msg[8] = (byte) (thislen);
+
+                    System.arraycopy(buffer, pos, msg, 9, thislen);
+                }
+
+                synchronized (c.channelSendLock)
+                {
+                    if (c.closeMessageSent == true)
+                        throw new ChannelClosedException("SSH channel is closed. (" + c.getReasonClosed() + ")");
+
+                    tm.sendMessage(msg);
+                }
+
+                pos += thislen;
+                len -= thislen;
+            }
+        }
+        finally
+        {
+            if (wasInterrupted)
+                Thread.currentThread().interrupt();
+        }
+    }
+
+    public int requestGlobalForward(String bindAddress, int bindPort, String targetAddress, int targetPort)
+            throws IOException
+    {
+        RemoteForwardingData rfd = new RemoteForwardingData();
+
+        rfd.bindAddress = bindAddress;
+        rfd.bindPort = bindPort;
+        rfd.targetAddress = targetAddress;
+        rfd.targetPort = targetPort;
+
+        synchronized (remoteForwardings)
+        {
+            Integer key = new Integer(bindPort);
+
+            if (remoteForwardings.get(key) != null)
+            {
+                throw new IOException("There is already a forwarding for remote port " + bindPort);
+            }
+
+            remoteForwardings.put(key, rfd);
+        }
+
+        synchronized (channels)
+        {
+            globalSuccessCounter = globalFailedCounter = 0;
+        }
+
+        PacketGlobalForwardRequest pgf = new PacketGlobalForwardRequest(true, bindAddress, bindPort);
+        tm.sendMessage(pgf.getPayload());
+
+        log.debug("Requesting a remote forwarding ('" + bindAddress + "', " + bindPort + ")");
+
+        try
+        {
+            waitForGlobalSuccessOrFailure();
+        }
+        catch (IOException e)
+        {
+            synchronized (remoteForwardings)
+            {
+                remoteForwardings.remove(rfd);
+            }
+            throw e;
+        }
+
+        return bindPort;
+    }
+
+    public void requestCancelGlobalForward(int bindPort) throws IOException
+    {
+        RemoteForwardingData rfd = null;
+
+        synchronized (remoteForwardings)
+        {
+            rfd = remoteForwardings.get(new Integer(bindPort));
+
+            if (rfd == null)
+                throw new IOException("Sorry, there is no known remote forwarding for remote port " + bindPort);
+        }
+
+        synchronized (channels)
+        {
+            globalSuccessCounter = globalFailedCounter = 0;
+        }
+
+        PacketGlobalCancelForwardRequest pgcf = new PacketGlobalCancelForwardRequest(true, rfd.bindAddress,
+                rfd.bindPort);
+        tm.sendMessage(pgcf.getPayload());
+
+        log.debug("Requesting cancelation of remote forward ('" + rfd.bindAddress + "', " + rfd.bindPort + ")");
+
+        waitForGlobalSuccessOrFailure();
+
+        /* Only now we are sure that no more forwarded connections will arrive */
+
+        synchronized (remoteForwardings)
+        {
+            remoteForwardings.remove(rfd);
+        }
+    }
+
+    public void registerThread(IChannelWorkerThread thr) throws IOException
+    {
+        synchronized (listenerThreads)
+        {
+            if (listenerThreadsAllowed == false)
+                throw new IOException("Too late, this connection is closed.");
+            listenerThreads.add(thr);
+        }
+    }
+
+    public Channel openDirectTCPIPChannel(String host_to_connect, int port_to_connect, String originator_IP_address,
+                                          int originator_port) throws IOException
+    {
+        Channel c = new Channel(this);
+
+        synchronized (c)
+        {
+            c.localID = addChannel(c);
+            // end of synchronized block forces writing out to main memory
+        }
+
+        PacketOpenDirectTCPIPChannel dtc = new PacketOpenDirectTCPIPChannel(c.localID, c.localWindow,
+                c.localMaxPacketSize, host_to_connect, port_to_connect, originator_IP_address, originator_port);
+
+        tm.sendMessage(dtc.getPayload());
+
+        waitUntilChannelOpen(c);
+
+        return c;
+    }
+
+    public Channel openSessionChannel() throws IOException
+    {
+        Channel c = new Channel(this);
+
+        synchronized (c)
+        {
+            c.localID = addChannel(c);
+            // end of synchronized block forces the writing out to main memory
+        }
+
+        log.debug("Sending SSH_MSG_CHANNEL_OPEN (Channel " + c.localID + ")");
+
+        PacketOpenSessionChannel smo = new PacketOpenSessionChannel(c.localID, c.localWindow, c.localMaxPacketSize);
+        tm.sendMessage(smo.getPayload());
+
+        waitUntilChannelOpen(c);
+
+        return c;
+    }
+
+    public void requestPTY(Channel c, String term, int term_width_characters, int term_height_characters,
+                           int term_width_pixels, int term_height_pixels, byte[] terminal_modes) throws IOException
+    {
+        PacketSessionPtyRequest spr;
+
+        synchronized (c)
+        {
+            if (c.state != Channel.STATE_OPEN)
+                throw new IOException("Cannot request PTY on this channel (" + c.getReasonClosed() + ")");
+
+            spr = new PacketSessionPtyRequest(c.remoteID, true, term, term_width_characters, term_height_characters,
+                    term_width_pixels, term_height_pixels, terminal_modes);
+
+            c.successCounter = c.failedCounter = 0;
+        }
+
+        synchronized (c.channelSendLock)
+        {
+            if (c.closeMessageSent)
+                throw new IOException("Cannot request PTY on this channel (" + c.getReasonClosed() + ")");
+            tm.sendMessage(spr.getPayload());
+        }
+
+        try
+        {
+            waitForChannelSuccessOrFailure(c);
+        }
+        catch (IOException e)
+        {
+            throw (IOException) new IOException("PTY request failed").initCause(e);
+        }
+    }
+
+    public void requestX11(Channel c, boolean singleConnection, String x11AuthenticationProtocol,
+                           String x11AuthenticationCookie, int x11ScreenNumber) throws IOException
+    {
+        PacketSessionX11Request psr;
+
+        synchronized (c)
+        {
+            if (c.state != Channel.STATE_OPEN)
+                throw new IOException("Cannot request X11 on this channel (" + c.getReasonClosed() + ")");
+
+            psr = new PacketSessionX11Request(c.remoteID, true, singleConnection, x11AuthenticationProtocol,
+                    x11AuthenticationCookie, x11ScreenNumber);
+
+            c.successCounter = c.failedCounter = 0;
+        }
+
+        synchronized (c.channelSendLock)
+        {
+            if (c.closeMessageSent)
+                throw new IOException("Cannot request X11 on this channel (" + c.getReasonClosed() + ")");
+            tm.sendMessage(psr.getPayload());
+        }
+
+        log.debug("Requesting X11 forwarding (Channel " + c.localID + "/" + c.remoteID + ")");
+
+        try
+        {
+            waitForChannelSuccessOrFailure(c);
+        }
+        catch (IOException e)
+        {
+            throw (IOException) new IOException("The X11 request failed.").initCause(e);
+        }
+    }
+
+    public void requestSubSystem(Channel c, String subSystemName) throws IOException
+    {
+        PacketSessionSubsystemRequest ssr;
+
+        synchronized (c)
+        {
+            if (c.state != Channel.STATE_OPEN)
+                throw new IOException("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")");
+
+            ssr = new PacketSessionSubsystemRequest(c.remoteID, true, subSystemName);
+
+            c.successCounter = c.failedCounter = 0;
+        }
+
+        synchronized (c.channelSendLock)
+        {
+            if (c.closeMessageSent)
+                throw new IOException("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")");
+            tm.sendMessage(ssr.getPayload());
+        }
+
+        try
+        {
+            waitForChannelSuccessOrFailure(c);
+        }
+        catch (IOException e)
+        {
+            throw (IOException) new IOException("The subsystem request failed.").initCause(e);
+        }
+    }
+
+    public void requestExecCommand(Channel c, String cmd) throws IOException
+    {
+        this.requestExecCommand(c, cmd, null);
+    }
+
+    /**
+     * @param charsetName The charset used to convert between Java Unicode Strings and byte encodings
+     */
+    public void requestExecCommand(Channel c, String cmd, String charsetName) throws IOException
+    {
+        PacketSessionExecCommand sm;
+
+        synchronized (c)
+        {
+            if (c.state != Channel.STATE_OPEN)
+                throw new IOException("Cannot execute command on this channel (" + c.getReasonClosed() + ")");
+
+            sm = new PacketSessionExecCommand(c.remoteID, true, cmd);
+
+            c.successCounter = c.failedCounter = 0;
+        }
+
+        synchronized (c.channelSendLock)
+        {
+            if (c.closeMessageSent)
+                throw new IOException("Cannot execute command on this channel (" + c.getReasonClosed() + ")");
+            tm.sendMessage(sm.getPayload(charsetName));
+        }
+
+        log.debug("Executing command (channel " + c.localID + ", '" + cmd + "')");
+
+        try
+        {
+            waitForChannelSuccessOrFailure(c);
+        }
+        catch (IOException e)
+        {
+            throw (IOException) new IOException("The execute request failed.").initCause(e);
+        }
+    }
+
+    public void requestShell(Channel c) throws IOException
+    {
+        PacketSessionStartShell sm;
+
+        synchronized (c)
+        {
+            if (c.state != Channel.STATE_OPEN)
+                throw new IOException("Cannot start shell on this channel (" + c.getReasonClosed() + ")");
+
+            sm = new PacketSessionStartShell(c.remoteID, true);
+
+            c.successCounter = c.failedCounter = 0;
+        }
+
+        synchronized (c.channelSendLock)
+        {
+            if (c.closeMessageSent)
+                throw new IOException("Cannot start shell on this channel (" + c.getReasonClosed() + ")");
+            tm.sendMessage(sm.getPayload());
+        }
+
+        try
+        {
+            waitForChannelSuccessOrFailure(c);
+        }
+        catch (IOException e)
+        {
+            throw (IOException) new IOException("The shell request failed.").initCause(e);
+        }
+    }
+
+    public void msgChannelExtendedData(byte[] msg, int msglen) throws IOException
+    {
+        if (msglen <= 13)
+            throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong size (" + msglen + ")");
+
+        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
+        int dataType = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff);
+        int len = ((msg[9] & 0xff) << 24) | ((msg[10] & 0xff) << 16) | ((msg[11] & 0xff) << 8) | (msg[12] & 0xff);
+
+        Channel c = getChannel(id);
+
+        if (c == null)
+            throw new IOException("Unexpected SSH_MSG_CHANNEL_EXTENDED_DATA message for non-existent channel " + id);
+
+        if (dataType != Packets.SSH_EXTENDED_DATA_STDERR)
+            throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has unknown type (" + dataType + ")");
+
+        if (len != (msglen - 13))
+            throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong len (calculated " + (msglen - 13)
+                    + ", got " + len + ")");
+
+        log.debug("Got SSH_MSG_CHANNEL_EXTENDED_DATA (channel " + id + ", " + len + ")");
+
+        synchronized (c)
+        {
+            if (c.state == Channel.STATE_CLOSED)
+                return; // ignore
+
+            if (c.state != Channel.STATE_OPEN)
+                throw new IOException("Got SSH_MSG_CHANNEL_EXTENDED_DATA, but channel is not in correct state ("
+                        + c.state + ")");
+
+            if (c.localWindow < len)
+                throw new IOException("Remote sent too much data, does not fit into window.");
+
+            c.localWindow -= len;
+
+            System.arraycopy(msg, 13, c.stderrBuffer, c.stderrWritepos, len);
+            c.stderrWritepos += len;
+
+            c.notifyAll();
+        }
+    }
+
+    /**
+     * Wait until for a condition.
+     *
+     * @param c Channel
+     * @param timeout in ms, 0 means no timeout.
+     * @param condition_mask minimum event mask (at least one of the conditions must be fulfilled)
+     * @return all current events
+     */
+    public int waitForCondition(Channel c, long timeout, int condition_mask)
+    {
+        boolean wasInterrupted = false;
+
+        try
+        {
+            long end_time = 0;
+            boolean end_time_set = false;
+
+            synchronized (c)
+            {
+                while (true)
+                {
+                    int current_cond = 0;
+
+                    int stdoutAvail = c.stdoutWritepos - c.stdoutReadpos;
+                    int stderrAvail = c.stderrWritepos - c.stderrReadpos;
+
+                    if (stdoutAvail > 0)
+                        current_cond = current_cond | ChannelCondition.STDOUT_DATA;
+
+                    if (stderrAvail > 0)
+                        current_cond = current_cond | ChannelCondition.STDERR_DATA;
+
+                    if (c.EOF)
+                        current_cond = current_cond | ChannelCondition.EOF;
+
+                    if (c.getExitStatus() != null)
+                        current_cond = current_cond | ChannelCondition.EXIT_STATUS;
+
+                    if (c.getExitSignal() != null)
+                        current_cond = current_cond | ChannelCondition.EXIT_SIGNAL;
+
+                    if (c.state == Channel.STATE_CLOSED)
+                        return current_cond | ChannelCondition.CLOSED | ChannelCondition.EOF;
+
+                    if ((current_cond & condition_mask) != 0)
+                        return current_cond;
+
+                    if (timeout > 0)
+                    {
+                        if (!end_time_set)
+                        {
+                            end_time = System.currentTimeMillis() + timeout;
+                            end_time_set = true;
+                        }
+                        else
+                        {
+                            timeout = end_time - System.currentTimeMillis();
+
+                            if (timeout <= 0)
+                                return current_cond | ChannelCondition.TIMEOUT;
+                        }
+                    }
+
+                    try
+                    {
+                        if (timeout > 0)
+                            c.wait(timeout);
+                        else
+                            c.wait();
+                    }
+                    catch (InterruptedException e)
+                    {
+                        wasInterrupted = true;
+                    }
+                }
+            }
+        }
+        finally
+        {
+            if (wasInterrupted)
+                Thread.currentThread().interrupt();
+        }
+    }
+
+    public int getAvailable(Channel c, boolean extended) throws IOException
+    {
+        synchronized (c)
+        {
+            int avail;
+
+            if (extended)
+                avail = c.stderrWritepos - c.stderrReadpos;
+            else
+                avail = c.stdoutWritepos - c.stdoutReadpos;
+
+            return ((avail > 0) ? avail : (c.EOF ? -1 : 0));
+        }
+    }
+
+    public int getChannelData(Channel c, boolean extended, byte[] target, int off, int len) throws IOException
+    {
+        boolean wasInterrupted = false;
+
+        try
+        {
+            int copylen = 0;
+            int increment = 0;
+            int remoteID = 0;
+            int localID = 0;
+
+            synchronized (c)
+            {
+                int stdoutAvail = 0;
+                int stderrAvail = 0;
+
+                while (true)
+                {
+                    /*
+                     * Data available? We have to return remaining data even if the
+                     * channel is already closed.
+                     */
+
+                    stdoutAvail = c.stdoutWritepos - c.stdoutReadpos;
+                    stderrAvail = c.stderrWritepos - c.stderrReadpos;
+
+                    if ((!extended) && (stdoutAvail != 0))
+                        break;
+
+                    if ((extended) && (stderrAvail != 0))
+                        break;
+
+                    /* Do not wait if more data will never arrive (EOF or CLOSED) */
+
+                    if ((c.EOF) || (c.state != Channel.STATE_OPEN))
+                        return -1;
+
+                    try
+                    {
+                        c.wait();
+                    }
+                    catch (InterruptedException ignore)
+                    {
+                        wasInterrupted = true;
+                    }
+                }
+
+                /* OK, there is some data. Return it. */
+
+                if (!extended)
+                {
+                    copylen = (stdoutAvail > len) ? len : stdoutAvail;
+                    System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, target, off, copylen);
+                    c.stdoutReadpos += copylen;
+
+                    if (c.stdoutReadpos != c.stdoutWritepos)
+
+                        System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, c.stdoutBuffer, 0, c.stdoutWritepos
+                                - c.stdoutReadpos);
+
+                    c.stdoutWritepos -= c.stdoutReadpos;
+                    c.stdoutReadpos = 0;
+                }
+                else
+                {
+                    copylen = (stderrAvail > len) ? len : stderrAvail;
+                    System.arraycopy(c.stderrBuffer, c.stderrReadpos, target, off, copylen);
+                    c.stderrReadpos += copylen;
+
+                    if (c.stderrReadpos != c.stderrWritepos)
+
+                        System.arraycopy(c.stderrBuffer, c.stderrReadpos, c.stderrBuffer, 0, c.stderrWritepos
+                                - c.stderrReadpos);
+
+                    c.stderrWritepos -= c.stderrReadpos;
+                    c.stderrReadpos = 0;
+                }
+
+                if (c.state != Channel.STATE_OPEN)
+                    return copylen;
+
+                if (c.localWindow < ((Channel.CHANNEL_BUFFER_SIZE + 1) / 2))
+                {
+                    int minFreeSpace = Math.min(Channel.CHANNEL_BUFFER_SIZE - c.stdoutWritepos,
+                            Channel.CHANNEL_BUFFER_SIZE - c.stderrWritepos);
+
+                    increment = minFreeSpace - c.localWindow;
+                    c.localWindow = minFreeSpace;
+                }
+
+                remoteID = c.remoteID; /* read while holding the lock */
+                localID = c.localID; /* read while holding the lock */
+            }
+
+            /*
+             * If a consumer reads stdout and stdin in parallel, we may end up with
+             * sending two msgWindowAdjust messages. Luckily, it
+             * does not matter in which order they arrive at the server.
+             */
+
+            if (increment > 0)
+            {
+                log.debug("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + localID + ", " + increment + ")");
+
+                synchronized (c.channelSendLock)
+                {
+                    byte[] msg = c.msgWindowAdjust;
+
+                    msg[0] = Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST;
+                    msg[1] = (byte) (remoteID >> 24);
+                    msg[2] = (byte) (remoteID >> 16);
+                    msg[3] = (byte) (remoteID >> 8);
+                    msg[4] = (byte) (remoteID);
+                    msg[5] = (byte) (increment >> 24);
+                    msg[6] = (byte) (increment >> 16);
+                    msg[7] = (byte) (increment >> 8);
+                    msg[8] = (byte) (increment);
+
+                    if (c.closeMessageSent == false)
+                        tm.sendMessage(msg);
+                }
+            }
+
+            return copylen;
+        }
+        finally
+        {
+            if (wasInterrupted)
+                Thread.currentThread().interrupt();
+        }
+
+    }
+
+    public void msgChannelData(byte[] msg, int msglen) throws IOException
+    {
+        if (msglen <= 9)
+            throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong size (" + msglen + ")");
+
+        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
+        int len = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff);
+
+        Channel c = getChannel(id);
+
+        if (c == null)
+            throw new IOException("Unexpected SSH_MSG_CHANNEL_DATA message for non-existent channel " + id);
+
+        if (len != (msglen - 9))
+            throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong len (calculated " + (msglen - 9) + ", got "
+                    + len + ")");
+
+        log.debug("Got SSH_MSG_CHANNEL_DATA (channel " + id + ", " + len + ")");
+
+        synchronized (c)
+        {
+            if (c.state == Channel.STATE_CLOSED)
+                return; // ignore
+
+            if (c.state != Channel.STATE_OPEN)
+                throw new IOException("Got SSH_MSG_CHANNEL_DATA, but channel is not in correct state (" + c.state + ")");
+
+            if (c.localWindow < len)
+                throw new IOException("Remote sent too much data, does not fit into window.");
+
+            c.localWindow -= len;
+
+            System.arraycopy(msg, 9, c.stdoutBuffer, c.stdoutWritepos, len);
+            c.stdoutWritepos += len;
+
+            c.notifyAll();
+        }
+    }
+
+    public void msgChannelWindowAdjust(byte[] msg, int msglen) throws IOException
+    {
+        if (msglen != 9)
+            throw new IOException("SSH_MSG_CHANNEL_WINDOW_ADJUST message has wrong size (" + msglen + ")");
+
+        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
+        int windowChange = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff);
+
+        Channel c = getChannel(id);
+
+        if (c == null)
+            throw new IOException("Unexpected SSH_MSG_CHANNEL_WINDOW_ADJUST message for non-existent channel " + id);
+
+        synchronized (c)
+        {
+            final long huge = 0xFFFFffffL; /* 2^32 - 1 */
+
+            c.remoteWindow += (windowChange & huge); /* avoid sign extension */
+
+            /* TODO - is this a good heuristic? */
+
+            if ((c.remoteWindow > huge))
+                c.remoteWindow = huge;
+
+            c.notifyAll();
+        }
+
+
+        log.debug("Got SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + id + ", " + windowChange + ")");
+    }
+
+    public void msgChannelOpen(byte[] msg, int msglen) throws IOException
+    {
+        TypesReader tr = new TypesReader(msg, 0, msglen);
+
+        tr.readByte(); // skip packet type
+        String channelType = tr.readString();
+        int remoteID = tr.readUINT32(); /* sender channel */
+        int remoteWindow = tr.readUINT32(); /* initial window size */
+        int remoteMaxPacketSize = tr.readUINT32(); /* maximum packet size */
+
+        if ("x11".equals(channelType))
+        {
+            synchronized (x11_magic_cookies)
+            {
+                /* If we did not request X11 forwarding, then simply ignore this bogus request. */
+
+                if (x11_magic_cookies.size() == 0)
+                {
+                    PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID,
+                            Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "X11 forwarding not activated", "");
+
+                    tm.sendAsynchronousMessage(pcof.getPayload());
+
+                    log.warning("Unexpected X11 request, denying it!");
+
+                    return;
+                }
+            }
+
+            String remoteOriginatorAddress = tr.readString();
+            int remoteOriginatorPort = tr.readUINT32();
+
+            Channel c = new Channel(this);
+
+            synchronized (c)
+            {
+                c.remoteID = remoteID;
+                c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */
+                c.remoteMaxPacketSize = remoteMaxPacketSize;
+                c.localID = addChannel(c);
+            }
+
+            /*
+             * The open confirmation message will be sent from another thread
+             */
+
+            RemoteX11AcceptThread rxat = new RemoteX11AcceptThread(c, remoteOriginatorAddress, remoteOriginatorPort);
+            rxat.setDaemon(true);
+            rxat.start();
+
+            return;
+        }
+
+        if ("forwarded-tcpip".equals(channelType))
+        {
+            String remoteConnectedAddress = tr.readString(); /* address that was connected */
+            int remoteConnectedPort = tr.readUINT32(); /* port that was connected */
+            String remoteOriginatorAddress = tr.readString(); /* originator IP address */
+            int remoteOriginatorPort = tr.readUINT32(); /* originator port */
+
+            RemoteForwardingData rfd = null;
+
+            synchronized (remoteForwardings)
+            {
+                rfd = remoteForwardings.get(new Integer(remoteConnectedPort));
+            }
+
+            if (rfd == null)
+            {
+                PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID,
+                        Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
+                        "No thanks, unknown port in forwarded-tcpip request", "");
+
+                /* Always try to be polite. */
+
+                tm.sendAsynchronousMessage(pcof.getPayload());
+
+                log.debug("Unexpected forwarded-tcpip request, denying it!");
+
+                return;
+            }
+
+            Channel c = new Channel(this);
+
+            synchronized (c)
+            {
+                c.remoteID = remoteID;
+                c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */
+                c.remoteMaxPacketSize = remoteMaxPacketSize;
+                c.localID = addChannel(c);
+            }
+
+            /*
+             * The open confirmation message will be sent from another thread.
+             */
+
+            RemoteAcceptThread rat = new RemoteAcceptThread(c, remoteConnectedAddress, remoteConnectedPort,
+                    remoteOriginatorAddress, remoteOriginatorPort, rfd.targetAddress, rfd.targetPort);
+
+            rat.setDaemon(true);
+            rat.start();
+
+            return;
+        }
+
+        if ((server_state != null) && ("session".equals(channelType)))
+        {
+            ServerConnectionCallback cb = null;
+            
+            synchronized (server_state)
+            {
+                cb = server_state.cb_conn;
+            }
+            
+            if (cb == null)
+            {
+                tm.sendAsynchronousMessage(new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
+                        "Sessions are currently not enabled", "en").getPayload());
+                
+                return;
+            }
+            
+            final Channel c = new Channel(this);
+
+            synchronized (c)
+            {
+                c.remoteID = remoteID;
+                c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */
+                c.remoteMaxPacketSize = remoteMaxPacketSize;
+                c.localID = addChannel(c);
+                c.state = Channel.STATE_OPEN;
+                c.ss = new ServerSessionImpl(c);
+            }
+
+            PacketChannelOpenConfirmation pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID,
+                    c.localWindow, c.localMaxPacketSize);
+
+            tm.sendAsynchronousMessage(pcoc.getPayload());
+
+            c.ss.sscb = cb.acceptSession(c.ss);
+
+            return;
+        }
+
+        /* Tell the server that we have no idea what it is talking about */
+
+        PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_UNKNOWN_CHANNEL_TYPE,
+                "Unknown channel type", "");
+
+        tm.sendAsynchronousMessage(pcof.getPayload());
+
+
+        log.warning("The peer tried to open an unsupported channel type (" + channelType + ")");
+    }
+
+    /* Starts the given runnable in a foreground (non-daemon) thread */
+    private void runAsync(Runnable r)
+    {
+        Thread t = new Thread(r);
+        t.start();        
+    }
+    
+    public void msgChannelRequest(byte[] msg, int msglen) throws IOException
+    {
+        TypesReader tr = new TypesReader(msg, 0, msglen);
+
+        tr.readByte(); // skip packet type
+        int id = tr.readUINT32();
+
+        Channel c = getChannel(id);
+
+        if (c == null)
+            throw new IOException("Unexpected SSH_MSG_CHANNEL_REQUEST message for non-existent channel " + id);
+
+        ServerSessionImpl server_session = null;
+
+        if (server_state != null)
+        {
+            synchronized (c)
+            {
+                server_session = c.ss;
+            }
+        }
+
+        String type = tr.readString("US-ASCII");
+        boolean wantReply = tr.readBoolean();
+
+        log.debug("Got SSH_MSG_CHANNEL_REQUEST (channel " + id + ", '" + type + "')");
+
+        if (type.equals("exit-status"))
+        {
+            if (wantReply != false)
+                throw new IOException(
+                        "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-status message, 'want reply' is true");
+
+            int exit_status = tr.readUINT32();
+
+            if (tr.remain() != 0)
+                throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
+
+            synchronized (c)
+            {
+                c.exit_status = new Integer(exit_status);
+                c.notifyAll();
+            }
+
+            log.debug("Got EXIT STATUS (channel " + id + ", status " + exit_status + ")");
+
+            return;
+        }
+
+        if ((server_state == null) && (type.equals("exit-signal")))
+        {
+            if (wantReply != false)
+                throw new IOException(
+                        "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-signal message, 'want reply' is true");
+
+            String signame = tr.readString("US-ASCII");
+            tr.readBoolean();
+            tr.readString();
+            tr.readString();
+
+            if (tr.remain() != 0)
+                throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
+
+            synchronized (c)
+            {
+                c.exit_signal = signame;
+                c.notifyAll();
+            }
+
+            log.debug("Got EXIT SIGNAL (channel " + id + ", signal " + signame + ")");
+
+            return;
+        }
+
+        if ((server_session != null) && (type.equals("pty-req")))
+        {
+            PtySettings pty = new PtySettings();
+
+            pty.term = tr.readString();
+            pty.term_width_characters = tr.readUINT32();
+            pty.term_height_characters = tr.readUINT32();
+            pty.term_width_pixels = tr.readUINT32();
+            pty.term_height_pixels = tr.readUINT32();
+            pty.terminal_modes = tr.readByteString();
+
+            if (tr.remain() != 0)
+                throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
+            
+            Runnable run_after_sending_success = null;
+            
+            ServerSessionCallback sscb = server_session.getServerSessionCallback();
+
+            if (sscb != null)
+                run_after_sending_success = sscb.requestPtyReq(server_session, pty);
+
+            if (wantReply)
+            {
+                if (run_after_sending_success != null)
+                {
+                    tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload());
+                }
+                else
+                {
+                    tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload());
+                }            
+            }
+            
+            if (run_after_sending_success != null)
+            {
+                runAsync(run_after_sending_success);
+            }
+            
+            return;
+        }
+        
+        if ((server_session != null) && (type.equals("subsystem")))
+        {
+            String command = tr.readString();
+            if (tr.remain() != 0)
+                throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
+            
+            Runnable run_after_sending_success = null;
+            ServerSessionCallback sscb = server_session.getServerSessionCallback();
+
+            if (sscb != null)
+                run_after_sending_success = sscb.requestSubsystem(server_session, command);
+
+            if (wantReply)
+            {
+                if (run_after_sending_success != null)
+                {
+                    tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload());
+                }
+                else
+                {
+                    tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload());
+                }
+            }
+            
+            if (run_after_sending_success != null)
+            {
+                runAsync(run_after_sending_success);
+            }
+            
+            return;
+        }
+
+        if ((server_session != null) && (type.equals("shell")))
+        {
+            if (tr.remain() != 0)
+                throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
+            
+            Runnable run_after_sending_success = null;
+            ServerSessionCallback sscb = server_session.getServerSessionCallback();
+
+            if (sscb != null)
+                run_after_sending_success = sscb.requestShell(server_session);
+
+            if (wantReply)
+            {
+                if (run_after_sending_success != null)
+                {
+                    tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload());
+                }
+                else
+                {
+                    tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload());
+                }
+            }
+            
+            if (run_after_sending_success != null)
+            {
+                runAsync(run_after_sending_success);
+            }
+            
+            return;
+        }
+        
+        if ((server_session != null) && (type.equals("exec")))
+        {
+            String command = tr.readString();
+            
+            if (tr.remain() != 0)
+                throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
+            
+            Runnable run_after_sending_success = null;
+            ServerSessionCallback sscb = server_session.getServerSessionCallback();
+
+            if (sscb != null)
+                run_after_sending_success = sscb.requestExec(server_session, command);
+
+            if (wantReply)
+            {
+                if (run_after_sending_success != null)
+                {
+                    tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload());
+                }
+                else
+                {
+                    tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload());
+                }
+            }
+            
+            if (run_after_sending_success != null)
+            {
+                runAsync(run_after_sending_success);
+            }
+            
+            return;
+        }
+
+        /* We simply ignore unknown channel requests, however, if the server wants a reply,
+         * then we signal that we have no idea what it is about.
+         */
+
+        if (wantReply)
+        {
+            tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload());
+        }
+
+        log.debug("Channel request '" + type + "' is not known, ignoring it");
+    }
+
+    public void msgChannelEOF(byte[] msg, int msglen) throws IOException
+    {
+        if (msglen != 5)
+            throw new IOException("SSH_MSG_CHANNEL_EOF message has wrong size (" + msglen + ")");
+
+        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
+
+        Channel c = getChannel(id);
+
+        if (c == null)
+            throw new IOException("Unexpected SSH_MSG_CHANNEL_EOF message for non-existent channel " + id);
+
+        synchronized (c)
+        {
+            c.EOF = true;
+            c.notifyAll();
+        }
+
+        log.debug("Got SSH_MSG_CHANNEL_EOF (channel " + id + ")");
+    }
+
+    public void msgChannelClose(byte[] msg, int msglen) throws IOException
+    {
+        if (msglen != 5)
+            throw new IOException("SSH_MSG_CHANNEL_CLOSE message has wrong size (" + msglen + ")");
+
+        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
+
+        Channel c = getChannel(id);
+
+        if (c == null)
+            throw new IOException("Unexpected SSH_MSG_CHANNEL_CLOSE message for non-existent channel " + id);
+
+        synchronized (c)
+        {
+            c.EOF = true;
+            c.state = Channel.STATE_CLOSED;
+            c.setReasonClosed("Close requested by remote");
+            c.closeMessageRecv = true;
+
+            removeChannel(c.localID);
+
+            c.notifyAll();
+        }
+
+        log.debug("Got SSH_MSG_CHANNEL_CLOSE (channel " + id + ")");
+    }
+
+    public void msgChannelSuccess(byte[] msg, int msglen) throws IOException
+    {
+        if (msglen != 5)
+            throw new IOException("SSH_MSG_CHANNEL_SUCCESS message has wrong size (" + msglen + ")");
+
+        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
+
+        Channel c = getChannel(id);
+
+        if (c == null)
+            throw new IOException("Unexpected SSH_MSG_CHANNEL_SUCCESS message for non-existent channel " + id);
+
+        synchronized (c)
+        {
+            c.successCounter++;
+            c.notifyAll();
+        }
+
+        log.debug("Got SSH_MSG_CHANNEL_SUCCESS (channel " + id + ")");
+    }
+
+    public void msgChannelFailure(byte[] msg, int msglen) throws IOException
+    {
+        if (msglen != 5)
+            throw new IOException("SSH_MSG_CHANNEL_FAILURE message has wrong size (" + msglen + ")");
+
+        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
+
+        Channel c = getChannel(id);
+
+        if (c == null)
+            throw new IOException("Unexpected SSH_MSG_CHANNEL_FAILURE message for non-existent channel " + id);
+
+        synchronized (c)
+        {
+            c.failedCounter++;
+            c.notifyAll();
+        }
+
+        log.debug("Got SSH_MSG_CHANNEL_FAILURE (channel " + id + ")");
+    }
+
+    public void msgChannelOpenConfirmation(byte[] msg, int msglen) throws IOException
+    {
+        PacketChannelOpenConfirmation sm = new PacketChannelOpenConfirmation(msg, 0, msglen);
+
+        Channel c = getChannel(sm.recipientChannelID);
+
+        if (c == null)
+            throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for non-existent channel "
+                    + sm.recipientChannelID);
+
+        synchronized (c)
+        {
+            if (c.state != Channel.STATE_OPENING)
+                throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for channel "
+                        + sm.recipientChannelID);
+
+            c.remoteID = sm.senderChannelID;
+            c.remoteWindow = sm.initialWindowSize & 0xFFFFffffL; /* convert UINT32 to long */
+            c.remoteMaxPacketSize = sm.maxPacketSize;
+            c.state = Channel.STATE_OPEN;
+            c.notifyAll();
+        }
+
+        log.debug("Got SSH_MSG_CHANNEL_OPEN_CONFIRMATION (channel " + sm.recipientChannelID + " / remote: "
+                + sm.senderChannelID + ")");
+    }
+
+    public void msgChannelOpenFailure(byte[] msg, int msglen) throws IOException
+    {
+        if (msglen < 5)
+            throw new IOException("SSH_MSG_CHANNEL_OPEN_FAILURE message has wrong size (" + msglen + ")");
+
+        TypesReader tr = new TypesReader(msg, 0, msglen);
+
+        tr.readByte(); // skip packet type
+        int id = tr.readUINT32(); /* sender channel */
+
+        Channel c = getChannel(id);
+
+        if (c == null)
+            throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE message for non-existent channel " + id);
+
+        int reasonCode = tr.readUINT32();
+        String description = tr.readString("UTF-8");
+
+        String reasonCodeSymbolicName = null;
+
+        switch (reasonCode)
+        {
+            case 1:
+                reasonCodeSymbolicName = "SSH_OPEN_ADMINISTRATIVELY_PROHIBITED";
+                break;
+            case 2:
+                reasonCodeSymbolicName = "SSH_OPEN_CONNECT_FAILED";
+                break;
+            case 3:
+                reasonCodeSymbolicName = "SSH_OPEN_UNKNOWN_CHANNEL_TYPE";
+                break;
+            case 4:
+                reasonCodeSymbolicName = "SSH_OPEN_RESOURCE_SHORTAGE";
+                break;
+            default:
+                reasonCodeSymbolicName = "UNKNOWN REASON CODE (" + reasonCode + ")";
+        }
+
+        StringBuilder descriptionBuffer = new StringBuilder();
+        descriptionBuffer.append(description);
+
+        for (int i = 0; i < descriptionBuffer.length(); i++)
+        {
+            char cc = descriptionBuffer.charAt(i);
+
+            if ((cc >= 32) && (cc <= 126))
+                continue;
+            descriptionBuffer.setCharAt(i, '\uFFFD');
+        }
+
+        synchronized (c)
+        {
+            c.EOF = true;
+            c.state = Channel.STATE_CLOSED;
+            c.setReasonClosed("The server refused to open the channel (" + reasonCodeSymbolicName + ", '"
+                    + descriptionBuffer.toString() + "')");
+            c.notifyAll();
+        }
+
+        log.debug("Got SSH_MSG_CHANNEL_OPEN_FAILURE (channel " + id + ")");
+    }
+
+    public void msgGlobalRequest(byte[] msg, int msglen) throws IOException
+    {
+        /* Currently we do not support any kind of global request */
+
+        TypesReader tr = new TypesReader(msg, 0, msglen);
+
+        tr.readByte(); // skip packet type
+        String requestName = tr.readString();
+        boolean wantReply = tr.readBoolean();
+
+        if (wantReply)
+        {
+            byte[] reply_failure = new byte[1];
+            reply_failure[0] = Packets.SSH_MSG_REQUEST_FAILURE;
+
+            tm.sendAsynchronousMessage(reply_failure);
+        }
+
+        /* We do not clean up the requestName String - that is OK for debug */
+
+        log.debug("Got SSH_MSG_GLOBAL_REQUEST (" + requestName + ")");
+    }
+
+    public void msgGlobalSuccess() throws IOException
+    {
+        synchronized (channels)
+        {
+            globalSuccessCounter++;
+            channels.notifyAll();
+        }
+
+        log.debug("Got SSH_MSG_REQUEST_SUCCESS");
+    }
+
+    public void msgGlobalFailure() throws IOException
+    {
+        synchronized (channels)
+        {
+            globalFailedCounter++;
+            channels.notifyAll();
+        }
+
+        log.debug("Got SSH_MSG_REQUEST_FAILURE");
+    }
+
+    public void handleMessage(byte[] msg, int msglen) throws IOException
+    {
+        if (msg == null)
+        {
+
+            log.debug("HandleMessage: got shutdown");
+
+            synchronized (listenerThreads)
+            {
+                for (IChannelWorkerThread lat : listenerThreads)
+                {
+                    lat.stopWorking();
+                }
+                listenerThreadsAllowed = false;
+            }
+
+            synchronized (channels)
+            {
+                shutdown = true;
+
+                for (Channel c : channels)
+                {
+                    synchronized (c)
+                    {
+                        c.EOF = true;
+                        c.state = Channel.STATE_CLOSED;
+                        c.setReasonClosed("The connection is being shutdown");
+                        c.closeMessageRecv = true; /*
+                                                    * You never know, perhaps
+                                                    * we are waiting for a
+                                                    * pending close message
+                                                    * from the server...
+                                                    */
+                        c.notifyAll();
+                    }
+                }
+
+                channels.clear();
+                channels.notifyAll(); /* Notify global response waiters */
+                return;
+            }
+        }
+
+        switch (msg[0])
+        {
+            case Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
+                msgChannelOpenConfirmation(msg, msglen);
+                break;
+            case Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST:
+                msgChannelWindowAdjust(msg, msglen);
+                break;
+            case Packets.SSH_MSG_CHANNEL_DATA:
+                msgChannelData(msg, msglen);
+                break;
+            case Packets.SSH_MSG_CHANNEL_EXTENDED_DATA:
+                msgChannelExtendedData(msg, msglen);
+                break;
+            case Packets.SSH_MSG_CHANNEL_REQUEST:
+                msgChannelRequest(msg, msglen);
+                break;
+            case Packets.SSH_MSG_CHANNEL_EOF:
+                msgChannelEOF(msg, msglen);
+                break;
+            case Packets.SSH_MSG_CHANNEL_OPEN:
+                msgChannelOpen(msg, msglen);
+                break;
+            case Packets.SSH_MSG_CHANNEL_CLOSE:
+                msgChannelClose(msg, msglen);
+                break;
+            case Packets.SSH_MSG_CHANNEL_SUCCESS:
+                msgChannelSuccess(msg, msglen);
+                break;
+            case Packets.SSH_MSG_CHANNEL_FAILURE:
+                msgChannelFailure(msg, msglen);
+                break;
+            case Packets.SSH_MSG_CHANNEL_OPEN_FAILURE:
+                msgChannelOpenFailure(msg, msglen);
+                break;
+            case Packets.SSH_MSG_GLOBAL_REQUEST:
+                msgGlobalRequest(msg, msglen);
+                break;
+            case Packets.SSH_MSG_REQUEST_SUCCESS:
+                msgGlobalSuccess();
+                break;
+            case Packets.SSH_MSG_REQUEST_FAILURE:
+                msgGlobalFailure();
+                break;
+            default:
+                throw new IOException("Cannot handle unknown channel message " + (msg[0] & 0xff));
+        }
+    }
+}