Merge "Unit test for ovsdb.southbound.ovsdb.transact"
authorSam Hague <shague@redhat.com>
Wed, 21 Oct 2015 12:03:37 +0000 (12:03 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 21 Oct 2015 12:03:37 +0000 (12:03 +0000)
255 files changed:
commons/parent/pom.xml
features/ovsdb/pom.xml
features/ovsdb/src/main/features/features.xml
hwvtepsouthbound/hwvtepsouthbound-features/src/main/features/features.xml
hwvtepsouthbound/hwvtepsouthbound-impl/pom.xml
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/config/default-config.xml
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionInstance.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepMonitorCallback.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSchemaConstants.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundConstants.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundMapper.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundProvider.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/InstanceIdentifierCodec.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/impl/HwvtepSouthboundProvider.java [deleted file]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactInvoker.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactInvokerImpl.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepOperationalCommandAggregator.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/TransactionCommand.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/TransactionInvoker.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/TransactionInvokerImpl.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/hwvtepsouthbound/impl/rev150901/HwvtepSouthboundModule.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/yang/hwvtepsouthbound-impl.yang
hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/hwvtepsouthbound/impl/rev150901/HwvtepSouthboundModuleTest.java
library/impl/src/test/java/org/opendaylight/ovsdb/lib/jsonrpc/JsonRpcDecoderTest.java
library/impl/src/test/java/org/opendaylight/ovsdb/lib/notation/VersionTest.java
library/it/src/test/java/org/opendaylight/ovsdb/integrationtest/ovsdbclient/TestBridge.java
library/it/src/test/java/org/opendaylight/ovsdb/integrationtest/ovsdbclient/VersionIncompatibleBridge.java
library/it/src/test/java/org/opendaylight/ovsdb/integrationtest/schema/hardwarevtep/HardwareVTEPIT.java
library/it/src/test/java/org/opendaylight/ovsdb/integrationtest/schema/openvswitch/OpenVSwitchIT.java
openstack/net-virt-providers/pom.xml
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/OF13Provider.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/EgressAclService.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/InboundNatService.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/IngressAclService.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/OutboundNatService.java
openstack/net-virt-providers/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/OF13ProviderTest.java
openstack/net-virt-providers/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/EgressAclServiceTest.java
openstack/net-virt-providers/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/IngressAclServiceTest.java
openstack/net-virt-sfc/api/pom.xml
openstack/net-virt-sfc/api/src/main/yang/ietf-acl.yang [deleted file]
openstack/net-virt-sfc/api/src/main/yang/netvirt-acl.yang
openstack/net-virt-sfc/api/src/main/yang/packet-fields.yang [deleted file]
openstack/net-virt-sfc/features/production/pom.xml
openstack/net-virt-sfc/features/production/src/main/features/features.xml
openstack/net-virt-sfc/features/test/src/main/features/features.xml
openstack/net-virt-sfc/impl/pom.xml
openstack/net-virt-sfc/impl/src/main/config/default-config.xml
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcAclListener.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcClassifierListener.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcProvider.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/openflow13/INetvirtSfcOF13Provider.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/openflow13/NetvirtSfcOF13Provider.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/rev141210/NetvirtSfcModule.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/rev141210/NetvirtSfcModuleFactory.java
openstack/net-virt-sfc/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/netvirt/sfc/rev141210/NetvirtSfcModuleTest.java
openstack/net-virt-sfc/it/pom.xml
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcIT.java
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/utils/AclUtils.java
openstack/net-virt-sfc/karaf/pom.xml
openstack/net-virt/pom.xml
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/ConfigActivator.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/FWaasHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/FloatingIPHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/LBaaSHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/LBaaSPoolHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/LBaaSPoolMemberHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/NetworkHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/NeutronCacheUtils.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/NorthboundEvent.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/PortHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/PortSecurityHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/RouterHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/SouthboundHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/SubnetHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/BridgeConfigurationManager.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/ConfigurationService.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/EgressAclProvider.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/GatewayMacResolver.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/IngressAclProvider.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/NetworkingProvider.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/SecurityServicesManager.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/TenantNetworkManager.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/BridgeConfigurationManagerImpl.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/MdsalUtils.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/NeutronL3Adapter.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/OvsdbInventoryServiceImpl.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/SecurityServicesImpl.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/SouthboundImpl.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/TenantNetworkManagerImpl.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/INeutronObject.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronFirewall.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronFirewallPolicy.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronFirewallRule.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronFloatingIP.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancer.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancerHealthMonitor.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancerListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancerPool.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancerPoolMember.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancer_SessionPersistence.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronNetwork.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronNetwork_Segment.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronPort.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronPort_AllowedAddressPairs.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronPort_ExtraDHCPOption.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronPort_VIFDetail.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronRouter.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronRouter_Interface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronRouter_NetworkReference.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSecurityGroup.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSecurityRule.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSubnet.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSubnetIPAllocationPool.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSubnet_HostRoute.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/Neutron_ID.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/Neutron_IPs.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronFirewallCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronFirewallPolicyCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronFirewallRuleCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronFloatingIPCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerHealthMonitorCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerListenerCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerPoolCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerPoolMemberCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronNetworkCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronPortCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronRouterCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronSecurityGroupCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronSecurityRuleCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronSubnetCRUD.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/NeutronCRUDInterfaces.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/AbstractNeutronInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFirewallInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFirewallPolicyInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFirewallRuleInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFloatingIPInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerHealthMonitorInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerListenerInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerPoolInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerPoolMemberInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronNetworkInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronPortInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronRouterInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronSecurityGroupInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronSecurityRuleInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronSubnetInterface.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronFirewallAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronFirewallPolicyAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronFirewallRuleAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronFloatingIPAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerHealthMonitorAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerListenerAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerPoolAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerPoolMemberAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronNetworkAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronPortAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronRouterAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronSecurityGroupAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronSecurityRuleAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronSubnetAware.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronFloatingIPChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronIAwareUtil.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronLoadBalancerPoolChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronLoadBalancerPoolMemberChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronNetworkChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronPortChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronRouterChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronSecurityGroupDataChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronSecurityRuleDataChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronSubnetChangeListener.java [new file with mode: 0644]
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/FWaasHandlerTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/FloatingIPHandlerTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/LBaaSHandlerTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/LBaaSPoolHandlerTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/LBaaSPoolMemberHandlerTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/NetworkHandlerTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/NeutronCacheUtilsTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/PortHandlerTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/PortSecurityHandlerTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/RouterHandlerTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/SouthboundHandlerTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/SubnetHandlerTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/impl/BridgeConfigurationManagerImplTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/impl/NeutronL3AdapterTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/impl/SecurityServicesImplTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/impl/TenantNetworkManagerImplTest.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/impl/VlanConfigurationCacheImplTest.java
ovs-sfc/src/main/java/org/opendaylight/controller/config/yang/config/ovssfc_provider/impl/OvsSfcProviderModule.java
ovsdb-ui/bundle/pom.xml
ovsdb-ui/bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml
ovsdb-ui/module/src/main/resources/ovsdb/Graph.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/LogicalGraph.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/OvsCore.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/assets/dhcp.png [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/assets/router.png [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/assets/vm.png [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/css/ovsdb.css [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/css/select2.min.css [new file with mode: 0755]
ovsdb-ui/module/src/main/resources/ovsdb/css/toggle-switch.css [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/index.tpl.html [deleted file]
ovsdb-ui/module/src/main/resources/ovsdb/lib/d3.min.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/lib/select2.full.min.js [new file with mode: 0755]
ovsdb-ui/module/src/main/resources/ovsdb/lib/sylvester.js [new file with mode: 0755]
ovsdb-ui/module/src/main/resources/ovsdb/matrix.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/mocks/ovsdb.controller.js [deleted file]
ovsdb-ui/module/src/main/resources/ovsdb/mocks/ovsdb.module.js [deleted file]
ovsdb-ui/module/src/main/resources/ovsdb/mocks/ovsdb.services.js [deleted file]
ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.constant.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.controller.js
ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.css [deleted file]
ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.directives.js [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.module.js
ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.services.js
ovsdb-ui/module/src/main/resources/ovsdb/spec/ovsdb.spec.js [deleted file]
ovsdb-ui/module/src/main/resources/ovsdb/views/graph_header.tpl.html [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/views/index.tpl.html [new file with mode: 0644]
ovsdb-ui/module/src/main/resources/ovsdb/views/root.tpl.html [moved from ovsdb-ui/module/src/main/resources/ovsdb/root.tpl.html with 97% similarity]
resources/commons/NetvirtSfc.json.postman_collection [new file with mode: 0644]
resources/commons/README
schemas/hardwarevtep/src/test/java/org/opendaylight/ovsdb/schema/hardwarevtep/HardwareVTEPTest.java
schemas/openvswitch/src/test/java/org/opendaylight/ovsdb/schema/openvswitch/OpenVSwitchTest.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/SouthboundProvider.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/InstanceIdentifierCodecTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/OvsdbConnectionInstanceTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/OvsdbConnectionManagerTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/OvsdbDataChangeListenerTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/OvsdbMonitorCallbackTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/OvsdbSchemaContantsTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/SouthboundMapperTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/SouthboundProviderTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/SouthboundUtilTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/AbstractTransactionCommandTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OpenVSwitchUpdateCommandTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbBridgeRemovedCommandTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbBridgeUpdateCommandTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbControllerRemovedCommandTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbControllerUpdateCommandTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbManagersRemovedCommandTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbManagersUpdateCommandTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbNodeRemoveCommandTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbOperationalCommandAggregatorTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbPortRemoveCommandTest.java [new file with mode: 0644]
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbPortUpdateCommandTest.java [new file with mode: 0644]
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/TransactionInvokerImplTest.java [new file with mode: 0644]
southbound/southbound-it/src/test/java/org/opendaylight/ovsdb/southbound/it/SouthboundIT.java
utils/config/src/test/java/org/opendaylight/ovsdb/utils/config/ConfigPropertiesTest.java
utils/mdsal-node/src/test/java/org/opendaylight/ovsdb/utils/mdsal/node/NodeUtilsTest.java
utils/mdsal-openflow/src/test/java/org/opendaylight/ovsdb/utils/mdsal/openflow/MatchUtilsTest.java
utils/servicehelper/src/test/java/org/opendaylight/ovsdb/utils/servicehelper/ServiceHelperTest.java

index f00ce8b4c727b56529e2be4ad8f56061090557d2..641001fb555920ebbc27971422eb667bffe82349 100644 (file)
@@ -101,9 +101,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <httpcomponents.version>4.2.1</httpcomponents.version>
     <portlet.version>2.0</portlet.version>
     <powermock.version>1.5.2</powermock.version>
+    <dlux.version>0.3.0-SNAPSHOT</dlux.version>
     <ovsdb.ui.version>0.1.0-SNAPSHOT</ovsdb.ui.version>
-    <dlux.loader.version>0.3.0-SNAPSHOT</dlux.loader.version>
-    <dlux.core.version>0.3.0-SNAPSHOT</dlux.core.version>
   </properties>
 
   <dependencyManagement>
index 1e8e2fd6651a535e7f1eb0d36183cc31ccd263f2..94cf2abe84776cdcc62da6497ad6fa5bcd7dbe87 100644 (file)
@@ -61,9 +61,9 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <openflowplugin.version>0.2.0-SNAPSHOT</openflowplugin.version>
     <sal.version>0.10.0-SNAPSHOT</sal.version>
     <yangtools.version>0.8.0-SNAPSHOT</yangtools.version>
-    <dlux.core.version>0.3.0-SNAPSHOT</dlux.core.version>
-    <ovsdb.ui.version>0.1.0-SNAPSHOT</ovsdb.ui.version>
     <config.version>0.4.0-SNAPSHOT</config.version>
+    <dlux.version>0.3.0-SNAPSHOT</dlux.version>
+    <ovsdb.ui.version>0.1.0-SNAPSHOT</ovsdb.ui.version>
   </properties>
 
   <dependencyManagement>
@@ -226,6 +226,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <version>${networkconfig.neutron.version}</version>
       <classifier>features</classifier>
       <type>xml</type>
+    </dependency>
+     <dependency>
+      <groupId>org.opendaylight.neutron</groupId>
+      <artifactId>dummyprovider</artifactId>
+      <version>${networkconfig.neutron.version}</version>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.openflowplugin</groupId>
@@ -309,5 +314,18 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <type>xml</type>
       <classifier>features</classifier>
     </dependency>
+    <!-- DLUX dependency for the UI -->
+    <dependency>
+      <groupId>org.opendaylight.dlux</groupId>
+      <artifactId>features-dlux</artifactId>
+      <version>${dlux.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+        <groupId>org.opendaylight.ovsdb</groupId>
+        <artifactId>ovsdb-ui-bundle</artifactId>
+        <version>${ovsdb.ui.version}</version>
+    </dependency>
   </dependencies>
 </project>
index 15bd93066b529a0b94ce8449065f074929200624..1abdab4e67534b0040e3952a154e7fc7f6c2d862 100644 (file)
@@ -8,6 +8,7 @@
   <repository>mvn:org.opendaylight.ovsdb/southbound-features/1.2.1-SNAPSHOT/xml/features</repository>
   <repository>mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.ovsdb/library-features/${ovsdb.library.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features</repository>
 
   <feature name="odl-ovsdb-all" description="OpenDaylight :: OVSDB :: all"
            version='${project.version}'>
     <bundle>mvn:org.opendaylight.ovsdb/utils.servicehelper/${ovsdb.utils.servicehelper.version}</bundle>
     <bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt/${openstack.netvirt.version}</bundle>
     <bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt-providers/${openstack.netvirt.providers.version}</bundle>
+    <bundle>mvn:org.opendaylight.neutron/dummyprovider/${networkconfig.neutron.version}</bundle>
     <configfile finalname="etc/opendaylight/karaf/netvirt-impl-default-config.xml">mvn:org.opendaylight.ovsdb/openstack.net-virt/${project.version}/xml/config</configfile>
     <configfile finalname="etc/opendaylight/karaf/netvirt-providers-impl-default-config.xml">mvn:org.opendaylight.ovsdb/openstack.net-virt-providers/${project.version}/xml/config</configfile>
   </feature>
   <feature name="odl-ovsdb-ui" description="OpenDaylight :: OVSDB :: DLUX Integration Plugin" version='${ovsdb.ui.version}'>
-    <feature version="${dlux.core.version}">odl-dlux-core</feature>
+    <feature version="${dlux.version}">odl-dlux-core</feature>
     <bundle>mvn:org.opendaylight.ovsdb/ovsdb-ui-bundle/${ovsdb.ui.version}</bundle>
   </feature>
 </features>
index 967a07c36ae80b821bfa68097e494519d100e769..366198c3ecec42cb10f70dff2920b76a7b4f68ab 100644 (file)
@@ -23,6 +23,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
     <feature version='${project.version}'>odl-ovsdb-hwvtepsouthbound-api</feature>
     <bundle>mvn:org.opendaylight.ovsdb/hwvtepsouthbound-impl/${project.version}</bundle>
+    <bundle>mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson.version}</bundle>
+    <bundle>mvn:com.fasterxml.jackson.core/jackson-core/${jackson.version}</bundle>
+    <bundle>mvn:com.fasterxml.jackson.core/jackson-databind/${jackson.version}</bundle>
+    <bundle>mvn:com.fasterxml.jackson.datatype/jackson-datatype-json-org/${jackson.version}</bundle>
+    <bundle>wrap:mvn:org.json/json/${org.json.version}</bundle>
     <configfile finalname="${configfile.directory}/hwvtepsouthbound.xml">mvn:org.opendaylight.ovsdb/hwvtepsouthbound-impl/${project.version}/xml/config</configfile>
   </feature>
   <feature name='odl-ovsdb-hwvtepsouthbound-rest' version='${project.version}' description='OpenDaylight :: hwvtepsouthbound :: REST'>
index 7d3d0fe29d5e020ec88982b337f195035293f517..4f30490d1875606c9a07ea9b0659f3924d1e41cc 100644 (file)
@@ -26,6 +26,16 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>hwvtepsouthbound-api</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>library</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>schema.hardwarevtep</artifactId>
+      <version>${project.version}</version>
+    </dependency>
 
     <!-- Testing Dependencies -->
     <dependency>
@@ -43,6 +53,16 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
 
   <build>
     <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Private-Package>org.opendaylight.ovsdb.lib.*,org.opendaylight.ovsdb.schema.hardwarevtep</Private-Package>
+            <Export-Package>org.opendaylight.ovsdb.hwvtepsouthbound.*,org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hwvtepsouthbound.impl.rev150901</Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
index 491fe69344e4150e63a09a7bb076874b59ab8fa6..addeb2b16588846816dbad56cbb63c0af309ce5f 100644 (file)
@@ -23,6 +23,18 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
             <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
             <name>binding-osgi-broker</name>
           </broker>
+          <schema-service>
+            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+            <name>yang-schema-service</name>
+          </schema-service>
+          <binding-normalized-node-serializer>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-normalized-node-serializer</type>
+            <name>runtime-mapping-singleton</name>
+          </binding-normalized-node-serializer>
+          <clustering-entity-ownership-service>
+             <type xmlns:ns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">ns:entity-ownership-service</type>
+             <name>entity-ownership-service</name>
+          </clustering-entity-ownership-service>
         </module>
       </modules>
     </data>
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionInstance.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionInstance.java
new file mode 100644 (file)
index 0000000..b405576
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactCommand;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactInvoker;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactInvokerImpl;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
+import org.opendaylight.ovsdb.lib.EchoServiceCallbackFilters;
+import org.opendaylight.ovsdb.lib.LockAquisitionCallback;
+import org.opendaylight.ovsdb.lib.LockStolenCallback;
+import org.opendaylight.ovsdb.lib.MonitorCallBack;
+import org.opendaylight.ovsdb.lib.MonitorHandle;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.lib.OvsdbConnectionInfo;
+import org.opendaylight.ovsdb.lib.message.MonitorRequest;
+import org.opendaylight.ovsdb.lib.message.MonitorRequestBuilder;
+import org.opendaylight.ovsdb.lib.message.MonitorSelect;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.lib.operations.Operation;
+import org.opendaylight.ovsdb.lib.operations.OperationResult;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.TableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class HwvtepConnectionInstance implements OvsdbClient{
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepConnectionInstance.class);
+    private ConnectionInfo connectionInfo;
+    private OvsdbClient client;
+    private InstanceIdentifier<Node> instanceIdentifier;
+    private TransactionInvoker txInvoker;
+    private Map<DatabaseSchema,TransactInvoker> transactInvokers;
+    private MonitorCallBack callback;
+    private volatile boolean hasDeviceOwnership = false;
+    private Entity connectedEntity;
+    private EntityOwnershipCandidateRegistration deviceOwnershipCandidateRegistration;
+
+
+    HwvtepConnectionInstance (ConnectionInfo key,OvsdbClient client,
+                    InstanceIdentifier<Node> iid, TransactionInvoker txInvoker) {
+        this.connectionInfo = key;
+        this.client = client;
+        this.instanceIdentifier = iid;
+        this.txInvoker = txInvoker;
+    }
+
+    public void transact(TransactCommand command) {
+        for (TransactInvoker transactInvoker: transactInvokers.values()) {
+            transactInvoker.invoke(command);
+        }
+    }
+
+    public void registerCallbacks() {
+        if ( this.callback == null) {
+            try {
+                List<String> databases = getDatabases().get();
+                this.callback = new HwvtepMonitorCallback(this,txInvoker);
+                for (String database : databases) {
+                    DatabaseSchema dbSchema = getSchema(database).get();
+                    if (dbSchema != null) {
+                        monitorAllTables(database, dbSchema);
+                    } else {
+                        LOG.warn("No schema reported for database {} for key {}",database,connectionInfo);
+                    }
+                }
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.warn("Exception attempting to registerCallbacks {}: {}",connectionInfo,e);
+            }
+        }
+    }
+
+    public void createTransactInvokers() {
+        if (transactInvokers == null) {
+            try {
+                transactInvokers = new HashMap<DatabaseSchema,TransactInvoker>();
+                List<String> databases = getDatabases().get();
+                for (String database : databases) {
+                    DatabaseSchema dbSchema = getSchema(database).get();
+                    if (dbSchema != null) {
+                        transactInvokers.put(dbSchema, new TransactInvokerImpl(this,dbSchema));
+                    }
+                }
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.warn("Exception attempting to createTransactionInvokers {}: {}",connectionInfo,e);
+            }
+        }
+    }
+
+    private void monitorAllTables(String database, DatabaseSchema dbSchema) {
+        Set<String> tables = dbSchema.getTables();
+        if (tables != null) {
+            List<MonitorRequest<GenericTableSchema>> monitorRequests = Lists.newArrayList();
+            for (String tableName : tables) {
+                GenericTableSchema tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
+                Set<String> columns = tableSchema.getColumns();
+                MonitorRequestBuilder<GenericTableSchema> monitorBuilder = MonitorRequestBuilder.builder(tableSchema);
+                for (String column : columns) {
+                    monitorBuilder.addColumn(column);
+                }
+                monitorRequests.add(monitorBuilder.with(new MonitorSelect(true, true, true, true)).build());
+            }
+            this.callback.update(monitor(dbSchema, monitorRequests, callback),dbSchema);
+        } else {
+            LOG.warn("No tables for schema {} for database {} for key {}",dbSchema,database,connectionInfo);
+        }
+    }
+
+    public ListenableFuture<List<String>> getDatabases() {
+        return client.getDatabases();
+    }
+
+    public ListenableFuture<DatabaseSchema> getSchema(String database) {
+        return client.getSchema(database);
+    }
+
+    public TransactionBuilder transactBuilder(DatabaseSchema dbSchema) {
+        return client.transactBuilder(dbSchema);
+    }
+
+    public ListenableFuture<List<OperationResult>> transact(DatabaseSchema dbSchema, List<Operation> operations) {
+        return client.transact(dbSchema, operations);
+    }
+
+    public <E extends TableSchema<E>> TableUpdates monitor(DatabaseSchema schema,
+                    List<MonitorRequest<E>> monitorRequests, MonitorCallBack callback) {
+        return client.monitor(schema, monitorRequests, callback);
+    }
+
+    @Override
+    public <E extends TableSchema<E>> TableUpdates monitor(DatabaseSchema schema,
+                    List<MonitorRequest<E>> monitorRequests, MonitorHandle monitorHandle, MonitorCallBack callback) {
+        return null;
+    }
+
+    public void cancelMonitor(MonitorHandle handler) {
+        client.cancelMonitor(handler);
+    }
+
+    public void lock(String lockId, LockAquisitionCallback lockedCallBack, LockStolenCallback stolenCallback) {
+        client.lock(lockId, lockedCallBack, stolenCallback);
+    }
+
+    public ListenableFuture<Boolean> steal(String lockId) {
+        return client.steal(lockId);
+    }
+
+    public ListenableFuture<Boolean> unLock(String lockId) {
+        return client.unLock(lockId);
+    }
+
+    public void startEchoService(EchoServiceCallbackFilters callbackFilters) {
+        client.startEchoService(callbackFilters);
+    }
+
+    public void stopEchoService() {
+        client.stopEchoService();
+    }
+
+    public OvsdbConnectionInfo getConnectionInfo() {
+        return client.getConnectionInfo();
+    }
+
+    public boolean isActive() {
+        return client.isActive();
+    }
+
+    public void disconnect() {
+        client.disconnect();
+    }
+
+    public DatabaseSchema getDatabaseSchema(String dbName) {
+        return client.getDatabaseSchema(dbName);
+    }
+
+    public <T extends TypedBaseTable<?>> T createTypedRowWrapper(Class<T> klazz) {
+        return client.createTypedRowWrapper(klazz);
+    }
+
+    public <T extends TypedBaseTable<?>> T createTypedRowWrapper(DatabaseSchema dbSchema, Class<T> klazz) {
+        return client.createTypedRowWrapper(dbSchema, klazz);
+    }
+
+    public <T extends TypedBaseTable<?>> T getTypedRowWrapper(Class<T> klazz, Row<GenericTableSchema> row) {
+        return client.getTypedRowWrapper(klazz, row);
+    }
+
+    public ConnectionInfo getMDConnectionInfo() {
+        return connectionInfo;
+    }
+
+    public void setMDConnectionInfo(ConnectionInfo key) {
+        this.connectionInfo = key;
+    }
+
+    public InstanceIdentifier<Node> getInstanceIdentifier() {
+        return instanceIdentifier;
+    }
+
+    public NodeKey getNodeKey() {
+        //TODO: What is the alternative here?
+        return getInstanceIdentifier().firstKeyOf(Node.class, NodeKey.class);
+    }
+
+    public NodeId getNodeId() {
+        return getNodeKey().getNodeId();
+    }
+
+    public void setInstanceIdentifier(InstanceIdentifier<Node> iid) {
+        this.instanceIdentifier = iid;
+    }
+
+    public Entity getConnectedEntity() {
+        return this.connectedEntity;
+    }
+
+    public void setConnectedEntity(Entity entity ) {
+        this.connectedEntity = entity;
+    }
+
+    public Boolean hasOvsdbClient(OvsdbClient otherClient) {
+        return client.equals(otherClient);
+    }
+
+    public Boolean getHasDeviceOwnership() {
+        return Boolean.valueOf(hasDeviceOwnership);
+    }
+
+    public void setHasDeviceOwnership(Boolean hasDeviceOwnership) {
+        if (hasDeviceOwnership != null) {
+            this.hasDeviceOwnership = hasDeviceOwnership.booleanValue();
+        }
+    }
+
+    public void setDeviceOwnershipCandidateRegistration(@Nonnull EntityOwnershipCandidateRegistration registration) {
+        this.deviceOwnershipCandidateRegistration = registration;
+    }
+
+    public void closeDeviceOwnershipCandidateRegistration() {
+        if (deviceOwnershipCandidateRegistration != null) {
+            this.deviceOwnershipCandidateRegistration.close();
+            setHasDeviceOwnership(Boolean.FALSE);
+        }
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java
new file mode 100644 (file)
index 0000000..3a117bd
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.lib.OvsdbConnectionListener;
+import org.opendaylight.ovsdb.lib.operations.Operation;
+import org.opendaylight.ovsdb.lib.operations.OperationResult;
+import org.opendaylight.ovsdb.lib.operations.Select;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoCloseable{
+    private Map<ConnectionInfo, HwvtepConnectionInstance> clients =
+                    new ConcurrentHashMap<ConnectionInfo,HwvtepConnectionInstance>();
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepConnectionManager.class);
+    private static final String ENTITY_TYPE = "hwvtep";
+
+    private DataBroker db;
+    private TransactionInvoker txInvoker;
+    private Map<ConnectionInfo,InstanceIdentifier<Node>> instanceIdentifiers =
+                    new ConcurrentHashMap<ConnectionInfo,InstanceIdentifier<Node>>();
+    private Map<Entity, HwvtepConnectionInstance> entityConnectionMap =
+                    new ConcurrentHashMap<>();
+    private EntityOwnershipService entityOwnershipService;
+    private HwvtepDeviceEntityOwnershipListener hwvtepDeviceEntityOwnershipListener;
+
+    public HwvtepConnectionManager(DataBroker db, TransactionInvoker txInvoker,
+                    EntityOwnershipService entityOwnershipService) {
+        this.db = db;
+        this.txInvoker = txInvoker;
+        this.entityOwnershipService = entityOwnershipService;
+        this.hwvtepDeviceEntityOwnershipListener = new HwvtepDeviceEntityOwnershipListener(this,entityOwnershipService);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (hwvtepDeviceEntityOwnershipListener != null) {
+            hwvtepDeviceEntityOwnershipListener.close();
+        }
+
+        for (OvsdbClient client: clients.values()) {
+            client.disconnect();
+        }
+    }
+
+    @Override
+    public void connected(@Nonnull final OvsdbClient client) {
+        HwvtepConnectionInstance hwClient = connectedButCallBacksNotRegistered(client);
+        registerEntityForOwnership(hwClient);
+        LOG.trace("connected client: {}", hwClient);
+    }
+
+    @Override
+    public void disconnected(OvsdbClient client) {
+        LOG.info("HWVTEP Disconnected from {}:{}. Cleaning up the operational data store"
+                        ,client.getConnectionInfo().getRemoteAddress(),
+                        client.getConnectionInfo().getRemotePort());
+        ConnectionInfo key = HwvtepSouthboundMapper.createConnectionInfo(client);
+        HwvtepConnectionInstance hwvtepConnectionInstance = getConnectionInstance(key);
+        if (hwvtepConnectionInstance != null) {
+            //TODO: txInvoker.invoke(new HwvtepNodeRemoveCommand(hwvtepConnectionInstance, null, null));
+            removeConnectionInstance(key);
+
+            // Unregister Cluster Ownership for ConnectionInfo
+            unregisterEntityForOwnership(hwvtepConnectionInstance);
+        } else {
+            LOG.warn("HWVTEP disconnected event did not find connection instance for {}", key);
+        }
+        LOG.trace("disconnected client: {}", client);
+    }
+
+    public HwvtepConnectionInstance connectedButCallBacksNotRegistered(final OvsdbClient externalClient) {
+        LOG.info("OVSDB Connection from {}:{}",externalClient.getConnectionInfo().getRemoteAddress(),
+                externalClient.getConnectionInfo().getRemotePort());
+        ConnectionInfo key = HwvtepSouthboundMapper.createConnectionInfo(externalClient);
+        HwvtepConnectionInstance hwvtepConnectionInstance = getConnectionInstance(key);
+
+        // Check if existing hwvtepConnectionInstance for the OvsdbClient present.
+        // In such cases, we will see if the hwvtepConnectionInstance has same externalClient.
+        if (hwvtepConnectionInstance != null) {
+            if (hwvtepConnectionInstance.hasOvsdbClient(externalClient)) {
+                LOG.warn("HWVTEP Connection Instance {} already exists for client {}", key, externalClient);
+                return hwvtepConnectionInstance;
+            }
+            LOG.warn("HWVTEP Connection Instance {} being replaced with client {}", key, externalClient);
+            hwvtepConnectionInstance.disconnect();
+
+            // Unregister Cluster Ownership for ConnectionInfo
+            // Because the hwvtepConnectionInstance is about to be completely replaced!
+            unregisterEntityForOwnership(hwvtepConnectionInstance);
+
+            removeConnectionInstance(key);
+        }
+
+        hwvtepConnectionInstance = new HwvtepConnectionInstance(key, externalClient, getInstanceIdentifier(key),
+                txInvoker);
+        hwvtepConnectionInstance.createTransactInvokers();
+        return hwvtepConnectionInstance;
+    }
+
+    /* TODO:
+    public OvsdbClient connect(InstanceIdentifier<Node> iid, OvsdbNodeAugmentation ovsdbNode)
+                    throws UnknownHostException {
+    }
+
+    public void disconnect(OvsdbNodeAugmentation ovsdbNode) throws UnknownHostException {
+        OvsdbConnectionInstance client = getConnectionInstance(ovsdbNode.getConnectionInfo());
+
+    }
+
+    */
+
+    private void putConnectionInstance(ConnectionInfo key,HwvtepConnectionInstance instance) {
+        ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+        clients.put(connectionInfo, instance);
+        LOG.info("Clients after put: {}", clients);
+    }
+
+    public HwvtepConnectionInstance getConnectionInstance(ConnectionInfo key) {
+        ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+        return clients.get(connectionInfo);
+    }
+
+    private void removeConnectionInstance(ConnectionInfo key) {
+        ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+        clients.remove(connectionInfo);
+        LOG.info("Clients after remove: {}", clients);
+    }
+
+    private void putInstanceIdentifier(ConnectionInfo key,InstanceIdentifier<Node> iid) {
+        ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+        instanceIdentifiers.put(connectionInfo, iid);
+    }
+
+    public InstanceIdentifier<Node> getInstanceIdentifier(ConnectionInfo key) {
+        ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+        InstanceIdentifier<Node> iid = instanceIdentifiers.get(connectionInfo);
+        return iid;
+    }
+
+    private void removeInstanceIdentifier(ConnectionInfo key) {
+        ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+        instanceIdentifiers.remove(connectionInfo);
+    }
+
+    private void registerEntityForOwnership(HwvtepConnectionInstance hwvtepConnectionInstance) {
+
+        Entity candidateEntity = getEntityFromConnectionInstance(hwvtepConnectionInstance);
+        entityConnectionMap.put(candidateEntity, hwvtepConnectionInstance);
+        hwvtepConnectionInstance.setConnectedEntity(candidateEntity);
+
+        try {
+            EntityOwnershipCandidateRegistration registration =
+                    entityOwnershipService.registerCandidate(candidateEntity);
+            hwvtepConnectionInstance.setDeviceOwnershipCandidateRegistration(registration);
+            LOG.info("HWVTEP entity {} is registered for ownership.", candidateEntity);
+
+            //If entity already has owner, it won't get notification from EntityOwnershipService
+            //so cache the connection instances.
+            Optional<EntityOwnershipState> ownershipStateOpt =
+                    entityOwnershipService.getOwnershipState(candidateEntity);
+            if (ownershipStateOpt.isPresent()) {
+                EntityOwnershipState ownershipState = ownershipStateOpt.get();
+                if (ownershipState.hasOwner() && !ownershipState.isOwner()) {
+                    if (getConnectionInstance(hwvtepConnectionInstance.getMDConnectionInfo()) != null) {
+                        LOG.info("OVSDB entity {} is already owned by other southbound plugin "
+                                + "instance, so *this* instance is NOT an OWNER of the device",
+                                hwvtepConnectionInstance.getConnectionInfo());
+                        putConnectionInstance(hwvtepConnectionInstance.getMDConnectionInfo(),hwvtepConnectionInstance);
+                    }
+                }
+            }
+        } catch (CandidateAlreadyRegisteredException e) {
+            LOG.warn("OVSDB entity {} was already registered for {} ownership", candidateEntity, e);
+        }
+
+    }
+
+    private Global getHwvtepGlobalTableEntry(HwvtepConnectionInstance connectionInstance) {
+        DatabaseSchema dbSchema = null;
+        Global globalRow = null;
+
+        try {
+            dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.databaseName).get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.warn("Not able to fetch schema for database {} from device {}",
+                    HwvtepSchemaConstants.databaseName,connectionInstance.getConnectionInfo(),e);
+        }
+
+        if (dbSchema != null) {
+            GenericTableSchema hwvtepSchema = TyperUtils.getTableSchema(dbSchema, Global.class);
+
+            List<String> hwvtepTableColumn = new ArrayList<String>();
+            hwvtepTableColumn.addAll(hwvtepSchema.getColumns());
+            Select<GenericTableSchema> selectOperation = op.select(hwvtepSchema);
+            selectOperation.setColumns(hwvtepTableColumn);;
+
+            ArrayList<Operation> operations = new ArrayList<Operation>();
+            operations.add(selectOperation);
+            operations.add(op.comment("Fetching hardware_vtep table rows"));
+
+            List<OperationResult> results = null;
+            try {
+                results = connectionInstance.transact(dbSchema, operations).get();
+                if (results != null ) {
+                    OperationResult selectResult = results.get(0);
+                    globalRow = TyperUtils.getTypedRowWrapper(
+                            dbSchema,Global.class,selectResult.getRows().get(0));
+                }
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.warn("Not able to fetch hardware_vtep table row from device {}",
+                        connectionInstance.getConnectionInfo(),e);
+            }
+        }
+        LOG.trace("Fetched global {} from hardware_vtep schema",globalRow);
+        return globalRow;
+    }
+
+    private Entity getEntityFromConnectionInstance(@Nonnull HwvtepConnectionInstance hwvtepConnectionInstance) {
+        YangInstanceIdentifier entityId = null;
+        InstanceIdentifier<Node> iid = hwvtepConnectionInstance.getInstanceIdentifier();;
+        if ( iid == null ) {
+            //TODO: Is Global the right one?
+            Global hwvtepGlobalRow = getHwvtepGlobalTableEntry(hwvtepConnectionInstance);
+            iid = HwvtepSouthboundMapper.getInstanceIdentifier(hwvtepGlobalRow);
+            LOG.info("InstanceIdentifier {} generated for device "
+                    + "connection {}",iid, hwvtepConnectionInstance.getConnectionInfo());
+
+        }
+        entityId = HwvtepSouthboundUtil.getInstanceIdentifierCodec().getYangInstanceIdentifier(iid);
+        Entity deviceEntity = new Entity(ENTITY_TYPE, entityId);
+        LOG.debug("Entity {} created for device connection {}",
+                deviceEntity, hwvtepConnectionInstance.getConnectionInfo());
+        return deviceEntity;
+    }
+    private void unregisterEntityForOwnership(HwvtepConnectionInstance hwvtepConnectionInstance) {
+        hwvtepConnectionInstance.closeDeviceOwnershipCandidateRegistration();
+        entityConnectionMap.remove(hwvtepConnectionInstance.getConnectedEntity());
+    }
+
+    public void handleOwnershipChanged(EntityOwnershipChange ownershipChange) {
+        HwvtepConnectionInstance hwvtepConnectionInstance = getConnectionInstanceFromEntity(ownershipChange.getEntity());
+        LOG.info("handleOwnershipChanged: {} event received for device {}",
+                ownershipChange, hwvtepConnectionInstance != null ? hwvtepConnectionInstance.getConnectionInfo()
+                        : "THAT'S NOT REGISTERED BY THIS SOUTHBOUND PLUGIN INSTANCE");
+
+        if (hwvtepConnectionInstance == null) {
+            if (ownershipChange.isOwner()) {
+                LOG.warn("handleOwnershipChanged: found no connection instance for {}", ownershipChange.getEntity());
+            } else {
+                // EntityOwnershipService sends notification to all the nodes, irrespective of whether
+                // that instance registered for the device ownership or not. It is to make sure that
+                // If all the controller instance that was connected to the device are down, so the
+                // running instance can clear up the operational data store even though it was not
+                // connected to the device.
+                LOG.debug("handleOwnershipChanged: found no connection instance for {}", ownershipChange.getEntity());
+            }
+
+            // If entity has no owner, clean up the operational data store (it's possible because owner controller
+            // might went down abruptly and didn't get a chance to clean up the operational data store.
+            if (!ownershipChange.hasOwner()) {
+                LOG.debug("{} has no onwer, cleaning up the operational data store", ownershipChange.getEntity());
+                // Below code might look weird but it's required. We want to give first opportunity to the
+                // previous owner of the device to clean up the operational data store if there is no owner now.
+                // That way we will avoid lot of nasty md-sal exceptions because of concurrent delete.
+                if (ownershipChange.wasOwner()) {
+                    cleanEntityOperationalData(ownershipChange.getEntity());
+                }
+                // If first cleanEntityOperationalData() was called, this call will be no-op.
+                cleanEntityOperationalData(ownershipChange.getEntity());
+            }
+            return;
+        }
+        //Connection detail need to be cached, irrespective of ownership result.
+        putConnectionInstance(hwvtepConnectionInstance.getMDConnectionInfo(),hwvtepConnectionInstance);
+
+        if (ownershipChange.isOwner() == hwvtepConnectionInstance.getHasDeviceOwnership()) {
+            LOG.debug("handleOwnershipChanged: no change in ownership for {}. Ownership status is : {}",
+                    hwvtepConnectionInstance.getConnectionInfo(), hwvtepConnectionInstance.getHasDeviceOwnership());
+            return;
+        }
+
+        hwvtepConnectionInstance.setHasDeviceOwnership(ownershipChange.isOwner());
+        // You were not an owner, but now you are
+        if (ownershipChange.isOwner()) {
+            LOG.info("handleOwnershipChanged: *this* southbound plugin instance is owner of device {}",
+                    hwvtepConnectionInstance.getConnectionInfo());
+
+            //*this* instance of southbound plugin is owner of the device,
+            //so register for monitor callbacks
+            hwvtepConnectionInstance.registerCallbacks();
+
+        } else {
+            //You were owner of the device, but now you are not. With the current ownership
+            //grant mechanism, this scenario should not occur. Because this scenario will occur
+            //when this controller went down or switch flap the connection, but in both the case
+            //it will go through the re-registration process. We need to implement this condition
+            //when clustering service implement a ownership grant strategy which can revoke the
+            //device ownership for load balancing the devices across the instances.
+            //Once this condition occur, we should unregister the callback.
+            LOG.error("handleOwnershipChanged: *this* southbound plugin instance is no longer the owner of device {}",
+                    hwvtepConnectionInstance.getNodeId().getValue());
+        }
+    }
+
+    private void cleanEntityOperationalData(Entity entity) {
+        //TODO: remove entity from Operational DataStore
+        LOG.error("cleanEntityOperationalData(): Code incomplete");
+    }
+
+    private HwvtepConnectionInstance getConnectionInstanceFromEntity(Entity entity) {
+        return entityConnectionMap.get(entity);
+    }
+
+    private class HwvtepDeviceEntityOwnershipListener implements EntityOwnershipListener {
+        private HwvtepConnectionManager hcm;
+        private EntityOwnershipListenerRegistration listenerRegistration;
+
+        HwvtepDeviceEntityOwnershipListener(HwvtepConnectionManager hcm, EntityOwnershipService entityOwnershipService) {
+            this.hcm = hcm;
+            listenerRegistration = entityOwnershipService.registerListener(ENTITY_TYPE, this);
+        }
+        public void close() {
+            listenerRegistration.close();
+        }
+        @Override
+        public void ownershipChanged(EntityOwnershipChange ownershipChange) {
+            hcm.handleOwnershipChanged(ownershipChange);
+        }
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepMonitorCallback.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepMonitorCallback.java
new file mode 100644 (file)
index 0000000..104ee10
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound;
+
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.HwvtepOperationalCommandAggregator;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
+import org.opendaylight.ovsdb.lib.MonitorCallBack;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HwvtepMonitorCallback implements MonitorCallBack {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepMonitorCallback.class);
+    private HwvtepConnectionInstance key;
+    private TransactionInvoker txInvoker;
+
+    HwvtepMonitorCallback(HwvtepConnectionInstance key,TransactionInvoker txInvoker) {
+        this.txInvoker = txInvoker;
+        this.key = key;
+    }
+
+    @Override
+    public void update(TableUpdates result, DatabaseSchema dbSchema) {
+        LOG.debug("result: {} dbSchema: {}",result,dbSchema);
+        txInvoker.invoke(new HwvtepOperationalCommandAggregator(key, result, dbSchema));
+        LOG.trace("update exit");
+    }
+
+    @Override
+    public void exception(Throwable exception) {
+        LOG.warn("exception {}", exception);
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSchemaConstants.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSchemaConstants.java
new file mode 100644 (file)
index 0000000..1b84a13
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound;
+
+public class HwvtepSchemaConstants {
+    public static final String databaseName = "hardware_vtep";
+    public enum HWVTEPSCHEMATABLES {
+        GLOBAL("Global", null, null),
+        MANAGER("Manager","Global","managers"),
+        PHYSICALSWITCH("Physical_Switch","Global","switches"),
+        PHYSICALPORT("Physical_Port","Physical_Switch","ports"),
+        TUNNEL("Tunnel","Physical_Switch","tunnels"),
+        LOGICALSWITCH("Logical_Switch","Physical_Port","vlan_bindings"),
+        ACL("ACL","Physical_Port","acl_bindings"),
+        LOGICALBINDINGSTATS("Logical_Binding_Stats","Physical_Port","vlan_stats"),
+//        PHYSICALLOCATORLOCAL("Physical_Locator","Tunnel","local"),
+//        PHYSICALLOCATORREMOTE("Physical_Locator","Tunnel","remote"),
+        UCASTMACSLOCAL("Ucast_Macs_Local",null, null),
+        UCASTMACSREMOTE("Ucast_Macs_Remote",null, null),
+        MCASTMACSLOCAL("Mcast_Macs_Local",null, null),
+        PHYSICALLOCATORSET("Physical_Locator_Set","Mcast_Macs_Local", "locator_set"),
+        MCASTMACSREMOTE("Mcast_Macs_Remote",null, null),
+        LOGICALROUTER("Logical_Router",null, null),
+        ARPSOURCESLOCAL("Arp_Sources_Local",null, null),
+        ARPSOURCESREMOTE("Arp_Sources_Remote",null, null),
+        PHYSICALLOCATOR("Physical_Locator","Physical_Locator_Set", "locators"),
+        ACLENTRY("Acl_Entry","ACL", "acl_entries");
+
+        private final String tableName;
+        private final String parentTableName;
+        private final String columnNameInParentTable;
+
+        private HWVTEPSCHEMATABLES(final String tableName, final String parentTableName,
+                                  final String columnNameInParentTable) {
+            this.tableName = tableName;
+            this.parentTableName = parentTableName;
+            this.columnNameInParentTable = columnNameInParentTable;
+        }
+
+        public String getTableName() {
+            return this.tableName;
+        }
+
+        public String getParentTableName() {
+            return this.parentTableName;
+        }
+
+        public String getColumnNameInParentTable() {
+            return this.columnNameInParentTable;
+        }
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundConstants.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundConstants.java
new file mode 100644 (file)
index 0000000..57ee2fc
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+
+public class HwvtepSouthboundConstants {
+
+    public static final TopologyId HWVTEP_TOPOLOGY_ID = new TopologyId(new Uri("hwvtep:1"));
+    public static final String HWVTEP_URI_PREFIX = "hwvtep";
+    public static final Integer DEFAULT_OVSDB_PORT = 6640;
+    public static final String IID_OTHER_CONFIG_KEY = "opendaylight-iid";
+    public static final String UUID = "uuid";
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundMapper.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundMapper.java
new file mode 100644 (file)
index 0000000..77cbcdb
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfoBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HwvtepSouthboundMapper {
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundMapper.class);
+    private static final String N_CONNECTIONS_STR = "n_connections";
+
+    private static NodeId createNodeId(HwvtepConnectionInstance client) {
+        NodeKey key = client.getInstanceIdentifier().firstKeyOf(Node.class, NodeKey.class);
+        return key.getNodeId();
+
+    }
+
+    public static InstanceIdentifier<Node> createInstanceIdentifier(NodeId nodeId) {
+        InstanceIdentifier<Node> nodePath = InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+                .child(Node.class,new NodeKey(nodeId));
+        return nodePath;
+    }
+
+    public static InstanceIdentifier<Node> createInstanceIdentifier (OvsdbClient client) {
+        return createInstanceIdentifier(createIpAddress(client.getConnectionInfo().getRemoteAddress()),
+                        new PortNumber(client.getConnectionInfo().getRemotePort()));
+    }
+
+    private static InstanceIdentifier<Node> createInstanceIdentifier(IpAddress ip, PortNumber port) {
+        String uriString = HwvtepSouthboundConstants.HWVTEP_URI_PREFIX + "://"
+                + new String(ip.getValue()) + ":" + port.getValue();
+        Uri uri = new Uri(uriString);
+        NodeId nodeId = new NodeId(uri);
+        InstanceIdentifier<Node> path = InstanceIdentifier.create(NetworkTopology.class)
+                        .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+                        .child(Node.class,new NodeKey(nodeId));
+        LOG.debug("Created ovsdb path: {}",path);
+        return path;
+    }
+
+    public static NodeId createManagedNodeId(InstanceIdentifier<Node> iid) {
+        NodeKey nodeKey = iid.firstKeyOf(Node.class, NodeKey.class);
+        return nodeKey.getNodeId();
+    }
+
+    public static IpAddress createIpAddress(InetAddress address) {
+        IpAddress ip = null;
+        if (address instanceof Inet4Address) {
+            ip = createIpAddress((Inet4Address)address);
+        } else if (address instanceof Inet6Address) {
+            ip = createIpAddress((Inet6Address)address);
+        }
+        return ip;
+    }
+
+    public static IpAddress createIpAddress(Inet4Address address) {
+        Ipv4Address ipv4 = new Ipv4Address(address.getHostAddress());
+        return new IpAddress(ipv4);
+    }
+
+    public static IpAddress createIpAddress(Inet6Address address) {
+        Ipv6Address ipv6 = new Ipv6Address(address.getHostAddress());
+        return new IpAddress(ipv6);
+    }
+
+    public static ConnectionInfo createConnectionInfo(OvsdbClient client) {
+        ConnectionInfoBuilder connectionInfoBuilder = new ConnectionInfoBuilder();
+        connectionInfoBuilder.setRemoteIp(createIpAddress(client.getConnectionInfo().getRemoteAddress()));
+        connectionInfoBuilder.setRemotePort(new PortNumber(client.getConnectionInfo().getRemotePort()));
+        connectionInfoBuilder.setLocalIp(createIpAddress(client.getConnectionInfo().getLocalAddress()));
+        connectionInfoBuilder.setLocalPort(new PortNumber(client.getConnectionInfo().getLocalPort()));
+        return connectionInfoBuilder.build();
+    }
+
+    public static ConnectionInfo suppressLocalIpPort(ConnectionInfo connectionInfo) {
+        ConnectionInfoBuilder connectionInfoBuilder = new ConnectionInfoBuilder();
+        connectionInfoBuilder.setRemoteIp(connectionInfo.getRemoteIp());
+        connectionInfoBuilder.setRemotePort(connectionInfo.getRemotePort());
+        return connectionInfoBuilder.build();
+    }
+
+    public static InstanceIdentifier<Node> getInstanceIdentifier(Global global) {
+        InstanceIdentifier<Node> iid = null;
+        if (global.getManagersColumn() != null
+                && global.getManagersColumn().getData() != null) {
+            String iidString = global.getManagersColumn().getData().iterator().next().toString();
+            iid = (InstanceIdentifier<Node>) HwvtepSouthboundUtil.deserializeInstanceIdentifier(iidString);
+        } else {
+            String nodeString = HwvtepSouthboundConstants.HWVTEP_URI_PREFIX + "://" +
+                            HwvtepSouthboundConstants.UUID + "/" + global.getUuid().toString();
+            NodeId nodeId = new NodeId(new Uri(nodeString));
+            NodeKey nodeKey = new NodeKey(nodeId);
+            TopologyKey topoKey = new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
+            iid = InstanceIdentifier.builder(NetworkTopology.class)
+                            .child(Topology.class, topoKey)
+                            .child(Node.class,nodeKey)
+                            .build();
+        }
+        return iid;
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundProvider.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundProvider.java
new file mode 100644 (file)
index 0000000..75f9446
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvokerImpl;
+import org.opendaylight.ovsdb.lib.OvsdbConnection;
+import org.opendaylight.ovsdb.lib.impl.OvsdbConnectionService;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+public class HwvtepSouthboundProvider implements BindingAwareProvider, AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundProvider.class);
+    private static final String ENTITY_TYPE = "ovsdb-hwvtepsouthbound-provider";
+
+    public static DataBroker getDb() {
+        return db;
+    }
+
+    private static DataBroker db;
+    private HwvtepConnectionManager cm;
+    private OvsdbConnection ovsdbConnection;
+    private TransactionInvoker txInvoker;
+    private EntityOwnershipService entityOwnershipService;
+    private EntityOwnershipCandidateRegistration registration;
+    private HwvtepsbPluginInstanceEntityOwnershipListener providerOwnershipChangeListener;
+
+    public HwvtepSouthboundProvider(
+            EntityOwnershipService entityOwnershipServiceDependency) {
+        this.entityOwnershipService = entityOwnershipServiceDependency;
+        registration = null;
+    }
+
+    @Override
+    public void onSessionInitiated(ProviderContext session) {
+        LOG.info("HwvtepSouthboundProvider Session Initiated");
+        db = session.getSALService(DataBroker.class);
+        txInvoker = new TransactionInvokerImpl(db);
+        cm = new HwvtepConnectionManager(db, txInvoker, entityOwnershipService);
+        //TODO: Add DataChange Listener
+
+        //Register listener for entityOnwership changes
+        providerOwnershipChangeListener =
+                new HwvtepsbPluginInstanceEntityOwnershipListener(this,this.entityOwnershipService);
+        entityOwnershipService.registerListener(ENTITY_TYPE,providerOwnershipChangeListener);
+
+        //register instance entity to get the ownership of the provider
+        Entity instanceEntity = new Entity(ENTITY_TYPE, ENTITY_TYPE);
+        try {
+            registration = entityOwnershipService.registerCandidate(instanceEntity);
+        } catch (CandidateAlreadyRegisteredException e) {
+            LOG.warn("HWVTEP Southbound Provider instance entity {} was already "
+                    + "registered for {} ownership", instanceEntity, e);
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        LOG.info("HwvtepSouthboundProvider Closed");
+        if(cm != null){
+            cm.close();
+            cm = null;
+        }
+        if(registration != null) {
+            registration.close();
+            registration = null;
+        }
+        if(providerOwnershipChangeListener != null) {
+            providerOwnershipChangeListener.close();
+            providerOwnershipChangeListener = null;
+        }
+    }
+
+    private void initializeHwvtepTopology(LogicalDatastoreType type) {
+        InstanceIdentifier<Topology> path = InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID));
+        initializeTopology(type);
+        ReadWriteTransaction transaction = db.newReadWriteTransaction();
+        CheckedFuture<Optional<Topology>, ReadFailedException> hwvtepTp = transaction.read(type, path);
+        try {
+            if (!hwvtepTp.get().isPresent()) {
+                TopologyBuilder tpb = new TopologyBuilder();
+                tpb.setTopologyId(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
+                transaction.put(type, path, tpb.build());
+                transaction.submit();
+            } else {
+                transaction.cancel();
+            }
+        } catch (Exception e) {
+            LOG.error("Error initializing hwvtep topology", e);
+        }
+    }
+
+    private void initializeTopology(LogicalDatastoreType type) {
+        ReadWriteTransaction transaction = db.newReadWriteTransaction();
+        InstanceIdentifier<NetworkTopology> path = InstanceIdentifier.create(NetworkTopology.class);
+        CheckedFuture<Optional<NetworkTopology>, ReadFailedException> topology = transaction.read(type,path);
+        try {
+            if (!topology.get().isPresent()) {
+                NetworkTopologyBuilder ntb = new NetworkTopologyBuilder();
+                transaction.put(type,path,ntb.build());
+                transaction.submit();
+            } else {
+                transaction.cancel();
+            }
+        } catch (Exception e) {
+            LOG.error("Error initializing hwvtep topology {}",e);
+        }
+    }
+
+    public void handleOwnershipChange(EntityOwnershipChange ownershipChange) {
+        if (ownershipChange.isOwner()) {
+            LOG.info("*This* instance of HWVTEP southbound provider is set as a MASTER instance");
+            LOG.info("Initialize HWVTEP topology {} in operational and config data store if not already present"
+                    ,HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
+            initializeHwvtepTopology(LogicalDatastoreType.OPERATIONAL);
+            initializeHwvtepTopology(LogicalDatastoreType.CONFIGURATION);
+        } else {
+            LOG.info("*This* instance of HWVTEP southbound provider is set as a SLAVE instance");
+        }
+        //TODO: How to make this co-exist with OvsdbSouthbound?
+        if (ovsdbConnection == null) {
+            ovsdbConnection = new OvsdbConnectionService();
+            ovsdbConnection.registerConnectionListener(cm);
+            ovsdbConnection.startOvsdbManager(HwvtepSouthboundConstants.DEFAULT_OVSDB_PORT);
+        }
+    }
+
+    private class HwvtepsbPluginInstanceEntityOwnershipListener implements EntityOwnershipListener {
+        private HwvtepSouthboundProvider hsp;
+        private EntityOwnershipListenerRegistration listenerRegistration;
+
+        HwvtepsbPluginInstanceEntityOwnershipListener(HwvtepSouthboundProvider hsp,
+                EntityOwnershipService entityOwnershipService) {
+            this.hsp = hsp;
+            listenerRegistration = entityOwnershipService.registerListener(ENTITY_TYPE, this);
+        }
+
+        public void close() {
+            this.listenerRegistration.close();
+        }
+        @Override
+        public void ownershipChanged(EntityOwnershipChange ownershipChange) {
+            hsp.handleOwnershipChange(ownershipChange);
+        }
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java
new file mode 100644 (file)
index 0000000..9616f2c
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.hwvtepsouthbound;
+
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HwvtepSouthboundUtil {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundUtil.class);
+
+    private static InstanceIdentifierCodec instanceIdentifierCodec;
+
+    private HwvtepSouthboundUtil() {
+        // Prevent instantiating a utility class
+    }
+
+    public static void setInstanceIdentifierCodec(InstanceIdentifierCodec iidc) {
+        instanceIdentifierCodec = iidc;
+    }
+
+    public static InstanceIdentifierCodec getInstanceIdentifierCodec() {
+        return instanceIdentifierCodec;
+    }
+
+    public static String serializeInstanceIdentifier(InstanceIdentifier<?> iid) {
+        return instanceIdentifierCodec.serialize(iid);
+    }
+
+    public static InstanceIdentifier<?> deserializeInstanceIdentifier(String iidString) {
+        InstanceIdentifier<?> result = null;
+        try {
+            result = instanceIdentifierCodec.bindingDeserializer(iidString);
+        } catch (DeserializationException e) {
+            LOG.warn("Unable to deserialize iidString", e);
+        }
+        return result;
+    }
+
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/InstanceIdentifierCodec.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/InstanceIdentifierCodec.java
new file mode 100644 (file)
index 0000000..df40fd2
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound;
+
+import java.net.URI;
+
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
+import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+
+public class InstanceIdentifierCodec extends AbstractModuleStringInstanceIdentifierCodec
+    implements SchemaContextListener {
+
+    private DataSchemaContextTree dataSchemaContextTree;
+    private SchemaContext context;
+    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
+
+    public InstanceIdentifierCodec(SchemaService schemaService,
+            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+        schemaService.registerSchemaContextListener(this);
+        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
+    }
+
+    @Override
+    protected DataSchemaContextTree getDataContextTree() {
+        return dataSchemaContextTree;
+    }
+
+    @Override
+    protected Module moduleForPrefix(final String prefix) {
+        return context.findModuleByName(prefix, null);
+    }
+
+    @Override
+    protected String prefixForNamespace(final URI namespace) {
+        final Module module = context.findModuleByNamespaceAndRevision(namespace, null);
+        return module == null ? null : module.getName();
+    }
+
+    @Override
+    public void onGlobalContextUpdated(SchemaContext context) {
+        this.context = context;
+        this.dataSchemaContextTree = DataSchemaContextTree.from(context);
+    }
+
+    public String serialize(InstanceIdentifier<?> iid) {
+        YangInstanceIdentifier normalizedIid = bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid);
+        return serialize(normalizedIid);
+    }
+
+    public YangInstanceIdentifier getYangInstanceIdentifier(InstanceIdentifier<?> iid) {
+        return bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid);
+    }
+
+    public  InstanceIdentifier<?> bindingDeserializer(String iidString) throws DeserializationException {
+        YangInstanceIdentifier normalizedYangIid = deserialize(iidString);
+        InstanceIdentifier<?> iid = bindingNormalizedNodeSerializer.fromYangInstanceIdentifier(normalizedYangIid);
+        return iid;
+    }
+
+    public InstanceIdentifier<?> bindingDeserializer(YangInstanceIdentifier yangIID) {
+        InstanceIdentifier<?> iid = bindingNormalizedNodeSerializer.fromYangInstanceIdentifier(yangIID);
+        return iid;
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/impl/HwvtepSouthboundProvider.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/impl/HwvtepSouthboundProvider.java
deleted file mode 100644 (file)
index 8ef25ea..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound.impl;
-
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class HwvtepSouthboundProvider implements BindingAwareProvider, AutoCloseable {
-
-    private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundProvider.class);
-
-    @Override
-    public void onSessionInitiated(ProviderContext session) {
-        LOG.info("HwvtepSouthboundProvider Session Initiated");
-    }
-
-    @Override
-    public void close() throws Exception {
-        LOG.info("HwvtepSouthboundProvider Closed");
-    }
-
-}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactCommand.java
new file mode 100644 (file)
index 0000000..ac9eeea
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound.transact;
+
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+
+public interface TransactCommand {
+
+    void execute(TransactionBuilder transaction);
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactInvoker.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactInvoker.java
new file mode 100644 (file)
index 0000000..a077116
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound.transact;
+
+public interface TransactInvoker {
+    void invoke(TransactCommand command);
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactInvokerImpl.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/TransactInvokerImpl.java
new file mode 100644 (file)
index 0000000..4402c88
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound.transact;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.lib.operations.OperationResult;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class TransactInvokerImpl implements TransactInvoker {
+    private static final Logger LOG = LoggerFactory.getLogger(TransactInvokerImpl.class);
+    private HwvtepConnectionInstance connectionInstance;
+    private DatabaseSchema dbSchema;
+
+    public TransactInvokerImpl(HwvtepConnectionInstance connectionInstance, DatabaseSchema dbSchema) {
+        this.connectionInstance = connectionInstance;
+        this.dbSchema = dbSchema;
+    }
+
+    @Override
+    public void invoke(TransactCommand command) {
+        TransactionBuilder tb = new TransactionBuilder(connectionInstance, dbSchema);
+        command.execute(tb);
+        ListenableFuture<List<OperationResult>> result = tb.execute();
+        LOG.debug("invoke: command: {}, tb: {}", command, tb);
+        if (tb.getOperations().size() > 0) {
+            try {
+                List<OperationResult> got = result.get();
+                LOG.debug("OVSDB transaction result: {}", got);
+            } catch (Exception e) {
+                LOG.warn("Transact execution exception: ", e);
+            }
+            LOG.trace("invoke exit command: {}, tb: {}", command, tb);
+        }
+    }
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepOperationalCommandAggregator.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/HwvtepOperationalCommandAggregator.java
new file mode 100644 (file)
index 0000000..a160707
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 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.ovsdb.hwvtepsouthbound.transactions.md;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+
+public class HwvtepOperationalCommandAggregator implements TransactionCommand {
+
+
+    private List<TransactionCommand> commands = new ArrayList<TransactionCommand>();
+
+    public HwvtepOperationalCommandAggregator(HwvtepConnectionInstance key,TableUpdates updates,
+            DatabaseSchema dbSchema) {
+        //TODO: Add commands in here
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        for (TransactionCommand command: commands) {
+            command.execute(transaction);
+        }
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/TransactionCommand.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/TransactionCommand.java
new file mode 100644 (file)
index 0000000..89dda90
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound.transactions.md;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+
+public interface TransactionCommand {
+
+    void execute(ReadWriteTransaction transaction);
+
+}
\ No newline at end of file
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/TransactionInvoker.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/TransactionInvoker.java
new file mode 100644 (file)
index 0000000..5e9fe9b
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound.transactions.md;
+
+public interface TransactionInvoker {
+
+    void invoke(TransactionCommand command);
+
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/TransactionInvokerImpl.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transactions/md/TransactionInvokerImpl.java
new file mode 100644 (file)
index 0000000..9599464
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015 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.ovsdb.hwvtepsouthbound.transactions.md;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+/*  TODO:
+ * Copied over as-is from southbound plugin. Good candidate to be common
+ * when refactoring code. 
+ */
+public class TransactionInvokerImpl implements TransactionInvoker,TransactionChainListener, Runnable, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(TransactionInvokerImpl.class);
+    private static final int QUEUE_SIZE = 10000;
+    private BindingTransactionChain chain;
+    private DataBroker db;
+    private BlockingQueue<TransactionCommand> inputQueue = new LinkedBlockingQueue<TransactionCommand>(QUEUE_SIZE);
+    private BlockingQueue<ReadWriteTransaction> successfulTransactionQueue
+        = new LinkedBlockingQueue<ReadWriteTransaction>(QUEUE_SIZE);
+    private BlockingQueue<AsyncTransaction<?, ?>> failedTransactionQueue
+        = new LinkedBlockingQueue<AsyncTransaction<?, ?>>(QUEUE_SIZE);
+    private ExecutorService executor;
+    private Map<ReadWriteTransaction,TransactionCommand> transactionToCommand
+        = new HashMap<ReadWriteTransaction,TransactionCommand>();
+    private List<ReadWriteTransaction> pendingTransactions = new ArrayList<ReadWriteTransaction>();
+
+    public TransactionInvokerImpl(DataBroker db) {
+        this.db = db;
+        this.chain = db.createTransactionChain(this);
+        ThreadFactory threadFact = new ThreadFactoryBuilder().setNameFormat("transaction-invoker-impl-%d").build();
+        executor = Executors.newSingleThreadExecutor(threadFact);
+        executor.submit(this);
+    }
+
+    @Override
+    public void invoke(final TransactionCommand command) {
+        // TODO what do we do if queue is full?
+        inputQueue.offer(command);
+    }
+
+    @Override
+    public void onTransactionChainFailed(TransactionChain<?, ?> chain,
+            AsyncTransaction<?, ?> transaction, Throwable cause) {
+        failedTransactionQueue.offer(transaction);
+    }
+
+    @Override
+    public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
+        // NO OP
+
+    }
+
+    @Override
+    public void run() {
+        while (true) {
+            forgetSuccessfulTransactions();
+            try {
+                List<TransactionCommand> commands = extractCommands();
+                for (TransactionCommand command: commands) {
+                    final ReadWriteTransaction transaction = chain.newReadWriteTransaction();
+                    recordPendingTransaction(command, transaction);
+                    command.execute(transaction);
+                    Futures.addCallback(transaction.submit(), new FutureCallback<Void>() {
+                        @Override
+                        public void onSuccess(final Void result) {
+                            successfulTransactionQueue.offer(transaction);
+                        }
+
+                        @Override
+                        public void onFailure(final Throwable throwable) {
+                            // NOOP - handled by failure of transaction chain
+                        }
+                    });
+                }
+            } catch (Exception e) {
+                LOG.warn("Exception invoking Transaction: ", e);
+            }
+        }
+    }
+
+    private List<TransactionCommand> extractResubmitCommands() {
+        AsyncTransaction<?, ?> transaction = failedTransactionQueue.poll();
+        List<TransactionCommand> commands = new ArrayList<TransactionCommand>();
+        if (transaction != null) {
+            int index = pendingTransactions.lastIndexOf(transaction);
+            List<ReadWriteTransaction> transactions =
+                    pendingTransactions.subList(index, pendingTransactions.size() - 1);
+            for (ReadWriteTransaction tx: transactions) {
+                commands.add(transactionToCommand.get(tx));
+            }
+            resetTransactionQueue();
+        }
+        return commands;
+    }
+
+    private void resetTransactionQueue() {
+        chain.close();
+        chain = db.createTransactionChain(this);
+        pendingTransactions = new ArrayList<ReadWriteTransaction>();
+        transactionToCommand = new HashMap<ReadWriteTransaction,TransactionCommand>();
+        failedTransactionQueue.clear();
+        successfulTransactionQueue.clear();
+    }
+
+    private void recordPendingTransaction(TransactionCommand command,
+            final ReadWriteTransaction transaction) {
+        transactionToCommand.put(transaction, command);
+        pendingTransactions.add(transaction);
+    }
+
+    private List<TransactionCommand> extractCommands() throws InterruptedException {
+        List<TransactionCommand> commands = extractResubmitCommands();
+        commands.addAll(extractCommandsFromQueue());
+        return commands;
+    }
+
+    private List<TransactionCommand> extractCommandsFromQueue() throws InterruptedException {
+        List<TransactionCommand> result = new ArrayList<TransactionCommand>();
+        TransactionCommand command = inputQueue.take();
+        while (command != null) {
+            result.add(command);
+            command = inputQueue.poll();
+        }
+        return result;
+    }
+
+    private void forgetSuccessfulTransactions() {
+        ReadWriteTransaction transaction = successfulTransactionQueue.poll();
+        while (transaction != null) {
+            pendingTransactions.remove(transaction);
+            transactionToCommand.remove(transaction);
+            transaction = successfulTransactionQueue.poll();
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        this.executor.shutdown();
+    }
+}
index 0a37e0155a760f7e671c34af1896ede44e8786b4..b4398e08c210779f63bfe1f287d4ee6fe3e94195 100644 (file)
@@ -8,7 +8,9 @@
 
 package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hwvtepsouthbound.impl.rev150901;
 
-import org.opendaylight.ovsdb.hwvtepsouthbound.impl.HwvtepSouthboundProvider;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundProvider;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
+import org.opendaylight.ovsdb.hwvtepsouthbound.InstanceIdentifierCodec;
 
 public class HwvtepSouthboundModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hwvtepsouthbound.impl.rev150901.AbstractHwvtepSouthboundModule {
     public HwvtepSouthboundModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
@@ -26,7 +28,9 @@ public class HwvtepSouthboundModule extends org.opendaylight.yang.gen.v1.urn.ope
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        HwvtepSouthboundProvider provider = new HwvtepSouthboundProvider();
+        HwvtepSouthboundUtil.setInstanceIdentifierCodec(new InstanceIdentifierCodec(getSchemaServiceDependency(),
+                        getBindingNormalizedNodeSerializerDependency()));
+        HwvtepSouthboundProvider provider = new HwvtepSouthboundProvider(getClusteringEntityOwnershipServiceDependency());
         getBrokerDependency().registerProvider(provider);
         return provider;
     }
index 2f8aae6d0138aa75d280ba34f8b74fb1f444e2b9..f9a24e387464b413946ff2c6240496e98d176d9e 100644 (file)
@@ -5,6 +5,8 @@ module hwvtepsouthbound-impl {
 
     import config { prefix config; revision-date 2013-04-05; }
     import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+    import opendaylight-entity-ownership-service {prefix eos; revision-date 2015-08-10;}
+    import opendaylight-md-sal-dom {prefix dom; revision-date 2013-10-28;}
 
     description
         "Service definition for hwvtepsouthbound project";
@@ -30,6 +32,30 @@ module hwvtepsouthbound-impl {
                     }
                 }
             }
+            container schema-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory false;
+                        config:required-identity dom:schema-service;
+                    }
+                }
+            }
+            container clustering-entity-ownership-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity eos:entity-ownership-service;
+                    }
+                }
+            }
+            container binding-normalized-node-serializer {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding:binding-normalized-node-serializer;
+                    }
+                }
+            }
         }
     }
 }
index 3b67519fe9e0716a53997aff03304660b8ab9b28..6f49c4c9234fcead8d90dc62193da203b6365541 100644 (file)
@@ -7,12 +7,13 @@
  */
 package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hwvtepsouthbound.impl.rev150901;
 
+import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.config.api.DependencyResolver;
 import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.ovsdb.hwvtepsouthbound.impl.HwvtepSouthboundProvider;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundProvider;
 
 import javax.management.ObjectName;
 
@@ -32,6 +33,8 @@ public class HwvtepSouthboundModuleTest {
         module.customValidation();
     }
 
+    //TODO: Ignore for now, will be replaced with better UT
+    @Ignore
     @Test
     public void testCreateInstance() throws Exception {
         // configure mocks
index a061d66bdc330f34a83b9e0fcb6f148ca8b78167..389e33f1fe47b218a93ffa730910b32a8a0f31c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
index e0560f8c90556bb791b0b1bf848983d83cc71938..6eb903358de7d328336bc83647d8780bab6225b0 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
index 2ccae3f178f71f02c9315ab8d43e575d0e523cf6..9c0645ed29083635f512adee30aa653db5f928d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
index 4fdc93a1c8dc5b25c8aa91cc90d15d0f2a808afc..8496f3fa022b33422c0e47788eb58716582b4bf0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, 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,
index 1768f6088ec1fdbd44fa17b122cd110c20260208..1d07fa28d2d9e2bc0bf9ffbacab49b89319b33c9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2014 Red Hat, Inc.
+ *  Copyright (C) 2014 Red Hat, 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,
index d31ec69c7d688a92970d5f319d51c69ec426c6ee..8d12cd163993a92c316c2cd0e0be9f8cce452efc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2014 Red Hat, Inc.
+ *  Copyright (C) 2014 Red Hat, 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,
index ceb03c0330f2414d63ad0695cb3b8dead86620da..76ca876bdd34368c4b7c57b54e54730bf4038838 100644 (file)
@@ -103,11 +103,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <groupId>org.opendaylight.controller.model</groupId>
       <artifactId>model-inventory</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.neutron</groupId>
-      <artifactId>neutron-spi</artifactId>
-      <version>${networkconfig.neutron.version}</version>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.openflowplugin.model</groupId>
       <artifactId>model-flow-base</artifactId>
@@ -263,6 +258,9 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
           <instructions>
             <Embed-Dependency>utils.config,utils.mdsal-openflow;type=!pom;inline=false</Embed-Dependency>
             <Embed-Transitive>true</Embed-Transitive>
+            <Export-Package>
+              org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.*
+            </Export-Package>
           </instructions>
         </configuration>
       </plugin>
index 12879dadda1c22db175238ea5b35d3002beb1fe8..c354d2dcefe32bc8d504ac8144a6c9fc0089b921 100644 (file)
@@ -19,10 +19,10 @@ import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
 import org.opendaylight.ovsdb.openstack.netvirt.MdsalHelper;
 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
@@ -1044,6 +1044,62 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
             LOG.warn("programLocalRules: No DCHP port seen in  network of {}", intf);
         }
     }
+
+    /*
+     * The function is for the new compute node joining the existing network.
+     * When a new VM is instantiated in the new compute node, neutron port add
+     * event is generated. This event is processed only for that node. So,
+     * loop through all the ports of the same network and install unicast mac
+     * flow for the VM's created on the TEP of the destination node in src node.
+     * This function will be executed even for any new VM creation in an existing
+     * network. If a cache is maintained to optimize the below flow addition, it will
+     * work only for one unstack and restack. For the next unstack and restack,
+     * it will not work since the cache would have been already deleted.
+     */
+    private void programTunnelRulesInNewNode(NeutronNetwork network,
+                                             String networkType, String segmentationId,
+                                             InetAddress src, InetAddress dst,
+                                             Node srcBridgeNode, Node dstBridgeNode,
+                                             OvsdbTerminationPointAugmentation intf){
+        try {
+            long localPort = southbound.getOFPort(intf);
+            if(localPort != 0)
+            {
+                LOG.debug("Interface update details {}", intf);
+
+                /*
+                 * When a network is added and the TEP destination is not present in a
+                 * node C1, tunnelin and broadcast rules will not be programmed, since
+                 * OF port is not created. So, when a new node C2 joins and create a new
+                 * VM, the tunnelin and broadcast rule will not be present in C1.
+                 * So, handling it in the case below to make ping work.
+                 */
+                if(securityServicesManager.getNeutronPortFromDhcpIntf(intf) == null){
+                    programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
+                }
+
+                /*
+                 * FIX for 4208 - loop through all the ports and add the VM's
+                 * unicast mac rule of the destination node in the source node.
+                 * When a new node is added, it needs to configure the VM unicast mac
+                 * flow rules which were created before it was joined to an existing
+                 * network.
+                 */
+                List<OvsdbTerminationPointAugmentation> ports = southbound.getTerminationPointsOfBridge(dstBridgeNode);
+                for (OvsdbTerminationPointAugmentation port : ports) {
+                    if(network == tenantNetworkManager.getTenantNetwork(port)){
+                        programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, port, false);
+                    }
+                    else{
+                        LOG.trace("Port {} is not part of network {}", port, network);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("Exception during handlingNeutron network add", e);
+        }
+    }
+
     @Override
     public boolean handleInterfaceUpdate(NeutronNetwork network, Node srcNode,
                                          OvsdbTerminationPointAugmentation intf) {
@@ -1060,7 +1116,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
             programVlanRules(network, srcNode, intf);
         } else if (isTunnel(networkType)){
 
-            boolean sourceTunnelStatus;
+            boolean sourceTunnelStatus = false;
             boolean destTunnelStatus = false;
             for (Node dstNode : nodes.values()) {
                 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
@@ -1080,6 +1136,8 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
                     }
                     if (destTunnelStatus) {
                         programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, false);
+                        programTunnelRulesInNewNode(network, networkType, segmentationId, src, dst,
+                                                    srcBridgeNode, dstBridgeNode, intf);
                     }
                 } else {
                     LOG.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
index ea0ab828b4cc522d0fd3b54eb637b4f246fc35c2..7faf6b048f84070a686195f433868ad595de3caf 100644 (file)
@@ -11,9 +11,9 @@ package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services;
 import java.math.BigInteger;
 import java.util.List;
 
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
@@ -49,6 +49,8 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
     private static final int DHCP_SOURCE_PORT = 67;
     private static final int DHCP_DESTINATION_PORT = 68;
     private static final String HOST_MASK = "/32";
+    private static final int PORT_RANGE_MIN = 1;
+    private static final int PORT_RANGE_MAX = 65535;
 
     public EgressAclService() {
         super(Service.EGRESS_ACL);
@@ -345,13 +347,22 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
                               NeutronSecurityRule portSecurityRule, String dstAddress,
                               boolean write, Integer protoPortMatchPriority) {
         MatchBuilder matchBuilder = new MatchBuilder();
-        String flowId = "Egress_Custom_Tcp" + segmentationId + "_" + srcMac + "_";
+        String flowId = "Egress_TCP_" + segmentationId + "_" + srcMac + "_";
         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
+
+        /* Custom TCP Match */
         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
-            flowId = flowId + portSecurityRule.getSecurityRulePortMin();
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
                                                      portSecurityRule.getSecurityRulePortMin());
         } else {
+            /* All TCP Match */
+            if(portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
+                    && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
+                flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_" +
+                    portSecurityRule.getSecurityRulePortMax()+ "_";
+                matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
+            }
             /*TODO TCP PortRange Match*/
 
         }
@@ -367,7 +378,7 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
                                                         new Ipv4Prefix(portSecurityRule
                                                                        .getSecurityRuleRemoteIpPrefix()));
         }
-        flowId = flowId + "_Permit_";
+        flowId = flowId + "_Permit";
         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
@@ -430,13 +441,22 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
                               boolean write, Integer protoPortMatchPriority) {
 
         MatchBuilder matchBuilder = new MatchBuilder();
-        String flowId = "Eress_UDP" + segmentationId + "_" + srcMac + "_";
+        String flowId = "Egress_UDP_" + segmentationId + "_" + srcMac + "_";
         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
+
+        /* Custom UDP Match */
         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
-            flowId = flowId + portSecurityRule.getSecurityRulePortMin();
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
                                                      portSecurityRule.getSecurityRulePortMin());
         } else {
+            /* All UDP Match */
+            if(portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
+                    && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
+                flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_" +
+                    portSecurityRule.getSecurityRulePortMax()+ "_";
+                matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
+            }
             /*TODO UDP PortRange Match*/
 
         }
@@ -452,7 +472,7 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
                                                         new Ipv4Prefix(portSecurityRule
                                                                        .getSecurityRuleRemoteIpPrefix()));
         }
-        flowId = flowId + "_Permit_";
+        flowId = flowId + "_Permit";
         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
index 2fe4ec5f77aa3904189d40ad8fc3ecbad2e68a12..2b9fb0ee01681b5fc9dcaeabcdc456f1c342eeab 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services;
 
 import java.math.BigInteger;
 import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.net.UnknownHostException;
 import java.util.List;
 
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
@@ -42,8 +44,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev14
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class InboundNatService extends AbstractServiceInstance implements ConfigInterface, InboundNatProvider {
+    private static final Logger LOG = LoggerFactory.getLogger(InboundNatService.class);
     public static final Class<? extends NxmNxReg> REG_FIELD = NxmNxReg3.class;
 
     public InboundNatService() {
@@ -127,6 +132,20 @@ public class InboundNatService extends AbstractServiceInstance implements Config
         InstructionBuilder ib;
 
         MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+        String ipAddress = excludedCidr.substring(0, excludedCidr.indexOf("/"));
+        InetAddress inetAddress;
+        try {
+            inetAddress = InetAddress.getByName(ipAddress);
+        } catch (UnknownHostException e) {
+            return new Status(StatusCode.BADREQUEST);
+        }
+        if (inetAddress instanceof Inet6Address) {
+            // WORKAROUND: For now ipv6 is not supported
+            // TODO: implement ipv6 cidr case
+            LOG.debug("ipv6 cidr is not implemented yet. cidr {}",
+                      excludedCidr);
+            return new Status(StatusCode.NOTIMPLEMENTED);
+        }
         MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(excludedCidr));
 
         // Goto Next Table
index 9a2eb90f7585610fed42a7e44ee21b87dff89f39..e8fa6b14c65f7496463e1b5ba4a29f874fd1f10d 100644 (file)
@@ -11,9 +11,9 @@ package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services;
 import java.math.BigInteger;
 import java.util.List;
 
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
@@ -46,6 +46,8 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
 
     private static final Logger LOG = LoggerFactory.getLogger(IngressAclService.class);
     private volatile SecurityServicesManager securityServicesManager;
+    private static final int PORT_RANGE_MIN = 1;
+    private static final int PORT_RANGE_MAX = 65535;
 
     public IngressAclService() {
         super(Service.INGRESS_ACL);
@@ -312,13 +314,22 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
 
         MatchBuilder matchBuilder = new MatchBuilder();
         FlowBuilder flowBuilder = new FlowBuilder();
-        String flowId = "Ingress_Custom_Tcp" + segmentationId + "_" + dstMac + "_";
+        String flowId = "Ingress_TCP_" + segmentationId + "_" + dstMac + "_";
         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
+
+        /* Custom TCP Match*/
         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
-            flowId = flowId + portSecurityRule.getSecurityRulePortMin();
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
                                                     portSecurityRule.getSecurityRulePortMin());
         } else {
+            /* All TCP Match */
+            if(portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
+                    && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
+                flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_" +
+                    portSecurityRule.getSecurityRulePortMax()+ "_";
+                matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
+            }
             /*TODO TCP PortRange Match*/
 
         }
@@ -336,7 +347,7 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
         }
         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
-        flowId = flowId + "_Permit_";
+        flowId = flowId + "_Permit";
         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
 
     }
@@ -357,13 +368,22 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
                               NeutronSecurityRule portSecurityRule, String srcAddress,
                               boolean write, Integer protoPortMatchPriority ) {
         MatchBuilder matchBuilder = new MatchBuilder();
-        String flowId = "ingressAclUDP" + segmentationId + "_" + dstMac + "_";
+        String flowId = "Ingress_UDP_" + segmentationId + "_" + dstMac + "_";
         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
+
+        /* Custom UDP Match */
         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
-            flowId = flowId + portSecurityRule.getSecurityRulePortMin();
+            flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
                                                     portSecurityRule.getSecurityRulePortMin());
         } else {
+            /* All UDP Match */
+            if(portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
+                    && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
+                flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_" +
+                    portSecurityRule.getSecurityRulePortMax()+ "_";
+                matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
+            }
             /*TODO TCP PortRange Match*/
 
         }
@@ -380,7 +400,7 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
         }
         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
-        flowId = flowId + "_Permit_";
+        flowId = flowId + "_Permit";
         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
 
     }
index d5389b12410705e98f6212afe1126a07894184e1..6b44c38d578df9d92d202f885aa98c942a6aab72 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services;
 
 import java.math.BigInteger;
 import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.net.UnknownHostException;
 import java.util.List;
 
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
@@ -44,8 +46,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.N
 import com.google.common.collect.Lists;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class OutboundNatService extends AbstractServiceInstance implements OutboundNatProvider, ConfigInterface {
+    private static final Logger LOG = LoggerFactory.getLogger(OutboundNatService.class);
+
     public OutboundNatService() {
         super(Service.OUTBOUND_NAT);
     }
@@ -164,6 +170,20 @@ public class OutboundNatService extends AbstractServiceInstance implements Outbo
         InstructionBuilder ib;
 
         MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
+        String ipAddress = excludedCidr.substring(0, excludedCidr.indexOf("/"));
+        InetAddress inetAddress;
+        try {
+            inetAddress = InetAddress.getByName(ipAddress);
+        } catch (UnknownHostException e) {
+            return new Status(StatusCode.BADREQUEST);
+        }
+        if (inetAddress instanceof Inet6Address) {
+            // WORKAROUND: For now ipv6 is not supported
+            // TODO: implement ipv6 cidr case
+            LOG.debug("ipv6 cidr is not implemented yet. cidr {}",
+                      excludedCidr);
+            return new Status(StatusCode.NOTIMPLEMENTED);
+        }
         MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(excludedCidr));
 
         // Goto Next Table
index 4dff41cf635594196109ff8540cb3911ce57c790..a4ce294d9d5972560cf36d3a47bc7d63ea703fcf 100644 (file)
@@ -34,7 +34,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
 import org.opendaylight.ovsdb.openstack.netvirt.MdsalHelper;
 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
index 531c238a159738804f45c1e93eb5832ba5425536..e72b4ce687635d3b1d01dc68f69f4da3b512a8b0 100644 (file)
@@ -31,9 +31,10 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
@@ -43,6 +44,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.N
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.powermock.api.mockito.PowerMockito;
 import org.powermock.modules.junit4.PowerMockRunner;
@@ -85,6 +88,8 @@ public class EgressAclServiceTest {
     private static final String SEGMENT_ID = "2";
     private static final Long DP_ID_LONG = (long) 1554;
     private static final Long LOCAL_PORT = (long) 124;
+    private static final int PORT_RANGE_MIN = 1;
+    private static final int PORT_RANGE_MAX = 65535;
     private static FlowBuilder flowBuilder;
     private static NodeBuilder nodeBuilder;
 
@@ -314,15 +319,24 @@ public class EgressAclServiceTest {
     @Test
     public void testProgramPortSecurityACLRuleAddTcp1() throws Exception {
         when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
-        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
-        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(20);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(20);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
 
-        egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
 
-        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
-        verify(writeTransaction, times(1)).submit();
-        verify(commitFuture, times(1)).get();
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(20, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port=portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
     }
 
     /**
@@ -331,15 +345,25 @@ public class EgressAclServiceTest {
     @Test
     public void testProgramPortSecurityACLRuleRemoveTcp1() throws Exception {
         when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
-        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
-        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(30);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(30);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
 
-        egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
 
-        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
-        verify(writeTransaction, times(1)).submit();
-        verify(commitFuture, times(1)).get();
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(30, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port=portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
     }
 
     /**
@@ -348,16 +372,31 @@ public class EgressAclServiceTest {
     @Test
     public void testProgramPortSecurityACLRuleAddTcp2() throws Exception {
         when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
-        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
-        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
-        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(40);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(40);
         when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
 
-        egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
 
-        verify(writeTransaction, times(4)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
-        verify(writeTransaction, times(2)).submit();
-        verify(commitFuture, times(2)).get();
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+        int port=portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
     }
 
     /**
@@ -368,14 +407,138 @@ public class EgressAclServiceTest {
         when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
         when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
         when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+        int port=portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test TCP add with port range (All TCP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddTcpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
+
+        Match match = flowBuilder.getMatch();
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match=(TcpMatch) match.getLayer4Match();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+    }
+
+    /**
+     *  Test TCP remove with port range (All TCP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveTcpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        Assert.assertEquals("Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                            PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test TCP add with port range (All TCP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddTcpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
         when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
 
-        egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
 
-        verify(writeTransaction, times(2)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
-        verify(writeTransaction, times(2)).submit();
-        verify(commitFuture, times(2)).get();
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test TCP remove with port range (All TCP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveTcpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        String expectedFlowId1 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
     }
 
     /**
@@ -387,16 +550,25 @@ public class EgressAclServiceTest {
         when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
         when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
 
-        egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
 
-        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
-        verify(writeTransaction, times(1)).submit();
-        verify(commitFuture, times(1)).get();
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
     }
 
     /**
-     *  Test UDP add with port no and CIDR selected.
+     *  Test UDP remove with port no and CIDR selected.
      */
     @Test
     public void testProgramPortSecurityACLRuleRemoveUdp1() throws Exception {
@@ -404,12 +576,21 @@ public class EgressAclServiceTest {
         when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
         when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
 
-        egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
 
-        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
-        verify(writeTransaction, times(1)).submit();
-        verify(commitFuture, times(1)).get();
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
     }
 
     /**
@@ -422,16 +603,33 @@ public class EgressAclServiceTest {
         when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
         when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
 
-        egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
 
-        verify(writeTransaction, times(4)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
-        verify(writeTransaction, times(2)).submit();
-        verify(commitFuture, times(2)).get();
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
     }
 
     /**
-     *  Test UDP add with port no and remote SG selected.
+     *  Test UDP remove with port no and remote SG selected.
      */
     @Test
     public void testProgramPortSecurityACLRuleRemoveUdp2() throws Exception {
@@ -440,12 +638,138 @@ public class EgressAclServiceTest {
         when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
         when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
 
-        egressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
 
-        verify(writeTransaction, times(2)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
-        verify(writeTransaction, times(2)).submit();
-        verify(commitFuture, times(2)).get();
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+
+    /**
+     *  Test UDP add with port (All UDP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddUdpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                            PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test UDP remove with port (All UDP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveUdpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        Assert.assertEquals("Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                            PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test UDP add with port (All UDP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddUdpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test UDP remove with port (All UDP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveUdpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(egressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        egressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        String expectedFlowId1 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Egress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
     }
 
     /**
@@ -526,9 +850,9 @@ public class EgressAclServiceTest {
         Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
         Short type = portSecurityRule.getSecurityRulePortMin().shortValue();
         Short code = portSecurityRule.getSecurityRulePortMax().shortValue();
-        String expectedFlowId1 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+        String expectedFlowId1 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
                                 + DEST_IP_1 + "_Permit";
-        String expectedFlowId2 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+        String expectedFlowId2 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
                                 + DEST_IP_2 + "_Permit";
         String actualFlowId = flowBuilder.getFlowName();
         if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
@@ -561,9 +885,9 @@ public class EgressAclServiceTest {
         Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetSource().getAddress().getValue());
         Short type = portSecurityRule.getSecurityRulePortMin().shortValue();
         Short code = portSecurityRule.getSecurityRulePortMax().shortValue();
-        String expectedFlowId1 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+        String expectedFlowId1 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
                                 + DEST_IP_1 + "_Permit";
-        String expectedFlowId2 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + type + "_" + code + "_"
+        String expectedFlowId2 = "Egress_ICMP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + type + "_" + code + "_"
                                 + DEST_IP_2 + "_Permit";
         String actualFlowId = flowBuilder.getFlowName();
         if(actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
index 6704a0a50600689c619d4ccebb5c1f88c716d065..51734e827eafd4939a295928bd381d400b1f7ccf 100644 (file)
@@ -37,9 +37,9 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
@@ -50,6 +50,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.N
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.powermock.api.mockito.PowerMockito;
 import org.powermock.modules.junit4.PowerMockRunner;
@@ -93,6 +95,8 @@ public class IngressAclServiceTest {
     private static final String SEGMENT_ID = "2";
     private static final Long DP_ID_LONG = (long) 1554;
     private static final Long LOCAL_PORT = (long) 124;
+    private static final int PORT_RANGE_MIN = 1;
+    private static final int PORT_RANGE_MAX = 65535;
     private static FlowBuilder flowBuilder;
     private static NodeBuilder nodeBuilder;
 
@@ -309,15 +313,25 @@ public class IngressAclServiceTest {
     @Test
     public void testProgramPortSecurityACLRuleAddTcp1() throws Exception {
         when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
-        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
-        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(20);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(20);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
 
-        ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
 
-        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
-        verify(writeTransaction, times(1)).submit();
-        verify(commitFuture, times(1)).get();
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(20, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
     }
 
     /**
@@ -326,15 +340,25 @@ public class IngressAclServiceTest {
     @Test
     public void testProgramPortSecurityACLRuleRemoveTcp1() throws Exception {
         when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
-        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
-        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(15);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(15);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
 
-        ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
 
-        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
-        verify(writeTransaction, times(1)).submit();
-        verify(commitFuture, times(1)).get();
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(15, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
     }
 
     /**
@@ -347,12 +371,29 @@ public class IngressAclServiceTest {
         when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
         when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
 
-        ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
 
-        verify(writeTransaction, times(4)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
-        verify(writeTransaction, times(2)).submit();
-        verify(commitFuture, times(2)).get();
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
     }
 
     /**
@@ -365,12 +406,143 @@ public class IngressAclServiceTest {
         when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
         when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
 
-        ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
 
-        verify(writeTransaction, times(2)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
-        verify(writeTransaction, times(2)).submit();
-        verify(commitFuture, times(2)).get();
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getTcpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+
+    /**
+     *  Test TCP add with port (All TCP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddTcpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                            PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test TCP remove with port (All TCP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveTcpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        Assert.assertEquals("Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                            PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test TCP add with port (All TCP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddTcpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                            PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test TCP remove with port (All TCP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveTcpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("tcp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof TcpMatch);
+        TcpMatch layer4Match = (TcpMatch) match.getLayer4Match();
+        String expectedFlowId1 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_TCP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
     }
 
     /**
@@ -382,16 +554,26 @@ public class IngressAclServiceTest {
         when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
         when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
 
-        ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
 
-        verify(writeTransaction, times(2)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
-        verify(writeTransaction, times(1)).submit();
-        verify(commitFuture, times(1)).get();
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
     }
 
     /**
-     *  Test UDP add with port no and CIDR selected.
+     *  Test UDP remove with port no and CIDR selected.
      */
     @Test
     public void testProgramPortSecurityACLRuleRemoveUdp1() throws Exception {
@@ -399,12 +581,22 @@ public class IngressAclServiceTest {
         when(portSecurityRule.getSecurityRulePortMax()).thenReturn(50);
         when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
 
-        ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
 
-        verify(writeTransaction, times(1)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
-        verify(writeTransaction, times(1)).submit();
-        verify(commitFuture, times(1)).get();
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +
+                            "_" + port + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
     }
 
     /**
@@ -417,16 +609,33 @@ public class IngressAclServiceTest {
         when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
         when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
 
-        ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,true);
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
 
-        verify(writeTransaction, times(4)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class), eq(true));
-        verify(writeTransaction, times(2)).submit();
-        verify(commitFuture, times(2)).get();
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
     }
 
     /**
-     *  Test UDP add with port no and remote SG selected.
+     *  Test UDP remove with port no and remote SG selected.
      */
     @Test
     public void testProgramPortSecurityACLRuleRemoveUdp2() throws Exception {
@@ -435,12 +644,141 @@ public class IngressAclServiceTest {
         when(portSecurityRule.getSecurityRulePortMin()).thenReturn(50);
         when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
         when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
 
-        ingressAclServiceSpy.programPortSecurityAcl(Long.valueOf(1554), "2", MAC_ADDRESS, 124, securityGroup,neutronSrcIpList,false);
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
 
-        verify(writeTransaction, times(2)).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
-        verify(writeTransaction, times(2)).submit();
-        verify(commitFuture, times(2)).get();
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        UdpMatch layer4Match = (UdpMatch) match.getLayer4Match();
+        Assert.assertEquals(50, layer4Match.getUdpDestinationPort().getValue().intValue());
+        int port = portSecurityRule.getSecurityRulePortMin();
+        String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_1 +
+                "_Permit";
+        String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + port + "_" + DEST_IP_2 +
+                "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test UDP add with ports (All UDP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddUdpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN  + "_" +
+                            PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test UDP remove with ports (All UDP) and CIDR selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveUdpAll1() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        Assert.assertEquals("Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS + "_" + PORT_RANGE_MIN  + "_" +
+                PORT_RANGE_MAX + "_0.0.0.0/24_Permit", flowBuilder.getFlowName());
+    }
+
+    /**
+     *  Test UDP add with ports (All UDP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleAddUdpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "writeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, true);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                        PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
+    }
+
+    /**
+     *  Test UDP remove with ports (All UDP) and remote SG selected.
+     */
+    @Test
+    public void testProgramPortSecurityACLRuleRemoveUdpAll2() throws Exception {
+        when(portSecurityRule.getSecurityRuleProtocol()).thenReturn("udp");
+        when(portSecurityRule.getSecurityRulePortMax()).thenReturn(PORT_RANGE_MAX);
+        when(portSecurityRule.getSecurityRulePortMin()).thenReturn(PORT_RANGE_MIN);
+        when(portSecurityRule.getSecurityRuleRemoteIpPrefix()).thenReturn("0.0.0.0/24");
+        when(portSecurityRule.getSecurityRemoteGroupID()).thenReturn("85cc3048-abc3-43cc-89b3-377341426ac5");
+        PowerMockito.doAnswer(answer()).when(ingressAclServiceSpy, "removeFlow", any(FlowBuilder.class),
+                                             any(NodeBuilder.class));
+        ingressAclServiceSpy.programPortSecurityAcl(DP_ID_LONG, SEGMENT_ID, MAC_ADDRESS, LOCAL_PORT, securityGroup,
+                                                   neutronSrcIpList, false);
+
+        Match match = flowBuilder.getMatch();
+        EthernetMatch ethMatch = match.getEthernetMatch();
+        Assert.assertEquals(MAC_ADDRESS, ethMatch.getEthernetDestination().getAddress().getValue());
+
+        Assert.assertTrue(match.getLayer4Match() instanceof UdpMatch);
+        String expectedFlowId1 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                        PORT_RANGE_MAX + "_" + DEST_IP_1 + "_Permit";
+        String expectedFlowId2 = "Ingress_UDP_" + SEGMENT_ID + "_" + MAC_ADDRESS +"_" + PORT_RANGE_MIN + "_" +
+                PORT_RANGE_MAX + "_" + DEST_IP_2 + "_Permit";
+        String actualFlowId = flowBuilder.getFlowName();
+        if (actualFlowId.equals(expectedFlowId1) || actualFlowId.equals(expectedFlowId2)) {
+            Assert.assertTrue(true);
+        } else {
+            Assert.assertTrue(false);
+        }
     }
 
     /**
index 706531d6df2f8c7c9eeb07090eab1314b7f21a20..8ffd3c9421adb835e4694a4df851530d5e358136 100644 (file)
@@ -22,6 +22,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <version>1.2.1-SNAPSHOT</version>
   <packaging>bundle</packaging>
 
+  <properties>
+    <sfc.project.version>0.2.0-SNAPSHOT</sfc.project.version>
+  </properties>
+
   <dependencies>
     <dependency>
       <groupId>org.opendaylight.mdsal.model</groupId>
@@ -35,5 +39,28 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <groupId>org.opendaylight.mdsal.model</groupId>
       <artifactId>yang-ext</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>sfc-model</artifactId>
+      <version>${sfc.project.version}</version>
+    </dependency>
   </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.yang.gen.v1.*;
+            </Export-Package>
+            <!--<Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>-->
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
 </project>
diff --git a/openstack/net-virt-sfc/api/src/main/yang/ietf-acl.yang b/openstack/net-virt-sfc/api/src/main/yang/ietf-acl.yang
deleted file mode 100644 (file)
index 3549cb4..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-module ietf-acl {
-  yang-version 1;
-
-  namespace "urn:ietf:params:xml:ns:yang:ietf-acl";
-
-  prefix acl;
-
-  import ietf-yang-types {
-      prefix "ietf";
-  }
-
-  import packet-fields {
-      prefix "packet-fields";
-  }
-
-  organization
-    "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
-
-  contact
-    "WG Web: http://tools.ietf.org/wg/netmod/
-    WG List: netmod@ietf.org
-
-    WG Chair: Juergen Schoenwaelder
-    j.schoenwaelder@jacobs-university.de
-
-    WG Chair: Tom Nadeau
-    tnadeau@lucidvision.com
-
-    Editor: Dean Bogdanovic
-    deanb@juniper.net
-
-    Editor: Kiran Agrahara Sreenivasa
-    kkoushik@brocade.com
-
-    Editor: Lisa Huang
-    yihuan@cisco.com
-
-    Editor: Dana Blair
-    dblair@cisco.com";
-
-  description
-    "This YANG module defines a component that describing the
-    configuration of Access Control Lists (ACLs).";
-
-  revision 2014-10-10 {
-    description "Creating base model for netmod.";
-    reference
-      "RFC 6020: YANG - A Data Modeling Language for the
-      Network Configuration Protocol (NETCONF)";
-  }
-
-  identity acl-base {
-    description "Base acl type for all ACL type identifiers.";
-  }
-
-  identity ip-acl {
-    base "acl:acl-base";
-    description "layer 3 ACL type";
-  }
- identity eth-acl {
-    base "acl:acl-base";
-    description "layer 2 ACL type";
-  }
-
-  typedef acl-type {
-    type identityref {
-      base "acl-base";
-    }
-    description
-      "This type is used to refer to an Access Control List
-      (ACL) type";
-  }
-
-  typedef acl-ref {
-    type leafref {
-      path "/acl:access-lists/acl:access-list/acl:acl-name";
-    }
-    description "This type is used by data models that
-    need to referenced an acl";
-  }
-
-  container access-lists {
-    description
-      "Access control lists.";
-
-    list access-list {
-      key acl-name;
-      description "
-        An access list (acl) is an ordered list of
-        access list entries (ace). Each ace has a
-        sequence number to define the order, list
-        of match criteria, and a list of actions.
-        Since there are several kinds of acls
-        implementeded with different attributes for
-        each and different for each vendor, this
-        model accomodates customizing acls for
-        each kind and for each vendor.
-        ";
-
-      leaf acl-name {
-        type string;
-        description "The name of access-list.
-        A device MAY restrict the length and value of
-        this name, possibly space and special
-        characters are not allowed.";
-      }
-
-      leaf acl-type {
-        type acl-type;
-        description "Type of ACL";
-      }
-
-      container acl-oper-data {
-        config false;
-
-        description "Overall ACL operational data";
-        leaf match-counter {
-          type ietf:counter64;
-          description "Total match count for ACL";
-        }
-
-        leaf-list targets {
-          type string;
-          description "List of targets where ACL is applied";
-        }
-      }
-
-      container access-list-entries {
-        description "The access-list-entries container contains
-          a list of access-list-entry(ACE).";
-
-          list access-list-entry {
-            key rule-name;
-            ordered-by user;
-
-            description "List of access list entries(ACE)";
-            leaf rule-name {
-              type string;
-              description "Entry name.";
-            }
-
-            container matches {
-              description "Define match criteria";
-              choice ace-type {
-                description "Type of ace.";
-                case ace-ip {
-                  uses packet-fields:acl-ip-header-fields;
-                  choice ace-ip-version {
-                    description "Choice of IP version.";
-                    case ace-ipv4 {
-                      uses packet-fields:acl-ipv4-header-fields;
-                    }
-                    case ace-ipv6 {
-                      uses packet-fields:acl-ipv6-header-fields;
-                    }
-                  }
-                }
-                case ace-eth {
-                  uses packet-fields:acl-eth-header-fields;
-                }
-              }
-              uses packet-fields:metadata;
-          }
-
-          container actions {
-            description "Define action criteria";
-            choice packet-handling {
-              default deny;
-
-              description "Packet handling action.";
-              case deny {
-                leaf deny {
-                  type empty;
-                  description "Deny action.";
-                }
-              }
-              case permit {
-                leaf permit {
-                  type empty;
-                  description "Permit action.";
-                }
-              }
-            }
-          }
-
-          container ace-oper-data {
-            config false;
-
-            description "Per ace operational data";
-            leaf match-counter {
-              type ietf:counter64;
-              description "Number of matches for an ace";
-            }
-          }
-        }
-      }
-    }
-  }
-}
index 50b90bdb449e44c35f276a8804b491ed3069f3d9..3d1a813e155f39a79751643c8c000736e2441921 100644 (file)
@@ -3,7 +3,7 @@ module netvirt-sfc-acl {
     namespace "urn:opendaylight:params:xml:ns:yang:netvirt:sfc:acl";
     prefix "acl";
 
-    import ietf-acl { prefix ietf-acl;}
+    import ietf-access-control-list { prefix ietf-acl;}
     import yang-ext { prefix ext; }
 
     revision "2015-01-05" {
@@ -11,8 +11,8 @@ module netvirt-sfc-acl {
     }
 
     // TODO: Add choice for Neutron and add fields there instead of at the root of matches
-    augment "/ietf-acl:access-lists/ietf-acl:access-list/ietf-acl:access-list-entries" +
-            "/ietf-acl:access-list-entry/ietf-acl:matches" {
+  //augment "/ietf-acl:access-lists/ietf-acl:access-list/ietf-acl:access-list-entries/ietf-acl:access-list-entry/ietf-acl:matches" {
+    augment "/ietf-acl:access-lists/ietf-acl:acl/ietf-acl:access-list-entries/ietf-acl:ace/ietf-acl:matches" {
         description "Neutron network uuid";
         leaf network-uuid {
             type string;
@@ -20,8 +20,7 @@ module netvirt-sfc-acl {
     }
 
     // TODO: Add choice for Neutron and add fields there instead of at the root of matches
-    augment "/ietf-acl:access-lists/ietf-acl:access-list/ietf-acl:access-list-entries" +
-            "/ietf-acl:access-list-entry/ietf-acl:actions" {
+    augment "/ietf-acl:access-lists/ietf-acl:acl/ietf-acl:access-list-entries/ietf-acl:ace/ietf-acl:actions" {
         description "Redirect traffic to SFC identified by SFC Path ID";
         leaf redirect-sfc {
             type string;
diff --git a/openstack/net-virt-sfc/api/src/main/yang/packet-fields.yang b/openstack/net-virt-sfc/api/src/main/yang/packet-fields.yang
deleted file mode 100644 (file)
index bea6777..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-module packet-fields {
-    yang-version 1;
-
-    namespace "urn:ietf:params:xml:ns:yang:packet-fields";
-
-    prefix packet-fields;
-
-    import ietf-inet-types {
-        prefix "inet";
-    }
-
-    import ietf-yang-types {
-        prefix "yang";
-    }
-
-    revision 2014-06-25 {
-        description "Initial version of packet fields used by access-lists";
-    }
-
-    grouping acl-transport-header-fields {
-        description "Transport header fields";
-
-        container source-port-range {
-             description "inclusive range of source ports";
-             leaf lower-port {
-                 mandatory true;
-                 type inet:port-number;
-             }
-             leaf upper-port {
-                 type inet:port-number;
-             }
-        }
-
-        container destination-port-range {
-             description "inclusive range of destination ports";
-             leaf lower-port {
-                 mandatory true;
-                 type inet:port-number;
-             }
-             leaf upper-port {
-                 type inet:port-number;
-             }
-        }
-    }
-
-    grouping acl-ip-header-fields {
-        description "Header fields common to ipv4 and ipv6";
-
-        uses acl-transport-header-fields;
-
-        leaf dscp {
-            type inet:dscp;
-        }
-
-        leaf ip-protocol {
-            type uint8;
-        }
-
-    }
-
-    grouping acl-ipv4-header-fields {
-        description "fields in IPv4 header";
-
-        leaf destination-ipv4-address {
-            type inet:ipv4-prefix;
-        }
-
-        leaf source-ipv4-address {
-            type inet:ipv4-prefix;
-        }
-
-    }
-
-    grouping acl-ipv6-header-fields {
-        description "fields in IPv6 header";
-
-        leaf destination-ipv6-address {
-            type inet:ipv6-prefix;
-        }
-
-        leaf source-ipv6-address {
-            type inet:ipv6-prefix;
-        }
-
-        leaf flow-label {
-            type inet:ipv6-flow-label;
-        }
-
-    }
-
-    grouping acl-eth-header-fields {
-        description "fields in ethernet header";
-
-        leaf destination-mac-address {
-            type yang:mac-address;
-        }
-
-        leaf destination-mac-address-mask {
-            type yang:mac-address;
-        }
-
-        leaf source-mac-address {
-            type yang:mac-address;
-        }
-
-        leaf source-mac-address-mask {
-            type yang:mac-address;
-        }
-    }
-
-    grouping timerange {
-        description "Define time range entries to restrict
-            the access. The time range is identified by a name
-            and then referenced by a function, so that those
-            time restrictions are imposed on the function itself.";
-
-        container absolute {
-            description
-                "Absolute time and date that
-                the associated function starts
-                going into effect.";
-
-            leaf start {
-                type yang:date-and-time;
-                description
-                "Start time and date";
-            }
-            leaf end {
-                type yang:date-and-time;
-                description "Absolute end time and date";
-            }
-            leaf active {
-                type boolean;
-                default "true";
-                description
-                    "Specify the associated function
-                    active or inactive state when
-                    starts going into effect";
-            }
-        } // container absolute
-    } //grouping timerange
-
-    grouping metadata {
-        description "Fields associated with a packet but not in the header";
-
-        leaf input-interface {
-             description "Packet was received on this interface";
-             type string;
-        }
-        uses timerange;
-    }
-}
index 6953792d3699af3fb6c4423931cd96fb6d813fe4..01fb239e0a0b09ca4db7f278c487135641b09322 100644 (file)
@@ -24,12 +24,14 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <maven>3.1.1</maven>
   </prerequisites>
   <properties>
+    <configfile.directory>etc/opendaylight/karaf</configfile.directory>
+    <dlux.version>0.3.0-SNAPSHOT</dlux.version>
     <mdsal.model.version>0.8.0-SNAPSHOT</mdsal.model.version>
     <mdsal.version>1.3.0-SNAPSHOT</mdsal.version>
+    <openflowplugin.version>0.2.0-SNAPSHOT</openflowplugin.version>
     <restconf.version>1.3.0-SNAPSHOT</restconf.version>
+    <sfc.version>0.2.0-SNAPSHOT</sfc.version>
     <yangtools.version>0.8.0-SNAPSHOT</yangtools.version>
-    <dlux.version>0.3.0-SNAPSHOT</dlux.version>
-    <configfile.directory>etc/opendaylight/karaf</configfile.directory>
   </properties>
   <dependencyManagement>
     <dependencies>
@@ -48,6 +50,13 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
         <type>pom</type>
         <scope>import</scope>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.ovsdb</groupId>
+        <artifactId>ovsdb-artifacts</artifactId>
+        <version>${project.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
     </dependencies>
   </dependencyManagement>
   <dependencies>
@@ -91,6 +100,37 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>features-ovsdb</artifactId>
+      <classifier>features</classifier>
+      <version>${project.version}</version>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>features-openflowplugin</artifactId>
+      <version>${openflowplugin.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfc</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfc-ovs</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>openstack.net-virt-sfc-impl</artifactId>
@@ -120,5 +160,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <artifactId>utils.mdsal-utils</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.servicehelper</artifactId>
+      <version>${project.version}</version>
+    </dependency>
   </dependencies>
 </project>
index 09cff5347d1047699c3a36eddf0d8655e7fb3c34..1b4ca16239b492ef20782f1e8df8308edc3bf561 100644 (file)
@@ -10,22 +10,32 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
 <features name="odl-ovsdb-sfc-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
-  <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.mdsal.model/features-mdsal-model/${mdsal.model.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.netconf/features-restconf/${restconf.version}/xml/features</repository>
-  <repository>mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features</repository>
-  <repository>mvn:org.opendaylight.ovsdb/southbound-features/1.2.1-SNAPSHOT/xml/features</repository>
+  <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/${openflowplugin.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.ovsdb/features-ovsdb/${project.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.ovsdb/southbound-features/${project.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.sfc/features-sfc/${sfc.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.sfc/features-sfc-ovs/${sfc.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
   <feature name='odl-ovsdb-sfc-api' version='${project.version}' description='OpenDaylight :: ovsdb-sfc :: api'>
     <feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
     <bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt-sfc-api/${project.version}</bundle>
   </feature>
   <feature name='odl-ovsdb-sfc' version='${project.version}' description='OpenDaylight :: ovsdb-sfc'>
     <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
-    <feature version='${project.version}'>odl-ovsdb-sfc-api</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-nsf-model</feature>
     <feature version='${project.version}'>odl-ovsdb-southbound-impl</feature>
-    <bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt-sfc-impl/${project.version}</bundle>
+    <feature version='${project.version}'>odl-ovsdb-openstack</feature>
+    <feature version='${sfc.version}'>odl-sfc-core</feature>
+    <feature version='${sfc.version}'>odl-sfc-ovs</feature>
+    <feature version="${openflowplugin.version}">odl-openflowplugin-flow-services</feature>
+    <feature version='${project.version}'>odl-ovsdb-sfc-api</feature>
     <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/${project.version}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/utils.servicehelper/${project.version}</bundle>
+    <bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt-sfc-impl/${project.version}</bundle>
     <configfile finalname="${configfile.directory}/openstack.net-virt-sfc.xml">mvn:org.opendaylight.ovsdb/openstack.net-virt-sfc-impl/${project.version}/xml/config</configfile>
   </feature>
   <feature name='odl-ovsdb-sfc-rest' version='${project.version}' description='OpenDaylight :: ovsdb-sfc :: REST'>
index 224fc9bb08cb1b78728368a7ed14e95cba57f06a..9dd3154362cc4931297cf5646899143e490bb89a 100644 (file)
@@ -14,7 +14,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <feature name='odl-ovsdb-sfc-test' version='${project.version}' description='OpenDaylight :: ovsdb-sfc-test'>
     <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.ovsdb/utils.southbound-utils/${project.version}</bundle>
-    <feature version='${project.version}'>odl-ovsdb-southbound-impl-ui</feature>
     <feature version='${project.version}'>odl-ovsdb-sfc-ui</feature>
   </feature>
 </features>
index 9de4d9c88a85950c1a0fbcab7f20ec1eaec72295..80f9a173c98dee73663f28263858bb078b49d53e 100644 (file)
@@ -25,7 +25,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <packaging>bundle</packaging>
 
   <properties>
+    <networkconfig.neutron.version>0.6.0-SNAPSHOT</networkconfig.neutron.version>
+    <openflowplugin.version>0.2.0-SNAPSHOT</openflowplugin.version>
     <sonar.jacoco.itReportPath>../it/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+    <sfc.project.version>0.2.0-SNAPSHOT</sfc.project.version>
   </properties>
 
   <dependencies>
@@ -34,6 +37,31 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>openstack.net-virt-sfc-api</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openstack.net-virt-providers</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>utils.mdsal-openflow</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.servicehelper</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
@@ -59,9 +87,33 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>sal-common-api</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.opendaylight.ovsdb</groupId>
-      <artifactId>utils.mdsal-utils</artifactId>
-      <version>${project.version}</version>
+      <groupId>org.opendaylight.openflowplugin.model</groupId>
+      <artifactId>model-flow-base</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin.model</groupId>
+      <artifactId>model-flow-service</artifactId>
+      <version>${openflowplugin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-topology</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>sfc-model</artifactId>
+      <version>${sfc.project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>sfc-ovs</artifactId>
+      <version>${sfc.project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>sfc-provider</artifactId>
+      <version>${sfc.project.version}</version>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
@@ -92,11 +144,22 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
 
   <build>
     <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Embed-Dependency>utils.mdsal-openflow;type=!pom;inline=false</Embed-Dependency>
+            <Embed-Transitive>true</Embed-Transitive>
+          </instructions>
+        </configuration>
+      </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
         <configuration>
-          <propertyExpansion>checkstyle.checker.severity=error</propertyExpansion>
+          <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
         </configuration>
       </plugin>
       <plugin>
index 6423930f6f34140e173eb9318c5da086ec0077c1..1aa106ae18a911d76b08b871f2e182aa6f9ba65a 100644 (file)
@@ -11,6 +11,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <capability>urn:opendaylight:params:xml:ns:yang:netvirt:sfc?module=netvirt-sfc&amp;revision=2014-12-10</capability>
     <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
     <capability>urn:opendaylight:params:xml:ns:yang:southbound:impl?module=southbound-impl&amp;revision=2014-12-10</capability>
+    <capability>urn:opendaylight:params:xml:ns:yang:netvirt:impl?module=netvirt-impl&amp;revision=2015-05-13</capability>
+    <capability>urn:opendaylight:params:xml:ns:yang:netvirt:providers:impl?module=netvirt-providers-impl&amp;revision=2015-05-13</capability>
   </required-capabilities>
   <configuration>
 
index 302be54ae402e7d8f80144f16436ee66d7cb0c55..f263c0f5dfd45a559755163592c0297b2f9bab40 100644 (file)
@@ -14,12 +14,12 @@ import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13.INetvirtSfcOF13Provider;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.AccessLists;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessList;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessListKey;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.AccessListEntries;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.AccessListEntry;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.AccessListEntryKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntries;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
@@ -31,7 +31,7 @@ import org.slf4j.LoggerFactory;
 /**
  * Data tree listener for AccessList.
  */
-public class NetvirtSfcAclListener extends AbstractDataTreeListener<AccessList> {
+public class NetvirtSfcAclListener extends AbstractDataTreeListener<Acl> {
     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcAclListener.class);
     private ListenerRegistration<NetvirtSfcAclListener> listenerRegistration;
     private MdsalUtils dbutils;
@@ -42,7 +42,7 @@ public class NetvirtSfcAclListener extends AbstractDataTreeListener<AccessList>
      * @param db MdSal {@link DataBroker}
      */
     public NetvirtSfcAclListener(final INetvirtSfcOF13Provider provider, final DataBroker db) {
-        super(provider, AccessList.class);
+        super(provider, Acl.class);
         Preconditions.checkNotNull(db, "DataBroker can not be null!");
 
         dbutils = new MdsalUtils(db);
@@ -50,10 +50,10 @@ public class NetvirtSfcAclListener extends AbstractDataTreeListener<AccessList>
     }
 
     private void registrationListener(final DataBroker db) {
-        final DataTreeIdentifier<AccessList> treeId =
+        final DataTreeIdentifier<Acl> treeId =
                 new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, getIetfAclIid());
         try {
-            LOG.info("Registering Data Change Listener for Netvirt AccesList configuration.");
+            LOG.info("Registering Data Change Listener for NetvirtSfc AccesList configuration.");
             listenerRegistration = db.registerDataTreeChangeListener(treeId, this);
         } catch (final Exception e) {
             LOG.warn("Netvirt AccesList DataChange listener registration fail!");
@@ -76,8 +76,8 @@ public class NetvirtSfcAclListener extends AbstractDataTreeListener<AccessList>
     }
 
     @Override
-    public void remove(final InstanceIdentifier<AccessList> identifier,
-                       final AccessList removeDataObj) {
+    public void remove(final InstanceIdentifier<Acl> identifier,
+                       final Acl removeDataObj) {
         Preconditions.checkNotNull(removeDataObj, "Removed object can not be null!");
         String aclName = removeDataObj.getAclName();
 
@@ -96,13 +96,13 @@ public class NetvirtSfcAclListener extends AbstractDataTreeListener<AccessList>
     }
 
     @Override
-    public void update(final InstanceIdentifier<AccessList> identifier,
-                       final AccessList original, final AccessList update) {
+    public void update(final InstanceIdentifier<Acl> identifier,
+                       final Acl original, final Acl update) {
     }
 
     @Override
-    public void add(final InstanceIdentifier<AccessList> identifier,
-                    final AccessList addDataObj) {
+    public void add(final InstanceIdentifier<Acl> identifier,
+                    final Acl addDataObj) {
         Preconditions.checkNotNull(addDataObj, "Added object can not be null!");
         String aclName = addDataObj.getAclName();
         LOG.debug("Adding accesslist = {}", identifier);
@@ -124,19 +124,19 @@ public class NetvirtSfcAclListener extends AbstractDataTreeListener<AccessList>
         return InstanceIdentifier.create(Classifiers.class);
     }
 
-    public InstanceIdentifier<AccessList> getIetfAclIid() {
-        return InstanceIdentifier.create(AccessLists.class).child(AccessList.class);
+    public InstanceIdentifier<Acl> getIetfAclIid() {
+        return InstanceIdentifier.create(AccessLists.class).child(Acl.class);
     }
 
     /**
-     * Create an {@link AccessListEntry} {@link InstanceIdentifier}.
+     * Create an {@link Ace} {@link InstanceIdentifier}.
      * @param aclName is the name of the ACL
      * @param ruleName is the name of the rule
-     * @return the {@link AccessListEntry} {@link InstanceIdentifier}
+     * @return the {@link Ace} {@link InstanceIdentifier}
      */
-    public InstanceIdentifier<AccessListEntry> getIetfAclEntryIid(String aclName, String ruleName) {
-        return InstanceIdentifier.create(AccessLists.class).child(AccessList.class,
-                new AccessListKey(aclName)).child(AccessListEntries.class).child(AccessListEntry.class,
-                new AccessListEntryKey(ruleName));
+    public InstanceIdentifier<Ace> getIetfAclEntryIid(String aclName, String ruleName) {
+        return InstanceIdentifier.create(AccessLists.class).child(Acl.class,
+                new AclKey(aclName)).child(AccessListEntries.class).child(Ace.class,
+                new AceKey(ruleName));
     }
 }
index df1102f83c5dfe2b371bcd58ccd1e56009295703..af8c8968f335bd3f5fbc73dce5413efb0c5ad2f5 100644 (file)
@@ -14,9 +14,9 @@ import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13.INetvirtSfcOF13Provider;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.AccessLists;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessList;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessListKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
@@ -51,7 +51,7 @@ public class NetvirtSfcClassifierListener extends AbstractDataTreeListener<Class
         final DataTreeIdentifier<Classifier> treeId =
                 new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, getClassifierIid());
         try {
-            LOG.info("Registering Data Change Listener for Netvirt Classifier configuration.");
+            LOG.info("Registering Data Change Listener for NetvirtSfc Classifier configuration.");
             listenerRegistration = db.registerDataTreeChangeListener(treeId, this);
         } catch (final Exception e) {
             LOG.warn("Netvirt Classifier DataChange listener registration fail!");
@@ -79,7 +79,7 @@ public class NetvirtSfcClassifierListener extends AbstractDataTreeListener<Class
         Preconditions.checkNotNull(removeDataObj, "Added object can not be null!");
         String aclName = removeDataObj.getAcl();
         // Read the ACL information from data store and make sure it exists.
-        AccessList acl = dbutils.read(LogicalDatastoreType.CONFIGURATION,getIetfAclIid(aclName));
+        Acl acl = dbutils.read(LogicalDatastoreType.CONFIGURATION, getIetfAclIid(aclName));
         if (acl == null) {
             LOG.debug("IETF ACL with name ={} is not yet configured. skip this operation", aclName);
             return;
@@ -108,7 +108,7 @@ public class NetvirtSfcClassifierListener extends AbstractDataTreeListener<Class
         Preconditions.checkNotNull(addDataObj, "Added object can not be null!");
         String aclName = addDataObj.getAcl();
         // Read the ACL information from data store and make sure it exists.
-        AccessList acl = dbutils.read(LogicalDatastoreType.CONFIGURATION,getIetfAclIid(aclName));
+        Acl acl = dbutils.read(LogicalDatastoreType.CONFIGURATION,getIetfAclIid(aclName));
         if (acl == null) {
             LOG.debug("IETF ACL with name ={} is not yet configured. skip this operation", aclName);
             return;
@@ -128,7 +128,7 @@ public class NetvirtSfcClassifierListener extends AbstractDataTreeListener<Class
         return InstanceIdentifier.create(Classifiers.class).child(Classifier.class);
     }
 
-    private InstanceIdentifier<AccessList> getIetfAclIid(String aclName) {
-        return InstanceIdentifier.create(AccessLists.class).child(AccessList.class, new AccessListKey(aclName));
+    private InstanceIdentifier<Acl> getIetfAclIid(String aclName) {
+        return InstanceIdentifier.create(AccessLists.class).child(Acl.class, new AclKey(aclName));
     }
 }
index 144514f9df74da5b8b09c736613b2f3ab28cf374..3dba7b4b57b779a62eaaf99b687ed665b8ea5ce9 100644 (file)
@@ -19,26 +19,17 @@ import org.slf4j.LoggerFactory;
 
 public class NetvirtSfcProvider implements BindingAwareProvider, AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcProvider.class);
-    private DataBroker dataBroker = null;
-    private BundleContext bundleContext = null;
     private NetvirtSfcAclListener aclListener;
-
     private NetvirtSfcClassifierListener classfierListener;
-    private INetvirtSfcOF13Provider provider;
-
-    public NetvirtSfcProvider(BundleContext bundleContext) {
-        LOG.info("NetvirtProvider: bundleContext: {}", bundleContext);
-        this.bundleContext = bundleContext;
-    }
 
     @Override
     public void onSessionInitiated(ProviderContext session) {
         LOG.info("NetvirtSfcProvider Session Initiated");
-        dataBroker = session.getSALService(DataBroker.class);
+        DataBroker dataBroker = session.getSALService(DataBroker.class);
 
-        provider = new NetvirtSfcOF13Provider(this.dataBroker);
-        aclListener = new NetvirtSfcAclListener(provider, this.dataBroker);
-        classfierListener = new NetvirtSfcClassifierListener(provider, this.dataBroker);
+        INetvirtSfcOF13Provider provider = new NetvirtSfcOF13Provider(dataBroker);
+        aclListener = new NetvirtSfcAclListener(provider, dataBroker);
+        classfierListener = new NetvirtSfcClassifierListener(provider, dataBroker);
     }
 
     @Override
index 067999ec2d61fdf596728068594ed04ebfe1fd1c..43ff43f02175361e8c952bbcd11ff90302bc86d6 100644 (file)
@@ -8,7 +8,7 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13;
 
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
 
 /**
@@ -24,7 +24,7 @@ public interface INetvirtSfcOF13Provider {
      * @param sff - Service Function Forwarder
      * @param acl - Access list includes rules that need to be installed in a SFF.
      */
-    public void addClassifierRules(Sff sff, AccessList acl);
+    public void addClassifierRules(Sff sff, Acl acl);
 
     /**
      * Method removes the OF rules corresponding to rules within ACL
@@ -33,5 +33,5 @@ public interface INetvirtSfcOF13Provider {
      * @param sff - Service Function Forwarder
      * @param acl - Access list includes rules that need to be installed in a SFF.
      */
-    public void removeClassifierRules(Sff sff, AccessList acl);
+    public void removeClassifierRules(Sff sff, Acl acl);
 }
index ca75a5879cf681a5967d9ab3a8fee0f5f7683f5c..a44b62360f5233fc6c130ada8fbfd7e5dc171cb1 100644 (file)
 
 package org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13;
 
+import java.util.Iterator;
+import java.util.List;
+
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessList;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
+import org.opendaylight.sfc.sfc_ovs.provider.SfcOvsUtil;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Actions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.actions.packet.handling.Deny;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.actions.packet.handling.Permit;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+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.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Open vSwitch OpenFlow 1.3 Networking Provider for Netvirt SFC
  * @author Arun Yerra
  */
 public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{
+    private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcOF13Provider.class);
+    private static final int DEFAULT_FLOW_PRIORITY = 32768;
+    private volatile NodeCacheManager nodeCacheManager;
+    private volatile Southbound southbound;
+    private MdsalUtils dbutils;
+    private PipelineOrchestrator orchestrator;
 
-    private final DataBroker dataService;
-
+    /**
+     * {@link NetvirtSfcOF13Provider} constructor.
+     * @param dataBroker MdSal {@link DataBroker}
+     */
     public NetvirtSfcOF13Provider(final DataBroker dataBroker) {
-        this.dataService = Preconditions.checkNotNull(dataBroker, "DataBroker can not be null!");
+        Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
+
+        //this.dataService = dataBroker;
+        dbutils = new MdsalUtils(dataBroker);
+
+        this.setDependencies(null);
     }
 
     @Override
-    public void addClassifierRules(Sff sff, AccessList acl) {
-        // TODO Auto-generated method stub
+    public void addClassifierRules(Sff sff, Acl acl) {
+        Preconditions.checkNotNull(sff, "Input service function forwarder cannot be NULL!");
+        Preconditions.checkNotNull(acl, "Input accesslist cannot be NULL!");
+
+        // Validate if any service function forwarder exists by the name, using SFC provider APIs.
+        ServiceFunctionForwarder serviceForwarder =
+                SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sff.getName());
+        if (serviceForwarder == null) {
+            LOG.debug("Service Function Forwarder = {} not yet configured. Skip processing !!", sff.getName());
+            return;
+        }
+
+        // If a service function forwarder exists, then get the corresponding OVS Bridge details and Openflow NodeId.
+        // If OVS Bridge augmentation is configured, the following API returns NULL.
+        String datapathId = SfcOvsUtil.getOpenFlowNodeIdForSff(serviceForwarder);
+        if (datapathId == null) {
+            LOG.debug("Service Function Forwarder = {} is not augemented with "
+                    + "OVS Bridge Information. Skip processing!!", sff.getName());
+        }
+        // If openflow Node Id is NULL, get all the bridge nodes using southbound apis and fetch
+        // SFF with matching name. From this bridge name, get the openflow data path ID.
+        if (datapathId == null) {
+            Node node = null;
+            final List<Node> nodes = nodeCacheManager.getBridgeNodes();
+            if (nodes.isEmpty()) {
+                LOG.debug("Noop with Classifier Creation on SFF={}. No Bridges configured YET!!", sff.getName());
+            } else {
+                for (Node dstNode : nodes) {
+                    LOG.debug("Processing Node={}, sff={}", dstNode.getNodeId().getValue(), sff.getName());
+                    if (dstNode.getNodeId().getValue().equalsIgnoreCase(sff.getName())) {
+                        LOG.debug("Found matching OVSDB Bridge Name!!= {}", dstNode.getNodeId().getValue());
+                        node = dstNode;
+                        break;
+                    }
+                }
+            }
+        }
+
+        LOG.debug("Processing the Classifier rules on Node={}", datapathId);
+        if (datapathId != null) {
+            // Program the OF flow on the corresponding open flow node.
+            Iterator<Ace> itr = acl.getAccessListEntries().getAce().iterator();
+            while (itr.hasNext()) {
+                Ace entry = itr.next();
+                programOfRules(entry, datapathId, true);
+            }
+        }
+    }
+
+    private void programOfRules(Ace entry, String datapathId, boolean write) {
+        NodeBuilder nodeBuilder = new NodeBuilder();
+        nodeBuilder.setId(new NodeId(Constants.OPENFLOW_NODE_PREFIX + datapathId));
+        nodeBuilder.setKey(new NodeKey(nodeBuilder.getId()));
+
+        //Create the match using match builder, by parsing the Accesslist Entry Match.
+        MatchBuilder matchBuilder = null;
+        matchBuilder = buildMatch(entry.getRuleName(), entry.getMatches(), datapathId);
+
+        InstructionsBuilder isb = null;
+        isb = buildActions(entry.getRuleName(), entry.getActions(), datapathId);
+
+        String flowId = "NETVIRT_SFC_FLOW" + "_" + entry.getRuleName();
+
+        FlowBuilder flowBuilder = new FlowBuilder();
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setMatch(matchBuilder.build());
+        flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY);
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(this.getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        flowBuilder.setInstructions(isb.build());
+
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    private InstructionsBuilder buildActions(String ruleName, Actions actions, String datapathId) {
+        InstructionBuilder ib = new InstructionBuilder();
+
+        if (actions.getPacketHandling() instanceof Deny) {
+            InstructionUtils.createDropInstructions(ib);
+        } else if (actions.getPacketHandling() instanceof Permit) {
+            //Permit actPermit = (Permit) actions.getPacketHandling();
+        } else {
+            InstructionUtils.createDropInstructions(ib);
+        }
+
+        ib.setOrder(0);
+        ib.setKey(new InstructionKey(0));
+        // Instructions List Stores Individual Instructions
+        List<Instruction> instructions = Lists.newArrayList();
+        instructions.add(ib.build());
+
+        // Call the InstructionBuilder Methods Containing Actions
+        ib = this.getMutablePipelineInstructionBuilder();
+        ib.setOrder(1);
+        ib.setKey(new InstructionKey(1));
+        instructions.add(ib.build());
 
+        // Add InstructionBuilder to the Instruction(s)Builder List
+        InstructionsBuilder isb = new InstructionsBuilder();
+        isb.setInstruction(instructions);
+        return isb;
+    }
+
+    private MatchBuilder buildMatch(String ruleName, Matches matches, String dpId) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+
+        if (matches.getAceType() instanceof AceIp) {
+            AceIp aceIp = (AceIp)matches.getAceType();
+            if (aceIp.getAceIpVersion() instanceof AceIpv4) {
+                AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
+                MatchUtils.createSrcL3IPv4Match(matchBuilder, aceIpv4.getSourceIpv4Network());
+                MatchUtils.createDstL3IPv4Match(matchBuilder, aceIpv4.getDestinationIpv4Network());
+                MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol());
+                MatchUtils.addLayer4Match(matchBuilder, aceIp.getProtocol().intValue(),
+                        aceIp.getSourcePortRange().getLowerPort().getValue().intValue(),
+                        aceIp.getDestinationPortRange().getLowerPort().getValue().intValue());
+            }
+        } else if (matches.getAceType() instanceof AceEth) {
+            AceEth aceEth = (AceEth) matches.getAceType();
+            MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(aceEth.getSourceMacAddress().getValue()));
+            MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(aceEth.getDestinationMacAddress().getValue()),
+                    new MacAddress(aceEth.getDestinationMacAddressMask().getValue()));
+        }
+
+        //MatchUtils.createInPortMatch(matchBuilder, Long.getLong(dpId), Long.getLong(matches.getInputInterface()));
+        return matchBuilder;
     }
 
     @Override
-    public void removeClassifierRules(Sff sff, AccessList acl) {
+    public void removeClassifierRules(Sff sff, Acl acl) {
         // TODO Auto-generated method stub
 
     }
+
+
+    protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}",
+                flowBuilder.build(), nodeBuilder.build());
+        dbutils.merge(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder), nodeBuilder.build());
+        dbutils.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder), flowBuilder.build());
+    }
+
+    protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        dbutils.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
+    }
+
+    private String getDpid(Node node) {
+        long dpid = southbound.getDataPathId(node);
+        if (dpid == 0) {
+            LOG.warn("getDpid: DPID could not be found for node: {}", node.getNodeId().getValue());
+        }
+        return String.valueOf(dpid);
+    }
+
+    private static InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        return InstanceIdentifier.builder(Nodes.class)
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
+                        nodeBuilder.getKey())
+                .augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(flowBuilder.getTableId()))
+                .child(Flow.class, flowBuilder.getKey()).build();
+    }
+
+    private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
+        createNodePath(NodeBuilder nodeBuilder) {
+        return InstanceIdentifier.builder(Nodes.class)
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
+                        nodeBuilder.getKey()).build();
+    }
+
+    private short getTable() {
+        return Service.INGRESS_ACL.getTable();
+    }
+
+    private final InstructionBuilder getMutablePipelineInstructionBuilder() {
+        Service nextService = orchestrator.getNextServiceInPipeline(Service.INGRESS_ACL);
+        if (nextService != null) {
+            return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable());
+        } else {
+            return InstructionUtils.createDropInstructions(new InstructionBuilder());
+        }
+    }
+
+    private void setDependencies(ServiceReference serviceReference) {
+        nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        orchestrator = (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
+    }
 }
index 9135aeb68c722d3441ba31defb61e8b1a37f3cb9..137b77f8ae2a49aa2406a8219f7ba7b4aea0d694 100644 (file)
@@ -8,7 +8,6 @@ import org.osgi.framework.BundleContext;
 public class NetvirtSfcModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev141210.AbstractNetvirtSfcModule {
 
     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcModule.class);
-    private BundleContext bundleContext = null;
 
     public NetvirtSfcModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
         super(identifier, dependencyResolver);
@@ -26,13 +25,8 @@ public class NetvirtSfcModule extends org.opendaylight.yang.gen.v1.urn.opendayli
     @Override
     public java.lang.AutoCloseable createInstance() {
         LOG.info("Netvirt SFC module initialization.");
-        //final NetvirtSfcProvider sfcProvider = new NetvirtSfcProvider(getDataBrokerDependency());
-        final NetvirtSfcProvider sfcProvider = new NetvirtSfcProvider(bundleContext);
+        NetvirtSfcProvider sfcProvider = new NetvirtSfcProvider();
         getBrokerDependency().registerProvider(sfcProvider);
         return sfcProvider;
     }
-
-    public void setBundleContext(BundleContext bundleContext) {
-        this.bundleContext = bundleContext;
-    }
 }
index 6bbc36823822daa2a6278a038859a203119f3674..8468b165e55c84a501f16482e6eb837ab5c15257 100644 (file)
@@ -17,36 +17,4 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class NetvirtSfcModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev141210.AbstractNetvirtSfcModuleFactory {
-    private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcModuleFactory.class);
-
-    @Override
-    public Module createModule(String instanceName,
-                               DependencyResolver dependencyResolver,
-                               DynamicMBeanWithInstance old, BundleContext bundleContext)
-            throws Exception {
-        Module module =  super.createModule(instanceName, dependencyResolver, old, bundleContext);
-        LOG.info("Created NetvirtSfcModule1= {}!!", (module instanceof NetvirtSfcModule));
-        setModuleBundleContext(bundleContext, module);
-        return module;
-    }
-
-    @Override
-    public Module createModule(String instanceName,
-                               DependencyResolver dependencyResolver, BundleContext bundleContext) {
-        Module module = super.createModule(instanceName, dependencyResolver, bundleContext);
-        LOG.info("Created NetvirtSfcModule2= {}!!", (module instanceof NetvirtSfcModule));
-        setModuleBundleContext(bundleContext, module);
-        return module;
-    }
-
-    private void setModuleBundleContext(BundleContext bundleContext,
-                                        Module module) {
-        if (module instanceof NetvirtSfcModule) {
-            LOG.info("Setting Bundle Context for NetvirtSfcModule!!");
-            ((NetvirtSfcModule)module).setBundleContext(bundleContext);
-        } else {
-            LOG.warn("Module is of type {} expected type {}",
-                    module.getClass(), NetvirtSfcModule.class);
-        }
-    }
 }
index 6bb1e19d294703a665dd6a95d66f8ed55e3b97cb..c5b03f0ed7eb72ee5f9d1a6f86e3639221b98531 100644 (file)
@@ -14,6 +14,7 @@ import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.NetvirtSfcProvider;
+import org.osgi.framework.BundleContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 
 import javax.management.ObjectName;
@@ -45,7 +46,6 @@ public class NetvirtSfcModuleTest {
 
         // create instance of module with injected mocks
         NetvirtSfcModule module = new NetvirtSfcModule(mock(ModuleIdentifier.class), dependencyResolver);
-        //module.setDataBroker(mock(ObjectName.class));
         // getInstance calls resolveInstance to get the broker dependency and then calls createInstance
         AutoCloseable closeable = module.getInstance();
         ((NetvirtSfcProvider)closeable).onSessionInitiated(session);
index bb8fc92fbbeb101ec4339e163554b4358561769f..a9dc254eb8da3537d5e12d93021c33bd993593fc 100644 (file)
@@ -53,15 +53,18 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <groupId>${project.groupId}</groupId>
       <artifactId>utils.mdsal-utils</artifactId>
       <version>${project.version}</version>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>utils.southbound-utils</artifactId>
       <version>${project.version}</version>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>concepts</artifactId>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.codehaus.sonar-plugins.java</groupId>
@@ -76,8 +79,20 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         <groupId>org.jacoco</groupId>
         <artifactId>jacoco-maven-plugin</artifactId>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <configuration>
+          <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
+        </configuration>
+      </plugin>
       <plugin>
         <artifactId>maven-failsafe-plugin</artifactId>
+        <!--<configuration>
+          <excludes>
+            <exclude>**/NetvirtSfcIT.java</exclude>
+          </excludes>
+        </configuration>-->
       </plugin>
     </plugins>
   </build>
index 9eef40d7af711119b5f4916ecadeaf123f84526e..443656e68e4c4597f8de2452a3b35aff4e52c868 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.sfc;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -30,20 +31,21 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.AclUtils;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ClassifierUtils;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.SfcUtils;
-import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.ovsdb.southbound.SouthboundUtil;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.AccessLists;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.AccessListsBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessListBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.AccessListEntriesBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.AccessListEntryBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.ActionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.MatchesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessListsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntriesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.ActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
 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.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.ClassifiersBuilder;
@@ -55,6 +57,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -63,6 +69,7 @@ import org.opendaylight.yangtools.yang.binding.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.karaf.options.LogLevelOption;
 import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
 import org.ops4j.pax.exam.options.MavenUrlReference;
 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
@@ -89,7 +96,8 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     public static final String CONNECTION_TYPE_ACTIVE = "active";
     public static final String CONNECTION_TYPE_PASSIVE = "passive";
     public static final String DEFAULT_SERVER_PORT = "6640";
-    public static final String BRIDGE_NAME = "brtest";
+    public static final String INTEGRATION_BRIDGE_NAME = "br-int";
+    private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
 
     @Override
     public String getModuleName() {
@@ -145,11 +153,17 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
 
     @Override
     public Option getLoggingOption() {
-        Option option = editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
-                logConfiguration(NetvirtSfcIT.class),
-                LogLevel.INFO.name());
-        option = composite(option, super.getLoggingOption());
-        return option;
+        return composite(
+                editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        logConfiguration(NetvirtSfcIT.class),
+                        LogLevel.INFO.name()),
+                editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.sfc",
+                        LogLevel.INFO.name()),
+                /*editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.ovsdb",
+                        LogLevelOption.LogLevel.TRACE.name()),*/
+                super.getLoggingOption());
     }
 
     protected String usage() {
@@ -181,16 +195,19 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         }
 
         try {
+            Thread.sleep(1000);
             super.setup();
         } catch (Exception e) {
             e.printStackTrace();
         }
 
+        getProperties();
+
         DataBroker dataBroker = getDatabroker(getProviderContext());
         mdsalUtils = new MdsalUtils(dataBroker);
         assertNotNull("mdsalUtils should not be null", mdsalUtils);
         southboundUtils = new SouthboundUtils(mdsalUtils);
-        getProperties();
+        assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
         setup.set(true);
     }
 
@@ -224,6 +241,30 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         return dataBroker;
     }
 
+    private Boolean getNetvirtTopology() {
+        LOG.info("getNetvirtTopology: looking for {}...", NETVIRT_TOPOLOGY_ID);
+        Boolean found = false;
+        final TopologyId topologyId = new TopologyId(new Uri(NETVIRT_TOPOLOGY_ID));
+        InstanceIdentifier<Topology> path =
+                InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
+        for (int i = 0; i < 60; i++) {
+            Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
+            if (topology != null) {
+                LOG.info("getNetvirtTopology: found {}...", NETVIRT_TOPOLOGY_ID);
+                found = true;
+                break;
+            } else {
+                LOG.info("getNetvirtTopology: still looking ({})...", i);
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return found;
+    }
+
     @Test
     public void testNetvirtSfcFeatureLoad() {
         assertTrue(true);
@@ -232,11 +273,11 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     private AccessListsBuilder setAccessLists () {
         MatchesBuilder matchesBuilder = aclUtils.createMatches(new MatchesBuilder(), 80);
         ActionsBuilder actionsBuilder = aclUtils.createActions(new ActionsBuilder(), Boolean.TRUE);
-        AccessListEntryBuilder accessListEntryBuilder = aclUtils.createAccessListEntryBuilder(
-                new AccessListEntryBuilder(), "http", matchesBuilder, actionsBuilder);
+        AceBuilder accessListEntryBuilder = aclUtils.createAccessListEntryBuilder(
+                new AceBuilder(), "http", matchesBuilder, actionsBuilder);
         AccessListEntriesBuilder accessListEntriesBuilder = aclUtils.createAccessListEntries(
                 new AccessListEntriesBuilder(), accessListEntryBuilder);
-        AccessListBuilder accessListBuilder = aclUtils.createAccessList(new AccessListBuilder(),
+        AclBuilder accessListBuilder = aclUtils.createAccessList(new AclBuilder(),
                 "http", accessListEntriesBuilder);
         AccessListsBuilder accessListsBuilder = aclUtils.createAccessLists(new AccessListsBuilder(),
                 accessListBuilder);
@@ -286,35 +327,41 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         assertNull(clazz.getSimpleName() + " should be null", result);
     }
 
+    /*
+     * Connect to an ovsdb node. Netvirt should add br-int, add the controller address
+     * and program the pipeline flows.
+     */
     @Test
     public void testDoIt() throws InterruptedException {
         ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(addressStr, portStr);
-        Node ovsdbNode = southboundUtils.connectOvsdbNode(connectionInfo);
-
-        String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
-        assertNotNull("Failed to get controller target", controllerTarget);
-        List<ControllerEntry> setControllerEntry = southboundUtils.createControllerEntry(controllerTarget);
-        Uri setUri = new Uri(controllerTarget);
-        Assert.assertTrue(southboundUtils.addBridge(connectionInfo, null, BRIDGE_NAME, null, true,
-                SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null,
-                setControllerEntry, null));
-        OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, BRIDGE_NAME);
-        Assert.assertNotNull("bridge was not found: " + BRIDGE_NAME,  bridge);
-        Assert.assertNotNull("ControllerEntry was not found: " + setControllerEntry.iterator().next(),
-                bridge.getControllerEntry());
-        List<ControllerEntry> getControllerEntries = bridge.getControllerEntry();
-        for (ControllerEntry entry : getControllerEntries) {
-            if (entry.getTarget() != null) {
-                Assert.assertEquals(setUri.toString(), entry.getTarget().toString());
+        assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
+        assertNotNull("node is not connected", southboundUtils.getOvsdbNode(connectionInfo));
+        ControllerEntry controllerEntry;
+        // Loop 10s checking if the controller was added
+        for (int i = 0; i < 10; i++) {
+            Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
+            assertNotNull("ovsdb node not found", ovsdbNode);
+            String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
+            assertNotNull("Failed to get controller target", controllerTarget);
+            OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, INTEGRATION_BRIDGE_NAME);
+            assertNotNull(bridge);
+            assertNotNull(bridge.getControllerEntry());
+            controllerEntry = bridge.getControllerEntry().iterator().next();
+            assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
+            if (controllerEntry.isIsConnected()) {
+                Assert.assertTrue(controllerEntry.isIsConnected());
+                break;
             }
+            Thread.sleep(1000);
         }
 
         /* TODO: add code to write to mdsal to exercise the sfc dataChangeListener */
         /* allow some time to let the impl code do it's work to push flows */
         /* or just comment out below lines and just manually verify on the bridges and reset them */
-        Thread.sleep(10000);
+        //Thread.sleep(10000);
 
-        Assert.assertTrue(southboundUtils.deleteBridge(connectionInfo, BRIDGE_NAME));
-        southboundUtils.disconnectOvsdbNode(connectionInfo);
+        assertTrue(southboundUtils.deleteBridge(connectionInfo, INTEGRATION_BRIDGE_NAME));
+        Thread.sleep(1000);
+        assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
     }
 }
index ac214bb98f3717c664396f54caf3f7d463fff0f5..dd6cce50dce3072505e21e58898bb567e934cdf6 100644 (file)
@@ -10,18 +10,18 @@ package org.opendaylight.ovsdb.openstack.netvirt.sfc.utils;
 
 import java.util.ArrayList;
 import java.util.List;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.AccessListsBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessList;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessListBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.AccessListEntriesBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.AccessListEntry;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.AccessListEntryBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.ActionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.MatchesBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.actions.packet.handling.PermitBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.matches.ace.type.AceIpBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessListsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntriesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.ActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.actions.packet.handling.PermitBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.DestinationPortRangeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev150611.acl.transport.header.fields.DestinationPortRangeBuilder;
 
 public class AclUtils {
     public MatchesBuilder createMatches (MatchesBuilder matchesBuilder, int destPort) {
@@ -45,10 +45,10 @@ public class AclUtils {
         return actionsBuilder;
     }
 
-    public AccessListEntryBuilder createAccessListEntryBuilder(AccessListEntryBuilder accessListEntryBuilder,
-                                                               String ruleName,
-                                                               MatchesBuilder matchesBuilder,
-                                                               ActionsBuilder actionsBuilder) {
+    public AceBuilder createAccessListEntryBuilder(AceBuilder accessListEntryBuilder,
+                                                   String ruleName,
+                                                   MatchesBuilder matchesBuilder,
+                                                   ActionsBuilder actionsBuilder) {
         accessListEntryBuilder.setRuleName(ruleName);
         accessListEntryBuilder.setMatches(matchesBuilder.build());
         accessListEntryBuilder.setActions(actionsBuilder.build());
@@ -57,16 +57,16 @@ public class AclUtils {
     }
 
     public AccessListEntriesBuilder createAccessListEntries(AccessListEntriesBuilder accessListEntriesBuilder,
-                                                            AccessListEntryBuilder accessListEntryBuilder) {
-        List<AccessListEntry> accessListEntriesList = new ArrayList<>();
+                                                            AceBuilder accessListEntryBuilder) {
+        List<Ace> accessListEntriesList = new ArrayList<>();
         accessListEntriesList.add(accessListEntryBuilder.build());
 
         return accessListEntriesBuilder;
     }
 
-    public AccessListBuilder createAccessList(AccessListBuilder accessListBuilder,
-                                              String aclName,
-                                              AccessListEntriesBuilder accessListEntriesBuilder) {
+    public AclBuilder createAccessList(AclBuilder accessListBuilder,
+                                       String aclName,
+                                       AccessListEntriesBuilder accessListEntriesBuilder) {
         accessListBuilder.setAclName(aclName);
         accessListBuilder.setAccessListEntries(accessListEntriesBuilder.build());
 
@@ -74,10 +74,10 @@ public class AclUtils {
     }
 
     public AccessListsBuilder createAccessLists(AccessListsBuilder accessListsBuilder,
-                                                AccessListBuilder accessListBuilder) {
-        List<AccessList> accessListList = new ArrayList<>();
+                                                AclBuilder accessListBuilder) {
+        List<Acl> accessListList = new ArrayList<>();
         accessListList.add(accessListBuilder.build());
-        accessListsBuilder.setAccessList(accessListList);
+        accessListsBuilder.setAcl(accessListList);
 
         return accessListsBuilder;
     }
index b7c0375e2f2e1bcfaa6124d1ec05137f55c4e9df..2119c4f54adfcc726c83c4307cf0691d959f234e 100644 (file)
@@ -25,6 +25,17 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
   <properties>
     <karaf.localFeature>odl-ovsdb-sfc-test</karaf.localFeature>
   </properties>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>openstack.net-virt-sfc-artifacts</artifactId>
+        <version>${project.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
   <dependencies>
     <dependency>
       <!-- scope is compile so all features (there is only one) are installed
index 3fa44351fdd2b861990ab625310224780fafd415..3b5584c3e3002a12c2ac69dcedb248d3b60636c4 100644 (file)
@@ -45,7 +45,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   </scm>
 
   <properties>
-    <networkconfig.neutron.version>0.6.0-SNAPSHOT</networkconfig.neutron.version>
+    <neutron.model.version>0.6.0-SNAPSHOT</neutron.model.version>
     <ovsdb.utils.config.version>1.2.1-SNAPSHOT</ovsdb.utils.config.version>
     <ovsdb.utils.servicehelper.version>1.2.1-SNAPSHOT</ovsdb.utils.servicehelper.version>
     <powermock.version>1.5.2</powermock.version>
@@ -100,16 +100,16 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-common-api</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.neutron</groupId>
-      <artifactId>neutron-spi</artifactId>
-      <version>${networkconfig.neutron.version}</version>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.ovsdb</groupId>
       <artifactId>southbound-api</artifactId>
       <version>1.2.1-SNAPSHOT</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.neutron</groupId>
+      <artifactId>model</artifactId>
+      <version>${neutron.model.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.ovsdb</groupId>
       <artifactId>utils.config</artifactId>
@@ -148,6 +148,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <groupId>org.opendaylight.mdsal.model</groupId>
       <artifactId>ietf-yang-types</artifactId>
     </dependency>
+    <dependency>
+      <groupId>commons-net</groupId>
+      <artifactId>commons-net</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
@@ -215,6 +219,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
             <Embed-Dependency>utils.config;type=!pom;inline=false</Embed-Dependency>
             <Embed-Transitive>true</Embed-Transitive>
             <Export-Package>
+              org.opendaylight.ovsdb.openstack.netvirt.translator,
               org.opendaylight.ovsdb.openstack.netvirt.api,
               org.opendaylight.ovsdb.openstack.netvirt
             </Export-Package>
index a3acb01dd8b4f936c5c0b74614efc43b87578cb3..e37b853b83d41b4a4dcd60e37fca71910ea89441 100644 (file)
@@ -16,7 +16,40 @@ import java.util.List;
 import org.apache.commons.lang3.tuple.Pair;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.neutron.spi.*;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.*;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronFirewallInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronFirewallPolicyInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronFirewallRuleInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronFloatingIPInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerHealthMonitorInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerListenerInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerPoolInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronLoadBalancerPoolMemberInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronNetworkInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronPortInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronRouterInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronSecurityGroupInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronSecurityRuleInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.impl.NeutronSubnetInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFirewallAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFirewallPolicyAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFirewallRuleAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFloatingIPAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolMemberAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronNetworkAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronPortAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronRouterAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityGroupAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityRuleAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSubnetAware;
 import org.opendaylight.ovsdb.openstack.netvirt.api.*;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.*;
 import org.osgi.framework.BundleActivator;
@@ -29,6 +62,7 @@ import org.slf4j.LoggerFactory;
 
 public class ConfigActivator implements BundleActivator {
     private static final Logger LOG = LoggerFactory.getLogger(ConfigActivator.class);
+    private List<ServiceRegistration<?>> translatorCRUDRegistrations = new ArrayList<ServiceRegistration<?>>();
     private List<Pair<Object, ServiceRegistration>> servicesAndRegistrations = new ArrayList<>();
     private ProviderContext providerContext;
 
@@ -39,6 +73,7 @@ public class ConfigActivator implements BundleActivator {
     @Override
     public void start(BundleContext context) throws Exception {
         LOG.info("ConfigActivator start:");
+        registerCRUDServiceProviders(context, this.providerContext);
 
         ConfigurationServiceImpl configurationService = new ConfigurationServiceImpl();
         registerService(context, new String[] {ConfigurationService.class.getName()},
@@ -168,11 +203,33 @@ public class ConfigActivator implements BundleActivator {
         trackService(context, RoutingProvider.class, neutronL3Adapter);
         trackService(context, L3ForwardingProvider.class, neutronL3Adapter);
         trackService(context, GatewayMacResolver.class, neutronL3Adapter);
+        trackService(context, IngressAclProvider.class, securityServices);
+        trackService(context, EgressAclProvider.class, securityServices);
 
         // We no longer need to track the services, avoid keeping references around
         servicesAndRegistrations.clear();
     }
 
+    private void registerCRUDServiceProviders(BundleContext context,
+            ProviderContext providerContext) {
+        LOG.debug("Registering CRUD service providers");
+        NeutronRouterInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronPortInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronSubnetInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronNetworkInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronSecurityGroupInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronSecurityRuleInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronFirewallInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronFirewallPolicyInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronFirewallRuleInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronLoadBalancerInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronLoadBalancerPoolInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronLoadBalancerListenerInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronLoadBalancerHealthMonitorInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronLoadBalancerPoolMemberInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+        NeutronFloatingIPInterface.registerNewInterface(context, providerContext, translatorCRUDRegistrations);
+    }
+
     private void trackService(BundleContext context, final Class<?> clazz, final ConfigInterface... dependents) {
         @SuppressWarnings("unchecked")
         ServiceTracker tracker = new ServiceTracker(context, clazz, null) {
@@ -206,9 +263,15 @@ public class ConfigActivator implements BundleActivator {
 
     @Override
     public void stop(BundleContext context) throws Exception {
-        LOG.info("ConfigActivator stop");
+        LOG.info("Stop Translator CRUD service provides");
         // ServiceTrackers and services are already released when bundle stops,
         // so we don't need to close the trackers or unregister the services
+        for (ServiceRegistration registration : translatorCRUDRegistrations) {
+            if (registration != null) {
+                registration.unregister();
+            }
+        }
+
     }
 
     private ServiceRegistration<?> registerService(BundleContext bundleContext, String[] interfaces,
index 7a3bf8a705f5a27e5e33e9ec743c9f97fd1fbed6..0b7881f31259d3f6b90773cd46933651b1697a15 100644 (file)
@@ -10,12 +10,12 @@ package org.opendaylight.ovsdb.openstack.netvirt;
 
 import java.net.HttpURLConnection;
 
-import org.opendaylight.neutron.spi.INeutronFirewallAware;
-import org.opendaylight.neutron.spi.INeutronFirewallPolicyAware;
-import org.opendaylight.neutron.spi.INeutronFirewallRuleAware;
-import org.opendaylight.neutron.spi.NeutronFirewall;
-import org.opendaylight.neutron.spi.NeutronFirewallPolicy;
-import org.opendaylight.neutron.spi.NeutronFirewallRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewall;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallPolicy;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFirewallAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFirewallPolicyAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFirewallRuleAware;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.osgi.framework.ServiceReference;
@@ -170,7 +170,7 @@ public class FWaasHandler extends AbstractHandler
     /**
      * Process the event.
      *
-     * @param abstractEvent@see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
+     * @param abstractEvent new FWaas Event@see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
      */
     @Override
     public void processEvent(AbstractEvent abstractEvent) {
index 679c1bb8c07d1a6d971eb95c4c6d76d79cdd2ca9..30e28ea438cfe4e0cdb284f262929ef744ec83c4 100644 (file)
@@ -10,8 +10,8 @@ package org.opendaylight.ovsdb.openstack.netvirt;
 
 import java.net.HttpURLConnection;
 
-import org.opendaylight.neutron.spi.INeutronFloatingIPAware;
-import org.opendaylight.neutron.spi.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFloatingIPAware;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
index 8bff814fb437bbd5c03ab69d00e16d2de9efb9a1..e305fd340cea7ec7c2f12d89cd12cc793d82e2d1 100644 (file)
@@ -12,15 +12,15 @@ import java.net.HttpURLConnection;
 import java.util.List;
 import java.util.Map;
 
-import org.opendaylight.neutron.spi.INeutronLoadBalancerAware;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolCRUD;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerAware;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
@@ -166,6 +166,8 @@ public class LBaaSHandler extends AbstractHandler
     /**
      * Useful utility for extracting the loadbalancer instance
      * configuration from the neutron LB cache
+     * @param neutronLB neutron load balancer object
+     * @return returns load balancer configuration
      */
     public LoadBalancerConfiguration extractLBConfiguration(NeutronLoadBalancer neutronLB) {
         String loadBalancerName = neutronLB.getLoadBalancerName();
index c0a3ab4c91bb8b82ef8985a4a027ed15d816d121..93b4ce626ecabb3b93fd2269bed9d627f8c08c1c 100755 (executable)
@@ -12,14 +12,14 @@ import java.net.HttpURLConnection;
 import java.util.List;
 import java.util.Map;
 
-import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolAware;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolAware;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
@@ -194,6 +194,8 @@ public class LBaaSPoolHandler extends AbstractHandler
     /**
      * Useful utility for extracting the loadbalancer instance. With
      * each LB pool, we allow multiple VIP and LB to be instantiated.
+     * @param neutronLBPool Neutron load balancer pool object
+     * @return list of loadbalancer configuration of pool members
      */
     public List<LoadBalancerConfiguration> extractLBConfiguration(NeutronLoadBalancerPool neutronLBPool) {
         String poolProtocol = neutronLBPool.getLoadBalancerPoolProtocol();
index d8834f5db7bd32437a4eb59070983ee38b80344c..9ff36f2b0e70de0c9b0f840aafb108412adc543a 100755 (executable)
@@ -12,15 +12,15 @@ import java.net.HttpURLConnection;
 import java.util.List;
 import java.util.Map;
 
-import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolMemberAware;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolMemberAware;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
@@ -191,6 +191,8 @@ public class LBaaSPoolMemberHandler extends AbstractHandler
     /**
      * Useful utility for extracting the loadbalancer instance
      * configuration from the neutron LB cache based on member info
+     * @param neutronLBPoolMember Neutron LB pool member object
+     * @return load balancer configuration of the pool member
      */
     public LoadBalancerConfiguration extractLBConfiguration(NeutronLoadBalancerPoolMember neutronLBPoolMember) {
         String memberID = neutronLBPoolMember.getID();
index 705c15e33b536da63b9a15a4311ccd3d3771ed8d..cbd4d80162cebf28503ebbb81710494aa603baf2 100644 (file)
@@ -11,9 +11,9 @@ package org.opendaylight.ovsdb.openstack.netvirt;
 import java.net.HttpURLConnection;
 import java.util.List;
 
-import org.opendaylight.neutron.spi.INeutronNetworkAware;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronNetworkAware;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
index c52c281256b636934febf1221638ad66721014c2..f6c2342558c9ed3d2d064feaa887a370c208e651 100755 (executable)
@@ -8,13 +8,13 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt;
 
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSubnet;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
 
 import java.util.AbstractMap;
 import java.util.Iterator;
@@ -25,6 +25,9 @@ public class NeutronCacheUtils {
 
     /**
      * Look up in the NeutronPortsCRUD cache and return the MAC address for a corresponding IP address
+     * @param neutronPortsCache Reference to port cache to get existing port related data. This interface
+     * basically read data from the md-sal data store.
+     * @param subnetID subnet to which given port is attached
      * @param ipAddr IP address of a member or VM
      * @return MAC address registered with that IP address
      */
@@ -58,6 +61,10 @@ public class NeutronCacheUtils {
     /**
      * Look up in the NeutronNetworkCRUD cache and NeutronSubnetCRUD cache for
      * extracting the provider segmentation_type and segmentation_id
+     * @param neutronNetworkCache Reference to neutron network cache to get existing network related data.
+     * This interface basically read data from the md-sal data store.
+     * @param neutronSubnetCache Reference to neutron subnet cache to get existing subnet related data.
+     * This interface basically read data from the md-sal data store.
      * @param subnetID Subnet UUID
      * @return {Type: ID} pair for that subnet ID
      */
index ae4609ae96baefda1eeeca3841150f13bd89f533..209e292b0aa49dd2ca75fa9ad06d3f82db0415fc 100644 (file)
@@ -8,15 +8,15 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt;
 
-import org.opendaylight.neutron.spi.NeutronFloatingIP;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronRouter;
-import org.opendaylight.neutron.spi.NeutronRouter_Interface;
-import org.opendaylight.neutron.spi.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 
 public class NorthboundEvent extends AbstractEvent {
index a59927ea8e61cc1c281ec87c4dbb7e1b944e9900..e374404ae52d615d17b36aa887f638bfea9fed7f 100644 (file)
@@ -11,8 +11,8 @@ package org.opendaylight.ovsdb.openstack.netvirt;
 import java.net.HttpURLConnection;
 import java.util.List;
 
-import org.opendaylight.neutron.spi.INeutronPortAware;
-import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronPortAware;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
index 76a6b9d35c358e9688c167462d113abac2e5e427..e6568000a947c14e8433c990d6355035a76c0bf5 100644 (file)
@@ -10,10 +10,10 @@ package org.opendaylight.ovsdb.openstack.netvirt;
 
 import java.net.HttpURLConnection;
 
-import org.opendaylight.neutron.spi.INeutronSecurityGroupAware;
-import org.opendaylight.neutron.spi.INeutronSecurityRuleAware;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityGroupAware;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityRuleAware;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.osgi.framework.ServiceReference;
index 7c914f8c31b65e39ffd9feb434d95d96bd613525..95b77606a03a030c603183c18e11095a989ff521 100644 (file)
@@ -10,9 +10,9 @@ package org.opendaylight.ovsdb.openstack.netvirt;
 
 import java.net.HttpURLConnection;
 
-import org.opendaylight.neutron.spi.INeutronRouterAware;
-import org.opendaylight.neutron.spi.NeutronRouter;
-import org.opendaylight.neutron.spi.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronRouterAware;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
index e16ebbc19fef6352fb39dfff56344844c2b1513a..ee5a2d6a6d57d3d9645e3a63bd904a32a0a34996 100644 (file)
@@ -10,7 +10,7 @@ package org.opendaylight.ovsdb.openstack.netvirt;
 
 import java.util.List;
 
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
 import org.opendaylight.ovsdb.openstack.netvirt.api.*;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
index 3e3a714db10bc65a784c83e55a7be8bcd9b20098..c74d11d12c327d4ba54869c19cf3ea9ff376a4ad 100644 (file)
@@ -10,8 +10,8 @@ package org.opendaylight.ovsdb.openstack.netvirt;
 
 import java.net.HttpURLConnection;
 
-import org.opendaylight.neutron.spi.INeutronSubnetAware;
-import org.opendaylight.neutron.spi.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSubnetAware;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
index 45d3018ba81fb71bef75c01931a37fa898c9563d..d58075cad0b467c11026db1a72dc67673212c52f 100644 (file)
@@ -8,7 +8,7 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.api;
 
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 
 import java.util.List;
@@ -74,7 +74,7 @@ public interface BridgeConfigurationManager {
      * For OpenFlow 1.3 the Integration Bridge is required and must have a physical device connected.
      * @param bridgeNode the {@link Node} that represents bridge
      * @param ovsdbNode the {@link Node} where the bridge is configured
-     * @param network the {@link org.opendaylight.neutron.spi.NeutronNetwork}
+     * @param network the {@link org.opendaylight.ovsdb.openstack.netvirt.translator}
      * @return True or False
      */
     boolean isNodeVlanReady(Node bridgeNode, Node ovsdbNode, NeutronNetwork network);
@@ -92,7 +92,7 @@ public interface BridgeConfigurationManager {
      * Returns true if the bridges required for the provider network type are created
      * If the bridges are not created, this method will attempt to create them
      * @param node the {@link Node} to query
-     * @param network the {@link org.opendaylight.neutron.spi.NeutronNetwork}
+     * @param network the {@link org.opendaylight.ovsdb.openstack.netvirt.translator}
      * @return True or False
      */
     boolean createLocalNetwork(Node node, NeutronNetwork network);
@@ -105,9 +105,9 @@ public interface BridgeConfigurationManager {
 
     /**
      * Returns the physical interface mapped to the given neutron physical network.
-     * @param node
-     * @param physicalNetwork
-     * @return
+     * @param node the {@link Node} to query
+     * @param physicalNetwork neutron physical network
+     * @return name of the physical interface
      */
     String getPhysicalInterfaceName(Node node, String physicalNetwork);
 
index b1beb944227541c20a7d105eaa08dc9f0ac90feb..a41eb1020eeb8faaae9a6d339f12aac06ae8e6b8 100644 (file)
@@ -22,52 +22,57 @@ import org.apache.commons.lang3.tuple.Pair;
 public interface ConfigurationService {
 
     /**
-     * Returns the name configured name of the Integration Bridge
+     * @return the name configured name of the Integration Bridge
      */
     String getIntegrationBridgeName();
 
     /**
      * Configures the name of the Integration Bridge
+     * @param integrationBridgeName name of integration bridge
      */
     void setIntegrationBridgeName(String integrationBridgeName);
 
     /**
-     * Returns the name configured name of the Network Bridge
+     * @return the name configured name of the Network Bridge
      */
     String getNetworkBridgeName();
 
     /**
      * Configures the name of the Network Bridge
+     * @param networkBridgeName Name of the network bridge
      */
     void setNetworkBridgeName(String networkBridgeName);
 
     /**
-     * Returns the name configured name of the ExternalBridge
+     * @return the name configured name of the ExternalBridge
      */
     String getExternalBridgeName();
 
     /**
      * Configures the name of the External Bridge
+     * @param externalBridgeName Name of external bridge
      */
     void setExternalBridgeName(String externalBridgeName);
 
     /**
-     * Returns the key used to access the Tunnel Endpoint configuration from Open vSwitch
+     * @return the key used to access the Tunnel Endpoint configuration from Open vSwitch
      */
     String getTunnelEndpointKey();
 
     /**
      * Sets the key used to access the Tunnel Endpoint configuration from Open vSwitch
+     * @param tunnelEndpointKey key of tunnel end point
      */
     void setTunnelEndpointKey(String tunnelEndpointKey);
 
     /**
-     * Returns a Map of patch port names where the key is a tuple of source bridge and destination bridge
+     * @return a Map of patch port names where the key is a tuple of source bridge and destination bridge
      */
     Map<Pair<String, String>, String> getPatchPortNames();
 
     /**
      * Sets the Map of source/destination bridges to patch port name
+     * @param patchPortNames Map of source/destination bridges to patch port name
      */
     void setPatchPortNames(Map<Pair<String, String>, String> patchPortNames);
 
@@ -80,22 +85,24 @@ public interface ConfigurationService {
     String getPatchPortName(Pair portTuple);
 
     /**
-     * Returns the key used to access the Tunnel Endpoint configuration from Open vSwitch
+     * @return the key used to access the Tunnel Endpoint configuration from Open vSwitch
      */
     String getProviderMappingsKey();
 
     /**
      * Sets the key used to access the Tunnel Endpoint configuration from Open vSwitch
+     * @param providerMappingsKey provide mapping key
      */
     void setProviderMappingsKey(String providerMappingsKey);
 
     /**
-     * Gets the default provider mapping
+     * @return Gets the default provider mapping
      */
     String getDefaultProviderMapping();
 
     /**
      * Sets the default provider mapping
+     * @param providerMapping provider mapping
      */
     void setDefaultProviderMapping(String providerMapping);
 
index a9d66426bdfabd5228d96dc0f9b63df43cf11572..7438ce28c981656a096bf02bad1bf41ea659f266 100644 (file)
@@ -10,8 +10,8 @@ package org.opendaylight.ovsdb.openstack.netvirt.api;
 
 import java.util.List;
 
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
 
 /**
  *  This interface allows egress Port Security flows to be written to devices.
index 4fb38991f0def9f90316a57791963048b456b93a..a96d78b4b57937847b604baab67439c71bf12e8e 100644 (file)
@@ -31,15 +31,17 @@ public interface GatewayMacResolver {
      * periodicRefresh flag.
      * @param externalNetworkBridgeDpid This bridge will be used for sending ARP request
      * @param gatewayIp ARP request will be send for this ip address
+     * @param sourceIpAddress Source IP address for the ARP request (localhost)
+     * @param sourceMacAddress Source MAC address for the ARP request (localhost)
      * @param periodicRefresh Do you want to periodically refresh the gateway mac?
-     * @return
+     * @return ListenableFuture that contains the mac address of gateway ip.
      */
     public ListenableFuture<MacAddress> resolveMacAddress( final Long externalNetworkBridgeDpid, final Ipv4Address gatewayIp,
             final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress, final Boolean periodicRefresh);
 
     /**
      * Method will stop the periodic refresh of the given gateway ip address.
-     * @param gatewayIp
+     * @param gatewayIp Gateway IP Address
      */
     public void stopPeriodicRefresh(final Ipv4Address gatewayIp);
 }
index 81fe7f6538589e985bff3a7142516b2272b0887f..5810f95d3860c7e2ff77adb2320dd4d33ca308cb 100644 (file)
@@ -10,8 +10,8 @@ package org.opendaylight.ovsdb.openstack.netvirt.api;
 
 import java.util.List;
 
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
 
 /**
  *  This interface allows ingress Port Security flows to be written to devices.
index 953a0b17f256cc0063930aa1457e177b338b6f0e..791e07aeac811c11945e363bb85501ba53d093db 100644 (file)
@@ -8,7 +8,7 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.api;
 
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.osgi.framework.ServiceReference;
@@ -19,27 +19,37 @@ import org.osgi.framework.ServiceReference;
 public interface NetworkingProvider {
 
     /**
-     * Returns the name of the NetworkingProvider
+     * @return the name of the NetworkingProvider
      */
     String getName();
 
     /**
-     * Return true if the provider supports Network Service Instances
+     * @return true if the provider supports Network Service Instances
      */
     boolean supportsServices();
 
     /**
-     * Return true if the provider supports per-tenant or "static" tunneling
+     * @return true if the provider supports per-tenant or "static" tunneling
      */
     boolean hasPerTenantTunneling();
 
     /**
      * Handle Interface Update Callback Method
+     * @param network Neutron Network attached to the interface
+     * @param source Source node where interface is attached
+     * @param intf Termination point attached to the node
+     * @return true if interface update handled successfully
      */
     boolean handleInterfaceUpdate(NeutronNetwork network, Node source, OvsdbTerminationPointAugmentation intf);
 
     /**
      * Handle Interface Delete Callback Method
+     * @param tunnelType Type of the tunnel (e.g. vxlan)
+     * @param network Neutron Network associated with the removed interface
+     * @param source Source node where interface was attached
+     * @param intf Termination point associated to the deleted interface
+     * @param isLastInstanceOnNode is last interface attached to the node ?
+     * @return true if interface delete handled successfully
      */
     boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node source,
                                   OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode);
@@ -49,11 +59,13 @@ public interface NetworkingProvider {
      * This method provides a set of common functionalities to initialize the Flow rules of an OVSDB node
      * that are Openflow Version specific. Hence we have this method in addition to the following
      * Openflow Node specific initialization method.
+     * @param node Node on which flow rules are going to be installed
      */
     void initializeFlowRules(Node node);
 
     /**
      * Initialize the Flow rules for a given OpenFlow node
+     * @param openflowNode Node on which flow rules are going to be installed
      */
     void initializeOFFlowRules(Node openflowNode);
 }
index b5f06675942b6b3cbfa16bad6e6977dd47b7dc11..997b7668256259d73735c8795207cdcc31de6f34 100644 (file)
@@ -8,14 +8,14 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.api;
 
-import java.util.List;
-
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 
+import java.util.List;
+
 /**
  * Open vSwitch isolates Tenant Networks using VLANs on the Integration Bridge.
  * This class manages the provisioning of these VLANs
@@ -43,6 +43,14 @@ public interface SecurityServicesManager {
      */
     NeutronPort getDhcpServerPort(OvsdbTerminationPointAugmentation intf);
 
+    /**
+      * Check if the given interface corresponds to a DHCP server port.
+      *
+      * @param intf the intf
+      * @return Return the DHCP neutron port
+      */
+    NeutronPort getNeutronPortFromDhcpIntf(OvsdbTerminationPointAugmentation intf);
+
     /**
      * Is the port a compute port.
      *
@@ -81,4 +89,11 @@ public interface SecurityServicesManager {
      */
     List<Neutron_IPs> getVmListForSecurityGroup(List<Neutron_IPs> srcAddressList,
                                                 String securityGroupUuid);
-}
\ No newline at end of file
+    /**
+     * Add or remove the security groups rules from the port.
+     * @param port the neutron port.
+     * @param securityGroup the security group associated with the port.
+     * @param write whether to add/delete flow.
+     */
+    void syncSecurityGroup(NeutronPort port, List<NeutronSecurityGroup> securityGroup, boolean write);
+}
index 482a6077bbcc3d82992fe94ab0a1947312b52529..ff6200a138fdae4979942a338fa7c34df3c02091 100644 (file)
@@ -8,8 +8,8 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.api;
 
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 
@@ -55,16 +55,22 @@ public interface TenantNetworkManager {
 
     /**
      * Get the Neutron Network ID for a given Segmentation ID
+     * @param segmentationId segmentation id of the neutron network
+     * @return Neutron network id associated with the given segmentation id
      */
     String getNetworkId(String segmentationId);
 
     /**
      * Network Created Callback
+     * @param node target node
+     * @param networkId Id of neutron network
+     * @return vlan assigned to the network
      */
     int networkCreated(Node node, String networkId);
 
     /**
      * Network Deleted Callback
+     * @param id Id of the neutron network
      */
     void networkDeleted(String id);
     NeutronNetwork getTenantNetwork(OvsdbTerminationPointAugmentation terminationPointAugmentation);
index f03a88f08b1b0bf8167d9dc3c3540a7f00ee065e..e58021f93b29a8e2f59c1b23b602a0a44cac67af 100644 (file)
@@ -8,7 +8,7 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.impl;
 
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
 import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
index 9420bbf6af7641dc2b59370dbdd900b78ea43340..b01dc1fc518076a0431e4255aaf2841266f96308 100644 (file)
@@ -61,7 +61,7 @@ public class MdsalUtils {
      *
      * @param logicalDatastoreType {@link LogicalDatastoreType} which should be modified
      * @param path {@link InstanceIdentifier} for path to read
-     * @param <D> the data object type
+     * @param data object of type D
      * @return the result of the request
      */
     public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean merge(
@@ -84,7 +84,7 @@ public class MdsalUtils {
      *
      * @param logicalDatastoreType {@link LogicalDatastoreType} which should be modified
      * @param path {@link InstanceIdentifier} for path to read
-     * @param <D> the data object type
+     * @param data object of type D
      * @return the result of the request
      */
     public <D extends org.opendaylight.yangtools.yang.binding.DataObject> boolean put(
index b381f87d53d720548cf3de5b5cdd59d321cf354a..ad447f22af946c2733a89a602d8b1b2df043f842 100644 (file)
@@ -10,16 +10,17 @@ package org.opendaylight.ovsdb.openstack.netvirt.impl;
 
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronFloatingIP;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronRouter;
-import org.opendaylight.neutron.spi.NeutronRouter_Interface;
-import org.opendaylight.neutron.spi.NeutronSubnet;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
 import org.opendaylight.ovsdb.openstack.netvirt.api.*;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
@@ -43,6 +44,7 @@ import java.net.UnknownHostException;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -70,6 +72,7 @@ public class NeutronL3Adapter implements ConfigInterface {
     private volatile ArpProvider arpProvider;
     private volatile RoutingProvider routingProvider;
     private volatile GatewayMacResolver gatewayMacResolver;
+    private volatile SecurityServicesManager securityServicesManager;
 
     private class FloatIpData {
         // br-int of node where floating ip is associated with tenant port
@@ -197,6 +200,8 @@ public class NeutronL3Adapter implements ConfigInterface {
      */
     public void handleNeutronPortEvent(final NeutronPort neutronPort, Action action) {
         LOG.debug("Neutron port {} event : {}", action, neutronPort.toString());
+
+        this.processSecurityGroupUpdate(neutronPort);
         if (!this.enabled) {
             return;
         }
@@ -326,7 +331,7 @@ public class NeutronL3Adapter implements ConfigInterface {
      * way around) on OpenFlow Table 100.
      *
      * @param actionIn the {@link org.opendaylight.ovsdb.openstack.netvirt.api.Action} action to be handled.
-     * @param neutronFloatingIP An {@link org.opendaylight.neutron.spi.NeutronFloatingIP} instance of NeutronFloatingIP object.
+     * @param neutronFloatingIP An {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP} instance of NeutronFloatingIP object.
      */
     public void handleNeutronFloatingIPEvent(final NeutronFloatingIP neutronFloatingIP,
                                              Action actionIn) {
@@ -529,7 +534,7 @@ public class NeutronL3Adapter implements ConfigInterface {
      * Process the event.
      *
      * @param action the {@link org.opendaylight.ovsdb.openstack.netvirt.api.Action} action to be handled.
-     * @param neutronNetwork An {@link org.opendaylight.neutron.spi.NeutronNetwork} instance of NeutronFloatingIP object.
+     * @param neutronNetwork An {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork} instance of NeutronFloatingIP object.
      */
     public void handleNeutronNetworkEvent(final NeutronNetwork neutronNetwork, Action action) {
         LOG.debug("neutronNetwork {}: network: {}", action, neutronNetwork);
@@ -544,7 +549,7 @@ public class NeutronL3Adapter implements ConfigInterface {
      * @param bridgeNode An instance of Node object.
      * @param intf An {@link org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105
      * .OvsdbTerminationPointAugmentation} instance of OvsdbTerminationPointAugmentation object.
-     * @param neutronNetwork An {@link org.opendaylight.neutron.spi.NeutronNetwork} instance of NeutronNetwork
+     * @param neutronNetwork An {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork} instance of NeutronNetwork
      * object.
      * @param action the {@link org.opendaylight.ovsdb.openstack.netvirt.api.Action} action to be handled.
      */
@@ -657,6 +662,50 @@ public class NeutronL3Adapter implements ConfigInterface {
         }
     }
 
+    private void processSecurityGroupUpdate(NeutronPort neutronPort) {
+        LOG.trace("processSecurityGroupUpdate:" + neutronPort);
+        /**
+         * Get updated data and original data for the the changed. Identify the security groups that got
+         * added and removed and call the appropriate providers for updating the flows.
+         */
+        try {
+            NeutronPort originalPort = neutronPort.getOriginalPort();
+            if (null == originalPort) {
+                LOG.debug("processSecurityGroupUpdate: originalport is empty");
+                return;
+            }
+            List<NeutronSecurityGroup> addedGroup = getsecurityGroupChanged(neutronPort,
+                                                                            neutronPort.getOriginalPort());
+            List<NeutronSecurityGroup> deletedGroup = getsecurityGroupChanged(neutronPort.getOriginalPort(),
+                                                                              neutronPort);
+
+            if (null != addedGroup && !addedGroup.isEmpty()) {
+                securityServicesManager.syncSecurityGroup(neutronPort,addedGroup,true);
+            }
+            if (null != deletedGroup && !deletedGroup.isEmpty()) {
+                securityServicesManager.syncSecurityGroup(neutronPort,deletedGroup,false);
+            }
+
+        } catch (Exception e) {
+            LOG.error("Exception in processSecurityGroupUpdate", e);
+        }
+    }
+
+    private List<NeutronSecurityGroup> getsecurityGroupChanged(NeutronPort port1, NeutronPort port2) {
+        LOG.trace("getsecurityGroupChanged:" + "Port1:" + port1 + "Port2" + port2);
+        ArrayList<NeutronSecurityGroup> list1 = new ArrayList<NeutronSecurityGroup>(port1.getSecurityGroups());
+        ArrayList<NeutronSecurityGroup> list2 = new ArrayList<NeutronSecurityGroup>(port2.getSecurityGroups());
+        for (Iterator<NeutronSecurityGroup> iterator = list1.iterator(); iterator.hasNext();) {
+            NeutronSecurityGroup securityGroup1 = iterator.next();
+            for (NeutronSecurityGroup securityGroup2 :list2) {
+                if (securityGroup1.getID().equals(securityGroup2.getID())) {
+                    iterator.remove();
+                }
+            }
+        }
+        return list1;
+    }
+
     private void programL3ForwardingStage1(Node node, Long dpid, String providerSegmentationId,
                                            String macAddress, String ipStr,
                                            Action actionForNode) {
@@ -1370,6 +1419,8 @@ public class NeutronL3Adapter implements ConfigInterface {
                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
         gatewayMacResolver =
                 (GatewayMacResolver) ServiceHelper.getGlobalInstance(GatewayMacResolver.class, this);
+        securityServicesManager =
+                (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
         initL3AdapterMembers();
     }
 
index ea6bc98e8b1b28cac5deb19cbc689d36b93f82e7..60388974f223e4af40a731c5a9f140e4b09eca8f 100644 (file)
@@ -8,7 +8,9 @@
 package org.opendaylight.ovsdb.openstack.netvirt.impl;
 
 import com.google.common.collect.Sets;
+
 import java.util.Set;
+
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
@@ -16,6 +18,13 @@ import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbInventoryService;
 import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbInventoryListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronFloatingIPChangeListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronNetworkChangeListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronPortChangeListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronRouterChangeListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronSubnetChangeListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronLoadBalancerPoolChangeListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronLoadBalancerPoolMemberChangeListener;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
@@ -61,6 +70,7 @@ public class OvsdbInventoryServiceImpl implements ConfigInterface, OvsdbInventor
     @Override
     public void providersReady() {
         ovsdbDataChangeListener.start();
+        initializeNeutronModelsDataChangeListeners(dataBroker);
         initializeNetvirtTopology();
     }
 
@@ -84,4 +94,16 @@ public class OvsdbInventoryServiceImpl implements ConfigInterface, OvsdbInventor
             LOG.error("Error initializing netvirt topology");
         }
     }
+
+    private void initializeNeutronModelsDataChangeListeners(
+            DataBroker db) {
+        new NeutronNetworkChangeListener(db);
+        new NeutronSubnetChangeListener(db);
+        new NeutronPortChangeListener(db);
+        new NeutronRouterChangeListener(db);
+        new NeutronFloatingIPChangeListener(db);
+        new NeutronLoadBalancerPoolChangeListener(db);
+        new NeutronLoadBalancerPoolMemberChangeListener(db);
+    }
+
 }
index 4409731be49429e09a8724485c43e607095a0814..277c5a26804135ba1e6ed36b12d2f6ad284f92f7 100644 (file)
@@ -8,33 +8,42 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.impl;
 
-import java.util.ArrayList;
-import java.util.List;
-
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSubnet;
-import org.opendaylight.neutron.spi.Neutron_IPs;
 import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
-
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class SecurityServicesImpl implements ConfigInterface, SecurityServicesManager {
     private static final Logger LOG = LoggerFactory.getLogger(TenantNetworkManagerImpl.class);
     private volatile INeutronPortCRUD neutronPortCache;
     private volatile INeutronSubnetCRUD neutronSubnetCache;
     private volatile Southbound southbound;
+    private volatile INeutronNetworkCRUD neutronNetworkCache;
+    private volatile ConfigurationService configurationService;
+    private volatile IngressAclProvider ingressAclProvider;
+    private volatile EgressAclProvider egressAclProvider;
+    private volatile SecurityServicesManager securityServicesManager;
 
     @Override
     public boolean isPortSecurityReady(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
@@ -133,9 +142,33 @@ public class SecurityServicesImpl implements ConfigInterface, SecurityServicesMa
             LOG.error("getDHCPServerPort:getDHCPServerPort failed due to ", e);
             return null;
         }
-
         return null;
+    }
 
+    @Override
+    public NeutronPort getNeutronPortFromDhcpIntf(
+            OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        if (neutronPortCache == null) {
+            LOG.error("getNeutronPortFromDhcpIntf: neutron port is null");
+            return null;
+        }
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(
+                terminationPointAugmentation,
+                Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId == null) {
+            return null;
+        }
+        NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
+        if (neutronPort == null) {
+            LOG.error("getNeutronPortFromDhcpIntf: neutron port of {} is not found", neutronPortId);
+            return null;
+        }
+        /* if the current port is a DHCP port, return true*/
+        if (neutronPort.getDeviceOwner().contains("dhcp")) {
+            LOG.trace("getNeutronPortFromDhcpIntf: neutronPort is a dhcp port", neutronPort );
+            return neutronPort;
+        }
+        return null;
     }
 
     @Override
@@ -301,10 +334,98 @@ public class SecurityServicesImpl implements ConfigInterface, SecurityServicesMa
 
     }
 
+    @Override
+    public void syncSecurityGroup(NeutronPort port, List<NeutronSecurityGroup> securityGroupList, boolean write) {
+        LOG.trace("syncSecurityGroup:" + securityGroupList + " Write:" + Boolean.valueOf(write));
+        if (null != port && null != port.getSecurityGroups()) {
+            Node node = getNode(port);
+            NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(port.getNetworkUUID());
+            String segmentationId = neutronNetwork.getProviderSegmentationID();
+            OvsdbTerminationPointAugmentation intf = getInterface(node, port);
+            long localPort = southbound.getOFPort(intf);
+            String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
+            if (attachedMac == null) {
+                LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
+                return;
+            }
+            long dpid = getDpidOfIntegrationBridge(node);
+            List<Neutron_IPs> srcAddressList = securityServicesManager.getIpAddressList(node, intf);
+            for (NeutronSecurityGroup securityGroupInPort:securityGroupList) {
+                ingressAclProvider.programPortSecurityAcl(dpid, segmentationId, attachedMac, localPort,
+                                                          securityGroupInPort, srcAddressList, write);
+                egressAclProvider.programPortSecurityAcl(dpid, segmentationId, attachedMac, localPort,
+                                                         securityGroupInPort, srcAddressList, write);
+            }
+        }
+    }
+
+    private long getDpidOfIntegrationBridge(Node node) {
+        LOG.trace("getDpidOfIntegrationBridge:" + node);
+        long dpid = 0L;
+        if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
+            dpid = getDpid(node);
+        }
+        return dpid;
+    }
+
+    private long getDpid(Node node) {
+        LOG.trace("getDpid" + node);
+        long dpid = southbound.getDataPathId(node);
+        if (dpid == 0) {
+            LOG.warn("getDpid: dpid not found: {}", node);
+        }
+        return dpid;
+    }
+
+    private Node getNode(NeutronPort port) {
+        LOG.trace("getNode:Port" + port);
+        List<Node> toplogyNodes = southbound.readOvsdbTopologyNodes();
+
+        for (Node topologyNode : toplogyNodes) {
+            try {
+                Node node = southbound.getBridgeNode(topologyNode,Constants.INTEGRATION_BRIDGE);
+                List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
+                for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
+                    String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
+                                                            Constants.EXTERNAL_ID_INTERFACE_ID);
+                    if (null != uuid && uuid.equals(port.getID())) {
+                        return node;
+                    }
+                }
+            } catch (Exception e) {
+                LOG.error("Exception during handlingNeutron network delete", e);
+            }
+        }
+        return null;
+    }
+
+    private OvsdbTerminationPointAugmentation getInterface(Node node, NeutronPort port) {
+        LOG.trace("getInterface:Node:" + node + " Port:" + port);
+        try {
+            List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
+            for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
+                String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
+                                                                      Constants.EXTERNAL_ID_INTERFACE_ID);
+                if (null != uuid && uuid.equals(port.getID())) {
+                    return ovsdbPort;
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("Exception during handlingNeutron network delete", e);
+        }
+        return null;
+    }
+
     @Override
     public void setDependencies(ServiceReference serviceReference) {
         southbound =
                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        neutronNetworkCache =
+                (INeutronNetworkCRUD) ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
+        configurationService =
+                (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
+        securityServicesManager =
+                (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
     }
 
     @Override
@@ -313,6 +434,10 @@ public class SecurityServicesImpl implements ConfigInterface, SecurityServicesMa
             neutronPortCache = (INeutronPortCRUD)impl;
         } else if (impl instanceof INeutronSubnetCRUD) {
             neutronSubnetCache = (INeutronSubnetCRUD) impl;
+        } else if (impl instanceof IngressAclProvider) {
+            ingressAclProvider = (IngressAclProvider) impl;
+        } else if (impl instanceof EgressAclProvider) {
+            egressAclProvider = (EgressAclProvider) impl;
         }
     }
-}
\ No newline at end of file
+}
index 4200448a6a05b8121ae8f0128d4a29c521ac948e..6b84f9f7f68170e86b220c8fe880f862f28e7e5e 100644 (file)
@@ -411,8 +411,8 @@ public class SouthboundImpl implements Southbound {
     /**
      * Method read ports from bridge node. Method will check if the provided node
      * has the ports details, if not, it will read from Operational data store.
-     * @param node
-     * @return
+     * @param node Target bridge to getch termination points from.
+     * @return List of termination points on the given bridge
      */
     public List<OvsdbTerminationPointAugmentation> getTerminationPointsOfBridge(Node node) {
         List<OvsdbTerminationPointAugmentation> tpAugmentations = extractTerminationPointAugmentations(node);
index 53ba42d27a9c93e5f7f5f520de5be42aed6797ef..6cb1f144fcbc26ed7546735e4f147c5ca77deba6 100644 (file)
@@ -9,11 +9,13 @@
 package org.opendaylight.ovsdb.openstack.netvirt.impl;
 
 import com.google.common.base.Preconditions;
+
 import java.util.List;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/INeutronObject.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/INeutronObject.java
new file mode 100644 (file)
index 0000000..4e3076c
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator;
+
+/**
+ * This class contains behaviour common to Neutron configuration objects
+ */
+public interface INeutronObject {
+
+    String getID();
+
+    void setID(String id);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronFirewall.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronFirewall.java
new file mode 100644 (file)
index 0000000..935fadb
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Firewall as a service
+ * (FWaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ * id                 uuid-str
+ * tenant_id          uuid-str
+ * name               String
+ * description        String
+ * admin_state_up     Bool
+ * status             String
+ * shared             Bool
+ * firewall_policy_id uuid-str
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ *
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronFirewall implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String firewallUUID;
+
+    @XmlElement (name = "tenant_id")
+    String firewallTenantID;
+
+    @XmlElement (name = "name")
+    String firewallName;
+
+    @XmlElement (name = "description")
+    String firewallDescription;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean firewallAdminStateIsUp;
+
+    @XmlElement (name = "status")
+    String firewallStatus;
+
+    @XmlElement (defaultValue = "false", name = "shared")
+    Boolean firewallIsShared;
+
+    @XmlElement (name = "firewall_policy_id")
+    String neutronFirewallPolicyID;
+
+    public String getID() {
+        return firewallUUID;
+    }
+
+    public void setID(String id) {
+        firewallUUID = id;
+    }
+
+    // @deprecated use getID()
+    public String getFirewallUUID() {
+        return firewallUUID;
+    }
+
+    // @deprecated use setID()
+    public void setFirewallUUID(String firewallUUID) {
+        this.firewallUUID = firewallUUID;
+    }
+
+    public String getFirewallTenantID() {
+        return firewallTenantID;
+    }
+
+    public void setFirewallTenantID(String firewallTenantID) {
+        this.firewallTenantID = firewallTenantID;
+    }
+
+    public String getFirewallName() {
+        return firewallName;
+    }
+
+    public void setFirewallName(String firewallName) {
+        this.firewallName = firewallName;
+    }
+
+    public String getFirewallDescription() {
+        return firewallDescription;
+    }
+
+    public void setFirewallDescription(String firewallDescription) {
+        this.firewallDescription = firewallDescription;
+    }
+
+    public Boolean getFirewallAdminStateIsUp() {
+        return firewallAdminStateIsUp;
+    }
+
+    public void setFirewallAdminStateIsUp(Boolean firewallAdminStateIsUp) {
+        this.firewallAdminStateIsUp = firewallAdminStateIsUp;
+    }
+
+    public String getFirewallStatus() {
+        return firewallStatus;
+    }
+
+    public void setFirewallStatus(String firewallStatus) {
+        this.firewallStatus = firewallStatus;
+    }
+
+    public Boolean getFirewallIsShared() {
+        return firewallIsShared;
+    }
+
+    public void setFirewallIsShared(Boolean firewallIsShared) {
+        this.firewallIsShared = firewallIsShared;
+    }
+
+    public String getFirewallPolicyID() {
+        return neutronFirewallPolicyID;
+    }
+
+    public void setNeutronFirewallPolicyID(String firewallPolicy) {
+        this.neutronFirewallPolicyID = firewallPolicy;
+    }
+
+    public NeutronFirewall extractFields(List<String> fields) {
+        NeutronFirewall ans = new NeutronFirewall();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setID(this.getID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setFirewallTenantID(this.getFirewallTenantID());
+            }
+            if (s.equals("name")) {
+                ans.setFirewallName(this.getFirewallName());
+            }
+            if(s.equals("description")) {
+                ans.setFirewallDescription(this.getFirewallDescription());
+            }
+            if (s.equals("admin_state_up")) {
+                ans.setFirewallAdminStateIsUp(firewallAdminStateIsUp);
+            }
+            if (s.equals("status")) {
+                ans.setFirewallStatus(this.getFirewallStatus());
+            }
+            if (s.equals("shared")) {
+                ans.setFirewallIsShared(firewallIsShared);
+            }
+            if (s.equals("firewall_policy_id")) {
+                ans.setNeutronFirewallPolicyID(this.getFirewallPolicyID());
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronFirewall{" +
+            "firewallUUID='" + firewallUUID + '\'' +
+            ", firewallTenantID='" + firewallTenantID + '\'' +
+            ", firewallName='" + firewallName + '\'' +
+            ", firewallDescription='" + firewallDescription + '\'' +
+            ", firewallAdminStateIsUp=" + firewallAdminStateIsUp +
+            ", firewallStatus='" + firewallStatus + '\'' +
+            ", firewallIsShared=" + firewallIsShared +
+            ", firewallRulePolicyID=" + neutronFirewallPolicyID +
+            '}';
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronFirewallPolicy.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronFirewallPolicy.java
new file mode 100644 (file)
index 0000000..ad9da39
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Firewall as a service
+ * (FWaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields.
+ * The implemented fields are as follows:
+ *
+ * id             uuid-str
+ * tenant_id      uuid-str
+ * name           String
+ * description    String
+ * shared         Boolean
+ * firewall_rules List
+ * audited        Boolean
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ *
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronFirewallPolicy implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String firewallPolicyUUID;
+
+    @XmlElement (name = "tenant_id")
+    String firewallPolicyTenantID;
+
+    @XmlElement (name = "name")
+    String firewallPolicyName;
+
+    @XmlElement (name = "description")
+    String firewallPolicyDescription;
+
+    @XmlElement (defaultValue = "false", name = "shared")
+    Boolean firewallPolicyIsShared;
+
+    @XmlElement (name = "firewall_rules")
+    List<String> firewallPolicyRules;
+
+    @XmlElement (defaultValue = "false", name = "audited")
+    Boolean firewallPolicyIsAudited;
+
+    public Boolean getFirewallPolicyIsAudited() {
+        return firewallPolicyIsAudited;
+    }
+
+    public void setFirewallPolicyIsAudited(Boolean firewallPolicyIsAudited) {
+        this.firewallPolicyIsAudited = firewallPolicyIsAudited;
+    }
+
+    public void setFirewallPolicyRules(List<String> firewallPolicyRules) {
+        this.firewallPolicyRules = firewallPolicyRules;
+    }
+
+    public List<String> getFirewallPolicyRules() {
+        return firewallPolicyRules;
+    }
+
+    public Boolean getFirewallPolicyIsShared() {
+        return firewallPolicyIsShared;
+    }
+
+    public void setFirewallPolicyIsShared(Boolean firewallPolicyIsShared) {
+        this.firewallPolicyIsShared = firewallPolicyIsShared;
+    }
+
+    public String getFirewallPolicyDescription() {
+        return firewallPolicyDescription;
+    }
+
+    public void setFirewallPolicyDescription(String firewallPolicyDescription) {
+        this.firewallPolicyDescription = firewallPolicyDescription;
+    }
+
+    public String getFirewallPolicyName() {
+        return firewallPolicyName;
+    }
+
+    public void setFirewallPolicyName(String firewallPolicyName) {
+        this.firewallPolicyName = firewallPolicyName;
+    }
+
+    public String getFirewallPolicyTenantID() {
+        return firewallPolicyTenantID;
+    }
+
+    public void setFirewallPolicyTenantID(String firewallPolicyTenantID) {
+        this.firewallPolicyTenantID = firewallPolicyTenantID;
+    }
+
+    public String getID() {
+        return firewallPolicyUUID;
+    }
+
+    public void setID(String id) {
+        firewallPolicyUUID = id;
+    }
+
+    // @deprecated use getID()
+    public String getFirewallPolicyUUID() {
+        return firewallPolicyUUID;
+    }
+
+    // @deprecated use setID()
+    public void setFirewallPolicyUUID(String firewallPolicyUUID) {
+        this.firewallPolicyUUID = firewallPolicyUUID;
+    }
+
+    public NeutronFirewallPolicy extractFields(List<String> fields) {
+        NeutronFirewallPolicy ans = new NeutronFirewallPolicy();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setID(this.getID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setFirewallPolicyTenantID(this.getFirewallPolicyTenantID());
+            }
+            if (s.equals("name")) {
+                ans.setFirewallPolicyName(this.getFirewallPolicyName());
+            }
+            if(s.equals("description")) {
+                ans.setFirewallPolicyDescription(this.getFirewallPolicyDescription());
+            }
+            if (s.equals("shared")) {
+                ans.setFirewallPolicyIsShared(firewallPolicyIsShared);
+            }
+            if (s.equals("firewall_rules")) {
+                List<String> firewallRuleList = new ArrayList<String>();
+                firewallRuleList.addAll(this.getFirewallPolicyRules());
+                ans.setFirewallPolicyRules(firewallRuleList);
+            }
+            if (s.equals("audited")) {
+                ans.setFirewallPolicyIsAudited(firewallPolicyIsAudited);
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronFirewallPolicy{" +
+            "firewallPolicyUUID='" + firewallPolicyUUID + '\'' +
+            ", firewallPolicyTenantID='" + firewallPolicyTenantID + '\'' +
+            ", firewallPolicyName='" + firewallPolicyName + '\'' +
+            ", firewallPolicyDescription='" + firewallPolicyDescription + '\'' +
+            ", firewallPolicyIsShared=" + firewallPolicyIsShared +
+            ", firewallPolicyRules=" + firewallPolicyRules +
+            ", firewallPolicyIsAudited='" + firewallPolicyIsAudited + '\'' +
+            '}';
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronFirewallRule.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronFirewallRule.java
new file mode 100644 (file)
index 0000000..9bc4c52
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Firewall as a service
+ * (FWaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields.
+ * The implemented fields are as follows:
+ *
+ * tenant_id               uuid-str
+ * name                    String
+ * description             String
+ * admin_state_up          Bool
+ * status                  String
+ * shared                  Bool
+ * firewall_policy_id      uuid-str
+ * protocol                String
+ * ip_version              Integer
+ * source_ip_address       String (IP addr or CIDR)
+ * destination_ip_address  String (IP addr or CIDR)
+ * source_port             Integer
+ * destination_port        Integer
+ * position                Integer
+ * action                  String
+ * enabled                 Bool
+ * id                      uuid-str
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ *
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronFirewallRule implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String firewallRuleUUID;
+
+    @XmlElement(name = "tenant_id")
+    String firewallRuleTenantID;
+
+    @XmlElement(name = "name")
+    String firewallRuleName;
+
+    @XmlElement(name = "description")
+    String firewallRuleDescription;
+
+    @XmlElement(name = "status")
+    String firewallRuleStatus;
+
+    @XmlElement(defaultValue = "false", name = "shared")
+    Boolean firewallRuleIsShared;
+
+    @XmlElement(name = "firewall_policy_id")
+    String firewallRulePolicyID;
+
+    @XmlElement(name = "protocol")
+    String firewallRuleProtocol;
+
+    @XmlElement(name = "ip_version")
+    Integer firewallRuleIpVer;
+
+    @XmlElement(name = "source_ip_address")
+    String firewallRuleSrcIpAddr;
+
+    @XmlElement(name = "destination_ip_address")
+    String firewallRuleDstIpAddr;
+
+    @XmlElement(name = "source_port")
+    Integer firewallRuleSrcPort;
+
+    @XmlElement(name = "destination_port")
+    Integer firewallRuleDstPort;
+
+    @XmlElement(name = "position")
+    Integer firewallRulePosition;
+
+    @XmlElement(name = "action")
+    String firewallRuleAction;
+
+    @XmlElement(name = "enabled")
+    Boolean firewallRuleIsEnabled;
+
+    public Boolean getFirewallRuleIsEnabled() {
+        return firewallRuleIsEnabled;
+    }
+
+    public void setFirewallRuleIsEnabled(Boolean firewallRuleIsEnabled) {
+        this.firewallRuleIsEnabled = firewallRuleIsEnabled;
+    }
+
+    public String getFirewallRuleAction() {
+        return firewallRuleAction;
+    }
+
+    public void setFirewallRuleAction(String firewallRuleAction) {
+        this.firewallRuleAction = firewallRuleAction;
+    }
+
+    public Integer getFirewallRulePosition() {
+        return firewallRulePosition;
+    }
+
+    public void setFirewallRulePosition(Integer firewallRulePosition) {
+        this.firewallRulePosition = firewallRulePosition;
+    }
+
+    public Integer getFirewallRuleDstPort() {
+        return firewallRuleDstPort;
+    }
+
+    public void setFirewallRuleDstPort(Integer firewallRuleDstPort) {
+        this.firewallRuleDstPort = firewallRuleDstPort;
+    }
+
+    public Integer getFirewallRuleSrcPort() {
+        return firewallRuleSrcPort;
+    }
+
+    public void setFirewallRuleSrcPort(Integer firewallRuleSrcPort) {
+        this.firewallRuleSrcPort = firewallRuleSrcPort;
+    }
+
+    public String getFirewallRuleDstIpAddr() {
+        return firewallRuleDstIpAddr;
+    }
+
+    public void setFirewallRuleDstIpAddr(String firewallRuleDstIpAddr) {
+        this.firewallRuleDstIpAddr = firewallRuleDstIpAddr;
+    }
+
+    public String getFirewallRuleSrcIpAddr() {
+        return firewallRuleSrcIpAddr;
+    }
+
+    public void setFirewallRuleSrcIpAddr(String firewallRuleSrcIpAddr) {
+        this.firewallRuleSrcIpAddr = firewallRuleSrcIpAddr;
+    }
+
+    public Integer getFirewallRuleIpVer() {
+        return firewallRuleIpVer;
+    }
+
+    public void setFirewallRuleIpVer(Integer firewallRuleIpVer) {
+        this.firewallRuleIpVer = firewallRuleIpVer;
+    }
+
+    public String getFirewallRuleProtocol() {
+        return firewallRuleProtocol;
+    }
+
+    public void setFirewallRuleProtocol(String firewallRuleProtocol) {
+        this.firewallRuleProtocol = firewallRuleProtocol;
+    }
+
+    public String getFirewallRulePolicyID() {
+        return firewallRulePolicyID;
+    }
+
+    public void setFirewallRulesPolicyID(String firewallRulePolicyID) {
+        this.firewallRulePolicyID = firewallRulePolicyID;
+    }
+
+    public Boolean getFirewallRuleIsShared() {
+        return firewallRuleIsShared;
+    }
+
+    public void setFirewallRuleIsShared(Boolean firewallRuleIsShared) {
+        this.firewallRuleIsShared = firewallRuleIsShared;
+    }
+
+    public String getFirewallRuleStatus() {
+        return firewallRuleStatus;
+    }
+
+    public void setFirewallRuleStatus(String firewallRuleStatus) {
+        this.firewallRuleStatus = firewallRuleStatus;
+    }
+
+    public String getFirewallRuleDescription() {
+        return firewallRuleDescription;
+    }
+
+    public void setFirewallRuleDescription(String firewallRuleDescription) {
+        this.firewallRuleDescription = firewallRuleDescription;
+    }
+
+    public String getFirewallRuleName() {
+        return firewallRuleName;
+    }
+
+    public void setFirewallRuleName(String firewallRuleName) {
+        this.firewallRuleName = firewallRuleName;
+    }
+
+    public String getFirewallRuleTenantID() {
+        return firewallRuleTenantID;
+    }
+
+    public void setFirewallRuleTenantID(String firewallRuleTenantID) {
+        this.firewallRuleTenantID = firewallRuleTenantID;
+    }
+
+    public String getID() {
+        return firewallRuleUUID;
+    }
+
+    public void setID(String id) {
+        firewallRuleUUID = id;
+    }
+
+    // @deprecated use getID()
+    public String getFirewallRuleUUID() {
+        return firewallRuleUUID;
+    }
+
+    // @deprecated use setID()
+    public void setFireWallRuleID(String firewallRuleUUID) {
+        this.firewallRuleUUID = firewallRuleUUID;
+    }
+
+    public NeutronFirewallRule extractFields(List<String> fields) {
+        NeutronFirewallRule ans = new NeutronFirewallRule();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setID(this.getID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setFirewallRuleTenantID(this.getFirewallRuleTenantID());
+            }
+            if (s.equals("name")) {
+                ans.setFirewallRuleName(this.getFirewallRuleName());
+            }
+            if (s.equals("description")) {
+                ans.setFirewallRuleDescription(this.getFirewallRuleDescription());
+            }
+            if (s.equals("status")) {
+                ans.setFirewallRuleStatus(this.getFirewallRuleStatus());
+            }
+            if (s.equals("shared")) {
+                ans.setFirewallRuleIsShared(firewallRuleIsShared);
+            }
+            if (s.equals("firewall_policy_id")) {
+                ans.setFirewallRulesPolicyID(this.getFirewallRulePolicyID());
+            }
+            if (s.equals("protocol")) {
+                ans.setFirewallRuleProtocol(this.getFirewallRuleProtocol());
+            }
+            if (s.equals("source_ip_address")) {
+                ans.setFirewallRuleSrcIpAddr(this.getFirewallRuleSrcIpAddr());
+            }
+            if (s.equals("destination_ip_address")) {
+                ans.setFirewallRuleDstIpAddr(this.getFirewallRuleDstIpAddr());
+            }
+            if (s.equals("source_port")) {
+                ans.setFirewallRuleSrcPort(this.getFirewallRuleSrcPort());
+            }
+            if (s.equals("destination_port")) {
+                ans.setFirewallRuleDstPort(this.getFirewallRuleDstPort());
+            }
+            if (s.equals("position")) {
+                ans.setFirewallRulePosition(this.getFirewallRulePosition());
+            }
+            if (s.equals("action")) {
+                ans.setFirewallRuleAction(this.getFirewallRuleAction());
+            }
+            if (s.equals("enabled")) {
+                ans.setFirewallRuleIsEnabled(firewallRuleIsEnabled);
+            }
+
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "firewallPolicyRules{" +
+            "firewallRuleUUID='" + firewallRuleUUID + '\'' +
+            ", firewallRuleTenantID='" + firewallRuleTenantID + '\'' +
+            ", firewallRuleName='" + firewallRuleName + '\'' +
+            ", firewallRuleDescription='" + firewallRuleDescription + '\'' +
+            ", firewallRuleStatus='" + firewallRuleStatus + '\'' +
+            ", firewallRuleIsShared=" + firewallRuleIsShared +
+            ", firewallRulePolicyID=" + firewallRulePolicyID +
+            ", firewallRuleProtocol='" + firewallRuleProtocol + '\'' +
+            ", firewallRuleIpVer=" + firewallRuleIpVer +
+            ", firewallRuleSrcIpAddr='" + firewallRuleSrcIpAddr + '\'' +
+            ", firewallRuleDstIpAddr='" + firewallRuleDstIpAddr + '\'' +
+            ", firewallRuleSrcPort=" + firewallRuleSrcPort +
+            ", firewallRuleDstPort=" + firewallRuleDstPort +
+            ", firewallRulePosition=" + firewallRulePosition +
+            ", firewallRuleAction='" + firewallRuleAction + '\'' +
+            ", firewallRuleIsEnabled=" + firewallRuleIsEnabled +
+            '}';
+    }
+
+    public void initDefaults() {
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronFloatingIP.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronFloatingIP.java
new file mode 100644 (file)
index 0000000..89bde70
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronFloatingIP implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement (name = "id")
+    String floatingIPUUID;
+
+    @XmlElement (name = "floating_network_id")
+    String floatingNetworkUUID;
+
+    @XmlElement (name = "port_id")
+    String portUUID;
+
+    @XmlElement (name = "fixed_ip_address")
+    String fixedIPAddress;
+
+    @XmlElement (name = "floating_ip_address")
+    String floatingIPAddress;
+
+    @XmlElement (name = "tenant_id")
+    String tenantUUID;
+
+    @XmlElement (name="router_id")
+    String routerUUID;
+
+    @XmlElement (name="status")
+    String status;
+
+    public NeutronFloatingIP() {
+    }
+
+    public String getID() {
+        return floatingIPUUID;
+    }
+
+    public void setID(String id) {
+        floatingIPUUID = id;
+    }
+
+    // @deprecated use getID()
+    public String getFloatingIPUUID() {
+        return floatingIPUUID;
+    }
+
+    // @deprecated use setID()
+    public void setFloatingIPUUID(String floatingIPUUID) {
+        this.floatingIPUUID = floatingIPUUID;
+    }
+
+    public String getFloatingNetworkUUID() {
+        return floatingNetworkUUID;
+    }
+
+    public void setFloatingNetworkUUID(String floatingNetworkUUID) {
+        this.floatingNetworkUUID = floatingNetworkUUID;
+    }
+
+    public String getPortUUID() {
+        return portUUID;
+    }
+
+    public String getRouterUUID() {
+        return routerUUID;
+    }
+
+    public void setPortUUID(String portUUID) {
+        this.portUUID = portUUID;
+    }
+
+    public String getFixedIPAddress() {
+        return fixedIPAddress;
+    }
+
+    public void setFixedIPAddress(String fixedIPAddress) {
+        this.fixedIPAddress = fixedIPAddress;
+    }
+
+    public String getFloatingIPAddress() {
+        return floatingIPAddress;
+    }
+
+    public void setFloatingIPAddress(String floatingIPAddress) {
+        this.floatingIPAddress = floatingIPAddress;
+    }
+
+    public String getTenantUUID() {
+        return tenantUUID;
+    }
+
+    public void setTenantUUID(String tenantUUID) {
+        this.tenantUUID = tenantUUID;
+    }
+
+    public void setRouterUUID(String routerUUID) {
+        this.routerUUID = routerUUID;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    /**
+     * This method copies selected fields from the object and returns them
+     * as a new object, suitable for marshaling.
+     *
+     * @param fields
+     *            List of attributes to be extracted
+     * @return an OpenStackFloatingIPs object with only the selected fields
+     * populated
+     */
+
+    public NeutronFloatingIP extractFields(List<String> fields) {
+        NeutronFloatingIP ans = new NeutronFloatingIP();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setID(this.getID());
+            }
+            if (s.equals("floating_network_id")) {
+                ans.setFloatingNetworkUUID(this.getFloatingNetworkUUID());
+            }
+            if (s.equals("port_id")) {
+                ans.setPortUUID(this.getPortUUID());
+            }
+            if (s.equals("fixed_ip_address")) {
+                ans.setFixedIPAddress(this.getFixedIPAddress());
+            }
+            if (s.equals("floating_ip_address")) {
+                ans.setFloatingIPAddress(this.getFloatingIPAddress());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setTenantUUID(this.getTenantUUID());
+            }
+            if (s.equals("router_id")) {
+                ans.setRouterUUID(this.getRouterUUID());
+            }
+            if (s.equals("status")) {
+                ans.setStatus(this.getStatus());
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronFloatingIP{" +
+            "fipUUID='" + floatingIPUUID + '\'' +
+            ", fipFloatingNetworkId='" + floatingNetworkUUID + '\'' +
+            ", fipPortUUID='" + portUUID + '\'' +
+            ", fipFixedIPAddress='" + fixedIPAddress + '\'' +
+            ", fipFloatingIPAddress=" + floatingIPAddress +
+            ", fipTenantId='" + tenantUUID + '\'' +
+            ", fipRouterId='" + routerUUID + '\'' +
+            ", fipStatus='" + status + '\'' +
+            '}';
+    }
+
+    public void initDefaults() {
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancer.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancer.java
new file mode 100644 (file)
index 0000000..cf95722
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ * id                 uuid-str
+ * tenant_id          uuid-str
+ * name               String
+ * description        String
+ * status             String
+ * vip_address        IP address
+ * vip_subnet         uuid-str
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancer implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String loadBalancerID;
+
+    @XmlElement (name = "tenant_id")
+    String loadBalancerTenantID;
+
+    @XmlElement (name = "name")
+    String loadBalancerName;
+
+    @XmlElement (name = "description")
+    String loadBalancerDescription;
+
+    @XmlElement (name = "status")
+    String loadBalancerStatus;
+
+    @XmlElement (name = "admin_state_up")
+    Boolean loadBalancerAdminStateUp;
+
+    @XmlElement (name = "vip_address")
+    String loadBalancerVipAddress;
+
+    @XmlElement (name = "vip_subnet_id")
+    String loadBalancerVipSubnetID;
+
+    public String getID() {
+        return loadBalancerID;
+    }
+
+    public void setID(String id) {
+        loadBalancerID = id;
+    }
+
+    // @deprecated use getID()
+    public String getLoadBalancerID() {
+        return loadBalancerID;
+    }
+
+    // @deprecated use setID()
+    public void setLoadBalancerID(String loadBalancerID) {
+        this.loadBalancerID = loadBalancerID;
+    }
+
+    public String getLoadBalancerTenantID() {
+        return loadBalancerTenantID;
+    }
+
+    public void setLoadBalancerTenantID(String loadBalancerTenantID) {
+        this.loadBalancerTenantID = loadBalancerTenantID;
+    }
+
+    public String getLoadBalancerName() {
+        return loadBalancerName;
+    }
+
+    public void setLoadBalancerName(String loadBalancerName) {
+        this.loadBalancerName = loadBalancerName;
+    }
+
+    public String getLoadBalancerDescription() {
+        return loadBalancerDescription;
+    }
+
+    public void setLoadBalancerDescription(String loadBalancerDescription) {
+        this.loadBalancerDescription = loadBalancerDescription;
+    }
+
+    public String getLoadBalancerStatus() {
+        return loadBalancerStatus;
+    }
+
+    public void setLoadBalancerStatus(String loadBalancerStatus) {
+        this.loadBalancerStatus = loadBalancerStatus;
+    }
+
+    public Boolean getLoadBalancerAdminStateUp() {
+        return loadBalancerAdminStateUp;
+    }
+
+    public void setLoadBalancerAdminStateUp(Boolean loadBalancerAdminStateUp) {
+        this.loadBalancerAdminStateUp = loadBalancerAdminStateUp;
+    }
+
+    public String getLoadBalancerVipAddress() {
+        return loadBalancerVipAddress;
+    }
+
+    public void setLoadBalancerVipAddress(String loadBalancerVipAddress) {
+        this.loadBalancerVipAddress = loadBalancerVipAddress;
+    }
+
+    public String getLoadBalancerVipSubnetID() {
+        return loadBalancerVipSubnetID;
+    }
+
+    public void setLoadBalancerVipSubnetID(String loadBalancerVipSubnetID) {
+        this.loadBalancerVipSubnetID = loadBalancerVipSubnetID;
+    }
+
+    public NeutronLoadBalancer extractFields(List<String> fields) {
+        NeutronLoadBalancer ans = new NeutronLoadBalancer();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setID(this.getID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setLoadBalancerTenantID(this.getLoadBalancerTenantID());
+            }
+            if (s.equals("name")) {
+                ans.setLoadBalancerName(this.getLoadBalancerName());
+            }
+            if(s.equals("description")) {
+                ans.setLoadBalancerDescription(this.getLoadBalancerDescription());
+            }
+            if (s.equals("vip_address")) {
+                ans.setLoadBalancerVipAddress(this.getLoadBalancerVipAddress());
+            }
+            if (s.equals("vip_subnet_id")) {
+                ans.setLoadBalancerVipSubnetID(this.getLoadBalancerVipSubnetID());
+            }
+            if (s.equals("status")) {
+                ans.setLoadBalancerStatus(this.getLoadBalancerStatus());
+            }
+            if (s.equals("admin_state_up")) {
+                ans.setLoadBalancerAdminStateUp(this.getLoadBalancerAdminStateUp());
+            }
+        }
+        return ans;
+    }
+
+    @Override public String toString() {
+        return "NeutronLoadBalancer{" +
+                "loadBalancerID='" + loadBalancerID + '\'' +
+                ", loadBalancerTenantID='" + loadBalancerTenantID + '\'' +
+                ", loadBalancerName='" + loadBalancerName + '\'' +
+                ", loadBalancerDescription='" + loadBalancerDescription + '\'' +
+                ", loadBalancerStatus='" + loadBalancerStatus + '\'' +
+                ", loadBalancerAdminStateUp='" + loadBalancerAdminStateUp + '\'' +
+                ", loadBalancerVipAddress='" + loadBalancerVipAddress + '\'' +
+                ", loadBalancerVipSubnetID='" + loadBalancerVipSubnetID + '\'' +
+                '}';
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancerHealthMonitor.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancerHealthMonitor.java
new file mode 100644 (file)
index 0000000..430cef8
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ *
+ * id                 uuid-str
+ * tenant_id          uuid-str
+ * type               String
+ * delay              Integer
+ * timeout            Integer
+ * max_retries        Integer
+ * http_method        String
+ * url_path           String
+ * expected_codes     String
+ * admin_state_up     Boolean
+ * status             String
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerHealthMonitor
+    implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String loadBalancerHealthMonitorID;
+
+    @XmlElement (name = "tenant_id")
+    String loadBalancerHealthMonitorTenantID;
+
+    @XmlElement (name = "type")
+    String loadBalancerHealthMonitorType;
+
+    @XmlElement (name = "delay")
+    Integer loadBalancerHealthMonitorDelay;
+
+    @XmlElement (name = "timeout")
+    Integer loadBalancerHealthMonitorTimeout;
+
+    @XmlElement (name = "max_retries")
+    Integer loadBalancerHealthMonitorMaxRetries;
+
+    @XmlElement (name = "http_method")
+    String loadBalancerHealthMonitorHttpMethod;
+
+    @XmlElement (name = "url_path")
+    String loadBalancerHealthMonitorUrlPath;
+
+    @XmlElement (name = "expected_codes")
+    String loadBalancerHealthMonitorExpectedCodes;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean loadBalancerHealthMonitorAdminStateIsUp;
+
+    @XmlElement (name = "pools")
+    List<Neutron_ID> loadBalancerHealthMonitorPools;
+
+    public String getID() {
+        return loadBalancerHealthMonitorID;
+    }
+
+    public void setID(String id) {
+        loadBalancerHealthMonitorID = id;
+    }
+
+    // @deprecated use getID()
+    public String getLoadBalancerHealthMonitorID() {
+        return loadBalancerHealthMonitorID;
+    }
+
+    // @deprecated use setID()
+    public void setLoadBalancerHealthMonitorID(String loadBalancerHealthMonitorID) {
+        this.loadBalancerHealthMonitorID = loadBalancerHealthMonitorID;
+    }
+
+    public String getLoadBalancerHealthMonitorTenantID() {
+        return loadBalancerHealthMonitorTenantID;
+    }
+
+    public void setLoadBalancerHealthMonitorTenantID(String loadBalancerHealthMonitorTenantID) {
+        this.loadBalancerHealthMonitorTenantID = loadBalancerHealthMonitorTenantID;
+    }
+
+    public String getLoadBalancerHealthMonitorType() {
+        return loadBalancerHealthMonitorType;
+    }
+
+    public void setLoadBalancerHealthMonitorType(String loadBalancerHealthMonitorType) {
+        this.loadBalancerHealthMonitorType = loadBalancerHealthMonitorType;
+    }
+
+    public Integer getLoadBalancerHealthMonitorDelay() {
+        return loadBalancerHealthMonitorDelay;
+    }
+
+    public void setLoadBalancerHealthMonitorDelay(Integer loadBalancerHealthMonitorDelay) {
+        this.loadBalancerHealthMonitorDelay = loadBalancerHealthMonitorDelay;
+    }
+
+    public Integer getLoadBalancerHealthMonitorTimeout() {
+        return loadBalancerHealthMonitorTimeout;
+    }
+
+    public void setLoadBalancerHealthMonitorTimeout(Integer loadBalancerHealthMonitorTimeout) {
+        this.loadBalancerHealthMonitorTimeout = loadBalancerHealthMonitorTimeout;
+    }
+
+    public Integer getLoadBalancerHealthMonitorMaxRetries() {
+        return loadBalancerHealthMonitorMaxRetries;
+    }
+
+    public void setLoadBalancerHealthMonitorMaxRetries(Integer loadBalancerHealthMonitorMaxRetries) {
+        this.loadBalancerHealthMonitorMaxRetries = loadBalancerHealthMonitorMaxRetries;
+    }
+
+    public String getLoadBalancerHealthMonitorHttpMethod() {
+        return loadBalancerHealthMonitorHttpMethod;
+    }
+
+    public void setLoadBalancerHealthMonitorHttpMethod(String loadBalancerHealthMonitorHttpMethod) {
+        this.loadBalancerHealthMonitorHttpMethod = loadBalancerHealthMonitorHttpMethod;
+    }
+
+    public String getLoadBalancerHealthMonitorUrlPath() {
+        return loadBalancerHealthMonitorUrlPath;
+    }
+
+    public void setLoadBalancerHealthMonitorUrlPath(String loadBalancerHealthMonitorUrlPath) {
+        this.loadBalancerHealthMonitorUrlPath = loadBalancerHealthMonitorUrlPath;
+    }
+
+    public String getLoadBalancerHealthMonitorExpectedCodes() {
+        return loadBalancerHealthMonitorExpectedCodes;
+    }
+
+    public void setLoadBalancerHealthMonitorExpectedCodes(String loadBalancerHealthMonitorExpectedCodes) {
+        this.loadBalancerHealthMonitorExpectedCodes = loadBalancerHealthMonitorExpectedCodes;
+    }
+
+    public Boolean getLoadBalancerHealthMonitorAdminStateIsUp() {
+        return loadBalancerHealthMonitorAdminStateIsUp;
+    }
+
+    public void setLoadBalancerHealthMonitorAdminStateIsUp(Boolean loadBalancerHealthMonitorAdminStateIsUp) {
+        this.loadBalancerHealthMonitorAdminStateIsUp = loadBalancerHealthMonitorAdminStateIsUp;
+    }
+
+    public List<Neutron_ID> getLoadBalancerHealthMonitorPools() {
+        return loadBalancerHealthMonitorPools;
+    }
+
+    public void setLoadBalancerHealthMonitorPools(List<Neutron_ID> loadBalancerHealthMonitorPools) {
+        this.loadBalancerHealthMonitorPools = loadBalancerHealthMonitorPools;
+    }
+
+    public NeutronLoadBalancerHealthMonitor extractFields(List<String> fields) {
+        NeutronLoadBalancerHealthMonitor ans = new NeutronLoadBalancerHealthMonitor();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setID(this.getID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setLoadBalancerHealthMonitorTenantID(this.getLoadBalancerHealthMonitorTenantID());
+            }
+            if (s.equals("type")) {
+                ans.setLoadBalancerHealthMonitorType(this.getLoadBalancerHealthMonitorType());
+            }
+            if (s.equals("delay")) {
+                ans.setLoadBalancerHealthMonitorDelay(this.getLoadBalancerHealthMonitorDelay());
+            }
+            if (s.equals("timeout")) {
+                ans.setLoadBalancerHealthMonitorTimeout(this.getLoadBalancerHealthMonitorTimeout());
+            }
+            if (s.equals("max_retries")) {
+                ans.setLoadBalancerHealthMonitorMaxRetries(this.getLoadBalancerHealthMonitorMaxRetries());
+            }
+            if (s.equals("http_method")) {
+                ans.setLoadBalancerHealthMonitorHttpMethod(this.getLoadBalancerHealthMonitorHttpMethod());
+            }
+            if(s.equals("url_path")) {
+                ans.setLoadBalancerHealthMonitorUrlPath(this.getLoadBalancerHealthMonitorUrlPath());
+            }
+            if (s.equals("expected_codes")) {
+                ans.setLoadBalancerHealthMonitorExpectedCodes(this.getLoadBalancerHealthMonitorExpectedCodes());
+            }
+            if (s.equals("admin_state_up")) {
+                ans.setLoadBalancerHealthMonitorAdminStateIsUp(loadBalancerHealthMonitorAdminStateIsUp);
+            }
+        }
+        return ans;
+    }
+
+    @Override public String toString() {
+        return "NeutronLoadBalancerHealthMonitor{" +
+                "loadBalancerHealthMonitorID='" + loadBalancerHealthMonitorID + '\'' +
+                ", loadBalancerHealthMonitorTenantID='" + loadBalancerHealthMonitorTenantID + '\'' +
+                ", loadBalancerHealthMonitorType='" + loadBalancerHealthMonitorType + '\'' +
+                ", loadBalancerHealthMonitorDelay=" + loadBalancerHealthMonitorDelay +
+                ", loadBalancerHealthMonitorTimeout=" + loadBalancerHealthMonitorTimeout +
+                ", loadBalancerHealthMonitorMaxRetries=" + loadBalancerHealthMonitorMaxRetries +
+                ", loadBalancerHealthMonitorHttpMethod='" + loadBalancerHealthMonitorHttpMethod + '\'' +
+                ", loadBalancerHealthMonitorUrlPath='" + loadBalancerHealthMonitorUrlPath + '\'' +
+                ", loadBalancerHealthMonitorExpectedCodes='" + loadBalancerHealthMonitorExpectedCodes + '\'' +
+                ", loadBalancerHealthMonitorAdminStateIsUp=" + loadBalancerHealthMonitorAdminStateIsUp +
+                '}';
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancerListener.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancerListener.java
new file mode 100644 (file)
index 0000000..48d19b5
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ * id                 uuid-str
+ * default_pool_id    String
+ * tenant_id          uuid-str
+ * name               String
+ * description        String
+ * shared             Bool
+ * protocol           String
+ * protocol_port      String
+ * load_balancer_id   String
+ * admin_state_up     Boolean
+ * status             String
+ *
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerListener
+    implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String loadBalancerListenerID;
+
+    @XmlElement (name = "default_pool_id")
+    String neutronLoadBalancerListenerDefaultPoolID;
+
+    @XmlElement (name = "connection_limit")
+    Integer neutronLoadBalancerListenerConnectionLimit;
+
+    @XmlElement (name = "tenant_id")
+    String loadBalancerListenerTenantID;
+
+    @XmlElement (name = "name")
+    String loadBalancerListenerName;
+
+    @XmlElement (name = "description")
+    String loadBalancerListenerDescription;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean loadBalancerListenerAdminStateIsUp;
+
+    @XmlElement (name = "protocol")
+    String neutronLoadBalancerListenerProtocol;
+
+    @XmlElement (name = "protocol_port")
+    String neutronLoadBalancerListenerProtocolPort;
+
+    @XmlElement (name = "load_balancers")
+    List<Neutron_ID> neutronLoadBalancerListenerLoadBalancerIDs;
+
+    public String getID() {
+        return loadBalancerListenerID;
+    }
+
+    public void setID(String id) {
+        loadBalancerListenerID = id;
+    }
+
+    // @deprecated use getID()
+    public String getLoadBalancerListenerID() {
+        return loadBalancerListenerID;
+    }
+
+    // @deprecated use setID()
+    public void setLoadBalancerListenerID(String loadBalancerListenerID) {
+        this.loadBalancerListenerID = loadBalancerListenerID;
+    }
+
+    public String getLoadBalancerListenerTenantID() {
+        return loadBalancerListenerTenantID;
+    }
+
+    public void setLoadBalancerListenerTenantID(String loadBalancerListenerTenantID) {
+        this.loadBalancerListenerTenantID = loadBalancerListenerTenantID;
+    }
+
+    public String getLoadBalancerListenerName() {
+        return loadBalancerListenerName;
+    }
+
+    public void setLoadBalancerListenerName(String loadBalancerListenerName) {
+        this.loadBalancerListenerName = loadBalancerListenerName;
+    }
+
+    public String getLoadBalancerListenerDescription() {
+        return loadBalancerListenerDescription;
+    }
+
+    public void setLoadBalancerListenerDescription(String loadBalancerListenerDescription) {
+        this.loadBalancerListenerDescription = loadBalancerListenerDescription;
+    }
+
+    public Boolean getLoadBalancerListenerAdminStateIsUp() {
+        return loadBalancerListenerAdminStateIsUp;
+    }
+
+    public void setLoadBalancerListenerAdminStateIsUp(Boolean loadBalancerListenerAdminStateIsUp) {
+        this.loadBalancerListenerAdminStateIsUp = loadBalancerListenerAdminStateIsUp;
+    }
+
+    public String getNeutronLoadBalancerListenerProtocol() {
+        return neutronLoadBalancerListenerProtocol;
+    }
+
+    public void setNeutronLoadBalancerListenerProtocol(String neutronLoadBalancerListenerProtocol) {
+        this.neutronLoadBalancerListenerProtocol = neutronLoadBalancerListenerProtocol;
+    }
+
+    public String getNeutronLoadBalancerListenerProtocolPort() {
+        return neutronLoadBalancerListenerProtocolPort;
+    }
+
+    public void setNeutronLoadBalancerListenerProtocolPort(String neutronLoadBalancerListenerProtocolPort) {
+        this.neutronLoadBalancerListenerProtocolPort = neutronLoadBalancerListenerProtocolPort;
+    }
+
+    public String getNeutronLoadBalancerListenerDefaultPoolID() {
+        return neutronLoadBalancerListenerDefaultPoolID;
+    }
+
+    public void setNeutronLoadBalancerListenerDefaultPoolID(String neutronLoadBalancerListenerDefaultPoolID) {
+        this.neutronLoadBalancerListenerDefaultPoolID = neutronLoadBalancerListenerDefaultPoolID;
+    }
+
+    public Integer getNeutronLoadBalancerListenerConnectionLimit() {
+        return neutronLoadBalancerListenerConnectionLimit;
+    }
+
+    public void setNeutronLoadBalancerListenerConnectionLimit(Integer neutronLoadBalancerListenerConnectionLimit) {
+        this.neutronLoadBalancerListenerConnectionLimit = neutronLoadBalancerListenerConnectionLimit;
+    }
+
+    public List<Neutron_ID> getNeutronLoadBalancerListenerLoadBalancerIDs() {
+        return neutronLoadBalancerListenerLoadBalancerIDs;
+    }
+
+    public void setNeutronLoadBalancerListenerLoadBalancerIDs(List<Neutron_ID> neutronLoadBalancerListenerLoadBalancerIDs) {
+        this.neutronLoadBalancerListenerLoadBalancerIDs = neutronLoadBalancerListenerLoadBalancerIDs;
+    }
+
+    public NeutronLoadBalancerListener extractFields(List<String> fields) {
+        NeutronLoadBalancerListener ans = new NeutronLoadBalancerListener();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setID(this.getID());
+            }
+            if(s.equals("default_pool_id")) {
+                ans.setNeutronLoadBalancerListenerDefaultPoolID(this.getNeutronLoadBalancerListenerDefaultPoolID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setLoadBalancerListenerTenantID(this.getLoadBalancerListenerTenantID());
+            }
+            if (s.equals("name")) {
+                ans.setLoadBalancerListenerName(this.getLoadBalancerListenerName());
+            }
+            if(s.equals("description")) {
+                ans.setLoadBalancerListenerDescription(this.getLoadBalancerListenerDescription());
+            }
+            if (s.equals("protocol")) {
+                ans.setNeutronLoadBalancerListenerProtocol(this.getNeutronLoadBalancerListenerProtocol());
+            }
+            if (s.equals("protocol_port")) {
+                ans.setNeutronLoadBalancerListenerProtocolPort(this.getNeutronLoadBalancerListenerProtocolPort());
+            }
+            if (s.equals("admin_state_up")) {
+                ans.setLoadBalancerListenerAdminStateIsUp(loadBalancerListenerAdminStateIsUp);
+            }
+        }
+        return ans;
+    }
+
+    @Override public String toString() {
+        return "NeutronLoadBalancerListener{" +
+                "loadBalancerListenerID='" + loadBalancerListenerID + '\'' +
+                ", neutronLoadBalancerListenerDefaultPoolID='" + neutronLoadBalancerListenerDefaultPoolID + '\'' +
+                ", neutronLoadBalancerListenerConnectionLimit='" + neutronLoadBalancerListenerConnectionLimit + '\'' +
+                ", loadBalancerListenerTenantID='" + loadBalancerListenerTenantID + '\'' +
+                ", loadBalancerListenerName='" + loadBalancerListenerName + '\'' +
+                ", loadBalancerListenerDescription='" + loadBalancerListenerDescription + '\'' +
+                ", loadBalancerListenerAdminStateIsUp=" + loadBalancerListenerAdminStateIsUp +
+                ", neutronLoadBalancerListenerProtocol='" + neutronLoadBalancerListenerProtocol + '\'' +
+                ", neutronLoadBalancerListenerProtocolPort='" + neutronLoadBalancerListenerProtocolPort + '\'' +
+                '}';
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancerPool.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancerPool.java
new file mode 100644 (file)
index 0000000..890dd38
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ * id                 uuid-str
+ * tenant_id          uuid-str
+ * name               String
+ * description        String
+ * protocol           String
+ * lb_algorithm       String
+ * healthmonitor_id   String
+ * admin_state_up     Bool
+ * status             String
+ * members            List &lt;NeutronLoadBalancerPoolMember&gt;
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerPool implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String loadBalancerPoolID;
+
+    @XmlElement (name = "tenant_id")
+    String loadBalancerPoolTenantID;
+
+    @XmlElement (name = "name")
+    String loadBalancerPoolName;
+
+    @XmlElement (name = "description")
+    String loadBalancerPoolDescription;
+
+    @XmlElement (name = "protocol")
+    String loadBalancerPoolProtocol;
+
+    @XmlElement (name = "lb_algorithm")
+    String loadBalancerPoolLbAlgorithm;
+
+    @XmlElement (name = "healthmonitor_id")
+    String neutronLoadBalancerPoolHealthMonitorID;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean loadBalancerPoolAdminStateIsUp;
+
+    @XmlElement(name = "listeners")
+    List<Neutron_ID> loadBalancerPoolListeners;
+
+    @XmlElement(name = "session_persistence")
+    NeutronLoadBalancer_SessionPersistence loadBalancerPoolSessionPersistence;
+
+    @XmlElement(name = "members")
+    List<NeutronLoadBalancerPoolMember> loadBalancerPoolMembers;
+
+    public NeutronLoadBalancerPool() {
+    }
+
+    public String getID() {
+        return loadBalancerPoolID;
+    }
+
+    public void setID(String id) {
+        loadBalancerPoolID = id;
+    }
+
+    // @deprecated use getID()
+    public String getLoadBalancerPoolID() {
+        return loadBalancerPoolID;
+    }
+
+    // @deprecated use setID()
+    public void setLoadBalancerPoolID(String loadBalancerPoolID) {
+        this.loadBalancerPoolID = loadBalancerPoolID;
+    }
+
+    public String getLoadBalancerPoolTenantID() {
+        return loadBalancerPoolTenantID;
+    }
+
+    public void setLoadBalancerPoolTenantID(String loadBalancerPoolTenantID) {
+        this.loadBalancerPoolTenantID = loadBalancerPoolTenantID;
+    }
+
+    public String getLoadBalancerPoolName() {
+        return loadBalancerPoolName;
+    }
+
+    public void setLoadBalancerPoolName(String loadBalancerPoolName) {
+        this.loadBalancerPoolName = loadBalancerPoolName;
+    }
+
+    public String getLoadBalancerPoolDescription() {
+        return loadBalancerPoolDescription;
+    }
+
+    public void setLoadBalancerPoolDescription(String loadBalancerPoolDescription) {
+        this.loadBalancerPoolDescription = loadBalancerPoolDescription;
+    }
+
+    public String getLoadBalancerPoolProtocol() {
+        return loadBalancerPoolProtocol;
+    }
+
+    public void setLoadBalancerPoolProtocol(String loadBalancerPoolProtocol) {
+        this.loadBalancerPoolProtocol = loadBalancerPoolProtocol;
+    }
+
+    public String getLoadBalancerPoolLbAlgorithm() {
+        return loadBalancerPoolLbAlgorithm;
+    }
+
+    public void setLoadBalancerPoolLbAlgorithm(String loadBalancerPoolLbAlgorithm) {
+        this.loadBalancerPoolLbAlgorithm = loadBalancerPoolLbAlgorithm;
+    }
+
+    public String getNeutronLoadBalancerPoolHealthMonitorID() {
+        return neutronLoadBalancerPoolHealthMonitorID;
+    }
+
+    public void setNeutronLoadBalancerPoolHealthMonitorID(String neutronLoadBalancerPoolHealthMonitorID) {
+        this.neutronLoadBalancerPoolHealthMonitorID = neutronLoadBalancerPoolHealthMonitorID;
+    }
+
+    public Boolean getLoadBalancerPoolAdminIsStateIsUp() {
+        return loadBalancerPoolAdminStateIsUp;
+    }
+
+    public void setLoadBalancerPoolAdminStateIsUp(Boolean loadBalancerPoolAdminStateIsUp) {
+        this.loadBalancerPoolAdminStateIsUp = loadBalancerPoolAdminStateIsUp;
+    }
+
+    public NeutronLoadBalancer_SessionPersistence getLoadBalancerPoolSessionPersistence() {
+        return loadBalancerPoolSessionPersistence;
+    }
+
+    public void setLoadBalancerSessionPersistence(NeutronLoadBalancer_SessionPersistence loadBalancerPoolSessionPersistence) {
+        this.loadBalancerPoolSessionPersistence = loadBalancerPoolSessionPersistence;
+    }
+
+    public List<Neutron_ID> getLoadBalancerPoolListeners() {
+        return loadBalancerPoolListeners;
+    }
+
+    public void setLoadBalancerPoolListeners(List<Neutron_ID> loadBalancerPoolListeners) {
+        this.loadBalancerPoolListeners = loadBalancerPoolListeners;
+    }
+
+    public List<NeutronLoadBalancerPoolMember> getLoadBalancerPoolMembers() {
+        /*
+         * Update the pool_id of the member to that this.loadBalancerPoolID
+         */
+        if (loadBalancerPoolMembers != null) {
+            for (NeutronLoadBalancerPoolMember member: loadBalancerPoolMembers) {
+                member.setPoolID(loadBalancerPoolID);
+            }
+            return loadBalancerPoolMembers;
+        }
+        return loadBalancerPoolMembers;
+    }
+
+    public void setLoadBalancerPoolMembers(List<NeutronLoadBalancerPoolMember> loadBalancerPoolMembers) {
+        this.loadBalancerPoolMembers = loadBalancerPoolMembers;
+    }
+
+    public void addLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember) {
+        this.loadBalancerPoolMembers.add(loadBalancerPoolMember);
+    }
+
+    public void removeLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember) {
+        this.loadBalancerPoolMembers.remove(loadBalancerPoolMember);
+    }
+
+    public NeutronLoadBalancerPool extractFields(List<String> fields) {
+        NeutronLoadBalancerPool ans = new NeutronLoadBalancerPool();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setID(this.getID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setLoadBalancerPoolTenantID(this.getLoadBalancerPoolTenantID());
+            }
+            if (s.equals("name")) {
+                ans.setLoadBalancerPoolName(this.getLoadBalancerPoolName());
+            }
+            if(s.equals("description")) {
+                ans.setLoadBalancerPoolDescription(this.getLoadBalancerPoolDescription());
+            }
+            if(s.equals("protocol")) {
+                ans.setLoadBalancerPoolProtocol(this.getLoadBalancerPoolProtocol());
+            }
+            if (s.equals("lb_algorithm")) {
+                ans.setLoadBalancerPoolLbAlgorithm(this.getLoadBalancerPoolLbAlgorithm());
+            }
+            if (s.equals("healthmonitor_id")) {
+                ans.setNeutronLoadBalancerPoolHealthMonitorID(this.getNeutronLoadBalancerPoolHealthMonitorID());
+            }
+            if (s.equals("admin_state_up")) {
+                ans.setLoadBalancerPoolAdminStateIsUp(loadBalancerPoolAdminStateIsUp);
+            }
+            if (s.equals("members")) {
+                ans.setLoadBalancerPoolMembers(getLoadBalancerPoolMembers());
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronLoadBalancerPool{" +
+            "id='" + loadBalancerPoolID + '\'' +
+            ", tenantID='" + loadBalancerPoolTenantID + '\'' +
+            ", name='" + loadBalancerPoolName + '\'' +
+            ", description='" + loadBalancerPoolDescription + '\'' +
+            ", protocol=" + loadBalancerPoolProtocol +'\''+
+            ", lbAlgorithm='" + loadBalancerPoolLbAlgorithm + '\'' +
+            ", healthmonitorID=" + neutronLoadBalancerPoolHealthMonitorID +
+            ", adminStateUp=" + loadBalancerPoolAdminStateIsUp +
+// todo: add loadBalancerPoolMembers as joined string
+            '}';
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancerPoolMember.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancerPoolMember.java
new file mode 100644 (file)
index 0000000..274aa6c
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerPoolMember
+    implements Serializable, INeutronObject {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * TODO: Plumb into LBaaS Pool. Members are nested underneath Pool CRUD.
+     */
+    @XmlElement (name = "id")
+    String poolMemberID;
+
+    @XmlElement (name = "tenant_id")
+    String poolMemberTenantID;
+
+    @XmlElement (name = "address")
+    String poolMemberAddress;
+
+    @XmlElement (name = "protocol_port")
+    Integer poolMemberProtoPort;
+
+    @XmlElement (name = "admin_state_up")
+    Boolean poolMemberAdminStateIsUp;
+
+    @XmlElement (name = "weight")
+    Integer poolMemberWeight;
+
+    @XmlElement (name = "subnet_id")
+    String poolMemberSubnetID;
+
+    String poolID;
+
+    public NeutronLoadBalancerPoolMember() {
+    }
+
+    @XmlTransient
+    public String getPoolID() {
+        return poolID;
+    }
+
+    public void setPoolID(String poolID) {
+        this.poolID = poolID;
+    }
+
+    public String getID() {
+        return poolMemberID;
+    }
+
+    public void setID(String id) {
+        poolMemberID = id;
+    }
+
+    // @deprecated use getID()
+    public String getPoolMemberID() {
+        return poolMemberID;
+    }
+
+    // @deprecated use setID()
+    public void setPoolMemberID(String poolMemberID) {
+        this.poolMemberID = poolMemberID;
+    }
+
+    public String getPoolMemberTenantID() {
+        return poolMemberTenantID;
+    }
+
+    public void setPoolMemberTenantID(String poolMemberTenantID) {
+        this.poolMemberTenantID = poolMemberTenantID;
+    }
+
+    public String getPoolMemberAddress() {
+        return poolMemberAddress;
+    }
+
+    public void setPoolMemberAddress(String poolMemberAddress) {
+        this.poolMemberAddress = poolMemberAddress;
+    }
+
+    public Integer getPoolMemberProtoPort() {
+        return poolMemberProtoPort;
+    }
+
+    public void setPoolMemberProtoPort(Integer poolMemberProtoPort) {
+        this.poolMemberProtoPort = poolMemberProtoPort;
+    }
+
+    public Boolean getPoolMemberAdminStateIsUp() {
+        return poolMemberAdminStateIsUp;
+    }
+
+    public void setPoolMemberAdminStateIsUp(Boolean poolMemberAdminStateIsUp) {
+        this.poolMemberAdminStateIsUp = poolMemberAdminStateIsUp;
+    }
+
+    public Integer getPoolMemberWeight() {
+        return poolMemberWeight;
+    }
+
+    public void setPoolMemberWeight(Integer poolMemberWeight) {
+        this.poolMemberWeight = poolMemberWeight;
+    }
+
+    public String getPoolMemberSubnetID() {
+        return poolMemberSubnetID;
+    }
+
+    public void setPoolMemberSubnetID(String poolMemberSubnetID) {
+        this.poolMemberSubnetID = poolMemberSubnetID;
+    }
+
+    public NeutronLoadBalancerPoolMember extractFields(List<String> fields) {
+        NeutronLoadBalancerPoolMember ans = new NeutronLoadBalancerPoolMember();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setID(this.getID());
+            }
+            if (s.equals("pool_id")) {
+                ans.setPoolID(this.getPoolID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setPoolMemberTenantID(this.getPoolMemberTenantID());
+            }
+            if (s.equals("address")) {
+                ans.setPoolMemberAddress(this.getPoolMemberAddress());
+            }
+            if(s.equals("protocol_port")) {
+                ans.setPoolMemberProtoPort(this.getPoolMemberProtoPort());
+            }
+            if (s.equals("admin_state_up")) {
+                ans.setPoolMemberAdminStateIsUp(poolMemberAdminStateIsUp);
+            }
+            if(s.equals("weight")) {
+                ans.setPoolMemberWeight(this.getPoolMemberWeight());
+            }
+            if(s.equals("subnet_id")) {
+                ans.setPoolMemberSubnetID(this.getPoolMemberSubnetID());
+            }
+        }
+        return ans;
+    }
+    @Override public String toString() {
+        return "NeutronLoadBalancerPoolMember{" +
+                "poolMemberID='" + poolMemberID + '\'' +
+                ", poolID='" + poolID + '\'' +
+                ", poolMemberTenantID='" + poolMemberTenantID + '\'' +
+                ", poolMemberAddress='" + poolMemberAddress + '\'' +
+                ", poolMemberProtoPort=" + poolMemberProtoPort +
+                ", poolMemberAdminStateIsUp=" + poolMemberAdminStateIsUp +
+                ", poolMemberWeight=" + poolMemberWeight +
+                ", poolMemberSubnetID='" + poolMemberSubnetID + '\'' +
+                '}';
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancer_SessionPersistence.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronLoadBalancer_SessionPersistence.java
new file mode 100644 (file)
index 0000000..7d3d63c
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronLoadBalancer_SessionPersistence implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name = "cookie_name")
+    String cookieName;
+
+    @XmlElement(name = "type")
+    String type;
+
+    public NeutronLoadBalancer_SessionPersistence() {
+    }
+
+    public NeutronLoadBalancer_SessionPersistence(String cookieName, String type) {
+        this.cookieName = cookieName;
+        this.type = type;
+    }
+
+    public String getCookieName() {
+        return cookieName;
+    }
+
+    public void setCookieName(String cookieName) {
+        this.cookieName = cookieName;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+}
+
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronNetwork.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronNetwork.java
new file mode 100644 (file)
index 0000000..b6396dc
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "network")
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronNetwork implements Serializable, INeutronObject {
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement (name = "id")
+    String networkUUID;
+
+    @XmlElement (name = "name")
+    String networkName;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean adminStateUp;
+
+    @XmlElement (defaultValue = "false", name = "shared")
+    Boolean shared;
+
+    @XmlElement (name = "tenant_id")
+    String tenantID;
+
+    //    @XmlElement (defaultValue = "false", name = "router:external")
+    @XmlElement (defaultValue="false", namespace="router", name="external")
+    Boolean routerExternal;
+
+    //    @XmlElement (defaultValue = "flat", name = "provider:network_type")
+    @XmlElement (namespace="provider", name="network_type")
+    String providerNetworkType;
+
+    //    @XmlElement (name = "provider:physical_network")
+    @XmlElement (namespace="provider", name="physical_network")
+    String providerPhysicalNetwork;
+
+    //    @XmlElement (name = "provider:segmentation_id")
+    @XmlElement (namespace="provider", name="segmentation_id")
+    String providerSegmentationID;
+
+    @XmlElement (name = "status")
+    String status;
+
+    @XmlElement (name = "subnets")
+    List<String> subnets;
+
+    @XmlElement (name="segments")
+    List<NeutronNetwork_Segment> segments;
+
+    @XmlElement (name="vlan_transparent")
+    Boolean vlanTransparent;
+
+    @XmlElement (name="mtu")
+    Integer mtu;
+
+    /* This attribute lists the ports associated with an instance
+     * which is needed for determining if that instance can be deleted
+     */
+
+    public NeutronNetwork() {
+    }
+
+    public void initDefaults() {
+        subnets = new ArrayList<String>();
+        if (status == null) {
+            status = "ACTIVE";
+        }
+        if (adminStateUp == null) {
+            adminStateUp = true;
+        }
+        if (shared == null) {
+            shared = false;
+        }
+        if (routerExternal == null) {
+            routerExternal = false;
+        }
+        if (providerNetworkType == null) {
+            providerNetworkType = "flat";
+        }
+    }
+
+    public String getID() { return networkUUID; }
+
+    public void setID(String id) { this.networkUUID = id; }
+
+    public String getNetworkUUID() {
+        return networkUUID;
+    }
+
+    public void setNetworkUUID(String networkUUID) {
+        this.networkUUID = networkUUID;
+    }
+
+    public String getNetworkName() {
+        return networkName;
+    }
+
+    public void setNetworkName(String networkName) {
+        this.networkName = networkName;
+    }
+
+    public boolean isAdminStateUp() {
+        return adminStateUp;
+    }
+
+    public Boolean getAdminStateUp() { return adminStateUp; }
+
+    public void setAdminStateUp(boolean newValue) {
+        adminStateUp = newValue;
+    }
+
+    public boolean isShared() { return shared; }
+
+    public Boolean getShared() { return shared; }
+
+    public void setShared(boolean newValue) {
+        shared = newValue;
+    }
+
+    public String getTenantID() {
+        return tenantID;
+    }
+
+    public void setTenantID(String tenantID) {
+        this.tenantID = tenantID;
+    }
+
+    public boolean isRouterExternal() { return routerExternal; }
+
+    public Boolean getRouterExternal() { return routerExternal; }
+
+    public void setRouterExternal(boolean newValue) {
+        routerExternal = newValue;
+    }
+
+    public String getProviderNetworkType() {
+        return providerNetworkType;
+    }
+
+    public void setProviderNetworkType(String providerNetworkType) {
+        this.providerNetworkType = providerNetworkType;
+    }
+
+    public String getProviderPhysicalNetwork() {
+        return providerPhysicalNetwork;
+    }
+
+    public void setProviderPhysicalNetwork(String providerPhysicalNetwork) {
+        this.providerPhysicalNetwork = providerPhysicalNetwork;
+    }
+
+    public String getProviderSegmentationID() {
+        return providerSegmentationID;
+    }
+
+    public void setProviderSegmentationID(String providerSegmentationID) {
+        this.providerSegmentationID = providerSegmentationID;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public List<String> getSubnets() {
+        return subnets;
+    }
+
+    public void setSubnets(List<String> subnets) {
+        this.subnets = subnets;
+    }
+
+    public void addSubnet(String uuid) {
+        subnets.add(uuid);
+    }
+
+    public void removeSubnet(String uuid) {
+        subnets.remove(uuid);
+    }
+
+    public void setSegments(List<NeutronNetwork_Segment> segments) {
+        this.segments = segments;
+    }
+
+    public List<NeutronNetwork_Segment> getSegments() {
+        return segments;
+    }
+
+    public Boolean getVlanTransparent() {
+        return vlanTransparent;
+    }
+
+    public void setVlanTransparent(Boolean input) {
+        this.vlanTransparent = input;
+    }
+
+    public Integer getMtu() {
+        return mtu;
+    }
+
+    public void setMtu(Integer input) {
+        mtu = input;
+    }
+
+    /**
+     * This method copies selected fields from the object and returns them
+     * as a new object, suitable for marshaling.
+     *
+     * @param fields
+     *            List of attributes to be extracted
+     * @return an OpenStackNetworks object with only the selected fields
+     * populated
+     */
+
+    public NeutronNetwork extractFields(List<String> fields) {
+        NeutronNetwork ans = new NeutronNetwork();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setNetworkUUID(this.getNetworkUUID());
+            }
+            if (s.equals("name")) {
+                ans.setNetworkName(this.getNetworkName());
+            }
+            if (s.equals("admin_state_up")) {
+                ans.setAdminStateUp(adminStateUp);
+            }
+            if (s.equals("status")) {
+                ans.setStatus(this.getStatus());
+            }
+            if (s.equals("subnets")) {
+                List<String> subnetList = new ArrayList<String>();
+                subnetList.addAll(this.getSubnets());
+                ans.setSubnets(subnetList);
+            }
+            if (s.equals("shared")) {
+                ans.setShared(shared);
+            }
+            if (s.equals("tenant_id")) {
+                ans.setTenantID(this.getTenantID());
+            }
+            if (s.equals("external")) {
+                ans.setRouterExternal(this.getRouterExternal());
+            }
+            if (s.equals("segmentation_id")) {
+                ans.setProviderSegmentationID(this.getProviderSegmentationID());
+            }
+            if (s.equals("physical_network")) {
+                ans.setProviderPhysicalNetwork(this.getProviderPhysicalNetwork());
+            }
+            if (s.equals("network_type")) {
+                ans.setProviderNetworkType(this.getProviderNetworkType());
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronNetwork [networkUUID=" + networkUUID + ", networkName=" + networkName + ", adminStateUp="
+                + adminStateUp + ", shared=" + shared + ", tenantID=" + tenantID + ", routerExternal=" + routerExternal
+                + ", providerNetworkType=" + providerNetworkType + ", providerPhysicalNetwork="
+                + providerPhysicalNetwork + ", providerSegmentationID=" + providerSegmentationID + ", status=" + status
+                + ", subnets=" + subnets + ", segments = " + segments + "]";
+    }
+}
+
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronNetwork_Segment.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronNetwork_Segment.java
new file mode 100644 (file)
index 0000000..2246f89
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "network")
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronNetwork_Segment implements Serializable {
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    private static final long serialVersionUID = 1L;
+
+    //    @XmlElement (defaultValue="flat", name="provider:network_type")
+    @XmlElement (defaultValue="flat", namespace="provider", name="network_type")
+    String providerNetworkType;
+
+    //    @XmlElement (name="provider:physical_network")
+    @XmlElement (namespace="provider", name="physical_network")
+    String providerPhysicalNetwork;
+
+    //    @XmlElement (name="provider:segmentation_id")
+    @XmlElement (namespace="provider", name="segmentation_id")
+    String providerSegmentationID;
+
+    public NeutronNetwork_Segment() {
+    }
+
+    public String getProviderNetworkType() {
+        return providerNetworkType;
+    }
+
+    public void setProviderNetworkType(String providerNetworkType) {
+        this.providerNetworkType = providerNetworkType;
+    }
+
+    public String getProviderPhysicalNetwork() {
+        return providerPhysicalNetwork;
+    }
+
+    public void setProviderPhysicalNetwork(String providerPhysicalNetwork) {
+        this.providerPhysicalNetwork = providerPhysicalNetwork;
+    }
+
+    public String getProviderSegmentationID() {
+        return providerSegmentationID;
+    }
+
+    public void setProviderSegmentationID(String providerSegmentationID) {
+        this.providerSegmentationID = providerSegmentationID;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronNetwork_Segment [ " +
+               ", providerNetworkType=" + providerNetworkType +
+               ", providerPhysicalNetwork=" + providerPhysicalNetwork +
+               ", providerSegmentationID=" + providerSegmentationID + "]";
+    }
+}
+
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronPort.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronPort.java
new file mode 100644 (file)
index 0000000..2608cd4
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronPort implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement (name = "id")
+    String portUUID;
+
+    @XmlElement (name = "network_id")
+    String networkUUID;
+
+    @XmlElement (name = "name")
+    String name;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean adminStateUp;
+
+    @XmlElement (name = "status")
+    String status;
+
+    @XmlElement (name = "mac_address")
+    String macAddress;
+
+    @XmlElement (name = "fixed_ips")
+    List<Neutron_IPs> fixedIPs;
+
+    @XmlElement (name = "device_id")
+    String deviceID;
+
+    @XmlElement (name = "device_owner")
+    String deviceOwner;
+
+    @XmlElement (name = "tenant_id")
+    String tenantID;
+
+    @XmlElement (name = "security_groups")
+    List<NeutronSecurityGroup> securityGroups;
+
+    @XmlElement (name = "allowed_address_pairs")
+    List<NeutronPort_AllowedAddressPairs> allowedAddressPairs;
+
+    //@XmlElement (name = "binding:host_id")
+    @XmlElement (namespace = "binding", name = "host_id")
+    String bindinghostID;
+
+    //@XmlElement (name = "binding:vnic_type")
+    @XmlElement (namespace = "binding", name = "vnic_type")
+    String bindingvnicType;
+
+    //@XmlElement (name = "binding:vif_type")
+    @XmlElement (namespace = "binding", name = "vif_type")
+    String bindingvifType;
+
+    //@XmlElement (name = "binding:vif_details")
+    @XmlElement (namespace = "binding", name = "vif_details")
+    List<NeutronPort_VIFDetail> vifDetails;
+
+    @XmlElement (name = "extra_dhcp_opts")
+    List<NeutronPort_ExtraDHCPOption> extraDHCPOptions;
+
+    NeutronPort originalPort;
+
+    public NeutronPort() {
+    }
+
+    public String getID() { return portUUID; }
+
+    public void setID(String id) { this.portUUID = id; }
+
+    public String getPortUUID() {
+        return portUUID;
+    }
+
+    public void setPortUUID(String portUUID) {
+        this.portUUID = portUUID;
+    }
+
+    public String getNetworkUUID() {
+        return networkUUID;
+    }
+
+    public void setNetworkUUID(String networkUUID) {
+        this.networkUUID = networkUUID;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public boolean isAdminStateUp() {
+        if (adminStateUp == null) {
+            return true;
+        }
+        return adminStateUp;
+    }
+
+    public Boolean getAdminStateUp() { return adminStateUp; }
+
+    public void setAdminStateUp(Boolean newValue) {
+            adminStateUp = newValue;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getMacAddress() {
+        return macAddress;
+    }
+
+    public void setMacAddress(String macAddress) {
+        this.macAddress = macAddress;
+    }
+
+    public List<Neutron_IPs> getFixedIPs() {
+        return fixedIPs;
+    }
+
+    public void setFixedIPs(List<Neutron_IPs> fixedIPs) {
+        this.fixedIPs = fixedIPs;
+    }
+
+    public String getDeviceID() {
+        return deviceID;
+    }
+
+    public void setDeviceID(String deviceID) {
+        this.deviceID = deviceID;
+    }
+
+    public String getDeviceOwner() {
+        return deviceOwner;
+    }
+
+    public void setDeviceOwner(String deviceOwner) {
+        this.deviceOwner = deviceOwner;
+    }
+
+    public String getTenantID() {
+        return tenantID;
+    }
+
+    public void setTenantID(String tenantID) {
+        this.tenantID = tenantID;
+    }
+
+    public List<NeutronSecurityGroup> getSecurityGroups() {
+        return securityGroups;
+    }
+
+    public void setSecurityGroups(List<NeutronSecurityGroup> securityGroups) {
+        this.securityGroups = securityGroups;
+    }
+
+    public List<NeutronPort_AllowedAddressPairs> getAllowedAddressPairs() {
+        return allowedAddressPairs;
+    }
+
+    public void setAllowedAddressPairs(List<NeutronPort_AllowedAddressPairs> allowedAddressPairs) {
+        this.allowedAddressPairs = allowedAddressPairs;
+    }
+
+    public List<NeutronPort_ExtraDHCPOption> getExtraDHCPOptions() {
+        return extraDHCPOptions;
+    }
+
+    public void setExtraDHCPOptions(List<NeutronPort_ExtraDHCPOption> extraDHCPOptions) {
+        this.extraDHCPOptions = extraDHCPOptions;
+    }
+
+    public List<NeutronPort_VIFDetail> getVIFDetail() {
+        return vifDetails;
+    }
+
+    public void setVIFDetail(List<NeutronPort_VIFDetail> vifDetails) {
+        this.vifDetails = vifDetails;
+    }
+
+    public String getBindinghostID() {
+      return bindinghostID;
+    }
+
+    public void setBindinghostID(String bindinghostID) {
+      this.bindinghostID = bindinghostID;
+    }
+
+    public String getBindingvnicType() {
+        return bindingvnicType;
+    }
+
+    public void setBindingvnicType(String bindingvnicType) {
+        this.bindingvnicType = bindingvnicType;
+    }
+
+    public String getBindingvifType() {
+        return bindingvifType;
+    }
+
+    public void setBindingvifType(String bindingvifType) {
+        this.bindingvifType = bindingvifType;
+    }
+
+    public NeutronPort getOriginalPort() {
+        return originalPort;
+    }
+
+
+    public void setOriginalPort(NeutronPort originalPort) {
+        this.originalPort = originalPort;
+    }
+
+    /**
+     * This method copies selected fields from the object and returns them
+     * as a new object, suitable for marshaling.
+     *
+     * @param fields
+     *            List of attributes to be extracted
+     * @return an OpenStackPorts object with only the selected fields
+     * populated
+     */
+
+    public NeutronPort extractFields(List<String> fields) {
+        NeutronPort ans = new NeutronPort();
+        for (String field: fields) {
+            if ("id".equals(field)) {
+                ans.setPortUUID(this.getPortUUID());
+            }
+            if ("network_id".equals(field)) {
+                ans.setNetworkUUID(this.getNetworkUUID());
+            }
+            if ("name".equals(field)) {
+                ans.setName(this.getName());
+            }
+            if ("admin_state_up".equals(field)) {
+                ans.setAdminStateUp(this.getAdminStateUp());
+            }
+            if ("status".equals(field)) {
+                ans.setStatus(this.getStatus());
+            }
+            if ("mac_address".equals(field)) {
+                ans.setMacAddress(this.getMacAddress());
+            }
+            if ("fixed_ips".equals(field)) {
+                ans.setFixedIPs(new ArrayList<Neutron_IPs>(this.getFixedIPs()));
+            }
+            if ("device_id".equals(field)) {
+                ans.setDeviceID(this.getDeviceID());
+            }
+            if ("device_owner".equals(field)) {
+                ans.setDeviceOwner(this.getDeviceOwner());
+            }
+            if ("tenant_id".equals(field)) {
+                ans.setTenantID(this.getTenantID());
+            }
+            if ("security_groups".equals(field)) {
+                ans.setSecurityGroups(new ArrayList<NeutronSecurityGroup>(this.getSecurityGroups()));
+            }
+        }
+        return ans;
+    }
+
+    public void initDefaults() {
+        adminStateUp = true;
+        if (status == null) {
+            status = "ACTIVE";
+        }
+        if (fixedIPs == null) {
+            fixedIPs = new ArrayList<Neutron_IPs>();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronPort [portUUID=" + portUUID + ", networkUUID=" + networkUUID + ", name=" + name
+                + ", adminStateUp=" + adminStateUp + ", status=" + status + ", macAddress=" + macAddress
+                + ", fixedIPs=" + fixedIPs + ", deviceID=" + deviceID + ", deviceOwner=" + deviceOwner + ", tenantID="
+                + tenantID + ", securityGroups=" + securityGroups
+                + ", bindinghostID=" + bindinghostID + ", bindingvnicType=" + bindingvnicType
+                + ", bindingvnicType=" + bindingvnicType + "]";
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronPort_AllowedAddressPairs.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronPort_AllowedAddressPairs.java
new file mode 100644 (file)
index 0000000..65448d0
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronPort_AllowedAddressPairs implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement (name = "port_id")
+    String portID;
+
+    @XmlElement (name = "mac_address")
+    String macAddress;
+
+    @XmlElement (name = "ip_address")
+    String ipAddress;
+
+    public NeutronPort_AllowedAddressPairs() {
+    }
+
+    public NeutronPort_AllowedAddressPairs(String portID, String macAddress, String ipAddress) {
+        this.portID = portID;
+        this.macAddress = macAddress;
+        this.ipAddress = ipAddress;
+    }
+
+    public String getPortID() { return(portID); }
+
+    public void setPortID(String portID) { this.portID = portID; }
+
+    public String getMacAddress() { return(macAddress); }
+
+    public void setMacAddress(String macAddress) { this.macAddress = macAddress; }
+
+    public String getIpAddress() { return(ipAddress); }
+
+    public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronPort_ExtraDHCPOption.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronPort_ExtraDHCPOption.java
new file mode 100644 (file)
index 0000000..554fac1
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronPort_ExtraDHCPOption implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement (name = "opt_value")
+    String value;
+
+    @XmlElement (name = "opt_name")
+    String name;
+
+    public NeutronPort_ExtraDHCPOption() {
+    }
+
+    public NeutronPort_ExtraDHCPOption(String value, String name) {
+        this.value = value;
+        this.name = name;
+    }
+
+    public String getValue() { return(value); }
+
+    public void setValue(String value) { this.value = value; }
+
+    public String getName() { return(name); }
+
+    public void setName(String name) { this.name = name; }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronPort_VIFDetail.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronPort_VIFDetail.java
new file mode 100644 (file)
index 0000000..c485259
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronPort_VIFDetail implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement (name = "port_filter")
+    Boolean portFilter;
+
+    @XmlElement (name = "ovs_hybrid_plug")
+    Boolean ovsHybridPlug;
+
+    public NeutronPort_VIFDetail() {
+    }
+
+    public NeutronPort_VIFDetail(Boolean portFilter, Boolean ovsHybridPlug) {
+        this.portFilter = portFilter;
+        this.ovsHybridPlug = ovsHybridPlug;
+    }
+
+    public Boolean getPortFilter() { return(portFilter); }
+
+    public void setPortFilter(Boolean portFilter) { this.portFilter = portFilter; }
+
+    public Boolean getOvsHybridPlug() { return(ovsHybridPlug); }
+
+    public void setOvsHybridPlug(Boolean ovsHybridPlug) { this.ovsHybridPlug = ovsHybridPlug; }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronRouter.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronRouter.java
new file mode 100644 (file)
index 0000000..cc64cd0
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronRouter implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+    @XmlElement (name = "id")
+    String routerUUID;
+
+    @XmlElement (name = "name")
+    String name;
+
+    @XmlElement (defaultValue = "true", name = "admin_state_up")
+    Boolean adminStateUp;
+
+    @XmlElement (name = "status")
+    String status;
+
+    @XmlElement (name = "tenant_id")
+    String tenantID;
+
+    @XmlElement (name = "external_gateway_info", nillable = true)
+    NeutronRouter_NetworkReference externalGatewayInfo;
+
+    @XmlElement (name = "distributed")
+    Boolean distributed;
+
+    @XmlElement (name = "gw_port_id", nillable = true)
+    String gatewayPortId;
+
+    @XmlElement (name = "routes")
+    List<String> routes;
+
+    /* Holds a map of OpenStackRouterInterfaces by subnet UUID
+     * used for internal mapping to DOVE
+     */
+    Map<String, NeutronRouter_Interface> interfaces;
+
+    public NeutronRouter() {
+        interfaces = new HashMap<String, NeutronRouter_Interface>();
+    }
+
+    public String getID() { return routerUUID; }
+
+    public void setID(String id) { this.routerUUID = id; }
+
+    public String getRouterUUID() {
+        return routerUUID;
+    }
+
+    public void setRouterUUID(String routerUUID) {
+        this.routerUUID = routerUUID;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public boolean isAdminStateUp() {
+        if (adminStateUp == null) {
+            return true;
+        }
+        return adminStateUp;
+    }
+
+    public Boolean getAdminStateUp() { return adminStateUp; }
+
+    public void setAdminStateUp(Boolean newValue) {
+        adminStateUp = newValue;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getTenantID() {
+        return tenantID;
+    }
+
+    public void setTenantID(String tenantID) {
+        this.tenantID = tenantID;
+    }
+
+    public NeutronRouter_NetworkReference getExternalGatewayInfo() {
+        return externalGatewayInfo;
+    }
+
+    public void setExternalGatewayInfo(NeutronRouter_NetworkReference externalGatewayInfo) {
+        this.externalGatewayInfo = externalGatewayInfo;
+    }
+
+    public Boolean getDistributed() {
+        return distributed;
+    }
+
+    public void setDistributed(Boolean distributed) {
+        this.distributed = distributed;
+    }
+
+    public String getGatewayPortId() {
+        return gatewayPortId;
+    }
+
+    public void setGatewayPortId(String gatewayPortId) {
+        this.gatewayPortId = gatewayPortId;
+    }
+
+    public List<String> getRoutes() {
+        return routes;
+    }
+
+    public void setRoutes(List<String> routes) {
+        this.routes = routes;
+    }
+
+    /**
+     * This method copies selected fields from the object and returns them
+     * as a new object, suitable for marshaling.
+     *
+     * @param fields
+     *            List of attributes to be extracted
+     * @return an OpenStackRouters object with only the selected fields
+     * populated
+     */
+    public NeutronRouter extractFields(List<String> fields) {
+        NeutronRouter ans = new NeutronRouter();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setRouterUUID(this.getRouterUUID());
+            }
+            if (s.equals("name")) {
+                ans.setName(this.getName());
+            }
+            if (s.equals("admin_state_up")) {
+                ans.setAdminStateUp(this.getAdminStateUp());
+            }
+            if (s.equals("status")) {
+                ans.setStatus(this.getStatus());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setTenantID(this.getTenantID());
+            }
+            if (s.equals("external_gateway_info")) {
+                ans.setExternalGatewayInfo(this.getExternalGatewayInfo());
+            }
+            if (s.equals("distributed")) {
+                ans.setDistributed(this.getDistributed());
+            }
+            if (s.equals("gw_port_id")) {
+                ans.setGatewayPortId(this.getGatewayPortId());
+            }
+            if (s.equals("routes")){
+                ans.setRoutes(this.getRoutes());
+            }
+        }
+        return ans;
+    }
+
+    public void setInterfaces(Map<String, NeutronRouter_Interface> input) {
+        interfaces = input;
+    }
+
+    public Map<String, NeutronRouter_Interface> getInterfaces() {
+        return interfaces;
+    }
+
+    public void addInterface(String s, NeutronRouter_Interface i) {
+        interfaces.put(s, i);
+    }
+
+    public void removeInterface(String s) {
+        interfaces.remove(s);
+    }
+
+    public void initDefaults() {
+        adminStateUp = true;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronRouter [" +
+            "id=" + routerUUID +
+            ", name=" + name +
+            ", adminStateUp=" + adminStateUp +
+            ", status=" + status +
+            ", tenantID=" + tenantID +
+            ", external_gateway_info=" + externalGatewayInfo +
+            ", distributed=" + distributed +
+            ", gw_port_id=" + gatewayPortId +
+            ", routes=" + routes +
+            ", interfaces=" + interfaces +
+            "]";
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronRouter_Interface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronRouter_Interface.java
new file mode 100644 (file)
index 0000000..9749533
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronRouter_Interface implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement (name = "subnet_id")
+    String subnetUUID;
+
+    @XmlElement (name = "port_id")
+    String portUUID;
+
+    @XmlElement (name = "id")
+    String id;
+
+    @XmlElement (name = "tenant_id")
+    String tenantID;
+
+    public NeutronRouter_Interface() {
+    }
+
+    public NeutronRouter_Interface(String subnetUUID, String portUUID) {
+        this.subnetUUID = subnetUUID;
+        this.portUUID = portUUID;
+    }
+
+    public String getSubnetUUID() {
+        return subnetUUID;
+    }
+
+    public void setSubnetUUID(String subnetUUID) {
+        this.subnetUUID = subnetUUID;
+    }
+
+    public String getPortUUID() {
+        return portUUID;
+    }
+
+    public void setPortUUID(String portUUID) {
+        this.portUUID = portUUID;
+    }
+
+    public String getID() {
+        return id;
+    }
+
+    public void setID(String id) {
+        this.id = id;
+    }
+
+    public void setTenantID(String tenantID) {
+        this.tenantID = tenantID;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronRouterInterface [" +
+            "subnetUUID=" + subnetUUID +
+            ", portUUID=" + portUUID +
+            ", id=" + id +
+            ", tenantID=" + tenantID + "]";
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronRouter_NetworkReference.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronRouter_NetworkReference.java
new file mode 100644 (file)
index 0000000..ddc2217
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronRouter_NetworkReference implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name = "network_id")
+    String networkID;
+
+    @XmlElement(name = "enable_snat")
+    Boolean enableSNAT;
+
+    @XmlElement(name = "external_fixed_ips")
+    List<Neutron_IPs> externalFixedIPs;
+
+    public NeutronRouter_NetworkReference() {
+    }
+
+    public String getNetworkID() {
+        return networkID;
+    }
+
+    public void setNetworkID(String networkID) {
+        this.networkID = networkID;
+    }
+
+    public Boolean getEnableSNAT() {
+        return enableSNAT;
+    }
+
+    public void setEnableSNAT(Boolean enableSNAT) {
+        this.enableSNAT = enableSNAT;
+    }
+
+    public List<Neutron_IPs> getExternalFixedIPs() {
+        return externalFixedIPs;
+    }
+
+    public void setExternalFixedIPs(List<Neutron_IPs> externalFixedIPs) {
+        this.externalFixedIPs = externalFixedIPs;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronRouterNetworkReference [networkID=" + networkID +
+            " enableSNAT=" + enableSNAT +
+            " externalFixedIPs=" + externalFixedIPs + "]";
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSecurityGroup.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSecurityGroup.java
new file mode 100644 (file)
index 0000000..9a5daed
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * OpenStack Neutron v2.0 Security Group bindings.
+ * See OpenStack Network API v2.0 Reference for description of
+ * annotated attributes. The current fields are as follows:
+ * <p>
+ * id                   uuid-str unique ID for the security group.
+ * name                 String name of the security group.
+ * description          String name of the security group.
+ * tenant_id            uuid-str Owner of security rule..
+ * security_group_rules List&lt;NeutronSecurityRule&gt; nested RO in the sec group.
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronSecurityGroup implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String securityGroupUUID;
+
+    @XmlElement(name = "name")
+    String securityGroupName;
+
+    @XmlElement(name = "description")
+    String securityGroupDescription;
+
+    @XmlElement(name = "tenant_id")
+    String securityGroupTenantID;
+
+    @XmlElement(name = "security_group_rules")
+    List<NeutronSecurityRule> neutronSecurityRule;
+
+    public NeutronSecurityGroup() {
+        neutronSecurityRule = new ArrayList<NeutronSecurityRule>();
+
+    }
+
+    public String getID() {
+        return securityGroupUUID;
+    }
+
+    public void setID(String id) {
+        securityGroupUUID = id;
+    }
+
+    // @deprecated use getID()
+    public String getSecurityGroupUUID() {
+        return securityGroupUUID;
+    }
+
+    // @deprecated use setID()
+    public void setSecurityGroupUUID(String securityGroupUUID) {
+        this.securityGroupUUID = securityGroupUUID;
+    }
+
+    public String getSecurityGroupName() {
+        return securityGroupName;
+    }
+
+    public void setSecurityGroupName(String securityGroupName) {
+        this.securityGroupName = securityGroupName;
+    }
+
+    public String getSecurityGroupDescription() {
+        return securityGroupDescription;
+    }
+
+    public void setSecurityGroupDescription(String securityGroupDescription) {
+        this.securityGroupDescription = securityGroupDescription;
+    }
+
+    public String getSecurityGroupTenantID() {
+        return securityGroupTenantID;
+    }
+
+    public void setSecurityGroupTenantID(String securityGroupTenantID) {
+        this.securityGroupTenantID = securityGroupTenantID;
+    }
+
+    // Rules In Group
+    public List<NeutronSecurityRule> getSecurityRules() {
+        return neutronSecurityRule;
+    }
+
+    public void setSecurityRules(List<NeutronSecurityRule> neutronSecurityRule) {
+        this.neutronSecurityRule = neutronSecurityRule;
+    }
+
+    public NeutronSecurityGroup extractFields(List<String> fields) {
+        NeutronSecurityGroup ans = new NeutronSecurityGroup ();
+        Iterator<String> i = fields.iterator ();
+        while (i.hasNext ()) {
+            String s = i.next ();
+            if (s.equals ("id")) {
+                ans.setID (this.getID ());
+            }
+            if (s.equals ("name")) {
+                ans.setSecurityGroupName (this.getSecurityGroupName ());
+            }
+            if (s.equals ("description")) {
+                ans.setSecurityGroupDescription (this.getSecurityGroupDescription ());
+            }
+            if (s.equals ("tenant_id")) {
+                ans.setSecurityGroupTenantID (this.getSecurityGroupTenantID ());
+            }
+            if (s.equals ("security_group_rules")) {
+                ans.setSecurityRules (this.getSecurityRules ());
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronSecurityGroup{" +
+                "securityGroupUUID='" + securityGroupUUID + '\'' +
+                ", securityGroupName='" + securityGroupName + '\'' +
+                ", securityGroupDescription='" + securityGroupDescription + '\'' +
+                ", securityGroupTenantID='" + securityGroupTenantID + '\'' +
+                ", securityRules=" + neutronSecurityRule + "]";
+    }
+
+    public void initDefaults() {
+        //TODO verify no defaults values are nessecary required.
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSecurityRule.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSecurityRule.java
new file mode 100644 (file)
index 0000000..bd6ddd5
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * See OpenStack Network API v2.0 Reference for description of
+ * annotated attributes. The current fields are as follows:
+ * <p>
+ * id                uuid (String) UUID for the security group rule.
+ * security_rule_id  uuid (String) The security group to associate rule.
+ * direction         String Direction the VM traffic  (ingress/egress).
+ * security_group_id The security group to associate rule with.
+ * protocol          String IP Protocol (icmp, tcp, udp, etc).
+ * port_range_min    Integer Port at start of range
+ * port_range_max    Integer Port at end of range
+ * ethertype         String ethertype in L2 packet (IPv4, IPv6, etc)
+ * remote_ip_prefix  String (IP cidr) CIDR for address range.
+ * remote_group_id   uuid-str Source security group to apply to rule.
+ * tenant_id         uuid-str Owner of security rule. Admin only outside tenant.
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronSecurityRule implements Serializable, INeutronObject {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "id")
+    String securityRuleUUID;
+
+    @XmlElement(name = "direction")
+    String securityRuleDirection;
+
+    @XmlElement(name = "protocol")
+    String securityRuleProtocol;
+
+    @XmlElement(name = "port_range_min")
+    Integer securityRulePortMin;
+
+    @XmlElement(name = "port_range_max")
+    Integer securityRulePortMax;
+
+    @XmlElement(name = "ethertype")
+    String securityRuleEthertype;
+
+    @XmlElement(name = "remote_ip_prefix")
+    String securityRuleRemoteIpPrefix;
+
+    @XmlElement(name = "remote_group_id")
+    String securityRemoteGroupID;
+
+    @XmlElement(name = "security_group_id")
+    String securityRuleGroupID;
+
+    @XmlElement(name = "tenant_id")
+    String securityRuleTenantID;
+
+    public NeutronSecurityRule() {
+    }
+
+    public String getID() {
+        return securityRuleUUID;
+    }
+
+    public void setID(String id) {
+        securityRuleUUID = id;
+    }
+
+    // @deprecated use getID()
+    public String getSecurityRuleUUID() {
+        return securityRuleUUID;
+    }
+
+    // @deprecated use setID()
+    public void setSecurityRuleUUID(String securityRuleUUID) {
+        this.securityRuleUUID = securityRuleUUID;
+    }
+
+    public String getSecurityRuleDirection() {
+        return securityRuleDirection;
+    }
+
+    public void setSecurityRuleDirection(String securityRuleDirection) {
+        this.securityRuleDirection = securityRuleDirection;
+    }
+
+    public String getSecurityRuleProtocol() {
+        return securityRuleProtocol;
+    }
+
+    public void setSecurityRuleProtocol(String securityRuleProtocol) {
+        this.securityRuleProtocol = securityRuleProtocol;
+    }
+
+    public Integer getSecurityRulePortMin() {
+        return securityRulePortMin;
+    }
+
+    public void setSecurityRulePortMin(Integer securityRulePortMin) {
+        this.securityRulePortMin = securityRulePortMin;
+    }
+
+    public Integer getSecurityRulePortMax() {
+        return securityRulePortMax;
+    }
+
+    public void setSecurityRulePortMax(Integer securityRulePortMax) {
+        this.securityRulePortMax = securityRulePortMax;
+    }
+
+    public String getSecurityRuleEthertype() {
+        return securityRuleEthertype;
+    }
+
+    public void setSecurityRuleEthertype(String securityRuleEthertype) {
+        this.securityRuleEthertype = securityRuleEthertype;
+    }
+
+    public String getSecurityRuleRemoteIpPrefix() {
+        return securityRuleRemoteIpPrefix;
+    }
+
+    public void setSecurityRuleRemoteIpPrefix(String securityRuleRemoteIpPrefix) {
+        this.securityRuleRemoteIpPrefix = securityRuleRemoteIpPrefix;
+    }
+
+    public String getSecurityRemoteGroupID() {
+        return securityRemoteGroupID;
+    }
+
+    public void setSecurityRemoteGroupID(String securityRemoteGroupID) {
+        this.securityRemoteGroupID = securityRemoteGroupID;
+    }
+
+    public String getSecurityRuleGroupID() {
+        return securityRuleGroupID;
+    }
+
+    public void setSecurityRuleGroupID(String securityRuleGroupID) {
+        this.securityRuleGroupID = securityRuleGroupID;
+    }
+
+    public String getSecurityRuleTenantID() {
+        return securityRuleTenantID;
+    }
+
+    public void setSecurityRuleTenantID(String securityRuleTenantID) {
+        this.securityRuleTenantID = securityRuleTenantID;
+    }
+
+    public NeutronSecurityRule extractFields(List<String> fields) {
+        NeutronSecurityRule ans = new NeutronSecurityRule();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setID(this.getID());
+            }
+            if (s.equals("direction")) {
+                ans.setSecurityRuleDirection(this.getSecurityRuleDirection());
+            }
+            if (s.equals("protocol")) {
+                ans.setSecurityRuleProtocol(this.getSecurityRuleProtocol());
+            }
+            if (s.equals("port_range_min")) {
+                ans.setSecurityRulePortMin(this.getSecurityRulePortMin());
+            }
+            if (s.equals("port_range_max")) {
+                ans.setSecurityRulePortMax(this.getSecurityRulePortMax());
+            }
+            if (s.equals("ethertype")) {
+                ans.setSecurityRuleEthertype(this.getSecurityRuleEthertype());
+            }
+            if (s.equals("remote_ip_prefix")) {
+                ans.setSecurityRuleRemoteIpPrefix(this.getSecurityRuleRemoteIpPrefix());
+            }
+            if (s.equals("remote_group_id")) {
+                ans.setSecurityRemoteGroupID(this.getSecurityRemoteGroupID());
+            }
+            if (s.equals("security_group_id")) {
+                ans.setSecurityRuleGroupID(this.getSecurityRuleGroupID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setSecurityRuleTenantID(this.getSecurityRuleTenantID());
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronSecurityRule{" +
+            "securityRuleUUID='" + securityRuleUUID + '\'' +
+            ", securityRuleDirection='" + securityRuleDirection + '\'' +
+            ", securityRuleProtocol='" + securityRuleProtocol + '\'' +
+            ", securityRulePortMin=" + securityRulePortMin +
+            ", securityRulePortMax=" + securityRulePortMax +
+            ", securityRuleEthertype='" + securityRuleEthertype + '\'' +
+            ", securityRuleRemoteIpPrefix='" + securityRuleRemoteIpPrefix + '\'' +
+            ", securityRemoteGroupID=" + securityRemoteGroupID +
+            ", securityRuleGroupID='" + securityRuleGroupID + '\'' +
+            ", securityRuleTenantID='" + securityRuleTenantID + '\'' +
+            '}';
+    }
+
+    public void initDefaults() {
+        //TODO verify no defaults values are nessecary required.
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSubnet.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSubnet.java
new file mode 100644 (file)
index 0000000..9d32fc3
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.commons.net.util.SubnetUtils;
+import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronSubnet implements Serializable, INeutronObject {
+    private static final Logger LOGGER = LoggerFactory
+            .getLogger(NeutronCRUDInterfaces.class);
+
+    private static final long serialVersionUID = 1L;
+    private static final int IPV4_VERSION = 4;
+    private static final int IPV6_VERSION = 6;
+    private static final int IPV6_LENGTH = 128;
+    private static final int IPV6_LENGTH_BYTES = 8;
+    private static final long IPV6_LSB_MASK = 0x000000FF;
+    private static final int IPV6_BYTE_OFFSET = 7;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement (name = "id")
+    String subnetUUID;
+
+    @XmlElement (name = "network_id")
+    String networkUUID;
+
+    @XmlElement (name = "name")
+    String name;
+
+    @XmlElement (defaultValue = "4", name = "ip_version")
+    Integer ipVersion;
+
+    @XmlElement (name = "cidr")
+    String cidr;
+
+    @XmlElement (name = "gateway_ip")
+    String gatewayIP;
+
+    @XmlElement (name = "dns_nameservers")
+    List<String> dnsNameservers;
+
+    @XmlElement (name = "allocation_pools")
+    List<NeutronSubnetIPAllocationPool> allocationPools;
+
+    @XmlElement (name = "host_routes")
+    List<NeutronSubnet_HostRoute> hostRoutes;
+
+    @XmlElement (defaultValue = "true", name = "enable_dhcp")
+    Boolean enableDHCP;
+
+    @XmlElement (name = "tenant_id")
+    String tenantID;
+
+    @XmlElement (name = "ipv6_address_mode", nillable = true)
+    String ipV6AddressMode;
+
+    @XmlElement (name = "ipv6_ra_mode", nillable = true)
+    String ipV6RaMode;
+
+    /* stores the OpenStackPorts associated with an instance
+     * used to determine if that instance can be deleted.
+     *
+     * @deprecated, will be removed in Boron
+     */
+
+    List<NeutronPort> myPorts;
+
+    public NeutronSubnet() {
+        myPorts = new ArrayList<NeutronPort>();
+    }
+
+    // @deprecated - will be removed in Boron
+    public void setPorts(List<NeutronPort> arg) {
+        myPorts = arg;
+    }
+
+    public String getID() { return subnetUUID; }
+
+    public void setID(String id) { this.subnetUUID = id; }
+
+    public String getSubnetUUID() {
+        return subnetUUID;
+    }
+
+    public void setSubnetUUID(String subnetUUID) {
+        this.subnetUUID = subnetUUID;
+    }
+
+    public String getNetworkUUID() {
+        return networkUUID;
+    }
+
+    public void setNetworkUUID(String networkUUID) {
+        this.networkUUID = networkUUID;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Integer getIpVersion() {
+        return ipVersion;
+    }
+
+    public void setIpVersion(Integer ipVersion) {
+        this.ipVersion = ipVersion;
+    }
+
+    public String getCidr() {
+        return cidr;
+    }
+
+    public void setCidr(String cidr) {
+        this.cidr = cidr;
+    }
+
+    public String getGatewayIP() {
+        return gatewayIP;
+    }
+
+    public void setGatewayIP(String gatewayIP) {
+        this.gatewayIP = gatewayIP;
+    }
+
+    public List<String> getDnsNameservers() {
+        return dnsNameservers;
+    }
+
+    public void setDnsNameservers(List<String> dnsNameservers) {
+        this.dnsNameservers = dnsNameservers;
+    }
+
+    public List<NeutronSubnetIPAllocationPool> getAllocationPools() {
+        return allocationPools;
+    }
+
+    public void setAllocationPools(List<NeutronSubnetIPAllocationPool> allocationPools) {
+        this.allocationPools = allocationPools;
+    }
+
+    public List<NeutronSubnet_HostRoute> getHostRoutes() {
+        return hostRoutes;
+    }
+
+    public void setHostRoutes(List<NeutronSubnet_HostRoute> hostRoutes) {
+        this.hostRoutes = hostRoutes;
+    }
+
+    public boolean isEnableDHCP() {
+        if (enableDHCP == null) {
+            return true;
+        }
+        return enableDHCP;
+    }
+
+    public Boolean getEnableDHCP() { return enableDHCP; }
+
+    public void setEnableDHCP(Boolean newValue) {
+            enableDHCP = newValue;
+    }
+
+    public String getTenantID() {
+        return tenantID;
+    }
+
+    public void setTenantID(String tenantID) {
+        this.tenantID = tenantID;
+    }
+
+    public String getIpV6AddressMode() { return ipV6AddressMode; }
+
+    public void setIpV6AddressMode(String ipV6AddressMode) { this.ipV6AddressMode = ipV6AddressMode; }
+
+    public String getIpV6RaMode() { return ipV6RaMode; }
+
+    public void setIpV6RaMode(String ipV6RaMode) { this.ipV6RaMode = ipV6RaMode; }
+
+    /**
+     * This method copies selected fields from the object and returns them
+     * as a new object, suitable for marshaling.
+     *
+     * @param fields
+     *            List of attributes to be extracted
+     * @return an OpenStackSubnets object with only the selected fields
+     * populated
+     */
+
+    public NeutronSubnet extractFields(List<String> fields) {
+        NeutronSubnet ans = new NeutronSubnet();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setSubnetUUID(this.getSubnetUUID());
+            }
+            if (s.equals("network_id")) {
+                ans.setNetworkUUID(this.getNetworkUUID());
+            }
+            if (s.equals("name")) {
+                ans.setName(this.getName());
+            }
+            if (s.equals("ip_version")) {
+                ans.setIpVersion(this.getIpVersion());
+            }
+            if (s.equals("cidr")) {
+                ans.setCidr(this.getCidr());
+            }
+            if (s.equals("gateway_ip")) {
+                ans.setGatewayIP(this.getGatewayIP());
+            }
+            if (s.equals("dns_nameservers")) {
+                List<String> nsList = new ArrayList<String>();
+                nsList.addAll(this.getDnsNameservers());
+                ans.setDnsNameservers(nsList);
+            }
+            if (s.equals("allocation_pools")) {
+                List<NeutronSubnetIPAllocationPool> aPools = new ArrayList<NeutronSubnetIPAllocationPool>();
+                aPools.addAll(this.getAllocationPools());
+                ans.setAllocationPools(aPools);
+            }
+            if (s.equals("host_routes")) {
+                List<NeutronSubnet_HostRoute> hRoutes = new ArrayList<NeutronSubnet_HostRoute>();
+                hRoutes.addAll(this.getHostRoutes());
+                ans.setHostRoutes(hRoutes);
+            }
+            if (s.equals("enable_dhcp")) {
+                ans.setEnableDHCP(this.getEnableDHCP());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setTenantID(this.getTenantID());
+            }
+            if (s.equals("ipv6_address_mode")) {
+                ans.setIpV6AddressMode(this.getIpV6AddressMode());
+            }
+            if (s.equals("ipv6_ra_mode")) {
+                ans.setIpV6RaMode(this.getIpV6RaMode());
+            }
+        }
+        return ans;
+    }
+
+    // @deprecated - will be removed in Boron
+    public List<NeutronPort> getPortsInSubnet() {
+        return myPorts;
+    }
+
+    // @deprecated - will be removed in Boron
+    public List<NeutronPort> getPortsInSubnet(String ignore) {
+       List<NeutronPort> answer = new ArrayList<NeutronPort>();
+       for (NeutronPort port : myPorts) {
+           if (!port.getDeviceOwner().equalsIgnoreCase(ignore)) {
+                answer.add(port);
+            }
+        }
+        return answer;
+    }
+
+    /* test to see if the cidr address used to define this subnet
+     * is a valid network address (an necessary condition when creating
+     * a new subnet)
+     */
+    public boolean isValidCIDR() {
+        // fix for Bug 2290 - need to wrap the existing test as
+        // IPv4 because SubnetUtils doesn't support IPv6
+        if (ipVersion == IPV4_VERSION) {
+            try {
+                SubnetUtils util = new SubnetUtils(cidr);
+                SubnetInfo info = util.getInfo();
+                if (!info.getNetworkAddress().equals(info.getAddress())) {
+                    return false;
+                }
+            } catch (IllegalArgumentException e) {
+                LOGGER.warn("Failure in isValidCIDR()", e);
+                return false;
+            }
+            return true;
+        }
+        if (ipVersion == IPV6_VERSION) {
+            // fix for Bug2290 - this is custom code because no classes
+            // with ODL-friendly licenses have been found
+            // extract address (in front of /) and length (after /)
+            String[] parts = cidr.split("/");
+            if (parts.length != 2) {
+                return false;
+            }
+            try {
+                int length = Integer.parseInt(parts[1]);
+                //TODO?: limit check on length
+                // convert to byte array
+                byte[] addrBytes = ((Inet6Address) InetAddress.getByName(parts[0])).getAddress();
+                int i;
+                for (i = length; i < IPV6_LENGTH; i++) {
+                    if (((((int) addrBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES)))) != 0) {
+                        return(false);
+                    }
+                }
+                return(true);
+            } catch (UnknownHostException e) {
+                LOGGER.warn("Failure in isValidCIDR()", e);
+                return(false);
+            }
+        }
+        return false;
+    }
+
+    /* test to see if the gateway IP specified overlaps with specified
+     * allocation pools (an error condition when creating a new subnet
+     * or assigning a gateway IP)
+     */
+    public boolean gatewayIP_Pool_overlap() {
+        Iterator<NeutronSubnetIPAllocationPool> i = allocationPools.iterator();
+        while (i.hasNext()) {
+            NeutronSubnetIPAllocationPool pool = i.next();
+            if (ipVersion == IPV4_VERSION && pool.contains(gatewayIP)) {
+                return true;
+            }
+            if (ipVersion == IPV6_VERSION && pool.containsV6(gatewayIP)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean initDefaults() {
+        if (enableDHCP == null) {
+            enableDHCP = true;
+        }
+        if (ipVersion == null) {
+            ipVersion = IPV4_VERSION;
+        }
+        dnsNameservers = new ArrayList<String>();
+        if (hostRoutes == null) {
+            hostRoutes = new ArrayList<NeutronSubnet_HostRoute>();
+        }
+        if (allocationPools == null) {
+            allocationPools = new ArrayList<NeutronSubnetIPAllocationPool>();
+            if (ipVersion == IPV4_VERSION) {
+                try {
+                    SubnetUtils util = new SubnetUtils(cidr);
+                    SubnetInfo info = util.getInfo();
+                    if (gatewayIP == null || ("").equals(gatewayIP)) {
+                        gatewayIP = info.getLowAddress();
+                    }
+                    if (allocationPools.size() < 1) {
+                        NeutronSubnetIPAllocationPool source =
+                            new NeutronSubnetIPAllocationPool(info.getLowAddress(),
+                                    info.getHighAddress());
+                        allocationPools = source.splitPool(gatewayIP);
+                    }
+                } catch (IllegalArgumentException e) {
+                    LOGGER.warn("Failure in initDefault()", e);
+                    return false;
+                }
+            }
+            if (ipVersion == IPV6_VERSION) {
+                String[] parts = cidr.split("/");
+                if (parts.length != 2) {
+                    return false;
+                }
+                try {
+                    int length = Integer.parseInt(parts[1]);
+                    BigInteger lowAddress_bi = NeutronSubnetIPAllocationPool.convertV6(parts[0]);
+                    String lowAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddress_bi.add(BigInteger.ONE));
+                    BigInteger mask = BigInteger.ONE.shiftLeft(length).subtract(BigInteger.ONE);
+                    String highAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddress_bi.add(mask).subtract(BigInteger.ONE));
+                    if (gatewayIP == null || ("").equals(gatewayIP)) {
+                        gatewayIP = lowAddress;
+                    }
+                    if (allocationPools.size() < 1) {
+                        NeutronSubnetIPAllocationPool source =
+                            new NeutronSubnetIPAllocationPool(lowAddress,
+                                    highAddress);
+                        allocationPools = source.splitPoolV6(gatewayIP);
+                    }
+                } catch (Exception e) {
+                    LOGGER.warn("Failure in initDefault()", e);
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /* this method tests to see if the supplied IPv4 address
+     * is valid for this subnet or not
+     */
+    public boolean isValidIP(String ipAddress) {
+        if (ipVersion == IPV4_VERSION) {
+            try {
+                SubnetUtils util = new SubnetUtils(cidr);
+                SubnetInfo info = util.getInfo();
+                return info.isInRange(ipAddress);
+            } catch (IllegalArgumentException e) {
+                LOGGER.warn("Failure in isValidIP()", e);
+                return false;
+            }
+        }
+
+        if (ipVersion == IPV6_VERSION) {
+            String[] parts = cidr.split("/");
+            try {
+                int length = Integer.parseInt(parts[1]);
+                byte[] cidrBytes = ((Inet6Address) InetAddress.getByName(parts[0])).getAddress();
+                byte[] ipBytes =  ((Inet6Address) InetAddress.getByName(ipAddress)).getAddress();
+                int i;
+                for (i = 0; i < length; i++) {
+                    if (((((int) cidrBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES)))) !=
+                        ((((int) ipBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES))))) {
+                        return(false);
+                    }
+                }
+                return(true);
+            } catch (UnknownHostException e) {
+                LOGGER.warn("Failure in isValidIP()", e);
+                return(false);
+            }
+        }
+        return false;
+    }
+
+    /* method to get the lowest available address of the subnet.
+     * go through all the allocation pools and keep the lowest of their
+     * low addresses.
+     */
+    public String getLowAddr() {
+        String ans = null;
+        Iterator<NeutronSubnetIPAllocationPool> i = allocationPools.iterator();
+        while (i.hasNext()) {
+            NeutronSubnetIPAllocationPool pool = i.next();
+            if (ans == null) {
+                ans = pool.getPoolStart();
+            }
+            else {
+                if (ipVersion == IPV4_VERSION &&
+                    NeutronSubnetIPAllocationPool.convert(pool.getPoolStart()) <
+                            NeutronSubnetIPAllocationPool.convert(ans)) {
+                    ans = pool.getPoolStart();
+                }
+                if (ipVersion == IPV6_VERSION &&
+                    NeutronSubnetIPAllocationPool.convertV6(pool.getPoolStart()).compareTo(NeutronSubnetIPAllocationPool.convertV6(ans)) < 0) {
+                    ans = pool.getPoolStart();
+                }
+           }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronSubnet [subnetUUID=" + subnetUUID + ", networkUUID=" + networkUUID + ", name=" + name
+                + ", ipVersion=" + ipVersion + ", cidr=" + cidr + ", gatewayIP=" + gatewayIP + ", dnsNameservers="
+                + dnsNameservers + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes
+                + ", enableDHCP=" + enableDHCP + ", tenantID=" + tenantID
+                + ", ipv6AddressMode=" + ipV6AddressMode
+                + ", ipv6RaMode=" + ipV6RaMode + "]";
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSubnetIPAllocationPool.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSubnetIPAllocationPool.java
new file mode 100644 (file)
index 0000000..38f31c7
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronSubnetIPAllocationPool implements Serializable {
+    private static final Logger LOGGER = LoggerFactory
+            .getLogger(NeutronSubnetIPAllocationPool.class);
+
+    private static final long serialVersionUID = 1L;
+
+    private static final int BYTE_LENGTH = 8;
+    private static final int IPV4_DOTTED_QUADS = 4;
+    private static final int IPV4_DOTTED_QUAD_OFFSET = 3;
+    private static final int IPV4_DOTTED_QUAD_MASK = 255;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name = "start")
+    String poolStart;
+
+    @XmlElement(name = "end")
+    String poolEnd;
+
+    public NeutronSubnetIPAllocationPool() {
+    }
+
+    public NeutronSubnetIPAllocationPool(String lowAddress, String highAddress) {
+        poolStart = lowAddress;
+        poolEnd = highAddress;
+    }
+
+    public String getPoolStart() {
+        return poolStart;
+    }
+
+    public void setPoolStart(String poolStart) {
+        this.poolStart = poolStart;
+    }
+
+    public String getPoolEnd() {
+        return poolEnd;
+    }
+
+    public void setPoolEnd(String poolEnd) {
+        this.poolEnd = poolEnd;
+    }
+
+    /**
+     * This method determines if this allocation pool contains the
+     * input IPv4 address
+     *
+     * @param inputString
+     *            IPv4 address in dotted decimal format
+     * @return a boolean on whether the pool contains the address or not
+     */
+
+    public boolean contains(String inputString) {
+        long inputIP = convert(inputString);
+        long startIP = convert(poolStart);
+        long endIP = convert(poolEnd);
+        return (inputIP >= startIP && inputIP <= endIP);
+    }
+
+    /**
+     * This static method converts the supplied IPv4 address to a long
+     * integer for comparison
+     *
+     * @param inputString
+     *            IPv4 address in dotted decimal format
+     * @return high-endian representation of the IPv4 address as a long.
+     *          This method will return 0 if the input is null.
+     */
+
+    static long convert(String inputString) {
+        long ans = 0;
+        if (inputString != null) {
+            String[] parts = inputString.split("\\.");
+            for (String part: parts) {
+                ans <<= BYTE_LENGTH;
+                ans |= Integer.parseInt(part);
+            }
+        }
+        return ans;
+    }
+
+    /**
+     * This method determines if this allocation pool contains the
+     * input IPv4 address
+     *
+     * @param inputString
+     *            IPv4 address in dotted decimal format
+     * @return a boolean on whether the pool contains the address or not
+     */
+
+    public boolean containsV6(String inputString) {
+        BigInteger inputIP = convertV6(inputString);
+        BigInteger startIP = convertV6(poolStart);
+        BigInteger endIP = convertV6(poolEnd);
+        return (inputIP.compareTo(startIP) >= 0 && inputIP.compareTo(endIP) <= 0);
+    }
+
+    /**
+     * This static method converts the supplied IPv4 address to a long
+     * integer for comparison
+     *
+     * @param inputString
+     *            IPv6 address in dotted decimal format
+     * @return high-endian representation of the IPv4 address as a BigInteger.
+     *          This method will return 0 if the input is null.
+     */
+
+    static BigInteger convertV6(String inputString) {
+        if (inputString == null) {
+            return BigInteger.ZERO;
+        }
+        try {
+            return new BigInteger(((Inet6Address) InetAddress.getByName(inputString)).getAddress());
+        } catch (Exception e) {
+            LOGGER.error("convertV6 error", e);
+            return BigInteger.ZERO;
+        }
+    }
+
+    /**
+     * This static method converts the supplied high-ending long back
+     * into a dotted decimal representation of an IPv4 address
+     *
+     * @param l
+     *            high-endian representation of the IPv4 address as a long
+     * @return IPv4 address in dotted decimal format
+     */
+    static String longToIP(long input) {
+        int part;
+        long ipLong = input;
+        String[] parts = new String[IPV4_DOTTED_QUADS];
+        for (part = 0; part < IPV4_DOTTED_QUADS; part++) {
+            parts[IPV4_DOTTED_QUAD_OFFSET-part] = String.valueOf(ipLong & IPV4_DOTTED_QUAD_MASK);
+            ipLong >>= BYTE_LENGTH;
+        }
+        return join(parts,".");
+    }
+
+    /**
+     * This static method converts the supplied high-ending long back
+     * into a dotted decimal representation of an IPv4 address
+     *
+     * @param l
+     *            high-endian representation of the IPv4 address as a long
+     * @return IPv4 address in dotted decimal format
+     */
+    static String bigIntegerToIP(BigInteger b) {
+        try {
+            return Inet6Address.getByAddress(b.toByteArray()).getHostAddress();
+        } catch (Exception e) {
+            LOGGER.error("bigIntegerToIP", e);
+            return "ERROR";
+        }
+    }
+
+    /*
+     * helper routine used by longToIP
+     */
+    public static String join(String r[],String separator)
+    {
+        if (r.length == 0) {
+            return "";
+        }
+        StringBuilder sb = new StringBuilder();
+        int i;
+        for(i = 0;i < r.length - 1;i++) {
+            sb.append(r[i]);
+            sb.append(separator);
+        }
+        return sb.toString() + r[i];
+    }
+
+    /*
+     * This method splits the current instance by removing the supplied
+     * parameter.
+     *
+     * If the parameter is either the low or high address,
+     * then that member is adjusted and a list containing just this instance
+     * is returned.
+     *
+     * If the parameter is in the middle of the pool, then
+     * create two new instances, one ranging from low to parameter-1
+     * the other ranging from parameter+1 to high
+     */
+    public List<NeutronSubnetIPAllocationPool> splitPool(String ipAddress) {
+        List<NeutronSubnetIPAllocationPool> ans = new ArrayList<NeutronSubnetIPAllocationPool>();
+        long gIP = NeutronSubnetIPAllocationPool.convert(ipAddress);
+        long sIP = NeutronSubnetIPAllocationPool.convert(poolStart);
+        long eIP = NeutronSubnetIPAllocationPool.convert(poolEnd);
+        long i;
+        NeutronSubnetIPAllocationPool p = new NeutronSubnetIPAllocationPool();
+        boolean poolStarted = false;
+        for (i = sIP; i <= eIP; i++) {
+            if (i == sIP) {
+                if (i != gIP) {
+                    p.setPoolStart(poolStart);
+                    poolStarted = true;
+                } else {
+                    //FIX for bug 533
+                    p.setPoolStart(NeutronSubnetIPAllocationPool.longToIP(i+1));
+                }
+            }
+            if (i == eIP) {
+                if (i != gIP) {
+                    p.setPoolEnd(poolEnd);
+                } else {
+                    p.setPoolEnd(NeutronSubnetIPAllocationPool.longToIP(i-1));
+                }
+                ans.add(p);
+            }
+            if (i != sIP && i != eIP) {
+                if (i != gIP) {
+                    if (!poolStarted) {
+                        p.setPoolStart(NeutronSubnetIPAllocationPool.longToIP(i));
+                        poolStarted = true;
+                    }
+                } else {
+                    p.setPoolEnd(NeutronSubnetIPAllocationPool.longToIP(i-1));
+                    poolStarted = false;
+                    ans.add(p);
+                    p = new NeutronSubnetIPAllocationPool();
+                    // Fix for 2120
+                    p.setPoolStart(NeutronSubnetIPAllocationPool.longToIP(i+1));
+                    poolStarted = true;
+                }
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronSubnetIPAllocationPool [" +
+            "start=" + poolStart +
+            ", end=" + poolEnd + "]";
+    }
+
+    /*
+     * This method splits the current instance by removing the supplied
+     * parameter.
+     *
+     * If the parameter is either the low or high address,
+     * then that member is adjusted and a list containing just this instance
+     * is returned.
+     new *
+     * If the parameter is in the middle of the pool, then
+     * create two new instances, one ranging from low to parameter-1
+     * the other ranging from parameter+1 to high
+     * If the pool is a single address, return null
+     */
+    public List<NeutronSubnetIPAllocationPool> splitPoolV6(String ipAddress) {
+        List<NeutronSubnetIPAllocationPool> ans = new ArrayList<NeutronSubnetIPAllocationPool>();
+        BigInteger gIP = NeutronSubnetIPAllocationPool.convertV6(ipAddress);
+        BigInteger sIP = NeutronSubnetIPAllocationPool.convertV6(poolStart);
+        BigInteger eIP = NeutronSubnetIPAllocationPool.convertV6(poolEnd);
+        if (gIP.compareTo(sIP) == 0 && gIP.compareTo(eIP) < 0) {
+            NeutronSubnetIPAllocationPool p = new NeutronSubnetIPAllocationPool();
+            p.setPoolStart(NeutronSubnetIPAllocationPool.bigIntegerToIP(sIP.add(BigInteger.ONE)));
+            p.setPoolEnd(poolEnd);
+            ans.add(p);
+            return(ans);
+        }
+        if (gIP.compareTo(eIP) == 0 && gIP.compareTo(sIP) > 0) {
+            NeutronSubnetIPAllocationPool p = new NeutronSubnetIPAllocationPool();
+            p.setPoolStart(poolStart);
+            p.setPoolEnd(NeutronSubnetIPAllocationPool.bigIntegerToIP(eIP.subtract(BigInteger.ONE)));
+            ans.add(p);
+            return(ans);
+        }
+        if (gIP.compareTo(eIP) < 0 && gIP.compareTo(sIP) > 0) {
+            NeutronSubnetIPAllocationPool p = new NeutronSubnetIPAllocationPool();
+            p.setPoolStart(poolStart);
+            p.setPoolEnd(NeutronSubnetIPAllocationPool.bigIntegerToIP(gIP.subtract(BigInteger.ONE)));
+            ans.add(p);
+            NeutronSubnetIPAllocationPool p2 = new NeutronSubnetIPAllocationPool();
+            p2.setPoolStart(NeutronSubnetIPAllocationPool.bigIntegerToIP(gIP.add(BigInteger.ONE)));
+            p2.setPoolEnd(poolEnd);
+            ans.add(p2);
+            return ans;
+        }
+        return null;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSubnet_HostRoute.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/NeutronSubnet_HostRoute.java
new file mode 100644 (file)
index 0000000..49743fe
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronSubnet_HostRoute implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name = "destination")
+    String destination;
+
+    @XmlElement(name = "nexthop")
+    String nextHop;
+
+    /**
+     *  HostRoute constructor
+     */
+    public NeutronSubnet_HostRoute() { }
+
+    @Override
+    public String toString() {
+        return "NeutronSubnetHostRoute [" +
+            "destination=" + destination +
+            ", nextHop=" + nextHop + "]";
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/Neutron_ID.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/Neutron_ID.java
new file mode 100644 (file)
index 0000000..acdae12
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class Neutron_ID implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name = "id")
+    String uuid;
+
+    public Neutron_ID() { }
+
+    public Neutron_ID(String uuid) {
+        this.uuid = uuid;
+    }
+
+    public String getID() {
+        return uuid;
+    }
+
+    public void setID(String uuid) {
+        this.uuid = uuid;
+    }
+
+    @Override
+    public String toString() {
+        return "Neutron_ID{" + "id='" + uuid + '\'' + "}";
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/Neutron_IPs.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/Neutron_IPs.java
new file mode 100644 (file)
index 0000000..41b8981
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class Neutron_IPs implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name = "ip_address")
+    String ipAddress;
+
+    @XmlElement(name = "subnet_id")
+    String subnetUUID;
+
+    public Neutron_IPs() { }
+
+    public Neutron_IPs(String uuid) {
+        subnetUUID = uuid;
+    }
+
+    public String getIpAddress() {
+        return ipAddress;
+    }
+
+    public void setIpAddress(String ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    public String getSubnetUUID() {
+        return subnetUUID;
+    }
+
+    public void setSubnetUUID(String subnetUUID) {
+        this.subnetUUID = subnetUUID;
+    }
+
+    @Override
+    public String toString() {
+        return "Neutron_IPs{" +
+               "ipAddress='" + ipAddress + '\'' +
+               ", subnetUUID='" + subnetUUID + '\'' + "}";
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronFirewallCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronFirewallCRUD.java
new file mode 100644 (file)
index 0000000..51b4021
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewall;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Firewall objects
+ */
+
+public interface INeutronFirewallCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *Firewall object exists
+     *
+     * @param uuid
+     *            UUID of the Firewall object
+     * @return boolean
+     */
+
+    boolean neutronFirewallExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Firewall object exists
+     *
+     * @param uuid
+     *            UUID of the Firewall object
+     * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewall}
+     *          OpenStackFirewall class
+     */
+
+    NeutronFirewall getNeutronFirewall(String uuid);
+
+    /**
+     * Applications call this interface method to return all Firewall objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronFirewall> getAllNeutronFirewalls();
+
+    /**
+     * Applications call this interface method to add a Firewall object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronFirewall(NeutronFirewall input);
+
+    /**
+     * Applications call this interface method to remove a Neutron Firewall object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the Firewall object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronFirewall(String uuid);
+
+    /**
+     * Applications call this interface method to edit a Firewall object
+     *
+     * @param uuid
+     *            identifier of the Firewall object
+     * @param delta
+     *            OpenStackFirewall object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronFirewall(String uuid, NeutronFirewall delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the Firewall object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronFirewallInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronFirewallPolicyCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronFirewallPolicyCRUD.java
new file mode 100644 (file)
index 0000000..6993dfb
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallPolicy;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Firewall Policy objects
+ *
+ */
+
+public interface INeutronFirewallPolicyCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *FirewallPolicy object exists
+     *
+     * @param uuid
+     *            UUID of the Firewall Policy object
+     * @return boolean
+     */
+
+    boolean neutronFirewallPolicyExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * FirewallPolicy object exists
+     *
+     * @param uuid
+     *            UUID of the Firewall Policy object
+     * @return {@link NeutronFirewallPolicy}
+     *          OpenStackFirewallPolicy class
+     */
+
+    NeutronFirewallPolicy getNeutronFirewallPolicy(String uuid);
+
+    /**
+     * Applications call this interface method to return all Firewall Policy objects
+     *
+     * @return List of OpenStack Firewall Policy objects
+     */
+
+    List<NeutronFirewallPolicy> getAllNeutronFirewallPolicies();
+
+    /**
+     * Applications call this interface method to add a Firewall Policy object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronFirewallPolicy(NeutronFirewallPolicy input);
+
+    /**
+     * Applications call this interface method to remove a Neutron FirewallPolicy object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the Firewall Policy object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronFirewallPolicy(String uuid);
+
+    /**
+     * Applications call this interface method to edit a FirewallPolicy object
+     *
+     * @param uuid
+     *            identifier of the Firewall Policy object
+     * @param delta
+     *            OpenStackFirewallPolicy object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronFirewallPolicy(String uuid, NeutronFirewallPolicy delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the Firewall Policy object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronFirewallPolicyInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronFirewallRuleCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronFirewallRuleCRUD.java
new file mode 100644 (file)
index 0000000..e3cce62
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallRule;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Firewall Rule objects
+ *
+ */
+
+public interface INeutronFirewallRuleCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *FirewallRule object exists
+     *
+     * @param uuid
+     *            UUID of the Firewall Rule object
+     * @return boolean
+     */
+
+    boolean neutronFirewallRuleExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * FirewallRule object exists
+     *
+     * @param uuid
+     *            UUID of the Firewall Rule object
+     * @return {@link NeutronFirewallRule}
+     *          OpenStackFirewall Rule class
+     */
+
+    NeutronFirewallRule getNeutronFirewallRule(String uuid);
+
+    /**
+     * Applications call this interface method to return all Firewall Rule objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronFirewallRule> getAllNeutronFirewallRules();
+
+    /**
+     * Applications call this interface method to add a Firewall Rule object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronFirewallRule(NeutronFirewallRule input);
+
+    /**
+     * Applications call this interface method to remove a Neutron FirewallRule object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the Firewall Rule object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronFirewallRule(String uuid);
+
+    /**
+     * Applications call this interface method to edit a FirewallRule object
+     *
+     * @param uuid
+     *            identifier of the Firewall Rule object
+     * @param delta
+     *            OpenStackFirewallRule object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronFirewallRule(String uuid, NeutronFirewallRule delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the Firewall Rule object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronFirewallRuleInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronFloatingIPCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronFloatingIPCRUD.java
new file mode 100644 (file)
index 0000000..73ee3c4
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+
+/**
+ * This interface defines the methods for CRUD of NB FloatingIP objects
+ *
+ */
+
+public interface INeutronFloatingIPCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * FloatingIP object exists
+     *
+     * @param uuid
+     *            UUID of the FloatingIP object
+     * @return boolean
+     */
+
+    boolean floatingIPExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * FloatingIP object exists
+     *
+     * @param uuid
+     *            UUID of the FloatingIP object
+     * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP}
+     *          OpenStack FloatingIP class
+     */
+
+    NeutronFloatingIP getFloatingIP(String uuid);
+
+    /**
+     * Applications call this interface method to return all FloatingIP objects
+     *
+     * @return a Set of OpenStackFloatingIPs objects
+     */
+
+    List<NeutronFloatingIP> getAllFloatingIPs();
+
+    /**
+     * Applications call this interface method to add a FloatingIP object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackFloatingIP object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addFloatingIP(NeutronFloatingIP input);
+
+    /**
+     * Applications call this interface method to remove a FloatingIP object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the FloatingIP object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeFloatingIP(String uuid);
+
+    /**
+     * Applications call this interface method to edit a FloatingIP object
+     *
+     * @param uuid
+     *            identifier of the FloatingIP object
+     * @param delta
+     *            OpenStackFloatingIP object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateFloatingIP(String uuid, NeutronFloatingIP delta);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerCRUD.java
new file mode 100644 (file)
index 0000000..7fc23c1
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancer objects
+ *
+ */
+
+public interface INeutronLoadBalancerCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *LoadBalancer object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancer object
+     * @return boolean
+     */
+
+    boolean neutronLoadBalancerExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * LoadBalancer object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancer object
+     * @return {@link NeutronLoadBalancer}
+     *          OpenStackLoadBalancer class
+     */
+
+    NeutronLoadBalancer getNeutronLoadBalancer(String uuid);
+
+    /**
+     * Applications call this interface method to return all LoadBalancer objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronLoadBalancer> getAllNeutronLoadBalancers();
+
+    /**
+     * Applications call this interface method to add a LoadBalancer object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronLoadBalancer(NeutronLoadBalancer input);
+
+    /**
+     * Applications call this interface method to remove a Neutron LoadBalancer object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the LoadBalancer object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronLoadBalancer(String uuid);
+
+    /**
+     * Applications call this interface method to edit a LoadBalancer object
+     *
+     * @param uuid
+     *            identifier of the LoadBalancer object
+     * @param delta
+     *            OpenStackLoadBalancer object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronLoadBalancer(String uuid, NeutronLoadBalancer delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the LoadBalancer object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronLoadBalancerInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerHealthMonitorCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerHealthMonitorCRUD.java
new file mode 100644 (file)
index 0000000..98f781f
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerHealthMonitor;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancerHealthMonitor objects
+ *
+ */
+
+public interface INeutronLoadBalancerHealthMonitorCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *LoadBalancerHealthMonitor object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerHealthMonitor object
+     * @return boolean
+     */
+
+    boolean neutronLoadBalancerHealthMonitorExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * LoadBalancerHealthMonitor object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerHealthMonitor object
+     * @return {@link NeutronLoadBalancerHealthMonitor}
+     *          OpenStackLoadBalancerHealthMonitor class
+     */
+
+    NeutronLoadBalancerHealthMonitor getNeutronLoadBalancerHealthMonitor(String uuid);
+
+    /**
+     * Applications call this interface method to return all LoadBalancerHealthMonitor objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronLoadBalancerHealthMonitor> getAllNeutronLoadBalancerHealthMonitors();
+
+    /**
+     * Applications call this interface method to add a LoadBalancerHealthMonitor object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor input);
+
+    /**
+     * Applications call this interface method to remove a Neutron LoadBalancerHealthMonitor object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the LoadBalancerHealthMonitor object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronLoadBalancerHealthMonitor(String uuid);
+
+    /**
+     * Applications call this interface method to edit a LoadBalancerHealthMonitor object
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerHealthMonitor object
+     * @param delta
+     *            OpenStackLoadBalancerHealthMonitor object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronLoadBalancerHealthMonitor(String uuid, NeutronLoadBalancerHealthMonitor delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerHealthMonitor object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronLoadBalancerHealthMonitorInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerListenerCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerListenerCRUD.java
new file mode 100644 (file)
index 0000000..b771368
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerListener;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancerListener objects
+ *
+ */
+
+public interface INeutronLoadBalancerListenerCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *LoadBalancerListener object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerListener object
+     * @return boolean
+     */
+
+    boolean neutronLoadBalancerListenerExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * LoadBalancerListener object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerListener object
+     * @return {@link NeutronLoadBalancerListener}
+     *          OpenStackLoadBalancerListener class
+     */
+
+    NeutronLoadBalancerListener getNeutronLoadBalancerListener(String uuid);
+
+    /**
+     * Applications call this interface method to return all LoadBalancerListener objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronLoadBalancerListener> getAllNeutronLoadBalancerListeners();
+
+    /**
+     * Applications call this interface method to add a LoadBalancerListener object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronLoadBalancerListener(NeutronLoadBalancerListener input);
+
+    /**
+     * Applications call this interface method to remove a Neutron LoadBalancerListener object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the LoadBalancerListener object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronLoadBalancerListener(String uuid);
+
+    /**
+     * Applications call this interface method to edit a LoadBalancerListener object
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerListener object
+     * @param delta
+     *            OpenStackLoadBalancerListener object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronLoadBalancerListener(String uuid, NeutronLoadBalancerListener delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerListener object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronLoadBalancerListenerInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerPoolCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerPoolCRUD.java
new file mode 100644 (file)
index 0000000..93185b3
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancerPool objects
+ *
+ */
+
+public interface INeutronLoadBalancerPoolCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *LoadBalancerPool object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerPool object
+     * @return boolean
+     */
+
+    boolean neutronLoadBalancerPoolExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * LoadBalancerPool object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerPool object
+     * @return {@link NeutronLoadBalancerPool}
+     *          OpenStackLoadBalancerPool class
+     */
+
+    NeutronLoadBalancerPool getNeutronLoadBalancerPool(String uuid);
+
+    /**
+     * Applications call this interface method to return all LoadBalancerPool objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronLoadBalancerPool> getAllNeutronLoadBalancerPools();
+
+    /**
+     * Applications call this interface method to add a LoadBalancerPool object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronLoadBalancerPool(NeutronLoadBalancerPool input);
+
+    /**
+     * Applications call this interface method to remove a Neutron LoadBalancerPool object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the LoadBalancerPool object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronLoadBalancerPool(String uuid);
+
+    /**
+     * Applications call this interface method to edit a LoadBalancerPool object
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerPool object
+     * @param delta
+     *            OpenStackLoadBalancerPool object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronLoadBalancerPool(String uuid, NeutronLoadBalancerPool delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerPool object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronLoadBalancerPoolInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerPoolMemberCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronLoadBalancerPoolMemberCRUD.java
new file mode 100644 (file)
index 0000000..a0b47f2
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+
+public interface INeutronLoadBalancerPoolMemberCRUD {
+
+    /**
+     * Applications call this interface method to determine if a particular
+     *NeutronLoadBalancerPoolMember object exists
+     *
+     * @param uuid
+     *            UUID of the NeutronLoadBalancerPoolMember object
+     * @return boolean
+     */
+
+    boolean neutronLoadBalancerPoolMemberExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * NeutronLoadBalancerPoolMember object exists
+     *
+     * @param uuid
+     *            UUID of the NeutronLoadBalancerPoolMember object
+     * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember}
+     *          OpenStackNeutronLoadBalancerPoolMember class
+     */
+
+    NeutronLoadBalancerPoolMember getNeutronLoadBalancerPoolMember(String uuid);
+
+    /**
+     * Applications call this interface method to return all NeutronLoadBalancerPoolMember objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronLoadBalancerPoolMember> getAllNeutronLoadBalancerPoolMembers();
+
+    /**
+     * Applications call this interface method to add a NeutronLoadBalancerPoolMember object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember input);
+
+    /**
+     * Applications call this interface method to remove a Neutron NeutronLoadBalancerPoolMember object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the NeutronLoadBalancerPoolMember object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronLoadBalancerPoolMember(String uuid);
+
+    /**
+     * Applications call this interface method to edit a NeutronLoadBalancerPoolMember object
+     *
+     * @param uuid
+     *            identifier of the NeutronLoadBalancerPoolMember object
+     * @param delta
+     *            OpenStackNeutronLoadBalancerPoolMember object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronLoadBalancerPoolMember(String uuid, NeutronLoadBalancerPoolMember delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the NeutronLoadBalancerPoolMember object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronLoadBalancerPoolMemberInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronNetworkCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronNetworkCRUD.java
new file mode 100644 (file)
index 0000000..8714666
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+
+/**
+ * This interface defines the methods for CRUD of NB network objects
+ *
+ */
+
+public interface INeutronNetworkCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * Network object exists
+     *
+     * @param uuid
+     *            UUID of the Network object
+     * @return boolean
+     */
+
+    boolean networkExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Network object exists
+     *
+     * @param uuid
+     *            UUID of the Network object
+     * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork}
+     *          OpenStack Network class
+     */
+
+    NeutronNetwork getNetwork(String uuid);
+
+    /**
+     * Applications call this interface method to return all Network objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    List<NeutronNetwork> getAllNetworks();
+
+    /**
+     * Applications call this interface method to add a Network object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNetwork(NeutronNetwork input);
+
+    /**
+     * Applications call this interface method to remove a Network object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the network object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNetwork(String uuid);
+
+    /**
+     * Applications call this interface method to edit a Network object
+     *
+     * @param uuid
+     *            identifier of the network object
+     * @param delta
+     *            OpenStackNetwork object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNetwork(String uuid, NeutronNetwork delta);
+
+    /**
+     * Applications call this interface method to determine if a Network object
+     * is use
+     *
+     * @param netUUID
+     *            identifier of the network object
+     *
+     * @return boolean on whether the network is in use or not
+     */
+
+    boolean networkInUse(String netUUID);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronPortCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronPortCRUD.java
new file mode 100644 (file)
index 0000000..f7d5271
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+
+/**
+ * This interface defines the methods for CRUD of NB Port objects
+ *
+ */
+
+public interface INeutronPortCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * Port object exists
+     *
+     * @param uuid
+     *            UUID of the Port object
+     * @return boolean
+     */
+
+    boolean portExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Port object exists
+     *
+     * @param uuid
+     *            UUID of the Port object
+     * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort}
+     *          OpenStack Port class
+     */
+
+    NeutronPort getPort(String uuid);
+
+    /**
+     * Applications call this interface method to return all Port objects
+     *
+     * @return List of OpenStackPorts objects
+     */
+
+    List<NeutronPort> getAllPorts();
+
+    /**
+     * Applications call this interface method to add a Port object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackPort object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addPort(NeutronPort input);
+
+    /**
+     * Applications call this interface method to remove a Port object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the Port object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removePort(String uuid);
+
+    /**
+     * Applications call this interface method to edit a Port object
+     *
+     * @param uuid
+     *            identifier of the Port object
+     * @param delta
+     *            OpenStackPort object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updatePort(String uuid, NeutronPort delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param macAddress
+     *            mac Address to be tested
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     *
+     * @deprecated - will be removed in Boron
+     */
+
+    boolean macInUse(String macAddress);
+
+    /**
+     * Applications call this interface method to retrieve the port associated with
+     * the gateway address of a subnet
+     *
+     * @param subnetUUID
+     *            identifier of the subnet
+     * @return OpenStackPorts object if the port exists and null if it does not
+     *
+     * @deprecated - will be removed in Boron
+     */
+
+    NeutronPort getGatewayPort(String subnetUUID);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronRouterCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronRouterCRUD.java
new file mode 100644 (file)
index 0000000..c2fcc3c
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+
+/**
+ * This interface defines the methods for CRUD of NB Router objects
+ *
+ */
+
+public interface INeutronRouterCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * Router object exists
+     *
+     * @param uuid
+     *            UUID of the Router object
+     * @return boolean
+     */
+
+    boolean routerExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Router object exists
+     *
+     * @param uuid
+     *            UUID of the Router object
+     * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter}
+     *          OpenStack Router class
+     */
+
+    NeutronRouter getRouter(String uuid);
+
+    /**
+     * Applications call this interface method to return all Router objects
+     *
+     * @return List of OpenStackRouters objects
+     */
+
+    List<NeutronRouter> getAllRouters();
+
+    /**
+     * Applications call this interface method to add a Router object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackRouter object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addRouter(NeutronRouter input);
+
+    /**
+     * Applications call this interface method to remove a Router object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the Router object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeRouter(String uuid);
+
+    /**
+     * Applications call this interface method to edit a Router object
+     *
+     * @param uuid
+     *            identifier of the Router object
+     * @param delta
+     *            OpenStackRouter object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateRouter(String uuid, NeutronRouter delta);
+
+    /**
+     * Applications call this interface method to check if a router is in use
+     *
+     * @param routerUUID
+     *            identifier of the Router object
+     * @return boolean on whether the router is in use or not
+     */
+
+    boolean routerInUse(String routerUUID);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronSecurityGroupCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronSecurityGroupCRUD.java
new file mode 100644 (file)
index 0000000..0fa139e
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Security Group objects
+ */
+
+public interface INeutronSecurityGroupCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * Security Group object exists
+     *
+     * @param uuid UUID of the Security Group object
+     * @return boolean
+     */
+
+    boolean neutronSecurityGroupExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Security Group object exists
+     *
+     * @param uuid UUID of the Security Group object
+     * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup}
+     * OpenStack Security Group class
+     */
+
+    NeutronSecurityGroup getNeutronSecurityGroup(String uuid);
+
+    /**
+     * Applications call this interface method to return all Security Group objects
+     *
+     * @return List of OpenStackSecurity Groups objects
+     */
+
+    List<NeutronSecurityGroup> getAllNeutronSecurityGroups();
+
+    /**
+     * Applications call this interface method to add a Security Group object to the
+     * concurrent map
+     *
+     * @param input OpenStackSecurity Group object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronSecurityGroup(NeutronSecurityGroup input);
+
+    /**
+     * Applications call this interface method to remove a Neutron Security Group object to the
+     * concurrent map
+     *
+     * @param uuid identifier for the security group object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronSecurityGroup(String uuid);
+
+    /**
+     * Applications call this interface method to edit a Security Group object
+     *
+     * @param uuid  identifier of the security group object
+     * @param delta OpenStackSecurity Group object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronSecurityGroup(String uuid, NeutronSecurityGroup delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid identifier of the security group object
+     * @return boolean on whether the Security Groups is already in use
+     */
+
+    boolean neutronSecurityGroupInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronSecurityRuleCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronSecurityRuleCRUD.java
new file mode 100644 (file)
index 0000000..42fbadc
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack Security Rule objects
+ */
+
+public interface INeutronSecurityRuleCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * Security Rule object exists
+     *
+     * @param uuid UUID of theSecurity Rule object
+     * @return boolean
+     */
+
+    boolean neutronSecurityRuleExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Security Rule object exists
+     *
+     * @param uuid UUID of the security rule object
+     * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule}
+     * OpenStackSecurity Rule class
+     */
+
+    NeutronSecurityRule getNeutronSecurityRule(String uuid);
+
+    /**
+     * Applications call this interface method to return all Security Rule objects
+     *
+     * @return List of OpenStack SecurityRules objects
+     */
+
+    List<NeutronSecurityRule> getAllNeutronSecurityRules();
+
+    /**
+     * Applications call this interface method to add a Security Rule object to the
+     * concurrent map
+     *
+     * @param input OpenStack security rule object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addNeutronSecurityRule(NeutronSecurityRule input);
+
+    /**
+     * Applications call this interface method to remove a Neutron Security Rule object to the
+     * concurrent map
+     *
+     * @param uuid identifier for the security rule object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeNeutronSecurityRule(String uuid);
+
+    /**
+     * Applications call this interface method to edit aSecurity Rule object
+     *
+     * @param uuid  identifier of the security rule object
+     * @param delta OpenStackSecurity Rule object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateNeutronSecurityRule(String uuid, NeutronSecurityRule delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid identifier of the security rule object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    boolean neutronSecurityRuleInUse(String uuid);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronSubnetCRUD.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/INeutronSubnetCRUD.java
new file mode 100644 (file)
index 0000000..b96646a
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.crud;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+
+/**
+ * This interface defines the methods for CRUD of NB Subnet objects
+ *
+ */
+
+public interface INeutronSubnetCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     * Subnet object exists
+     *
+     * @param uuid
+     *            UUID of the Subnet object
+     * @return boolean
+     */
+
+    boolean subnetExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * Subnet object exists
+     *
+     * @param uuid
+     *            UUID of the Subnet object
+     * @return {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet}
+     *          OpenStack Subnet class
+     */
+
+    NeutronSubnet getSubnet(String uuid);
+
+    /**
+     * Applications call this interface method to return all Subnet objects
+     *
+     * @return List of OpenStackSubnets objects
+     */
+
+    List<NeutronSubnet> getAllSubnets();
+
+    /**
+     * Applications call this interface method to add a Subnet object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackSubnet object
+     * @return boolean on whether the object was added or not
+     */
+
+    boolean addSubnet(NeutronSubnet input);
+
+    /**
+     * Applications call this interface method to remove a Subnet object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the Subnet object
+     * @return boolean on whether the object was removed or not
+     */
+
+    boolean removeSubnet(String uuid);
+
+    /**
+     * Applications call this interface method to edit a Subnet object
+     *
+     * @param uuid
+     *            identifier of the Subnet object
+     * @param delta
+     *            OpenStackSubnet object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    boolean updateSubnet(String uuid, NeutronSubnet delta);
+
+    /**
+     * Applications call this interface method to determine if a Subnet object
+     * is use
+     *
+     * @param subnetUUID
+     *            identifier of the subnet object
+     *
+     * @return boolean on whether the subnet is in use or not
+     *
+     * @deprecated - will be removed in Boron
+     */
+
+    boolean subnetInUse(String subnetUUID);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/NeutronCRUDInterfaces.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/NeutronCRUDInterfaces.java
new file mode 100644 (file)
index 0000000..4f61e51
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.crud;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronCRUDInterfaces {
+    private static final Logger LOGGER = LoggerFactory
+            .getLogger(NeutronCRUDInterfaces.class);
+
+    private INeutronNetworkCRUD networkInterface;
+    private INeutronSubnetCRUD subnetInterface;
+    private INeutronPortCRUD portInterface;
+    private INeutronRouterCRUD routerInterface;
+    private INeutronFloatingIPCRUD fipInterface;
+    private INeutronSecurityGroupCRUD sgInterface;
+    private INeutronSecurityRuleCRUD srInterface;
+    private INeutronFirewallCRUD fwInterface;
+    private INeutronFirewallPolicyCRUD fwpInterface;
+    private INeutronFirewallRuleCRUD fwrInterface;
+    private INeutronLoadBalancerCRUD lbInterface;
+    private INeutronLoadBalancerPoolCRUD lbpInterface;
+    private INeutronLoadBalancerListenerCRUD lblInterface;
+    private INeutronLoadBalancerHealthMonitorCRUD lbhmInterface;
+    private INeutronLoadBalancerPoolMemberCRUD lbpmInterface;
+    public NeutronCRUDInterfaces() {
+    }
+
+    public INeutronNetworkCRUD getNetworkInterface() {
+        return networkInterface;
+    }
+
+    public INeutronSubnetCRUD getSubnetInterface() {
+        return subnetInterface;
+    }
+
+    public INeutronPortCRUD getPortInterface() {
+        return portInterface;
+    }
+
+    public INeutronRouterCRUD getRouterInterface() {
+        return routerInterface;
+    }
+
+    public INeutronFloatingIPCRUD getFloatingIPInterface() {
+        return fipInterface;
+    }
+
+    public INeutronSecurityGroupCRUD getSecurityGroupInterface() {
+        return sgInterface;
+    }
+
+    public INeutronSecurityRuleCRUD getSecurityRuleInterface() {
+        return srInterface;
+    }
+
+    public INeutronFirewallCRUD getFirewallInterface() {
+        return fwInterface;
+    }
+
+    public INeutronFirewallPolicyCRUD getFirewallPolicyInterface() {
+        return fwpInterface;
+    }
+
+    public INeutronFirewallRuleCRUD getFirewallRuleInterface() {
+        return fwrInterface;
+    }
+
+    public INeutronLoadBalancerCRUD getLoadBalancerInterface() {
+        return lbInterface;
+    }
+
+    public INeutronLoadBalancerPoolCRUD getLoadBalancerPoolInterface() {
+        return lbpInterface;
+    }
+
+    public INeutronLoadBalancerListenerCRUD getLoadBalancerListenerInterface() {
+        return lblInterface;
+    }
+
+    public INeutronLoadBalancerHealthMonitorCRUD getLoadBalancerHealthMonitorInterface() {
+        return lbhmInterface;
+    }
+
+    public INeutronLoadBalancerPoolMemberCRUD getLoadBalancerPoolMemberInterface() {
+        return lbpmInterface;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronNetworkCRUD(Object obj) {
+        networkInterface = (INeutronNetworkCRUD) getInstances(INeutronNetworkCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronSubnetCRUD(Object obj) {
+        subnetInterface = (INeutronSubnetCRUD) getInstances(INeutronSubnetCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronPortCRUD(Object obj) {
+        portInterface = (INeutronPortCRUD) getInstances(INeutronPortCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronRouterCRUD(Object obj) {
+        routerInterface = (INeutronRouterCRUD) getInstances(INeutronRouterCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronFloatingIPCRUD(Object obj) {
+        fipInterface = (INeutronFloatingIPCRUD) getInstances(INeutronFloatingIPCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronSecurityGroupCRUD(Object obj) {
+        sgInterface = (INeutronSecurityGroupCRUD) getInstances(INeutronSecurityGroupCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronSecurityRuleCRUD(Object obj) {
+        srInterface = (INeutronSecurityRuleCRUD) getInstances(INeutronSecurityRuleCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronFirewallCRUD(Object obj) {
+        fwInterface = (INeutronFirewallCRUD) getInstances(INeutronFirewallCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronFirewallPolicyCRUD(Object obj) {
+        fwpInterface = (INeutronFirewallPolicyCRUD) getInstances(INeutronFirewallPolicyCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronFirewallRuleCRUD(Object obj) {
+        fwrInterface = (INeutronFirewallRuleCRUD) getInstances(INeutronFirewallRuleCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronLoadBalancerCRUD(Object obj) {
+        lbInterface = (INeutronLoadBalancerCRUD) getInstances(INeutronLoadBalancerCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronLoadBalancerPoolCRUD(Object obj) {
+        lbpInterface = (INeutronLoadBalancerPoolCRUD) getInstances(INeutronLoadBalancerPoolCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronLoadBalancerListenerCRUD(Object obj) {
+        lblInterface = (INeutronLoadBalancerListenerCRUD) getInstances(INeutronLoadBalancerListenerCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronLoadBalancerHealthMonitorCRUD(Object obj) {
+        lbhmInterface = (INeutronLoadBalancerHealthMonitorCRUD) getInstances(INeutronLoadBalancerHealthMonitorCRUD.class, obj);
+        return this;
+    }
+
+    public NeutronCRUDInterfaces fetchINeutronLoadBalancerPoolMemberCRUD(Object obj) {
+        lbpmInterface = (INeutronLoadBalancerPoolMemberCRUD) getInstances(INeutronLoadBalancerPoolMemberCRUD.class, obj);
+        return this;
+    }
+
+    public Object getInstances(Class<?> clazz, Object bundle) {
+        try {
+            BundleContext bCtx = FrameworkUtil.getBundle(bundle.getClass()).getBundleContext();
+
+            ServiceReference<?>[] services = null;
+            services = bCtx.getServiceReferences(clazz.getName(), null);
+            if (services != null) {
+                return bCtx.getService(services[0]);
+            }
+        } catch (Exception e) {
+            LOGGER.error("Error in getInstances", e);
+        }
+        return null;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/AbstractNeutronInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/AbstractNeutronInterface.java
new file mode 100644 (file)
index 0000000..178a228
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2015 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.INeutronObject;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+
+
+public abstract class AbstractNeutronInterface<T extends DataObject, S extends INeutronObject> implements AutoCloseable {
+    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractNeutronInterface.class);
+    private static final int DEDASHED_UUID_LENGTH = 32;
+    private static final int DEDASHED_UUID_START = 0;
+    private static final int DEDASHED_UUID_DIV1 = 8;
+    private static final int DEDASHED_UUID_DIV2 = 12;
+    private static final int DEDASHED_UUID_DIV3 = 16;
+    private static final int DEDASHED_UUID_DIV4 = 20;
+
+    private DataBroker db;
+
+    AbstractNeutronInterface(ProviderContext providerContext) {
+        this.db = providerContext.getSALService(DataBroker.class);
+    }
+
+    public DataBroker getDataBroker() {
+        return db;
+    }
+
+    protected abstract InstanceIdentifier<T> createInstanceIdentifier(T item);
+
+    protected abstract T toMd(S neutronObject);
+
+    protected abstract T toMd(String uuid);
+
+    protected <T extends org.opendaylight.yangtools.yang.binding.DataObject> T readMd(InstanceIdentifier<T> path) {
+        T result = null;
+        final ReadOnlyTransaction transaction = getDataBroker().newReadOnlyTransaction();
+        CheckedFuture<Optional<T>, ReadFailedException> future = transaction.read(LogicalDatastoreType.CONFIGURATION, path);
+        if (future != null) {
+            Optional<T> optional;
+            try {
+                optional = future.checkedGet();
+                if (optional.isPresent()) {
+                    result = optional.get();
+                }
+            } catch (ReadFailedException e) {
+                LOGGER.warn("Failed to read {}", path, e);
+            }
+        }
+        transaction.close();
+        return result;
+    }
+
+    protected boolean addMd(S neutronObject) {
+        // TODO think about adding existence logic
+        return updateMd(neutronObject);
+    }
+
+    protected boolean updateMd(S neutronObject) {
+        WriteTransaction transaction = getDataBroker().newWriteOnlyTransaction();
+        T item = toMd(neutronObject);
+        InstanceIdentifier<T> iid = createInstanceIdentifier(item);
+        transaction.put(LogicalDatastoreType.CONFIGURATION, iid, item,true);
+        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+        try {
+            future.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOGGER.warn("Transation failed ",e);
+            return false;
+        }
+        return true;
+    }
+
+    protected boolean removeMd(T item) {
+        WriteTransaction transaction = getDataBroker().newWriteOnlyTransaction();
+        InstanceIdentifier<T> iid = createInstanceIdentifier(item);
+        transaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
+        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+        try {
+            future.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOGGER.warn("Transation failed ",e);
+            return false;
+        }
+        return true;
+    }
+
+    protected Uuid toUuid(String uuid) {
+        Preconditions.checkNotNull(uuid);
+        Uuid result;
+        try {
+            result = new Uuid(uuid);
+        } catch(IllegalArgumentException e) {
+            // OK... someone didn't follow RFC 4122... lets try this the hard way
+            String dedashed = uuid.replace("-", "");
+            if(dedashed.length() == DEDASHED_UUID_LENGTH) {
+                String redashed = dedashed.substring(DEDASHED_UUID_START, DEDASHED_UUID_DIV1)
+                        + "-"
+                        + dedashed.substring(DEDASHED_UUID_DIV1, DEDASHED_UUID_DIV2)
+                        + "-"
+                        + dedashed.substring(DEDASHED_UUID_DIV2, DEDASHED_UUID_DIV3)
+                        + "-"
+                        + dedashed.substring(DEDASHED_UUID_DIV3, DEDASHED_UUID_DIV4)
+                        + "-"
+                        + dedashed.substring(DEDASHED_UUID_DIV4, DEDASHED_UUID_LENGTH);
+                result = new Uuid(redashed);
+            } else {
+                throw e;
+            }
+        }
+        return result;
+    }
+
+    // this method uses reflection to update an object from it's delta.
+
+    protected boolean overwrite(Object target, Object delta) {
+        Method[] methods = target.getClass().getMethods();
+
+        for(Method toMethod: methods){
+            if(toMethod.getDeclaringClass().equals(target.getClass())
+                    && toMethod.getName().startsWith("set")){
+
+                String toName = toMethod.getName();
+                String fromName = toName.replace("set", "get");
+
+                try {
+                    Method fromMethod = delta.getClass().getMethod(fromName);
+                    Object value = fromMethod.invoke(delta, (Object[])null);
+                    if(value != null){
+                        toMethod.invoke(target, value);
+                    }
+                } catch (Exception e) {
+                    LOGGER.error("Error in overwrite", e);
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void close() throws Exception {
+        // TODO Auto-generated method stub
+
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFirewallInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFirewallInterface.java
new file mode 100644 (file)
index 0000000..485eb8b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.INeutronObject;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewall;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronFirewallCRUD;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronFirewallInterface extends AbstractNeutronInterface implements INeutronFirewallCRUD {
+
+    NeutronFirewallInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronFirewallInterface neutronFirewallInterface = new NeutronFirewallInterface(providerContext);
+        ServiceRegistration<INeutronFirewallCRUD> neutronFirewallInterfaceRegistration = context.registerService(INeutronFirewallCRUD.class, neutronFirewallInterface, null);
+        if(neutronFirewallInterfaceRegistration != null) {
+            registrations.add(neutronFirewallInterfaceRegistration);
+        }
+    }
+
+    @Override
+    public boolean neutronFirewallExists(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public NeutronFirewall getNeutronFirewall(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public List<NeutronFirewall> getAllNeutronFirewalls() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean addNeutronFirewall(NeutronFirewall input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean removeNeutronFirewall(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean updateNeutronFirewall(String uuid, NeutronFirewall delta) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean neutronFirewallInUse(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected InstanceIdentifier createInstanceIdentifier(DataObject item) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected DataObject toMd(INeutronObject neutronObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected DataObject toMd(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFirewallPolicyInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFirewallPolicyInterface.java
new file mode 100644 (file)
index 0000000..514a1dc
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.INeutronObject;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallPolicy;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronFirewallPolicyCRUD;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ */
+
+public class NeutronFirewallPolicyInterface extends AbstractNeutronInterface implements INeutronFirewallPolicyCRUD {
+
+    NeutronFirewallPolicyInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronFirewallPolicyExists(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public NeutronFirewallPolicy getNeutronFirewallPolicy(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public List<NeutronFirewallPolicy> getAllNeutronFirewallPolicies() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean addNeutronFirewallPolicy(NeutronFirewallPolicy input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean removeNeutronFirewallPolicy(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean updateNeutronFirewallPolicy(String uuid,
+            NeutronFirewallPolicy delta) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean neutronFirewallPolicyInUse(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected InstanceIdentifier createInstanceIdentifier(DataObject item) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected DataObject toMd(INeutronObject neutronObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected DataObject toMd(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronFirewallPolicyInterface neutronFirewallPolicyInterface = new NeutronFirewallPolicyInterface(providerContext);
+        ServiceRegistration<INeutronFirewallPolicyCRUD> neutronFirewallPolicyInterfaceRegistration = context.registerService(INeutronFirewallPolicyCRUD.class, neutronFirewallPolicyInterface, null);
+        if(neutronFirewallPolicyInterfaceRegistration != null) {
+            registrations.add(neutronFirewallPolicyInterfaceRegistration);
+        }
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFirewallRuleInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFirewallRuleInterface.java
new file mode 100644 (file)
index 0000000..f056d18
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.INeutronObject;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronFirewallRuleCRUD;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronFirewallRuleInterface extends AbstractNeutronInterface implements INeutronFirewallRuleCRUD {
+
+    NeutronFirewallRuleInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronFirewallRuleExists(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public NeutronFirewallRule getNeutronFirewallRule(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public List<NeutronFirewallRule> getAllNeutronFirewallRules() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean addNeutronFirewallRule(NeutronFirewallRule input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean removeNeutronFirewallRule(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean updateNeutronFirewallRule(String uuid,
+            NeutronFirewallRule delta) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean neutronFirewallRuleInUse(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected InstanceIdentifier createInstanceIdentifier(DataObject item) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected DataObject toMd(INeutronObject neutronObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected DataObject toMd(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronFirewallRuleInterface neutronFirewallRuleInterface = new NeutronFirewallRuleInterface(providerContext);
+        ServiceRegistration<INeutronFirewallRuleCRUD> neutronFirewallRuleInterfaceRegistration = context.registerService(INeutronFirewallRuleCRUD.class, neutronFirewallRuleInterface, null);
+        if(neutronFirewallRuleInterfaceRegistration != null) {
+            registrations.add(neutronFirewallRuleInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFloatingIPInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronFloatingIPInterface.java
new file mode 100644 (file)
index 0000000..20dc3c3
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronFloatingIPCRUD;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.Floatingips;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.FloatingipBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronFloatingIPInterface extends AbstractNeutronInterface<Floatingip, NeutronFloatingIP> implements INeutronFloatingIPCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronFloatingIPInterface.class);
+
+    NeutronFloatingIPInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    // IfNBFloatingIPCRUD interface methods
+
+    @Override
+    public boolean floatingIPExists(String uuid) {
+        Floatingip fip = readMd(createInstanceIdentifier(toMd(uuid)));
+        return (fip != null);
+    }
+
+    @Override
+    public NeutronFloatingIP getFloatingIP(String uuid) {
+        Floatingip fip = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (fip == null) {
+            return null;
+        }
+        return fromMd(fip);
+    }
+
+    @Override
+    public List<NeutronFloatingIP> getAllFloatingIPs() {
+        Set<NeutronFloatingIP> allIPs = new HashSet<NeutronFloatingIP>();
+        Floatingips fips = readMd(createInstanceIdentifier());
+        if (fips != null) {
+            for (Floatingip fip: fips.getFloatingip()) {
+                allIPs.add(fromMd(fip));
+            }
+        }
+        LOGGER.debug("Exiting getAllFloatingIPs, Found {} FloatingIPs", allIPs.size());
+        List<NeutronFloatingIP> ans = new ArrayList<NeutronFloatingIP>();
+        ans.addAll(allIPs);
+        return ans;
+    }
+
+    @Override
+    public boolean addFloatingIP(NeutronFloatingIP input) {
+        if (floatingIPExists(input.getID())) {
+            return false;
+        }
+        return addMd(input);
+    }
+
+    @Override
+    public boolean removeFloatingIP(String uuid) {
+        NeutronFloatingIP fip = getFloatingIP(uuid);
+        if (fip == null) {
+            return false;
+        }
+        return removeMd(toMd(uuid));
+    }
+
+    @Override
+    public boolean updateFloatingIP(String uuid, NeutronFloatingIP delta) {
+        NeutronFloatingIP target = getFloatingIP(uuid);
+        if (target == null) {
+            return false;
+        }
+        delta.setPortUUID(target.getPortUUID());
+        delta.setFixedIPAddress(target.getFixedIPAddress());
+        return updateMd(delta);
+    }
+
+    @Override
+    protected Floatingip toMd(String uuid) {
+        FloatingipBuilder floatingipBuilder = new FloatingipBuilder();
+        floatingipBuilder.setUuid(toUuid(uuid));
+        return floatingipBuilder.build();
+    }
+
+    @Override
+    protected Floatingip toMd(NeutronFloatingIP floatingIp) {
+        FloatingipBuilder floatingipBuilder = new FloatingipBuilder();
+        if (floatingIp.getFixedIPAddress() != null) {
+            floatingipBuilder.setFixedIpAddress(new IpAddress(floatingIp.getFixedIPAddress().toCharArray()));
+        }
+        if(floatingIp.getFloatingIPAddress() != null) {
+            floatingipBuilder.setFloatingIpAddress(new IpAddress(floatingIp.getFloatingIPAddress().toCharArray()));
+        }
+        if (floatingIp.getFloatingNetworkUUID() != null) {
+            floatingipBuilder.setFloatingNetworkId(toUuid(floatingIp.getFloatingNetworkUUID()));
+        }
+        if (floatingIp.getPortUUID() != null) {
+            floatingipBuilder.setPortId(toUuid(floatingIp.getPortUUID()));
+        }
+        if (floatingIp.getRouterUUID() != null) {
+            floatingipBuilder.setRouterId(toUuid(floatingIp.getRouterUUID()));
+        }
+        if (floatingIp.getStatus() != null) {
+            floatingipBuilder.setStatus(floatingIp.getStatus());
+        }
+        if (floatingIp.getTenantUUID() != null) {
+            floatingipBuilder.setTenantId(toUuid(floatingIp.getTenantUUID()));
+        }
+        if (floatingIp.getID() != null) {
+            floatingipBuilder.setUuid(toUuid(floatingIp.getID()));
+        }
+        else {
+            LOGGER.warn("Attempting to write neutron floating IP without UUID");
+        }
+        return floatingipBuilder.build();
+    }
+
+    protected NeutronFloatingIP fromMd(Floatingip fip) {
+        NeutronFloatingIP result = new NeutronFloatingIP();
+        result.setID(String.valueOf(fip.getUuid().getValue()));
+        if (fip.getFloatingNetworkId() != null) {
+            result.setFloatingNetworkUUID(String.valueOf(fip.getFloatingNetworkId().getValue()));
+        }
+        if (fip.getPortId() != null) {
+            result.setPortUUID(String.valueOf(fip.getPortId().getValue()));
+        }
+        if (fip.getFixedIpAddress() != null ) {
+            result.setFixedIPAddress(String.valueOf(fip.getFixedIpAddress().getValue()));
+        }
+        if (fip.getFloatingIpAddress() != null) {
+            result.setFloatingIPAddress(String.valueOf(fip.getFloatingIpAddress().getValue()));
+        }
+        if (fip.getTenantId() != null) {
+            result.setTenantUUID(String.valueOf(fip.getTenantId().getValue()));
+        }
+        if (fip.getRouterId() != null) {
+            result.setRouterUUID(String.valueOf(fip.getRouterId().getValue()));
+        }
+        result.setStatus(fip.getStatus());
+        return result;
+    }
+
+    @Override
+    protected InstanceIdentifier<Floatingip> createInstanceIdentifier(
+            Floatingip item) {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Floatingips.class)
+                .child(Floatingip.class,item.getKey());
+    }
+
+    protected InstanceIdentifier<Floatingips> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Floatingips.class);
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronFloatingIPInterface neutronFloatingIPInterface = new NeutronFloatingIPInterface(providerContext);
+        ServiceRegistration<INeutronFloatingIPCRUD> neutronFloatingIPInterfaceRegistration = context.registerService(INeutronFloatingIPCRUD.class, neutronFloatingIPInterface, null);
+        if (neutronFloatingIPInterfaceRegistration != null) {
+            registrations.add(neutronFloatingIPInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerHealthMonitorInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerHealthMonitorInterface.java
new file mode 100644 (file)
index 0000000..8f6cf29
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerHealthMonitor;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerHealthMonitorCRUD;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Healthmonitors;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronLoadBalancerHealthMonitorInterface extends AbstractNeutronInterface<Healthmonitors, NeutronLoadBalancerHealthMonitor> implements INeutronLoadBalancerHealthMonitorCRUD {
+
+    NeutronLoadBalancerHealthMonitorInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerHealthMonitorExists(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public NeutronLoadBalancerHealthMonitor getNeutronLoadBalancerHealthMonitor(
+            String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public List<NeutronLoadBalancerHealthMonitor> getAllNeutronLoadBalancerHealthMonitors() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancerHealthMonitor(
+            NeutronLoadBalancerHealthMonitor input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancerHealthMonitor(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancerHealthMonitor(String uuid,
+            NeutronLoadBalancerHealthMonitor delta) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean neutronLoadBalancerHealthMonitorInUse(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected InstanceIdentifier<Healthmonitors> createInstanceIdentifier(
+            Healthmonitors item) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Healthmonitors toMd(NeutronLoadBalancerHealthMonitor neutronObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Healthmonitors toMd(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronLoadBalancerHealthMonitorInterface neutronLoadBalancerHealthMonitorInterface = new NeutronLoadBalancerHealthMonitorInterface(providerContext);
+        ServiceRegistration<INeutronLoadBalancerHealthMonitorCRUD> neutronLoadBalancerHealthMonitorInterfaceRegistration = context.registerService(INeutronLoadBalancerHealthMonitorCRUD.class, neutronLoadBalancerHealthMonitorInterface, null);
+        if(neutronLoadBalancerHealthMonitorInterfaceRegistration != null) {
+            registrations.add(neutronLoadBalancerHealthMonitorInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerInterface.java
new file mode 100644 (file)
index 0000000..770516e
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Loadbalancers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.loadbalancers.Loadbalancer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.loadbalancers.LoadbalancerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TODO: Migrate this to consume the MD-SAL data store, so that it can read all the data from data store.
+ * No need to worry about the write/update related methods here. OVSDB net-virt will use these CRUD Interface
+ * only for reading. We will cleanup these interface/methods later.
+ */
+public class NeutronLoadBalancerInterface extends AbstractNeutronInterface<Loadbalancer, NeutronLoadBalancer> implements INeutronLoadBalancerCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronLoadBalancerInterface.class);
+    private ConcurrentMap<String, NeutronLoadBalancer> loadBalancerDB  = new ConcurrentHashMap<String, NeutronLoadBalancer>();
+
+
+    NeutronLoadBalancerInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerExists(String uuid) {
+        return loadBalancerDB.containsKey(uuid);
+    }
+
+    @Override
+    public NeutronLoadBalancer getNeutronLoadBalancer(String uuid) {
+        if (!neutronLoadBalancerExists(uuid)) {
+            LOGGER.debug("No LoadBalancer Have Been Defined");
+            return null;
+        }
+        return loadBalancerDB.get(uuid);
+    }
+
+    @Override
+    public List<NeutronLoadBalancer> getAllNeutronLoadBalancers() {
+        Set<NeutronLoadBalancer> allLoadBalancers = new HashSet<NeutronLoadBalancer>();
+        for (Entry<String, NeutronLoadBalancer> entry : loadBalancerDB.entrySet()) {
+            NeutronLoadBalancer loadBalancer = entry.getValue();
+            allLoadBalancers.add(loadBalancer);
+        }
+        LOGGER.debug("Exiting getLoadBalancers, Found {} OpenStackLoadBalancer", allLoadBalancers.size());
+        List<NeutronLoadBalancer> ans = new ArrayList<NeutronLoadBalancer>();
+        ans.addAll(allLoadBalancers);
+        return ans;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancer(NeutronLoadBalancer input) {
+        if (neutronLoadBalancerExists(input.getID())) {
+            return false;
+        }
+        loadBalancerDB.putIfAbsent(input.getID(), input);
+        //TODO: add code to find INeutronLoadBalancerAware services and call newtorkCreated on them
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancer(String uuid) {
+        if (!neutronLoadBalancerExists(uuid)) {
+            return false;
+        }
+        loadBalancerDB.remove(uuid);
+        //TODO: add code to find INeutronLoadBalancerAware services and call newtorkDeleted on them
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancer(String uuid, NeutronLoadBalancer delta) {
+        if (!neutronLoadBalancerExists(uuid)) {
+            return false;
+        }
+        NeutronLoadBalancer target = loadBalancerDB.get(uuid);
+        return overwrite(target, delta);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerInUse(String loadBalancerUUID) {
+        return !neutronLoadBalancerExists(loadBalancerUUID);
+    }
+
+    @Override
+    protected Loadbalancer toMd(String uuid) {
+        LoadbalancerBuilder loadBalancersBuilder = new LoadbalancerBuilder();
+        loadBalancersBuilder.setUuid(toUuid(uuid));
+        return loadBalancersBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<Loadbalancer> createInstanceIdentifier(
+            Loadbalancer loadBalancer) {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Loadbalancers.class)
+                .child(Loadbalancer.class, loadBalancer.getKey());
+    }
+
+    @Override
+    protected Loadbalancer toMd(NeutronLoadBalancer loadBalancer) {
+        LoadbalancerBuilder loadBalancersBuilder = new LoadbalancerBuilder();
+        loadBalancersBuilder.setAdminStateUp(loadBalancer.getLoadBalancerAdminStateUp());
+        if (loadBalancer.getLoadBalancerDescription() != null) {
+            loadBalancersBuilder.setDescr(loadBalancer.getLoadBalancerDescription());
+        }
+        if (loadBalancer.getLoadBalancerName() != null) {
+            loadBalancersBuilder.setName(loadBalancer.getLoadBalancerName());
+        }
+        if (loadBalancer.getLoadBalancerStatus() != null) {
+            loadBalancersBuilder.setStatus(loadBalancer.getLoadBalancerStatus());
+        }
+        if (loadBalancer.getLoadBalancerTenantID() != null) {
+            loadBalancersBuilder.setTenantId(toUuid(loadBalancer.getLoadBalancerTenantID()));
+        }
+        if (loadBalancer.getLoadBalancerVipAddress() != null) {
+            loadBalancersBuilder.setVipAddress(new IpAddress(loadBalancer.getLoadBalancerVipAddress().toCharArray()));
+        }
+        if (loadBalancer.getLoadBalancerVipSubnetID() != null) {
+            loadBalancersBuilder.setVipSubnetId(toUuid(loadBalancer.getLoadBalancerVipSubnetID()));
+        }
+        if (loadBalancer.getID() != null) {
+            loadBalancersBuilder.setUuid(toUuid(loadBalancer.getID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron load balancer without UUID");
+        }
+        return loadBalancersBuilder.build();
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronLoadBalancerInterface neutronLoadBalancerInterface = new NeutronLoadBalancerInterface(providerContext);
+        ServiceRegistration<INeutronLoadBalancerCRUD> neutronLoadBalancerInterfaceRegistration = context.registerService(INeutronLoadBalancerCRUD.class, neutronLoadBalancerInterface, null);
+        if(neutronLoadBalancerInterfaceRegistration != null) {
+            registrations.add(neutronLoadBalancerInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerListenerInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerListenerInterface.java
new file mode 100644 (file)
index 0000000..1d16029
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerListener;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerListenerCRUD;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Listeners;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronLoadBalancerListenerInterface extends AbstractNeutronInterface<Listeners, NeutronLoadBalancerListener> implements INeutronLoadBalancerListenerCRUD {
+
+    NeutronLoadBalancerListenerInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerListenerExists(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public NeutronLoadBalancerListener getNeutronLoadBalancerListener(
+            String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public List<NeutronLoadBalancerListener> getAllNeutronLoadBalancerListeners() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancerListener(
+            NeutronLoadBalancerListener input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancerListener(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancerListener(String uuid,
+            NeutronLoadBalancerListener delta) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean neutronLoadBalancerListenerInUse(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected InstanceIdentifier<Listeners> createInstanceIdentifier(
+            Listeners item) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Listeners toMd(NeutronLoadBalancerListener neutronObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Listeners toMd(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronLoadBalancerListenerInterface neutronLoadBalancerListenerInterface = new NeutronLoadBalancerListenerInterface(providerContext);
+        ServiceRegistration<INeutronLoadBalancerListenerCRUD> neutronLoadBalancerListenerInterfaceRegistration = context.registerService(INeutronLoadBalancerListenerCRUD.class, neutronLoadBalancerListenerInterface, null);
+        if(neutronLoadBalancerListenerInterfaceRegistration != null) {
+            registrations.add(neutronLoadBalancerListenerInterfaceRegistration);
+        }
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerPoolInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerPoolInterface.java
new file mode 100644 (file)
index 0000000..adc1c38
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer_SessionPersistence;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_ID;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Pools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.Pool;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.PoolBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.pool.attributes.SessionPersistenceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+/**
+ * TODO: Migrate this to consume the MD-SAL data store, so that it can read all the data from data store.
+ * No need to worry about the write/update related methods here. OVSDB net-virt will use these CRUD Interface
+ * only for reading. We will cleanup these interface/methods later.
+ */
+
+public class NeutronLoadBalancerPoolInterface extends AbstractNeutronInterface<Pool, NeutronLoadBalancerPool> implements INeutronLoadBalancerPoolCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronLoadBalancerPoolInterface.class);
+    private ConcurrentMap<String, NeutronLoadBalancerPool> loadBalancerPoolDB = new ConcurrentHashMap<String, NeutronLoadBalancerPool>();
+
+    private static final ImmutableBiMap<Class<? extends ProtocolBase>,String> PROTOCOL_MAP
+            = new ImmutableBiMap.Builder<Class<? extends ProtocolBase>,String>()
+            .put(ProtocolHttp.class,"HTTP")
+            .put(ProtocolHttps.class,"HTTPS")
+            .put(ProtocolTcp.class,"TCP")
+            .build();
+
+    NeutronLoadBalancerPoolInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerPoolExists(String uuid) {
+        return loadBalancerPoolDB.containsKey(uuid);
+    }
+
+    @Override
+    public NeutronLoadBalancerPool getNeutronLoadBalancerPool(String uuid) {
+        if (!neutronLoadBalancerPoolExists(uuid)) {
+            LOGGER.debug("No LoadBalancerPool has Been Defined");
+            return null;
+        }
+        return loadBalancerPoolDB.get(uuid);
+    }
+
+    @Override
+    public List<NeutronLoadBalancerPool> getAllNeutronLoadBalancerPools() {
+        Set<NeutronLoadBalancerPool> allLoadBalancerPools = new HashSet<NeutronLoadBalancerPool>();
+        for (Entry<String, NeutronLoadBalancerPool> entry : loadBalancerPoolDB.entrySet()) {
+            NeutronLoadBalancerPool loadBalancerPool = entry.getValue();
+            allLoadBalancerPools.add(loadBalancerPool);
+        }
+        LOGGER.debug("Exiting getLoadBalancerPools, Found {} OpenStackLoadBalancerPool", allLoadBalancerPools.size());
+        List<NeutronLoadBalancerPool> ans = new ArrayList<NeutronLoadBalancerPool>();
+        ans.addAll(allLoadBalancerPools);
+        return ans;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancerPool(NeutronLoadBalancerPool input) {
+        if (neutronLoadBalancerPoolExists(input.getID())) {
+            return false;
+        }
+        loadBalancerPoolDB.putIfAbsent(input.getID(), input);
+        //TODO: add code to find INeutronLoadBalancerPoolAware services and call newtorkCreated on them
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancerPool(String uuid) {
+        if (!neutronLoadBalancerPoolExists(uuid)) {
+            return false;
+        }
+        loadBalancerPoolDB.remove(uuid);
+        //TODO: add code to find INeutronLoadBalancerPoolAware services and call newtorkDeleted on them
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancerPool(String uuid, NeutronLoadBalancerPool delta) {
+        if (!neutronLoadBalancerPoolExists(uuid)) {
+            return false;
+        }
+        NeutronLoadBalancerPool target = loadBalancerPoolDB.get(uuid);
+        return overwrite(target, delta);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerPoolInUse(String loadBalancerPoolUUID) {
+        return !neutronLoadBalancerPoolExists(loadBalancerPoolUUID);
+    }
+
+    @Override
+    protected Pool toMd(String uuid) {
+        PoolBuilder poolsBuilder = new PoolBuilder();
+        poolsBuilder.setUuid(toUuid(uuid));
+        return poolsBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<Pool> createInstanceIdentifier(Pool pools) {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Pools.class)
+                .child(Pool.class, pools.getKey());
+    }
+
+    @Override
+    protected Pool toMd(NeutronLoadBalancerPool pool) {
+        PoolBuilder poolBuilder = new PoolBuilder();
+        poolBuilder.setAdminStateUp(pool.getLoadBalancerPoolAdminIsStateIsUp());
+        if (pool.getLoadBalancerPoolDescription() != null) {
+            poolBuilder.setDescr(pool.getLoadBalancerPoolDescription());
+        }
+        if (pool.getNeutronLoadBalancerPoolHealthMonitorID() != null) {
+            poolBuilder.setHealthmonitorId(toUuid(pool.getNeutronLoadBalancerPoolHealthMonitorID()));
+        }
+        if (pool.getLoadBalancerPoolLbAlgorithm() != null) {
+            poolBuilder.setLbAlgorithm(pool.getLoadBalancerPoolLbAlgorithm());
+        }
+        if (pool.getLoadBalancerPoolListeners() != null) {
+            List<Uuid> listListener = new ArrayList<Uuid>();
+            for (Neutron_ID neutron_id : pool.getLoadBalancerPoolListeners()) {
+                listListener.add(toUuid(neutron_id.getID()));
+            }
+            poolBuilder.setListeners(listListener);
+        }
+        // because members are another container, we don't want to copy
+        // it over, so just skip it here
+        if (pool.getLoadBalancerPoolName() != null) {
+            poolBuilder.setName(pool.getLoadBalancerPoolName());
+        }
+        if (pool.getLoadBalancerPoolProtocol() != null) {
+            ImmutableBiMap<String, Class<? extends ProtocolBase>> mapper =
+                PROTOCOL_MAP.inverse();
+            poolBuilder.setProtocol((Class<? extends ProtocolBase>) mapper.get(pool.getLoadBalancerPoolProtocol()));
+        }
+        if (pool.getLoadBalancerPoolSessionPersistence() != null) {
+            NeutronLoadBalancer_SessionPersistence sessionPersistence = pool.getLoadBalancerPoolSessionPersistence();
+            SessionPersistenceBuilder sessionPersistenceBuilder = new SessionPersistenceBuilder();
+            sessionPersistenceBuilder.setCookieName(sessionPersistence.getCookieName());
+            sessionPersistenceBuilder.setType(sessionPersistence.getType());
+            poolBuilder.setSessionPersistence(sessionPersistenceBuilder.build());
+        }
+        if (pool.getLoadBalancerPoolTenantID() != null) {
+            poolBuilder.setTenantId(toUuid(pool.getLoadBalancerPoolTenantID()));
+        }
+        if (pool.getID() != null) {
+            poolBuilder.setUuid(toUuid(pool.getID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron load balancer pool without UUID");
+        }
+        return poolBuilder.build();
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronLoadBalancerPoolInterface neutronLoadBalancerPoolInterface = new NeutronLoadBalancerPoolInterface(providerContext);
+        ServiceRegistration<INeutronLoadBalancerPoolCRUD> neutronLoadBalancerPoolInterfaceRegistration = context.registerService(INeutronLoadBalancerPoolCRUD.class, neutronLoadBalancerPoolInterface, null);
+        if(neutronLoadBalancerPoolInterfaceRegistration != null) {
+            registrations.add(neutronLoadBalancerPoolInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerPoolMemberInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronLoadBalancerPoolMemberInterface.java
new file mode 100644 (file)
index 0000000..2e6aa92
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolMemberCRUD;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.pool.Members;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronLoadBalancerPoolMemberInterface extends
+        AbstractNeutronInterface<Members, NeutronLoadBalancerPoolMember> implements INeutronLoadBalancerPoolMemberCRUD {
+
+    NeutronLoadBalancerPoolMemberInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerPoolMemberExists(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public NeutronLoadBalancerPoolMember getNeutronLoadBalancerPoolMember(
+            String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public List<NeutronLoadBalancerPoolMember> getAllNeutronLoadBalancerPoolMembers() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancerPoolMember(
+            NeutronLoadBalancerPoolMember input) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancerPoolMember(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancerPoolMember(String uuid,
+            NeutronLoadBalancerPoolMember delta) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean neutronLoadBalancerPoolMemberInUse(String uuid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected InstanceIdentifier<Members> createInstanceIdentifier(Members item) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Members toMd(NeutronLoadBalancerPoolMember neutronObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Members toMd(String uuid) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronLoadBalancerPoolMemberInterface neutronLoadBalancerPoolMemberInterface = new NeutronLoadBalancerPoolMemberInterface(providerContext);
+        ServiceRegistration<INeutronLoadBalancerPoolMemberCRUD> neutronLoadBalancerPoolMemberInterfaceRegistration = context.registerService(INeutronLoadBalancerPoolMemberCRUD.class, neutronLoadBalancerPoolMemberInterface, null);
+        if(neutronLoadBalancerPoolMemberInterfaceRegistration != null) {
+            registrations.add(neutronLoadBalancerPoolMemberInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronNetworkInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronNetworkInterface.java
new file mode 100644 (file)
index 0000000..03e38eb
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork_Segment;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.ext.rev150712.NetworkL3Extension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.ext.rev150712.NetworkL3ExtensionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeFlat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtensionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.neutron.networks.network.Segments;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.neutron.networks.network.SegmentsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronNetworkInterface extends AbstractNeutronInterface<Network,NeutronNetwork> implements INeutronNetworkCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronNetworkInterface.class);
+
+    private static final ImmutableBiMap<Class<? extends NetworkTypeBase>,String> NETWORK_MAP
+            = new ImmutableBiMap.Builder<Class<? extends NetworkTypeBase>,String>()
+            .put(NetworkTypeFlat.class,"flat")
+            .put(NetworkTypeGre.class,"gre")
+            .put(NetworkTypeVlan.class,"vlan")
+            .put(NetworkTypeVxlan.class,"vxlan")
+            .build();
+
+    NeutronNetworkInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    // IfNBNetworkCRUD methods
+
+    @Override
+    public boolean networkExists(String uuid) {
+        Network network = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (network == null) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public NeutronNetwork getNetwork(String uuid) {
+        Network network = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (network == null) {
+            return null;
+        }
+        return fromMd(network);
+    }
+
+    @Override
+    public List<NeutronNetwork> getAllNetworks() {
+        Set<NeutronNetwork> allNetworks = new HashSet<NeutronNetwork>();
+        Networks networks = readMd(createInstanceIdentifier());
+        if (networks != null) {
+            for (Network network: networks.getNetwork()) {
+                allNetworks.add(fromMd(network));
+            }
+        }
+        LOGGER.debug("Exiting getAllNetworks, Found {} OpenStackNetworks", allNetworks.size());
+        List<NeutronNetwork> ans = new ArrayList<NeutronNetwork>();
+        ans.addAll(allNetworks);
+        return ans;
+    }
+
+    @Override
+    public boolean addNetwork(NeutronNetwork input) {
+        if (networkExists(input.getID())) {
+            return false;
+        }
+        addMd(input);
+        return true;
+    }
+
+    @Override
+    public boolean removeNetwork(String uuid) {
+        if (!networkExists(uuid)) {
+            return false;
+        }
+        return removeMd(toMd(uuid));
+    }
+
+    @Override
+    public boolean updateNetwork(String uuid, NeutronNetwork delta) {
+        if (!networkExists(uuid)) {
+            return false;
+        }
+/* note: because what we get is *not* a delta but (at this point) the updated
+ * object, this is much simpler - just replace the value and update the mdsal
+ * with it */
+        updateMd(delta);
+        return true;
+    }
+
+    @Override
+    public boolean networkInUse(String netUUID) {
+        if (!networkExists(netUUID)) {
+            return true;
+        }
+        return false;
+    }
+
+    protected NeutronNetwork fromMd(Network network) {
+        NeutronNetwork result = new NeutronNetwork();
+        result.setAdminStateUp(network.isAdminStateUp());
+        result.setNetworkName(network.getName());
+        result.setShared(network.isShared());
+        result.setStatus(network.getStatus());
+        if (network.getSubnets() != null) {
+            List<String> neutronSubnets = new ArrayList<String>();
+            for( Uuid subnet : network.getSubnets()) {
+               neutronSubnets.add(subnet.getValue());
+            }
+            result.setSubnets(neutronSubnets);
+        }
+// todo remove '-' chars as tenant id doesn't use them
+        result.setTenantID(network.getTenantId().getValue());
+        result.setID(network.getUuid().getValue());
+
+        NetworkL3Extension l3Extension = network.getAugmentation(NetworkL3Extension.class);
+        result.setRouterExternal(l3Extension.isExternal());
+
+        NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
+        result.setProviderPhysicalNetwork(providerExtension.getPhysicalNetwork());
+        result.setProviderSegmentationID(providerExtension.getSegmentationId());
+        result.setProviderNetworkType(NETWORK_MAP.get(providerExtension.getNetworkType()));
+        List<NeutronNetwork_Segment> segments = new ArrayList<NeutronNetwork_Segment>();
+        if (providerExtension.getSegments() != null) {
+            for (Segments segment: providerExtension.getSegments()) {
+                NeutronNetwork_Segment neutronSegment = new NeutronNetwork_Segment();
+                neutronSegment.setProviderPhysicalNetwork(segment.getPhysicalNetwork());
+                neutronSegment.setProviderSegmentationID(segment.getSegmentationId());
+                neutronSegment.setProviderNetworkType(NETWORK_MAP.get(segment.getNetworkType()));
+                segments.add(neutronSegment);
+            }
+        }
+        result.setSegments(segments);
+        return result;
+    }
+
+    private void fillExtensions(NetworkBuilder networkBuilder,
+                                NeutronNetwork network) {
+        NetworkL3ExtensionBuilder l3ExtensionBuilder = new NetworkL3ExtensionBuilder();
+        if (network.getRouterExternal() != null) {
+            l3ExtensionBuilder.setExternal(network.getRouterExternal());
+        }
+
+        NetworkProviderExtensionBuilder providerExtensionBuilder = new NetworkProviderExtensionBuilder();
+        if (network.getProviderPhysicalNetwork() != null) {
+            providerExtensionBuilder.setPhysicalNetwork(network.getProviderPhysicalNetwork());
+        }
+        if (network.getProviderSegmentationID() != null) {
+            providerExtensionBuilder.setSegmentationId(network.getProviderSegmentationID());
+        }
+        if (network.getProviderNetworkType() != null) {
+            ImmutableBiMap<String, Class<? extends NetworkTypeBase>> mapper =
+                NETWORK_MAP.inverse();
+            providerExtensionBuilder.setNetworkType((Class<? extends NetworkTypeBase>) mapper.get(network.getProviderNetworkType()));
+        }
+        if (network.getSegments() != null) {
+            List<Segments> segments = new ArrayList<Segments>();
+            long count = 0;
+            for( NeutronNetwork_Segment segment : network.getSegments()) {
+                count++;
+                SegmentsBuilder segmentsBuilder = new SegmentsBuilder();
+                if (segment.getProviderPhysicalNetwork() != null) {
+                    segmentsBuilder.setPhysicalNetwork(segment.getProviderPhysicalNetwork());
+                }
+                if (segment.getProviderSegmentationID() != null) {
+                    segmentsBuilder.setSegmentationId(segment.getProviderSegmentationID());
+                }
+                if (segment.getProviderNetworkType() != null) {
+                    ImmutableBiMap<String, Class<? extends NetworkTypeBase>> mapper =
+                        NETWORK_MAP.inverse();
+                    segmentsBuilder.setNetworkType((Class<? extends NetworkTypeBase>) mapper.get(segment.getProviderNetworkType()));
+                }
+                segmentsBuilder.setSegmentationIndex(Long.valueOf(count));
+                segments.add(segmentsBuilder.build());
+            }
+            providerExtensionBuilder.setSegments(segments);
+        }
+        if (network.getProviderSegmentationID() != null) {
+            providerExtensionBuilder.setSegmentationId(network.getProviderSegmentationID());
+        }
+
+        networkBuilder.addAugmentation(NetworkL3Extension.class,
+                                       l3ExtensionBuilder.build());
+        networkBuilder.addAugmentation(NetworkProviderExtension.class,
+                                       providerExtensionBuilder.build());
+    }
+
+    protected Network toMd(NeutronNetwork network) {
+        NetworkBuilder networkBuilder = new NetworkBuilder();
+        fillExtensions(networkBuilder, network);
+
+        networkBuilder.setAdminStateUp(network.getAdminStateUp());
+        if (network.getNetworkName() != null) {
+            networkBuilder.setName(network.getNetworkName());
+        }
+        if (network.getShared() != null) {
+            networkBuilder.setShared(network.getShared());
+        }
+        if (network.getStatus() != null) {
+            networkBuilder.setStatus(network.getStatus());
+        }
+        if (network.getSubnets() != null) {
+            List<Uuid> subnets = new ArrayList<Uuid>();
+            for( String subnet : network.getSubnets()) {
+                subnets.add(toUuid(subnet));
+            }
+            networkBuilder.setSubnets(subnets);
+        }
+        if (network.getTenantID() != null) {
+            networkBuilder.setTenantId(toUuid(network.getTenantID()));
+        }
+        if (network.getNetworkUUID() != null) {
+            networkBuilder.setUuid(toUuid(network.getNetworkUUID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron network without UUID");
+        }
+        return networkBuilder.build();
+    }
+
+    protected Network toMd(String uuid) {
+        NetworkBuilder networkBuilder = new NetworkBuilder();
+        networkBuilder.setUuid(toUuid(uuid));
+        return networkBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<Network> createInstanceIdentifier(Network network) {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Networks.class)
+                .child(Network.class,network.getKey());
+    }
+
+    protected InstanceIdentifier<Networks> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Networks.class);
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronNetworkInterface neutronNetworkInterface = new NeutronNetworkInterface(providerContext);
+        ServiceRegistration<INeutronNetworkCRUD> neutronNetworkInterfaceRegistration = context.registerService(INeutronNetworkCRUD.class, neutronNetworkInterface, null);
+        if(neutronNetworkInterfaceRegistration != null) {
+            registrations.add(neutronNetworkInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronPortInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronPortInterface.java
new file mode 100644 (file)
index 0000000..c1ab927
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_AllowedAddressPairs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_ExtraDHCPOption;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_VIFDetail;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtensionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetails;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetailsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.AllowedAddressPairs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.AllowedAddressPairsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.ExtraDhcpOpts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.ExtraDhcpOptsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIpsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronPortInterface extends AbstractNeutronInterface<Port, NeutronPort> implements INeutronPortCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronPortInterface.class);
+
+    NeutronPortInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    // IfNBPortCRUD methods
+
+    @Override
+    public boolean portExists(String uuid) {
+        Port port = readMd(createInstanceIdentifier(toMd(uuid)));
+        return port != null;
+    }
+
+    @Override
+    public NeutronPort getPort(String uuid) {
+        Port port = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (port == null) {
+            return null;
+        }
+        return fromMd(port);
+    }
+
+    @Override
+    public List<NeutronPort> getAllPorts() {
+        Set<NeutronPort> allPorts = new HashSet<NeutronPort>();
+        Ports ports = readMd(createInstanceIdentifier());
+        if (ports != null) {
+            for (Port port : ports.getPort()) {
+                allPorts.add(fromMd(port));
+            }
+        }
+        LOGGER.debug("Exiting getAllPorts, Found {} OpenStackPorts", allPorts.size());
+        List<NeutronPort> ans = new ArrayList<NeutronPort>();
+        ans.addAll(allPorts);
+        return ans;
+    }
+
+    @Override
+    public boolean addPort(NeutronPort input) {
+        if (portExists(input.getID())) {
+            return false;
+        }
+        addMd(input);
+        return true;
+    }
+
+    @Override
+    public boolean removePort(String uuid) {
+        if (!portExists(uuid)) {
+            return false;
+        }
+        return removeMd(toMd(uuid));
+    }
+
+    @Override
+    public boolean updatePort(String uuid, NeutronPort delta) {
+        if (!portExists(uuid)) {
+            return false;
+        }
+        updateMd(delta);
+        return true;
+    }
+
+    // @deprecated, will be removed in Boron
+    @Override
+    public boolean macInUse(String macAddress) {
+        return false;
+    }
+
+    // @deprecated, will be removed in Boron
+    @Override
+    public NeutronPort getGatewayPort(String subnetUUID) {
+        return null;
+    }
+
+    @Override
+    protected InstanceIdentifier<Port> createInstanceIdentifier(Port port) {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Ports.class)
+                .child(Port.class, port.getKey());
+    }
+
+    protected InstanceIdentifier<Ports> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Ports.class);
+    }
+
+    protected void addExtensions(Port port, NeutronPort result) {
+        PortBindingExtension binding = port.getAugmentation(PortBindingExtension.class);
+        result.setBindinghostID(binding.getHostId());
+        if (binding.getVifDetails() != null) {
+            List<NeutronPort_VIFDetail> details = new ArrayList<NeutronPort_VIFDetail>();
+            for (VifDetails vifDetail : binding.getVifDetails()) {
+                NeutronPort_VIFDetail detail = new NeutronPort_VIFDetail();
+                detail.setPortFilter(vifDetail.isPortFilter());
+                detail.setOvsHybridPlug(vifDetail.isOvsHybridPlug());
+                details.add(detail);
+            }
+            result.setVIFDetail(details);
+        }
+        result.setBindingvifType(binding.getVifType());
+        result.setBindingvnicType(binding.getVnicType());
+    }
+
+    protected NeutronPort fromMd(Port port) {
+        NeutronPort result = new NeutronPort();
+        result.setAdminStateUp(port.isAdminStateUp());
+        if (port.getAllowedAddressPairs() != null) {
+            List<NeutronPort_AllowedAddressPairs> pairs = new ArrayList<NeutronPort_AllowedAddressPairs>();
+            for (AllowedAddressPairs mdPair : port.getAllowedAddressPairs()) {
+                NeutronPort_AllowedAddressPairs pair = new NeutronPort_AllowedAddressPairs();
+                pair.setIpAddress(mdPair.getIpAddress());
+                pair.setMacAddress(mdPair.getMacAddress());
+                pair.setPortID(mdPair.getPortId());
+                pairs.add(pair);
+            }
+            result.setAllowedAddressPairs(pairs);
+        }
+        result.setDeviceID(port.getDeviceId());
+        result.setDeviceOwner(port.getDeviceOwner());
+        if (port.getExtraDhcpOpts() != null) {
+            List<NeutronPort_ExtraDHCPOption> options = new ArrayList<NeutronPort_ExtraDHCPOption>();
+            for (ExtraDhcpOpts opt : port.getExtraDhcpOpts()) {
+                NeutronPort_ExtraDHCPOption arg = new NeutronPort_ExtraDHCPOption();
+                arg.setName(opt.getOptName());
+                arg.setValue(opt.getOptValue());
+                options.add(arg);
+            }
+            result.setExtraDHCPOptions(options);
+        }
+        if (port.getFixedIps() != null) {
+            List<Neutron_IPs> ips = new ArrayList<Neutron_IPs>();
+            for (FixedIps mdIP : port.getFixedIps()) {
+                Neutron_IPs ip = new Neutron_IPs();
+                ip.setIpAddress(String.valueOf(mdIP.getIpAddress().getValue()));
+                ip.setSubnetUUID(mdIP.getSubnetId().getValue());
+                ips.add(ip);
+            }
+            result.setFixedIPs(ips);
+        }
+        result.setMacAddress(port.getMacAddress());
+        result.setName(port.getName());
+        result.setNetworkUUID(String.valueOf(port.getNetworkId().getValue()));
+        if (port.getSecurityGroups() != null) {
+            Set<NeutronSecurityGroup> allGroups = new HashSet<NeutronSecurityGroup>();
+            NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces().fetchINeutronSecurityGroupCRUD(this);
+            INeutronSecurityGroupCRUD sgIf = interfaces.getSecurityGroupInterface();
+            for (Uuid sgUuid : port.getSecurityGroups()) {
+                allGroups.add(sgIf.getNeutronSecurityGroup(sgUuid.getValue()));
+            }
+            List<NeutronSecurityGroup> groups = new ArrayList<NeutronSecurityGroup>();
+            groups.addAll(allGroups);
+            result.setSecurityGroups(groups);
+        }
+        result.setStatus(port.getStatus());
+        if (port.getTenantId() != null) {
+            result.setTenantID(String.valueOf(port.getTenantId().getValue()).replace("-", ""));
+        }
+        result.setPortUUID(String.valueOf(port.getUuid().getValue()));
+        addExtensions(port, result);
+        return result;
+    }
+
+    @Override
+    protected Port toMd(NeutronPort neutronPort) {
+        PortBindingExtensionBuilder bindingBuilder = new PortBindingExtensionBuilder();
+        if (neutronPort.getBindinghostID() != null) {
+            bindingBuilder.setHostId(neutronPort.getBindinghostID());
+        }
+        if (neutronPort.getVIFDetail() != null) {
+            List<VifDetails> listVifDetail = new ArrayList<VifDetails>();
+            for (NeutronPort_VIFDetail detail: neutronPort.getVIFDetail()) {
+                VifDetailsBuilder vifDetailsBuilder = new VifDetailsBuilder();
+                if (detail.getPortFilter() != null) {
+                    vifDetailsBuilder.setPortFilter(detail.getPortFilter());
+                }
+                if (detail.getOvsHybridPlug() != null) {
+                    vifDetailsBuilder.setOvsHybridPlug(detail.getOvsHybridPlug());
+                }
+                listVifDetail.add(vifDetailsBuilder.build());
+            }
+            bindingBuilder.setVifDetails(listVifDetail);
+        }
+        if (neutronPort.getBindingvifType() != null) {
+            bindingBuilder.setVifType(neutronPort.getBindingvifType());
+        }
+        if (neutronPort.getBindingvnicType() != null) {
+            bindingBuilder.setVnicType(neutronPort.getBindingvnicType());
+        }
+
+        PortBuilder portBuilder = new PortBuilder();
+        portBuilder.addAugmentation(PortBindingExtension.class,
+                                    bindingBuilder.build());
+        portBuilder.setAdminStateUp(neutronPort.isAdminStateUp());
+        if(neutronPort.getAllowedAddressPairs() != null) {
+            List<AllowedAddressPairs> listAllowedAddressPairs = new ArrayList<AllowedAddressPairs>();
+            for (NeutronPort_AllowedAddressPairs allowedAddressPairs : neutronPort.getAllowedAddressPairs()) {
+                    AllowedAddressPairsBuilder allowedAddressPairsBuilder = new AllowedAddressPairsBuilder();
+                    allowedAddressPairsBuilder.setIpAddress(allowedAddressPairs.getIpAddress());
+                    allowedAddressPairsBuilder.setMacAddress(allowedAddressPairs.getMacAddress());
+                    allowedAddressPairsBuilder.setPortId(allowedAddressPairs.getPortID());
+                    listAllowedAddressPairs.add(allowedAddressPairsBuilder.build());
+            }
+            portBuilder.setAllowedAddressPairs(listAllowedAddressPairs);
+        }
+        if (neutronPort.getDeviceID() != null) {
+            portBuilder.setDeviceId(neutronPort.getDeviceID());
+        }
+        if (neutronPort.getDeviceOwner() != null) {
+        portBuilder.setDeviceOwner(neutronPort.getDeviceOwner());
+        }
+        if (neutronPort.getExtraDHCPOptions() != null) {
+            List<ExtraDhcpOpts> listExtraDHCPOptions = new ArrayList<ExtraDhcpOpts>();
+            for (NeutronPort_ExtraDHCPOption extraDHCPOption : neutronPort.getExtraDHCPOptions()) {
+                ExtraDhcpOptsBuilder extraDHCPOptsBuilder = new ExtraDhcpOptsBuilder();
+                extraDHCPOptsBuilder.setOptName(extraDHCPOption.getName());
+                extraDHCPOptsBuilder.setOptValue(extraDHCPOption.getValue());
+                listExtraDHCPOptions.add(extraDHCPOptsBuilder.build());
+            }
+            portBuilder.setExtraDhcpOpts(listExtraDHCPOptions);
+        }
+        if (neutronPort.getFixedIPs() != null) {
+            List<FixedIps> listNeutronIPs = new ArrayList<FixedIps>();
+            for (Neutron_IPs neutron_IPs : neutronPort.getFixedIPs()) {
+                FixedIpsBuilder fixedIpsBuilder = new FixedIpsBuilder();
+                fixedIpsBuilder.setIpAddress(new IpAddress(neutron_IPs.getIpAddress().toCharArray()));
+                fixedIpsBuilder.setSubnetId(toUuid(neutron_IPs.getSubnetUUID()));
+                listNeutronIPs.add(fixedIpsBuilder.build());
+            }
+            portBuilder.setFixedIps(listNeutronIPs);
+        }
+        if (neutronPort.getMacAddress() != null) {
+            portBuilder.setMacAddress(neutronPort.getMacAddress());
+        }
+        if (neutronPort.getName() != null) {
+        portBuilder.setName(neutronPort.getName());
+        }
+        if (neutronPort.getNetworkUUID() != null) {
+        portBuilder.setNetworkId(toUuid(neutronPort.getNetworkUUID()));
+        }
+        if (neutronPort.getSecurityGroups() != null) {
+            List<Uuid> listSecurityGroups = new ArrayList<Uuid>();
+            for (NeutronSecurityGroup neutronSecurityGroup : neutronPort.getSecurityGroups()) {
+                listSecurityGroups.add(toUuid(neutronSecurityGroup.getID()));
+            }
+            portBuilder.setSecurityGroups(listSecurityGroups);
+        }
+        if (neutronPort.getStatus() != null) {
+            portBuilder.setStatus(neutronPort.getStatus());
+        }
+        if (neutronPort.getTenantID() != null) {
+            portBuilder.setTenantId(toUuid(neutronPort.getTenantID()));
+        }
+        if (neutronPort.getPortUUID() != null) {
+            portBuilder.setUuid(toUuid(neutronPort.getPortUUID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron port without UUID");
+        }
+        return portBuilder.build();
+    }
+
+    @Override
+    protected Port toMd(String uuid) {
+        PortBuilder portBuilder = new PortBuilder();
+        portBuilder.setUuid(toUuid(uuid));
+        return portBuilder.build();
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronPortInterface neutronPortInterface = new NeutronPortInterface(providerContext);
+        ServiceRegistration<INeutronPortCRUD> neutronPortInterfaceRegistration = context.registerService(INeutronPortCRUD.class, neutronPortInterface, null);
+        if(neutronPortInterfaceRegistration != null) {
+            registrations.add(neutronPortInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronRouterInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronRouterInterface.java
new file mode 100644 (file)
index 0000000..a1ab293
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_NetworkReference;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronRouterCRUD;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.RouterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.ExternalGatewayInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.ExternalGatewayInfoBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.external_gateway_info.ExternalFixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.external_gateway_info.ExternalFixedIpsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronRouterInterface extends  AbstractNeutronInterface<Router, NeutronRouter> implements INeutronRouterCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronRouterInterface.class);
+    // methods needed for creating caches
+
+
+    NeutronRouterInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+
+    // IfNBRouterCRUD Interface methods
+
+    @Override
+    public boolean routerExists(String uuid) {
+        Router router = readMd(createInstanceIdentifier(toMd(uuid)));
+        return router != null;
+    }
+
+    @Override
+    public NeutronRouter getRouter(String uuid) {
+        Router router = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (router == null) {
+            return null;
+        }
+        return fromMd(router);
+    }
+
+    @Override
+    public List<NeutronRouter> getAllRouters() {
+        Set<NeutronRouter> allRouters = new HashSet<NeutronRouter>();
+        Routers routers = readMd(createInstanceIdentifier());
+        if (routers != null) {
+            for (Router router: routers.getRouter()) {
+                allRouters.add(fromMd(router));
+            }
+        }
+        LOGGER.debug("Exiting getAllRouters, Found {} Routers", allRouters.size());
+        List<NeutronRouter> ans = new ArrayList<NeutronRouter>();
+        ans.addAll(allRouters);
+        return ans;
+    }
+
+    @Override
+    public boolean addRouter(NeutronRouter input) {
+        if (routerExists(input.getID())) {
+            return false;
+        }
+        addMd(input);
+        return true;
+    }
+
+    @Override
+    public boolean removeRouter(String uuid) {
+        if (!routerExists(uuid)) {
+            return false;
+        }
+        return removeMd(toMd(uuid));
+    }
+
+    @Override
+    public boolean updateRouter(String uuid, NeutronRouter delta) {
+        if (!routerExists(uuid)) {
+            return false;
+        }
+        updateMd(delta);
+        return true;
+    }
+
+    @Override
+    public boolean routerInUse(String routerUUID) {
+        if (!routerExists(routerUUID)) {
+            return true;
+        }
+        NeutronRouter target = getRouter(routerUUID);
+        return (target.getInterfaces().size() > 0);
+    }
+
+    @Override
+    protected Router toMd(NeutronRouter router) {
+
+        RouterBuilder routerBuilder = new RouterBuilder();
+
+        if (router.getRouterUUID() != null) {
+            routerBuilder.setUuid(toUuid(router.getRouterUUID()));
+        }
+        if (router.getName() != null) {
+            routerBuilder.setName(router.getName());
+        }
+        if (router.getTenantID() != null && !router.getTenantID().isEmpty()) {
+            routerBuilder.setTenantId(toUuid(router.getTenantID()));
+        }
+        if (router.getStatus() != null) {
+            routerBuilder.setStatus(router.getStatus());
+        }
+        if (router.getGatewayPortId() != null && !router.getGatewayPortId().isEmpty()) {
+            routerBuilder.setGatewayPortId(toUuid(router.getGatewayPortId()));
+        }
+        routerBuilder.setAdminStateUp(router.getAdminStateUp());
+        routerBuilder.setDistributed(router.getDistributed());
+        if (router.getRoutes() != null) {
+            List<String> routes = new ArrayList<String>();
+            for (String route : router.getRoutes()) {
+                routes.add(route);
+            }
+            routerBuilder.setRoutes(routes);
+        }
+        if (router.getExternalGatewayInfo() != null) {
+            ExternalGatewayInfo externalGatewayInfo = null;
+            List<NeutronRouter_NetworkReference> neutronRouter_NetworkReferences = new ArrayList<NeutronRouter_NetworkReference>();
+            neutronRouter_NetworkReferences.add(router.getExternalGatewayInfo());
+            for (NeutronRouter_NetworkReference externalGatewayInfos : neutronRouter_NetworkReferences) {
+                ExternalGatewayInfoBuilder builder = new ExternalGatewayInfoBuilder();
+                builder.setEnableSnat(externalGatewayInfos.getEnableSNAT());
+                builder.setExternalNetworkId(toUuid(externalGatewayInfos.getNetworkID()));
+                if (externalGatewayInfos.getExternalFixedIPs() != null) {
+                    List<ExternalFixedIps> externalFixedIps = new ArrayList<ExternalFixedIps>();
+                    for (Neutron_IPs eIP : externalGatewayInfos.getExternalFixedIPs()) {
+                        ExternalFixedIpsBuilder eFixedIpBuilder = new ExternalFixedIpsBuilder();
+                        eFixedIpBuilder.setIpAddress(new IpAddress(eIP.getIpAddress().toCharArray()));
+                        eFixedIpBuilder.setSubnetId(toUuid(eIP.getSubnetUUID()));
+                        externalFixedIps.add(eFixedIpBuilder.build());
+                    }
+                    builder.setExternalFixedIps(externalFixedIps);
+                }
+                externalGatewayInfo = builder.build();
+            }
+            routerBuilder.setExternalGatewayInfo(externalGatewayInfo);
+        }
+        if (router.getInterfaces() != null) {
+            Map<String, NeutronRouter_Interface> mapInterfaces = new HashMap<String, NeutronRouter_Interface>();
+            List<Interfaces> interfaces = new ArrayList<Interfaces>();
+            for (Entry<String, NeutronRouter_Interface> entry : mapInterfaces.entrySet()) {
+                interfaces.add((Interfaces) entry.getValue());
+            }
+            routerBuilder.setInterfaces(interfaces);
+        }
+        if (router.getID() != null) {
+            routerBuilder.setUuid(toUuid(router.getID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron router without UUID");
+        }
+        return routerBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<Router> createInstanceIdentifier(Router router) {
+        return InstanceIdentifier.create(Neutron.class)
+                 .child(Routers.class)
+                 .child(Router.class, router.getKey());
+    }
+
+    protected InstanceIdentifier<Routers> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class).child(Routers.class);
+    }
+
+    @Override
+    protected Router toMd(String uuid) {
+        RouterBuilder routerBuilder = new RouterBuilder();
+        routerBuilder.setUuid(toUuid(uuid));
+        return routerBuilder.build();
+    }
+
+    public NeutronRouter fromMd(Router router) {
+        NeutronRouter result = new NeutronRouter();
+        result.setID(String.valueOf(router.getUuid().getValue()));
+        result.setName(router.getName());
+        result.setTenantID(String.valueOf(router.getTenantId().getValue()));
+        result.setAdminStateUp(router.isAdminStateUp());
+        result.setStatus(router.getStatus());
+        result.setDistributed(router.isDistributed());
+        if (router.getGatewayPortId() != null) {
+            result.setGatewayPortId(String.valueOf(router.getGatewayPortId().getValue()));
+        }
+        if (router.getRoutes() != null) {
+            List<String> routes = new ArrayList<String>();
+            for (String route : router.getRoutes()) {
+                routes.add(route);
+            }
+            result.setRoutes(routes);
+        }
+
+        if (router.getExternalGatewayInfo() != null) {
+            NeutronRouter_NetworkReference extGwInfo = new NeutronRouter_NetworkReference();
+            extGwInfo.setNetworkID(String.valueOf(router.getExternalGatewayInfo().getExternalNetworkId().getValue()));
+            extGwInfo.setEnableSNAT(router.getExternalGatewayInfo().isEnableSnat());
+            if (router.getExternalGatewayInfo().getExternalFixedIps() != null) {
+                List<Neutron_IPs> fixedIPs = new ArrayList<Neutron_IPs>();
+                for (ExternalFixedIps mdFixedIP : router.getExternalGatewayInfo().getExternalFixedIps()) {
+                     Neutron_IPs fixedIP = new Neutron_IPs();
+                     fixedIP.setSubnetUUID(String.valueOf(mdFixedIP.getSubnetId().getValue()));
+                     fixedIP.setIpAddress(String.valueOf(mdFixedIP.getIpAddress().getValue()));
+                     fixedIPs.add(fixedIP);
+                }
+                extGwInfo.setExternalFixedIPs(fixedIPs);
+            }
+            result.setExternalGatewayInfo(extGwInfo);
+        }
+
+        if (router.getInterfaces() != null) {
+            Map<String, NeutronRouter_Interface> interfaces = new HashMap<String, NeutronRouter_Interface>();
+            for (Interfaces mdInterface : router.getInterfaces()) {
+                NeutronRouter_Interface pojoInterface = new NeutronRouter_Interface();
+                String id = String.valueOf(mdInterface.getUuid().getValue());
+                pojoInterface.setID(id);
+                pojoInterface.setTenantID(String.valueOf(mdInterface.getTenantId().getValue()));
+                pojoInterface.setSubnetUUID(String.valueOf(mdInterface.getSubnetId().getValue()));
+                pojoInterface.setPortUUID(String.valueOf(mdInterface.getPortId().getValue()));
+                interfaces.put(id, pojoInterface);
+            }
+            result.setInterfaces(interfaces);
+        }
+        return result;
+    }
+    
+    public static void registerNewInterface(BundleContext context,
+            ProviderContext providerContext,
+            List<ServiceRegistration<?>> registrations) {
+       NeutronRouterInterface neutronRouterInterface = new NeutronRouterInterface(providerContext);
+       ServiceRegistration<INeutronRouterCRUD> neutronRouterInterfaceRegistration = context.registerService(INeutronRouterCRUD.class, neutronRouterInterface, null);
+       if(neutronRouterInterfaceRegistration != null) {
+               registrations.add(neutronRouterInterfaceRegistration);
+       }
+       }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronSecurityGroupInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronSecurityGroupInterface.java
new file mode 100644 (file)
index 0000000..c30dd5c
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityRuleCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.SecurityGroups;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroupBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class NeutronSecurityGroupInterface extends AbstractNeutronInterface<SecurityGroup,NeutronSecurityGroup> implements INeutronSecurityGroupCRUD {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronSecurityGroupInterface.class);
+
+    NeutronSecurityGroupInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    @Override
+    public boolean neutronSecurityGroupExists(String uuid) {
+        SecurityGroup group = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (group == null) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public NeutronSecurityGroup getNeutronSecurityGroup(String uuid) {
+        SecurityGroup group = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (group == null) {
+            return null;
+        }
+        return fromMd(group);
+    }
+
+    @Override
+    public List<NeutronSecurityGroup> getAllNeutronSecurityGroups() {
+        Set<NeutronSecurityGroup> allSecurityGroups = new HashSet<NeutronSecurityGroup>();
+        SecurityGroups groups = readMd(createInstanceIdentifier());
+        if (groups != null) {
+            for (SecurityGroup group: groups.getSecurityGroup()) {
+                allSecurityGroups.add(fromMd(group));
+            }
+        }
+        LOGGER.debug("Exiting getSecurityGroups, Found {} OpenStackSecurityGroup", allSecurityGroups.size());
+        List<NeutronSecurityGroup> ans = new ArrayList<NeutronSecurityGroup>();
+        ans.addAll(allSecurityGroups);
+        return ans;
+    }
+
+    @Override
+    public boolean addNeutronSecurityGroup(NeutronSecurityGroup input) {
+        if (neutronSecurityGroupExists(input.getID())) {
+            return false;
+        }
+        addMd(input);
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronSecurityGroup(String uuid) {
+        if (!neutronSecurityGroupExists(uuid)) {
+            return false;
+        }
+        removeMd(toMd(uuid));
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronSecurityGroup(String uuid, NeutronSecurityGroup delta) {
+        if (!neutronSecurityGroupExists(uuid)) {
+            return false;
+        }
+        updateMd(delta);
+        return true;
+    }
+
+    @Override
+    public boolean neutronSecurityGroupInUse(String securityGroupUUID) {
+        return !neutronSecurityGroupExists(securityGroupUUID);
+    }
+
+    protected NeutronSecurityGroup fromMd(SecurityGroup group) {
+        NeutronSecurityGroup answer = new NeutronSecurityGroup();
+        if (group.getName() != null) {
+            answer.setSecurityGroupName(group.getName());
+        }
+        if (group.getDescription() != null) {
+            answer.setSecurityGroupDescription(group.getDescription());
+        }
+        if (group.getTenantId() != null) {
+            answer.setSecurityGroupTenantID(group.getTenantId().getValue().replace("-",""));
+        }
+        if (group.getSecurityRules() != null) {
+            NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+                .fetchINeutronSecurityRuleCRUD(this);
+            INeutronSecurityRuleCRUD srCrud = interfaces.getSecurityRuleInterface();
+
+            List<NeutronSecurityRule> rules = new ArrayList<NeutronSecurityRule>();
+            for (Uuid uuid: group.getSecurityRules()) {
+                 rules.add(srCrud.getNeutronSecurityRule(uuid.getValue()));
+            }
+            answer.setSecurityRules(rules);
+        }
+        if (group.getUuid() != null) {
+            answer.setID(group.getUuid().getValue());
+        }
+        return answer;
+    }
+
+    @Override
+    protected SecurityGroup toMd(NeutronSecurityGroup securityGroup) {
+        SecurityGroupBuilder securityGroupBuilder = new SecurityGroupBuilder();
+        if (securityGroup.getSecurityGroupName() != null) {
+            securityGroupBuilder.setName(securityGroup.getSecurityGroupName());
+        }
+        if (securityGroup.getSecurityGroupDescription() != null) {
+            securityGroupBuilder.setDescription(securityGroup.getSecurityGroupDescription());
+        }
+        if (securityGroup.getSecurityGroupTenantID() != null) {
+            securityGroupBuilder.setTenantId(toUuid(securityGroup.getSecurityGroupTenantID()));
+        }
+        if (securityGroup.getSecurityRules() != null) {
+            List<Uuid> neutronSecurityRule = new ArrayList<Uuid>();
+            for (NeutronSecurityRule securityRule : securityGroup.getSecurityRules()) {
+                if (securityRule.getID() != null) {
+                    neutronSecurityRule.add(toUuid(securityRule.getID()));
+                }
+            }
+            securityGroupBuilder.setSecurityRules(neutronSecurityRule);
+        }
+        if (securityGroup.getID() != null) {
+            securityGroupBuilder.setUuid(toUuid(securityGroup.getID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron securityGroup without UUID");
+        }
+
+        return securityGroupBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<SecurityGroup> createInstanceIdentifier(SecurityGroup securityGroup) {
+        return InstanceIdentifier.create(Neutron.class)
+            .child(SecurityGroups.class).child(SecurityGroup.class,
+                                               securityGroup.getKey());
+    }
+
+    protected InstanceIdentifier<SecurityGroups> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+            .child(SecurityGroups.class);
+    }
+
+    @Override
+    protected SecurityGroup toMd(String uuid) {
+        SecurityGroupBuilder securityGroupBuilder = new SecurityGroupBuilder();
+        securityGroupBuilder.setUuid(toUuid(uuid));
+        return securityGroupBuilder.build();
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronSecurityGroupInterface neutronSecurityGroupInterface = new NeutronSecurityGroupInterface(providerContext);
+        ServiceRegistration<INeutronSecurityGroupCRUD> neutronSecurityGroupInterfaceRegistration = context.registerService(INeutronSecurityGroupCRUD.class, neutronSecurityGroupInterface, null);
+        if(neutronSecurityGroupInterfaceRegistration != null) {
+            registrations.add(neutronSecurityGroupInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronSecurityRuleInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronSecurityRuleInterface.java
new file mode 100644 (file)
index 0000000..cfcc9cd
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2014, 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityRuleCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmpV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolUdp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRuleBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+
+public class NeutronSecurityRuleInterface extends AbstractNeutronInterface<SecurityRule, NeutronSecurityRule> implements INeutronSecurityRuleCRUD {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronSecurityRuleInterface.class);
+
+    private static final ImmutableBiMap<Class<? extends DirectionBase>,String> DIRECTION_MAP
+    = new ImmutableBiMap.Builder<Class<? extends DirectionBase>,String>()
+    .put(DirectionEgress.class,"egress")
+    .put(DirectionIngress.class,"ingress")
+    .build();
+    private static final ImmutableBiMap<Class<? extends ProtocolBase>,String> PROTOCOL_MAP
+    = new ImmutableBiMap.Builder<Class<? extends ProtocolBase>,String>()
+    .put(ProtocolIcmp.class,"icmp")
+    .put(ProtocolTcp.class,"tcp")
+    .put(ProtocolUdp.class,"udp")
+    .put(ProtocolIcmpV6.class,"icmpv6")
+    .build();
+    private static final ImmutableBiMap<Class<? extends EthertypeBase>,String> ETHERTYPE_MAP
+    = new ImmutableBiMap.Builder<Class<? extends EthertypeBase>,String>()
+    .put(EthertypeV4.class,"IPv4")
+    .put(EthertypeV6.class,"IPv6")
+    .build();
+
+    NeutronSecurityRuleInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    private void updateSecGroupRuleInSecurityGroup(NeutronSecurityRule input) {
+        NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+            .fetchINeutronSecurityGroupCRUD(this);
+        INeutronSecurityGroupCRUD sgCrud = interfaces.getSecurityGroupInterface();
+        NeutronSecurityGroup sg = sgCrud.getNeutronSecurityGroup(input.getSecurityRuleGroupID());
+        if(sg != null && sg.getSecurityRules() != null) {
+            for(NeutronSecurityRule sgr :sg.getSecurityRules()) {
+                if(sgr != null && sgr.getID() != null && sgr.getID().equals(input.getID())) {
+                    int index = sg.getSecurityRules().indexOf(sgr);
+                    sg.getSecurityRules().set(index, input);
+                }
+            }
+        }
+        if (sg != null) {
+            sg.getSecurityRules().add(input);
+        }
+    }
+
+    private void removeSecGroupRuleFromSecurityGroup(NeutronSecurityRule input) {
+        NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+            .fetchINeutronSecurityGroupCRUD(this);
+        INeutronSecurityGroupCRUD sgCrud = interfaces.getSecurityGroupInterface();
+        NeutronSecurityGroup sg = sgCrud.getNeutronSecurityGroup(input.getSecurityRuleGroupID());
+        if(sg != null && sg.getSecurityRules() != null) {
+            List<NeutronSecurityRule> toRemove = new ArrayList<NeutronSecurityRule>();
+            for(NeutronSecurityRule sgr :sg.getSecurityRules()) {
+                if(sgr.getID() != null && sgr.getID().equals(input.getID())) {
+                    toRemove.add(sgr);
+                }
+            }
+            sg.getSecurityRules().removeAll(toRemove);
+        }
+    }
+
+    @Override
+    public boolean neutronSecurityRuleExists(String uuid) {
+        SecurityRule rule = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (rule == null) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public NeutronSecurityRule getNeutronSecurityRule(String uuid) {
+        SecurityRule rule = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (rule == null) {
+            return null;
+        }
+        return fromMd(rule);
+    }
+
+    @Override
+    public List<NeutronSecurityRule> getAllNeutronSecurityRules() {
+        Set<NeutronSecurityRule> allSecurityRules = new HashSet<NeutronSecurityRule>();
+        SecurityRules rules = readMd(createInstanceIdentifier());
+        if (rules != null) {
+            for (SecurityRule rule: rules.getSecurityRule()) {
+                allSecurityRules.add(fromMd(rule));
+            }
+        }
+        LOGGER.debug("Exiting getSecurityRule, Found {} OpenStackSecurityRule", allSecurityRules.size());
+        List<NeutronSecurityRule> ans = new ArrayList<NeutronSecurityRule>();
+        ans.addAll(allSecurityRules);
+        return ans;
+    }
+
+    @Override
+    public boolean addNeutronSecurityRule(NeutronSecurityRule input) {
+        if (neutronSecurityRuleExists(input.getID())) {
+            return false;
+        }
+        updateSecGroupRuleInSecurityGroup(input);
+        addMd(input);
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronSecurityRule(String uuid) {
+        if (!neutronSecurityRuleExists(uuid)) {
+            return false;
+        }
+        removeSecGroupRuleFromSecurityGroup(getNeutronSecurityRule(uuid));
+        removeMd(toMd(uuid));
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronSecurityRule(String uuid, NeutronSecurityRule delta) {
+        if (!neutronSecurityRuleExists(uuid)) {
+            return false;
+        }
+        updateSecGroupRuleInSecurityGroup(delta);
+        updateMd(delta);
+        return true;
+    }
+
+    @Override
+    public boolean neutronSecurityRuleInUse(String securityRuleUUID) {
+        return !neutronSecurityRuleExists(securityRuleUUID);
+    }
+
+    protected NeutronSecurityRule fromMd(SecurityRule rule) {
+        NeutronSecurityRule answer = new NeutronSecurityRule();
+        if (rule.getTenantId() != null) {
+            answer.setSecurityRuleTenantID(rule.getTenantId().getValue().replace("-",""));
+        }
+        if (rule.getDirection() != null) {
+            answer.setSecurityRuleDirection(DIRECTION_MAP.get(rule.getDirection()));
+        }
+        if (rule.getSecurityGroupId() != null) {
+            answer.setSecurityRuleGroupID(rule.getSecurityGroupId().getValue());
+        }
+        if (rule.getRemoteGroupId() != null) {
+            answer.setSecurityRemoteGroupID(rule.getRemoteGroupId().getValue());
+        }
+        if (rule.getRemoteIpPrefix() != null) {
+            answer.setSecurityRuleRemoteIpPrefix(rule.getRemoteIpPrefix().getIpv4Prefix() != null?
+                    rule.getRemoteIpPrefix().getIpv4Prefix().getValue():rule.getRemoteIpPrefix().getIpv6Prefix().getValue());
+        }
+        if (rule.getProtocol() != null) {
+            answer.setSecurityRuleProtocol(PROTOCOL_MAP.get(rule.getProtocol()));
+        }
+        if (rule.getEthertype() != null) {
+            answer.setSecurityRuleEthertype(ETHERTYPE_MAP.get(rule.getEthertype()));
+        }
+        if (rule.getPortRangeMin() != null) {
+            answer.setSecurityRulePortMin(Integer.valueOf(rule.getPortRangeMin()));
+        }
+        if (rule.getPortRangeMax() != null) {
+            answer.setSecurityRulePortMax(Integer.valueOf(rule.getPortRangeMax()));
+        }
+        if (rule.getId() != null) {
+            answer.setID(rule.getId().getValue());
+        }
+        return answer;
+    }
+
+    @Override
+    protected SecurityRule toMd(NeutronSecurityRule securityRule) {
+        SecurityRuleBuilder securityRuleBuilder = new SecurityRuleBuilder();
+
+        if (securityRule.getSecurityRuleTenantID() != null) {
+            securityRuleBuilder.setTenantId(toUuid(securityRule.getSecurityRuleTenantID()));
+        }
+        if (securityRule.getSecurityRuleDirection() != null) {
+            ImmutableBiMap<String, Class<? extends DirectionBase>> mapper =
+                    DIRECTION_MAP.inverse();
+            securityRuleBuilder.setDirection((Class<? extends DirectionBase>) mapper.get(securityRule.getSecurityRuleDirection()));
+        }
+        if (securityRule.getSecurityRuleGroupID() != null) {
+            securityRuleBuilder.setSecurityGroupId(toUuid(securityRule.getSecurityRuleGroupID()));
+        }
+        if (securityRule.getSecurityRemoteGroupID() != null) {
+            securityRuleBuilder.setRemoteGroupId(toUuid(securityRule.getSecurityRemoteGroupID()));
+        }
+        if (securityRule.getSecurityRuleRemoteIpPrefix() != null) {
+            securityRuleBuilder.setRemoteIpPrefix(new IpPrefix(securityRule.getSecurityRuleRemoteIpPrefix().toCharArray()));
+        }
+        if (securityRule.getSecurityRuleProtocol() != null) {
+            ImmutableBiMap<String, Class<? extends ProtocolBase>> mapper =
+                    PROTOCOL_MAP.inverse();
+            securityRuleBuilder.setProtocol((Class<? extends ProtocolBase>) mapper.get(securityRule.getSecurityRuleProtocol()));
+        }
+        if (securityRule.getSecurityRuleEthertype() != null) {
+            ImmutableBiMap<String, Class<? extends EthertypeBase>> mapper =
+                    ETHERTYPE_MAP.inverse();
+            securityRuleBuilder.setEthertype((Class<? extends EthertypeBase>) mapper.get(securityRule.getSecurityRuleEthertype()));
+        }
+        if (securityRule.getSecurityRulePortMin() != null) {
+            securityRuleBuilder.setPortRangeMin(Integer.valueOf(securityRule.getSecurityRulePortMin()));
+        }
+        if (securityRule.getSecurityRulePortMax() != null) {
+            securityRuleBuilder.setPortRangeMax(Integer.valueOf(securityRule.getSecurityRulePortMax()));
+        }
+        if (securityRule.getID() != null) {
+            securityRuleBuilder.setId(toUuid(securityRule.getID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron securityRule without UUID");
+        }
+        return securityRuleBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<SecurityRule> createInstanceIdentifier(SecurityRule securityRule) {
+        return InstanceIdentifier.create(Neutron.class)
+            .child(SecurityRules.class).child(SecurityRule.class,
+                                              securityRule.getKey());
+    }
+
+    protected InstanceIdentifier<SecurityRules> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+            .child(SecurityRules.class);
+    }
+
+    @Override
+    protected SecurityRule toMd(String uuid) {
+        SecurityRuleBuilder securityRuleBuilder = new SecurityRuleBuilder();
+        securityRuleBuilder.setId(toUuid(uuid));
+        return securityRuleBuilder.build();
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronSecurityRuleInterface neutronSecurityRuleInterface = new NeutronSecurityRuleInterface(providerContext);
+        ServiceRegistration<INeutronSecurityRuleCRUD> neutronSecurityRuleInterfaceRegistration = context.registerService(INeutronSecurityRuleCRUD.class, neutronSecurityRuleInterface, null);
+        if(neutronSecurityRuleInterfaceRegistration != null) {
+            registrations.add(neutronSecurityRuleInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronSubnetInterface.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/crud/impl/NeutronSubnetInterface.java
new file mode 100644 (file)
index 0000000..fd22808
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.crud.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnetIPAllocationPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Base;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Off;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Slaac;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Stateful;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Stateless;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.AllocationPools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.AllocationPoolsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronSubnetInterface extends AbstractNeutronInterface<Subnet, NeutronSubnet> implements INeutronSubnetCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronSubnetInterface.class);
+
+    private static final ImmutableBiMap<Class<? extends IpVersionBase>,Integer> IPV_MAP
+            = new ImmutableBiMap.Builder<Class<? extends IpVersionBase>,Integer>()
+            .put(IpVersionV4.class,Integer.valueOf(4))
+            .put(IpVersionV6.class,Integer.valueOf(6))
+            .build();
+
+    private static final ImmutableBiMap<Class<? extends Dhcpv6Base>,String> DHCPV6_MAP
+            = new ImmutableBiMap.Builder<Class<? extends Dhcpv6Base>,String>()
+            .put(Dhcpv6Off.class,"off")
+            .put(Dhcpv6Stateful.class,"dhcpv6-stateful")
+            .put(Dhcpv6Slaac.class,"slaac")
+            .put(Dhcpv6Stateless.class,"dhcpv6-stateless")
+            .build();
+
+    NeutronSubnetInterface(ProviderContext providerContext) {
+        super(providerContext);
+    }
+
+    // IfNBSubnetCRUD methods
+
+    @Override
+    public boolean subnetExists(String uuid) {
+        Subnet subnet = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (subnet == null) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public NeutronSubnet getSubnet(String uuid) {
+        Subnet subnet = readMd(createInstanceIdentifier(toMd(uuid)));
+        if (subnet == null) {
+            return null;
+        }
+        return fromMd(subnet);
+    }
+
+    @Override
+    public List<NeutronSubnet> getAllSubnets() {
+        Set<NeutronSubnet> allSubnets = new HashSet<NeutronSubnet>();
+        Subnets subnets = readMd(createInstanceIdentifier());
+        if (subnets != null) {
+            for (Subnet subnet: subnets.getSubnet()) {
+                allSubnets.add(fromMd(subnet));
+            }
+        }
+        LOGGER.debug("Exiting getAllSubnets, Found {} OpenStackSubnets", allSubnets.size());
+        List<NeutronSubnet> ans = new ArrayList<NeutronSubnet>();
+        ans.addAll(allSubnets);
+        return ans;
+    }
+
+    @Override
+    public boolean addSubnet(NeutronSubnet input) {
+        String id = input.getID();
+        if (subnetExists(id)) {
+            return false;
+        }
+        addMd(input);
+        NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+            .fetchINeutronNetworkCRUD(this);
+        INeutronNetworkCRUD networkIf = interfaces.getNetworkInterface();
+
+        NeutronNetwork targetNet = networkIf.getNetwork(input.getNetworkUUID());
+        targetNet.addSubnet(id);
+        return true;
+    }
+
+    @Override
+    public boolean removeSubnet(String uuid) {
+        NeutronSubnet target = getSubnet(uuid);
+        if (target == null) {
+            return false;
+        }
+        removeMd(toMd(uuid));
+        NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+            .fetchINeutronNetworkCRUD(this);
+        INeutronNetworkCRUD networkIf = interfaces.getNetworkInterface();
+
+        NeutronNetwork targetNet = networkIf.getNetwork(target.getNetworkUUID());
+        targetNet.removeSubnet(uuid);
+        return true;
+    }
+
+    @Override
+    public boolean updateSubnet(String uuid, NeutronSubnet delta) {
+        if (!subnetExists(uuid)) {
+            return false;
+        }
+/* note: because what we get is *not* a delta but (at this point) the updated
+ * object, this is much simpler - just replace the value and update the mdsal
+ * with it */
+        updateMd(delta);
+        return true;
+    }
+
+// note: this is being set to false in preparation for deprecation and removal
+    @Override
+    public boolean subnetInUse(String subnetUUID) {
+        return false;
+    }
+
+    protected NeutronSubnet fromMd(Subnet subnet) {
+        NeutronSubnet result = new NeutronSubnet();
+        result.setName(subnet.getName());
+        result.setTenantID(String.valueOf(subnet.getTenantId().getValue()).replace("-",""));
+        result.setNetworkUUID(subnet.getNetworkId().getValue());
+        result.setIpVersion(IPV_MAP.get(subnet.getIpVersion()));
+        result.setCidr(subnet.getCidr());
+        result.setGatewayIP(String.valueOf(subnet.getGatewayIp().getValue()));
+        result.setIpV6RaMode(DHCPV6_MAP.get(subnet.getIpv6RaMode()));
+        result.setIpV6AddressMode(DHCPV6_MAP.get(subnet.getIpv6AddressMode()));
+        result.setEnableDHCP(subnet.isEnableDhcp());
+        if (subnet.getAllocationPools() != null) {
+            List<NeutronSubnetIPAllocationPool> allocationPools = new ArrayList<NeutronSubnetIPAllocationPool>();
+            for (AllocationPools allocationPool : subnet.getAllocationPools()) {
+                NeutronSubnetIPAllocationPool pool = new NeutronSubnetIPAllocationPool();
+                pool.setPoolStart(allocationPool.getStart());
+                pool.setPoolEnd(allocationPool.getEnd());
+                allocationPools.add(pool);
+            }
+            result.setAllocationPools(allocationPools);
+        }
+        if (subnet.getDnsNameservers() != null) {
+            List<String> dnsNameServers = new ArrayList<String>();
+            for (IpAddress dnsNameServer : subnet.getDnsNameservers()) {
+                dnsNameServers.add(String.valueOf(dnsNameServer.getValue()));
+            }
+            result.setDnsNameservers(dnsNameServers);
+        }
+        result.setID(subnet.getUuid().getValue());
+// read through the ports and put the ones in this subnet into the internal
+// myPorts object.
+// @deprecated and will be removed in Boron
+        Set<NeutronPort> allPorts = new HashSet<NeutronPort>();
+        NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+            .fetchINeutronPortCRUD(this);
+        INeutronPortCRUD portIf = interfaces.getPortInterface();
+        for (NeutronPort port : portIf.getAllPorts()) {
+            if (port.getFixedIPs() != null) {
+                for (Neutron_IPs ip : port.getFixedIPs()) {
+                    if (ip.getSubnetUUID().equals(result.getID())) {
+                        allPorts.add(port);
+                    }
+                }
+            }
+        }
+        List<NeutronPort> ports = new ArrayList<NeutronPort>();
+        ports.addAll(allPorts);
+        result.setPorts(ports);
+        return result;
+    }
+
+    protected Subnet toMd(NeutronSubnet subnet) {
+        SubnetBuilder subnetBuilder = new SubnetBuilder();
+        if (subnet.getName() != null) {
+            subnetBuilder.setName(subnet.getName());
+        }
+        if (subnet.getTenantID() != null) {
+            subnetBuilder.setTenantId(toUuid(subnet.getTenantID()));
+        }
+        if (subnet.getNetworkUUID() != null) {
+            subnetBuilder.setNetworkId(toUuid(subnet.getNetworkUUID()));
+        }
+        if (subnet.getIpVersion() != null) {
+            ImmutableBiMap<Integer, Class<? extends IpVersionBase>> mapper =
+                    IPV_MAP.inverse();
+            subnetBuilder.setIpVersion((Class<? extends IpVersionBase>) mapper.get(subnet
+                    .getIpVersion()));
+        }
+        if (subnet.getCidr() != null) {
+            subnetBuilder.setCidr(subnet.getCidr());
+        }
+        if (subnet.getGatewayIP() != null) {
+            IpAddress ipAddress = new IpAddress(subnet.getGatewayIP()
+                    .toCharArray());
+            subnetBuilder.setGatewayIp(ipAddress);
+        }
+        if (subnet.getIpV6RaMode() != null) {
+            ImmutableBiMap<String, Class<? extends Dhcpv6Base>> mapper =
+                    DHCPV6_MAP.inverse();
+            subnetBuilder.setIpv6RaMode((Class<? extends Dhcpv6Base>) mapper.get(subnet.getIpV6RaMode()));
+        }
+        if (subnet.getIpV6AddressMode() != null) {
+            ImmutableBiMap<String, Class<? extends Dhcpv6Base>> mapper =
+                    DHCPV6_MAP.inverse();
+            subnetBuilder.setIpv6AddressMode((Class<? extends Dhcpv6Base>) mapper.get(subnet.getIpV6AddressMode()));
+        }
+        subnetBuilder.setEnableDhcp(subnet.getEnableDHCP());
+        if (subnet.getAllocationPools() != null) {
+            List<AllocationPools> allocationPools = new ArrayList<AllocationPools>();
+            for (NeutronSubnetIPAllocationPool allocationPool : subnet
+                    .getAllocationPools()) {
+                AllocationPoolsBuilder builder = new AllocationPoolsBuilder();
+                builder.setStart(allocationPool.getPoolStart());
+                builder.setEnd(allocationPool.getPoolEnd());
+                AllocationPools temp = builder.build();
+                allocationPools.add(temp);
+            }
+            subnetBuilder.setAllocationPools(allocationPools);
+        }
+        if (subnet.getDnsNameservers() != null) {
+            List<IpAddress> dnsNameServers = new ArrayList<IpAddress>();
+            for (String dnsNameServer : subnet.getDnsNameservers()) {
+                IpAddress ipAddress = new IpAddress(dnsNameServer.toCharArray());
+                dnsNameServers.add(ipAddress);
+            }
+            subnetBuilder.setDnsNameservers(dnsNameServers);
+        }
+        if (subnet.getID() != null) {
+            subnetBuilder.setUuid(toUuid(subnet.getID()));
+        } else {
+            LOGGER.warn("Attempting to write neutron subnet without UUID");
+        }
+        return subnetBuilder.build();
+    }
+
+    @Override
+    protected InstanceIdentifier<Subnet> createInstanceIdentifier(Subnet subnet) {
+        return InstanceIdentifier.create(Neutron.class).child(Subnets.class)
+                .child(Subnet.class, subnet.getKey());
+    }
+
+    protected InstanceIdentifier<Subnets> createInstanceIdentifier() {
+        return InstanceIdentifier.create(Neutron.class)
+                .child(Subnets.class);
+    }
+
+    @Override
+    protected Subnet toMd(String uuid) {
+        SubnetBuilder subnetBuilder = new SubnetBuilder();
+        subnetBuilder.setUuid(toUuid(uuid));
+        return subnetBuilder.build();
+    }
+
+    public static void registerNewInterface(BundleContext context,
+                                            ProviderContext providerContext,
+                                            List<ServiceRegistration<?>> registrations) {
+        NeutronSubnetInterface neutronSubnetInterface = new NeutronSubnetInterface(providerContext);
+        ServiceRegistration<INeutronSubnetCRUD> neutronSubnetInterfaceRegistration = context.registerService(INeutronSubnetCRUD.class, neutronSubnetInterface, null);
+        if(neutronSubnetInterfaceRegistration != null) {
+            registrations.add(neutronSubnetInterfaceRegistration);
+        }
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronFirewallAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronFirewallAware.java
new file mode 100644 (file)
index 0000000..f5348cb
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewall;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Firewall Rules needs to implement
+ *
+ */
+
+public interface INeutronFirewallAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified firewall can be created
+     *
+     * @param firewall
+     *            instance of proposed new Firewall object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronFirewall(NeutronFirewall firewall);
+
+    /**
+     * Services provide this interface method for taking action after a firewall has been created
+     *
+     * @param firewall
+     *            instance of new Firewall object
+     */
+    void neutronFirewallCreated(NeutronFirewall firewall);
+
+    /**
+     * Services provide this interface method to indicate if the specified firewall can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the firewall object using patch semantics
+     * @param original
+     *            instance of the Firewall object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronFirewall(NeutronFirewall delta, NeutronFirewall original);
+
+    /**
+     * Services provide this interface method for taking action after a firewall has been updated
+     *
+     * @param firewall
+     *            instance of modified Firewall object
+     */
+    void neutronFirewallUpdated(NeutronFirewall firewall);
+
+    /**
+     * Services provide this interface method to indicate if the specified firewall can be deleted
+     *
+     * @param firewall
+     *            instance of the Firewall object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronFirewall(NeutronFirewall firewall);
+
+    /**
+     * Services provide this interface method for taking action after a firewall has been deleted
+     *
+     * @param firewall
+     *            instance of deleted Firewall object
+     */
+    void neutronFirewallDeleted(NeutronFirewall firewall);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronFirewallPolicyAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronFirewallPolicyAware.java
new file mode 100644 (file)
index 0000000..2b8c0c4
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallPolicy;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Firewall Policys needs to implement
+ *
+ */
+
+public interface INeutronFirewallPolicyAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified firewallPolicy can be created
+     *
+     * @param firewallPolicy
+     *            instance of proposed new Firewall Policy object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronFirewallPolicy(NeutronFirewallPolicy firewallPolicy);
+
+    /**
+     * Services provide this interface method for taking action after a firewallPolicy has been created
+     *
+     * @param firewallPolicy
+     *            instance of new Firewall Policy object
+     */
+    void neutronFirewallPolicyCreated(NeutronFirewallPolicy firewallPolicy);
+
+    /**
+     * Services provide this interface method to indicate if the specified firewallPolicy can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the firewallPolicy object using patch semantics
+     * @param original
+     *            instance of the Firewall Policy object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronFirewallPolicy(NeutronFirewallPolicy delta, NeutronFirewallPolicy original);
+
+    /**
+     * Services provide this interface method for taking action after a firewallPolicy has been updated
+     *
+     * @param firewallPolicy
+     *            instance of modified Firewall Policy object
+     */
+    void neutronFirewallPolicyUpdated(NeutronFirewallPolicy firewallPolicy);
+
+    /**
+     * Services provide this interface method to indicate if the specified firewallPolicy can be deleted
+     *
+     * @param firewallPolicy
+     *            instance of the Firewall Policy object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronFirewallPolicy(NeutronFirewallPolicy firewallPolicy);
+
+    /**
+     * Services provide this interface method for taking action after a firewallPolicy has been deleted
+     *
+     * @param firewallPolicy
+     *            instance of deleted Firewall Policy object
+     */
+    void neutronFirewallPolicyDeleted(NeutronFirewallPolicy firewallPolicy);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronFirewallRuleAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronFirewallRuleAware.java
new file mode 100644 (file)
index 0000000..efc5752
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallRule;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Firewall Rules needs to implement
+ *
+ */
+
+public interface INeutronFirewallRuleAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified firewallRule can be created
+     *
+     * @param firewallRule
+     *            instance of proposed new Firewall Rule object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronFirewallRule(NeutronFirewallRule firewallRule);
+
+    /**
+     * Services provide this interface method for taking action after a firewallRule has been created
+     *
+     * @param firewallRule
+     *            instance of new Firewall Rule object
+     */
+    void neutronFirewallRuleCreated(NeutronFirewallRule firewallRule);
+
+    /**
+     * Services provide this interface method to indicate if the specified firewallRule can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the firewallRule object using patch semantics
+     * @param original
+     *            instance of the Firewall Rule object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronFirewallRule(NeutronFirewallRule delta, NeutronFirewallRule original);
+
+    /**
+     * Services provide this interface method for taking action after a firewallRule has been updated
+     *
+     * @param firewallRule
+     *            instance of modified Firewall Rule object
+     */
+    void neutronFirewallRuleUpdated(NeutronFirewallRule firewallRule);
+
+    /**
+     * Services provide this interface method to indicate if the specified firewallRule can be deleted
+     *
+     * @param firewallRule
+     *            instance of the Firewall Rule object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronFirewallRule(NeutronFirewallRule firewallRule);
+
+    /**
+     * Services provide this interface method for taking action after a firewallRule has been deleted
+     *
+     * @param firewallRule
+     *            instance of deleted Firewall Rule object
+     */
+    void neutronFirewallRuleDeleted(NeutronFirewallRule firewallRule);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronFloatingIPAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronFloatingIPAware.java
new file mode 100644 (file)
index 0000000..f9ca5e7
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron FloatingIPs needs to implement
+ *
+ */
+
+public interface INeutronFloatingIPAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified floatingIP can be created
+     *
+     * @param floatingIP
+     *            instance of proposed new Neutron FloatingIP object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateFloatingIP(NeutronFloatingIP floatingIP);
+
+    /**
+     * Services provide this interface method for taking action after a floatingIP has been created
+     *
+     * @param floatingIP
+     *            instance of new Neutron FloatingIP object
+     */
+    void neutronFloatingIPCreated(NeutronFloatingIP floatingIP);
+
+    /**
+     * Services provide this interface method to indicate if the specified floatingIP can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the floatingIP object using patch semantics
+     * @param original
+     *            instance of the Neutron FloatingIP object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateFloatingIP(NeutronFloatingIP delta, NeutronFloatingIP original);
+
+    /**
+     * Services provide this interface method for taking action after a floatingIP has been updated
+     *
+     * @param floatingIP
+     *            instance of modified Neutron FloatingIP object
+     */
+    void neutronFloatingIPUpdated(NeutronFloatingIP floatingIP);
+
+    /**
+     * Services provide this interface method to indicate if the specified floatingIP can be deleted
+     *
+     * @param floatingIP
+     *            instance of the Neutron FloatingIP object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteFloatingIP(NeutronFloatingIP floatingIP);
+
+    /**
+     * Services provide this interface method for taking action after a floatingIP has been deleted
+     *
+     * @param floatingIP
+     *            instance of deleted Neutron FloatingIP object
+     */
+    void neutronFloatingIPDeleted(NeutronFloatingIP floatingIP);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerAware.java
new file mode 100644 (file)
index 0000000..84f68cf
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancer Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancer can be created
+     *
+     * @param loadBalancer
+     *            instance of proposed new LoadBalancer object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronLoadBalancer(NeutronLoadBalancer loadBalancer);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancer has been created
+     *
+     * @param loadBalancer
+     *            instance of new LoadBalancer object
+     */
+    void neutronLoadBalancerCreated(NeutronLoadBalancer loadBalancer);
+
+    /**
+     * Services provide this interface method to indicate if the
+     * specified loadBalancer can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancer object using patch semantics
+     * @param original
+     *            instance of the LoadBalancer object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronLoadBalancer(NeutronLoadBalancer delta, NeutronLoadBalancer original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancer has been updated
+     *
+     * @param loadBalancer
+     *            instance of modified LoadBalancer object
+     */
+    void neutronLoadBalancerUpdated(NeutronLoadBalancer loadBalancer);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancer can be deleted
+     *
+     * @param loadBalancer
+     *            instance of the LoadBalancer object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronLoadBalancer(NeutronLoadBalancer loadBalancer);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancer has been deleted
+     *
+     * @param loadBalancer
+     *            instance of deleted LoadBalancer object
+     */
+    void neutronLoadBalancerDeleted(NeutronLoadBalancer loadBalancer);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerHealthMonitorAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerHealthMonitorAware.java
new file mode 100644 (file)
index 0000000..bd46389
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerHealthMonitor;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancerHealthMonitor Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerHealthMonitorAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerHealthMonitor can be created
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of proposed new LoadBalancerHealthMonitor object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerHealthMonitor has been created
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of new LoadBalancerHealthMonitor object
+     */
+    void neutronLoadBalancerHealthMonitorCreated(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerHealthMonitor can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancerHealthMonitor object using patch semantics
+     * @param original
+     *            instance of the LoadBalancerHealthMonitor object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor delta,
+            NeutronLoadBalancerHealthMonitor original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerHealthMonitor has been updated
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of modified LoadBalancerHealthMonitor object
+     */
+    void neutronLoadBalancerHealthMonitorUpdated(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerHealthMonitor can be deleted
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of the LoadBalancerHealthMonitor object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerHealthMonitor has been deleted
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of deleted LoadBalancerHealthMonitor object
+     */
+    void neutronLoadBalancerHealthMonitorDeleted(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerListenerAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerListenerAware.java
new file mode 100644 (file)
index 0000000..a54689d
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerListener;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancerListener Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerListenerAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerListener can be created
+     *
+     * @param loadBalancerListener
+     *            instance of proposed new LoadBalancerListener object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronLoadBalancerListener(NeutronLoadBalancerListener loadBalancerListener);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerListener has been created
+     *
+     * @param loadBalancerListener
+     *            instance of new LoadBalancerListener object
+     */
+    void neutronLoadBalancerListenerCreated(NeutronLoadBalancerListener loadBalancerListener);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerListener can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancerListener object using patch semantics
+     * @param original
+     *            instance of the LoadBalancerListener object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronLoadBalancerListener(NeutronLoadBalancerListener delta,
+            NeutronLoadBalancerListener original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerListener has been updated
+     *
+     * @param loadBalancerListener
+     *            instance of modified LoadBalancerListener object
+     */
+    void neutronLoadBalancerListenerUpdated(NeutronLoadBalancerListener loadBalancerListener);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerListener can be deleted
+     *
+     * @param loadBalancerListener
+     *            instance of the LoadBalancerListener object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronLoadBalancerListener(NeutronLoadBalancerListener loadBalancerListener);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerListener has been deleted
+     *
+     * @param loadBalancerListener
+     *            instance of deleted LoadBalancerListener object
+     */
+    void neutronLoadBalancerListenerDeleted(NeutronLoadBalancerListener loadBalancerListener);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerPoolAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerPoolAware.java
new file mode 100644 (file)
index 0000000..76d5410
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancerPool Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerPoolAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPool can be created
+     *
+     * @param loadBalancerPool
+     *            instance of proposed new LoadBalancerPool object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronLoadBalancerPool(NeutronLoadBalancerPool loadBalancerPool);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPool has been created
+     *
+     * @param loadBalancerPool
+     *            instance of new LoadBalancerPool object
+     */
+    void neutronLoadBalancerPoolCreated(NeutronLoadBalancerPool loadBalancerPool);
+
+    /**
+     * Services provide this interface method to indicate if the
+     * specified loadBalancerPool can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancerPool object using patch semantics
+     * @param original
+     *            instance of the LoadBalancerPool object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronLoadBalancerPool(NeutronLoadBalancerPool delta, NeutronLoadBalancerPool original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPool has been updated
+     *
+     * @param loadBalancerPool
+     *            instance of modified LoadBalancerPool object
+     */
+    void neutronLoadBalancerPoolUpdated(NeutronLoadBalancerPool loadBalancerPool);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPool can be deleted
+     *
+     * @param loadBalancerPool
+     *            instance of the LoadBalancerPool object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronLoadBalancerPool(NeutronLoadBalancerPool loadBalancerPool);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPool has been deleted
+     *
+     * @param loadBalancerPool
+     *            instance of deleted LoadBalancerPool object
+     */
+    void neutronLoadBalancerPoolDeleted(NeutronLoadBalancerPool loadBalancerPool);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerPoolMemberAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronLoadBalancerPoolMemberAware.java
new file mode 100644 (file)
index 0000000..d1e333f
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+
+public interface INeutronLoadBalancerPoolMemberAware {
+
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPoolMember can be created
+     *
+     * @param loadBalancerPoolMember
+     *            instance of proposed new LoadBalancerPool object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPoolMember has been created
+     *
+     * @param loadBalancerPoolMember
+     *            instance of new LoadBalancerPool object
+     */
+    void neutronLoadBalancerPoolMemberCreated(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPoolMember can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancerPoolMember object using patch semantics
+     * @param original
+     *            instance of the LoadBalancerPool object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember delta,
+            NeutronLoadBalancerPoolMember original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPoolMember has been updated
+     *
+     * @param loadBalancerPoolMember
+     *            instance of modified LoadBalancerPool object
+     */
+    void neutronLoadBalancerPoolMemberUpdated(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPoolMember can be deleted
+     *
+     * @param loadBalancerPoolMember
+     *            instance of the LoadBalancerPool object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPoolMember has been deleted
+     *
+     * @param loadBalancerPoolMember
+     *            instance of deleted LoadBalancerPool object
+     */
+    void neutronLoadBalancerPoolMemberDeleted(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronNetworkAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronNetworkAware.java
new file mode 100644 (file)
index 0000000..70f69c4
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Networks needs to implement
+ *
+ */
+
+public interface INeutronNetworkAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified network can be created
+     *
+     * @param network
+     *            instance of proposed new Neutron Network object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateNetwork(NeutronNetwork network);
+
+    /**
+     * Services provide this interface method for taking action after a network has been created
+     *
+     * @param network
+     *            instance of new Neutron Network object
+     */
+    void neutronNetworkCreated(NeutronNetwork network);
+
+    /**
+     * Services provide this interface method to indicate if the specified network can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the network object using patch semantics
+     * @param original
+     *            instance of the Neutron Network object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateNetwork(NeutronNetwork delta, NeutronNetwork original);
+
+    /**
+     * Services provide this interface method for taking action after a network has been updated
+     *
+     * @param network
+     *            instance of modified Neutron Network object
+     */
+    void neutronNetworkUpdated(NeutronNetwork network);
+
+    /**
+     * Services provide this interface method to indicate if the specified network can be deleted
+     *
+     * @param network
+     *            instance of the Neutron Network object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteNetwork(NeutronNetwork network);
+
+    /**
+     * Services provide this interface method for taking action after a network has been deleted
+     *
+     * @param network
+     *            instance of deleted Neutron Network object
+     */
+    void neutronNetworkDeleted(NeutronNetwork network);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronPortAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronPortAware.java
new file mode 100644 (file)
index 0000000..e697482
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Ports needs to implement
+ *
+ */
+
+public interface INeutronPortAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified port can be created
+     *
+     * @param port
+     *            instance of proposed new Neutron Port object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreatePort(NeutronPort port);
+
+    /**
+     * Services provide this interface method for taking action after a port has been created
+     *
+     * @param port
+     *            instance of new Neutron Port object
+     */
+    void neutronPortCreated(NeutronPort port);
+
+    /**
+     * Services provide this interface method to indicate if the specified port can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the port object using patch semantics
+     * @param original
+     *            instance of the Neutron Port object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdatePort(NeutronPort delta, NeutronPort original);
+
+    /**
+     * Services provide this interface method for taking action after a port has been updated
+     *
+     * @param port
+     *            instance of modified Neutron Port object
+     */
+    void neutronPortUpdated(NeutronPort port);
+
+    /**
+     * Services provide this interface method to indicate if the specified port can be deleted
+     *
+     * @param port
+     *            instance of the Neutron Port object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeletePort(NeutronPort port);
+
+    /**
+     * Services provide this interface method for taking action after a port has been deleted
+     *
+     * @param port
+     *            instance of deleted Port Network object
+     */
+    void neutronPortDeleted(NeutronPort port);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronRouterAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronRouterAware.java
new file mode 100644 (file)
index 0000000..8577e7d
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Routers needs to implement
+ *
+ */
+
+public interface INeutronRouterAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified router can be created
+     *
+     * @param router
+     *            instance of proposed new Neutron Router object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateRouter(NeutronRouter router);
+
+    /**
+     * Services provide this interface method for taking action after a router has been created
+     *
+     * @param router
+     *            instance of new Neutron Router object
+     */
+    void neutronRouterCreated(NeutronRouter router);
+
+    /**
+     * Services provide this interface method to indicate if the specified router can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the router object using patch semantics
+     * @param original
+     *            instance of the Neutron Router object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateRouter(NeutronRouter delta, NeutronRouter original);
+
+    /**
+     * Services provide this interface method for taking action after a router has been updated
+     *
+     * @param router
+     *            instance of modified Neutron Router object
+     */
+    void neutronRouterUpdated(NeutronRouter router);
+
+    /**
+     * Services provide this interface method to indicate if the specified router can be deleted
+     *
+     * @param router
+     *            instance of the Neutron Router object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteRouter(NeutronRouter router);
+
+    /**
+     * Services provide this interface method for taking action after a router has been deleted
+     *
+     * @param router
+     *            instance of deleted Router Network object
+     */
+    void neutronRouterDeleted(NeutronRouter router);
+
+    /**
+     * Services provide this interface method to indicate if the
+     * specified interface can be attached to the specified router
+     *
+     * @param router
+     *            instance of the base Neutron Router object
+     * @param routerInterface
+     *            instance of the NeutronRouter_Interface to be attached to the router
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the attach operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface);
+
+    /**
+     * Services provide this interface method for taking action
+     * after an interface has been added to a router
+     *
+     * @param router
+     *            instance of the base Neutron Router object
+     * @param routerInterface
+     *            instance of the NeutronRouter_Interface being attached to the router
+     */
+    void neutronRouterInterfaceAttached(NeutronRouter router, NeutronRouter_Interface routerInterface);
+
+    /**
+     * Services provide this interface method to indicate if the
+     * specified interface can be detached from the specified router
+     *
+     * @param router
+     *            instance of the base Neutron Router object
+     * @param routerInterface
+     *            instance of the NeutronRouter_Interface to be detached to the router
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the detach operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface);
+
+    /**
+     * Services provide this interface method for taking action after an interface has been removed from a router
+     *
+     * @param router
+     *            instance of the base Neutron Router object
+     * @param routerInterface
+     *            instance of the NeutronRouter_Interface being detached from the router
+     */
+    void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronSecurityGroupAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronSecurityGroupAware.java
new file mode 100644 (file)
index 0000000..d0323eb
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Security Groups needs to implement
+ */
+
+public interface INeutronSecurityGroupAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified security group can be created
+     *
+     * @param securityGroup instance of proposed new Neutron Security Group object
+     * @return integer
+     * the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     * results in the create operation being interrupted and the returned status value reflected in the
+     * HTTP response.
+     */
+    int canCreateNeutronSecurityGroup(NeutronSecurityGroup securityGroup);
+
+    /**
+     * Services provide this interface method for taking action after a security group has been created
+     *
+     * @param securityGroup instance of new Neutron Security Group object
+     */
+    void neutronSecurityGroupCreated(NeutronSecurityGroup securityGroup);
+
+    /**
+     * Services provide this interface method to indicate if the specified security group can be changed using the specified
+     * delta
+     *
+     * @param delta    updates to the security group object using patch semantics
+     * @param original instance of the Neutron Security Group object to be updated
+     * @return integer
+     * the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     * results in the update operation being interrupted and the returned status value reflected in the
+     * HTTP response.
+     */
+    int canUpdateNeutronSecurityGroup(NeutronSecurityGroup delta, NeutronSecurityGroup original);
+
+    /**
+     * Services provide this interface method for taking action after a security group has been updated
+     *
+     * @param securityGroup instance of modified Neutron Security Group object
+     */
+    void neutronSecurityGroupUpdated(NeutronSecurityGroup securityGroup);
+
+    /**
+     * Services provide this interface method to indicate if the specified security group can be deleted
+     *
+     * @param securityGroup instance of the Neutron Security Group object to be deleted
+     * @return integer
+     * the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     * results in the delete operation being interrupted and the returned status value reflected in the
+     * HTTP response.
+     */
+    int canDeleteNeutronSecurityGroup(NeutronSecurityGroup securityGroup);
+
+    /**
+     * Services provide this interface method for taking action after a security group has been deleted
+     *
+     * @param securityGroup instance of deleted Neutron Security Group object
+     */
+    void neutronSecurityGroupDeleted(NeutronSecurityGroup securityGroup);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronSecurityRuleAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronSecurityRuleAware.java
new file mode 100644 (file)
index 0000000..6a8eaef
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 Red Hat, 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+
+/**
+ * This interface defines the methods required to be aware of Neutron Security Rules
+ */
+
+public interface INeutronSecurityRuleAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified security rule can be created
+     *
+     * @param securityRule instance of proposed new Neutron Security Rule object
+     * @return integer
+     * the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     * results in the create operation being interrupted and the returned status value reflected in the
+     * HTTP response.
+     */
+    int canCreateNeutronSecurityRule(NeutronSecurityRule securityRule);
+
+    /**
+     * Services provide this interface method for taking action after a security rule has been created
+     *
+     * @param securityRule instance of new Neutron Security Rule object
+     */
+    void neutronSecurityRuleCreated(NeutronSecurityRule securityRule);
+
+    /**
+     * Services provide this interface method to indicate if the specified security rule can be changed using the specified
+     * delta
+     *
+     * @param delta    updates to the security rule object using patch semantics
+     * @param original instance of the Neutron Security Rule object to be updated
+     * @return integer
+     * the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     * results in the update operation being interrupted and the returned status value reflected in the
+     * HTTP response.
+     */
+    int canUpdateNeutronSecurityRule(NeutronSecurityRule delta, NeutronSecurityRule original);
+
+    /**
+     * Services provide this interface method for taking action after a security rule has been updated
+     *
+     * @param securityRule instance of modified Neutron Security Rule object
+     */
+    void neutronSecurityRuleUpdated(NeutronSecurityRule securityRule);
+
+    /**
+     * Services provide this interface method to indicate if the specified security rule can be deleted
+     *
+     * @param securityRule instance of the Neutron Security Rule object to be deleted
+     * @return integer
+     * the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     * results in the delete operation being interrupted and the returned status value reflected in the
+     * HTTP response.
+     */
+    int canDeleteNeutronSecurityRule(NeutronSecurityRule securityRule);
+
+    /**
+     * Services provide this interface method for taking action after a security rule has been deleted
+     *
+     * @param securityRule instance of deleted Neutron Security Rule object
+     */
+    void neutronSecurityRuleDeleted(NeutronSecurityRule securityRule);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronSubnetAware.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/INeutronSubnetAware.java
new file mode 100644 (file)
index 0000000..55ae58b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013, 2015 IBM Corporation 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.ovsdb.openstack.netvirt.translator.iaware;
+
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of Neutron Subnets needs to implement
+ *
+ */
+
+public interface INeutronSubnetAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified subnet can be created
+     *
+     * @param subnet
+     *            instance of proposed new Neutron Subnet object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canCreateSubnet(NeutronSubnet subnet);
+
+    /**
+     * Services provide this interface method for taking action after a subnet has been created
+     *
+     * @param subnet
+     *            instance of new Neutron Subnet object
+     */
+    void neutronSubnetCreated(NeutronSubnet subnet);
+
+    /**
+     * Services provide this interface method to indicate if the specified subnet can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the subnet object using patch semantics
+     * @param original
+     *            instance of the Neutron Subnet object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canUpdateSubnet(NeutronSubnet delta, NeutronSubnet original);
+
+    /**
+     * Services provide this interface method for taking action after a subnet has been updated
+     *
+     * @param subnet
+     *            instance of modified Neutron Subnet object
+     */
+    void neutronSubnetUpdated(NeutronSubnet subnet);
+
+    /**
+     * Services provide this interface method to indicate if the specified subnet can be deleted
+     *
+     * @param subnet
+     *            instance of the Subnet Router object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    int canDeleteSubnet(NeutronSubnet subnet);
+
+    /**
+     * Services provide this interface method for taking action after a subnet has been deleted
+     *
+     * @param subnet
+     *            instance of deleted Router Subnet object
+     */
+    void neutronSubnetDeleted(NeutronSubnet subnet);
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronFloatingIPChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronFloatingIPChangeListener.java
new file mode 100644 (file)
index 0000000..44adae8
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronFloatingIPAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.Floatingips;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronFloatingIPChangeListener implements DataChangeListener, AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronFloatingIPChangeListener.class);
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronFloatingIPChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Floatingip> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Floatingips.class)
+                .child(Floatingip.class);
+        LOG.debug("Register listener for Neutron FloatingIp model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}",changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronFloatingIPAware.class, this);
+        createFloatingIP(changes, subscribers);
+        updateFloatingIP(changes, subscribers);
+        deleteFloatingIP(changes, subscribers);
+    }
+
+    private void createFloatingIP(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newFloatingIP : changes.getCreatedData().entrySet()) {
+               if(newFloatingIP.getValue() instanceof Floatingip){
+                NeutronFloatingIP floatingip= fromMd((Floatingip)newFloatingIP.getValue());
+                for(Object entry: subscribers){
+                    INeutronFloatingIPAware subscriber = (INeutronFloatingIPAware)entry;
+                    subscriber.neutronFloatingIPCreated(floatingip);
+                }
+               }
+        }
+    }
+
+    private void updateFloatingIP(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updateFloatingIP : changes.getUpdatedData().entrySet()) {
+               if(updateFloatingIP.getValue() instanceof Floatingip){
+                NeutronFloatingIP floatingip = fromMd((Floatingip)updateFloatingIP.getValue());
+                for(Object entry: subscribers){
+                    INeutronFloatingIPAware subscriber = (INeutronFloatingIPAware)entry;
+                    subscriber.neutronFloatingIPUpdated(floatingip);
+                }
+               }
+        }
+    }
+
+    private void deleteFloatingIP(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedFloatingIPPath : changes.getRemovedPaths()) {
+               if(deletedFloatingIPPath.getTargetType().equals(Floatingip.class)){
+                NeutronFloatingIP floatingip = fromMd((Floatingip)changes.getOriginalData().get(deletedFloatingIPPath));
+                for(Object entry: subscribers){
+                    INeutronFloatingIPAware subscriber = (INeutronFloatingIPAware)entry;
+                    subscriber.neutronFloatingIPDeleted(floatingip);
+                }
+               }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronFloatingIPInterface.java class of Neutron Northbound class.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronFloatingIP fromMd(Floatingip fip) {
+        NeutronFloatingIP result = new NeutronFloatingIP();
+        result.setID(String.valueOf(fip.getUuid().getValue()));
+        if (fip.getFloatingNetworkId() != null) {
+            result.setFloatingNetworkUUID(String.valueOf(fip.getFloatingNetworkId().getValue()));
+        }
+        if (fip.getPortId() != null) {
+            result.setPortUUID(String.valueOf(fip.getPortId().getValue()));
+        }
+        if (fip.getFixedIpAddress() != null ) {
+            result.setFixedIPAddress(String.valueOf(fip.getFixedIpAddress().getValue()));
+        }
+        if (fip.getFloatingIpAddress() != null) {
+            result.setFloatingIPAddress(String.valueOf(fip.getFloatingIpAddress().getValue()));
+        }
+        if (fip.getTenantId() != null) {
+            result.setTenantUUID(String.valueOf(fip.getTenantId().getValue()));
+        }
+        if (fip.getRouterId() != null) {
+            result.setRouterUUID(String.valueOf(fip.getRouterId().getValue()));
+        }
+        result.setStatus(fip.getStatus());
+        return result;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronIAwareUtil.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronIAwareUtil.java
new file mode 100644 (file)
index 0000000..c8466fe
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronIAwareUtil {
+    private static final Logger LOGGER = LoggerFactory
+            .getLogger(NeutronIAwareUtil.class);
+
+    private NeutronIAwareUtil() {
+    }
+
+    public static Object[] getInstances(Class<?> clazz,Object bundle) {
+        Object instances[] = null;
+        try {
+            BundleContext bCtx = FrameworkUtil.getBundle(bundle.getClass())
+                    .getBundleContext();
+
+            ServiceReference<?>[] services = null;
+                services = bCtx.getServiceReferences(clazz.getName(),
+                        null);
+            if (services != null) {
+                instances = new Object[services.length];
+                for (int i = 0; i < services.length; i++) {
+                    instances[i] = bCtx.getService(services[i]);
+                }
+            }
+        } catch (Exception e) {
+            LOGGER.error("Instance reference is NULL", e);
+        }
+        return instances;
+    }
+
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronLoadBalancerPoolChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronLoadBalancerPoolChangeListener.java
new file mode 100644 (file)
index 0000000..84f398f
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer_SessionPersistence;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_ID;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Pools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.Pool;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.pool.members.Member;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronLoadBalancerPoolChangeListener implements DataChangeListener, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronLoadBalancerPoolChangeListener.class);
+
+    private static final ImmutableBiMap<Class<? extends ProtocolBase>,String> PROTOCOL_MAP
+            = new ImmutableBiMap.Builder<Class<? extends ProtocolBase>,String>()
+            .put(ProtocolHttp.class, "HTTP")
+            .put(ProtocolHttps.class, "HTTPS")
+            .put(ProtocolIcmp.class, "ICMP")
+            .put(ProtocolTcp.class,"TCP")
+            .build();
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronLoadBalancerPoolChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Pool> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Pools.class)
+                .child(Pool.class);
+        LOG.debug("Register listener for Neutron Load Balancer Pool model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, AsyncDataBroker.DataChangeScope.ONE);
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+
+    @Override
+    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}", changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronLoadBalancerPoolAware.class, this);
+        createPool(changes, subscribers);
+        updatePool(changes, subscribers);
+        deletePool(changes, subscribers);
+    }
+
+    private void createPool(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newPool : changes.getCreatedData().entrySet()) {
+               if(newPool.getValue() instanceof Pool){
+                NeutronLoadBalancerPool loadBalancerPool = fromMd((Pool) newPool.getValue());
+                for (Object entry : subscribers) {
+                    INeutronLoadBalancerPoolAware subscriber = (INeutronLoadBalancerPoolAware) entry;
+                    subscriber.neutronLoadBalancerPoolCreated(loadBalancerPool);
+                }
+               }
+        }
+    }
+    private void updatePool(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updatePool : changes.getUpdatedData().entrySet()) {
+               if(updatePool.getValue() instanceof Pool){
+                NeutronLoadBalancerPool loadBalancerPool = fromMd((Pool)updatePool.getValue());
+                for(Object entry: subscribers){
+                    INeutronLoadBalancerPoolAware subscriber = (INeutronLoadBalancerPoolAware) entry;
+                    subscriber.neutronLoadBalancerPoolUpdated(loadBalancerPool);
+                }
+               }
+        }
+    }
+    private void deletePool(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedPoolPath : changes.getRemovedPaths()) {
+               if(deletedPoolPath.getTargetType().equals(Pool.class)){
+                NeutronLoadBalancerPool loadBalancerPool = fromMd((Pool)changes.getOriginalData().get(deletedPoolPath));
+                for(Object entry: subscribers){
+                    INeutronLoadBalancerPoolAware subscriber = (INeutronLoadBalancerPoolAware) entry;
+                    subscriber.neutronLoadBalancerPoolDeleted(loadBalancerPool);
+                }
+               }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronLoadBalancerPool.java class of Neutron Northbound class.
+     * in the original location, this method is called extractFields.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronLoadBalancerPool fromMd(Pool pool) {
+        NeutronLoadBalancerPool result = new NeutronLoadBalancerPool();
+
+        result.setID(pool.getUuid().getValue());
+        result.setLoadBalancerPoolTenantID(pool.getTenantId().getValue());
+        result.setLoadBalancerPoolName(pool.getName());
+        result.setLoadBalancerPoolDescription(pool.getDescr());
+        result.setLoadBalancerPoolProtocol(PROTOCOL_MAP.get(pool.getProtocol()));
+        result.setLoadBalancerPoolLbAlgorithm(pool.getLbAlgorithm());
+
+        // TODO: setNeutronLoadBalancerPoolHealthMonitorID is a list? Fill in, when its needed.
+        if (pool.getHealthmonitorId() != null) {
+               result.setNeutronLoadBalancerPoolHealthMonitorID(pool.getHealthmonitorId().getValue());
+        }
+
+        result.setLoadBalancerPoolAdminStateIsUp(pool.isAdminStateUp());
+
+        List<Neutron_ID> listeners = new ArrayList();
+        if (pool.getListeners() != null) {
+            for (Uuid listenerUuid : pool.getListeners()) {
+                listeners.add(new Neutron_ID(listenerUuid.getValue()));
+            }
+        }
+        result.setLoadBalancerPoolListeners(listeners);
+
+        if (pool.getSessionPersistence() != null) {
+            NeutronLoadBalancer_SessionPersistence sessionPersistence = new NeutronLoadBalancer_SessionPersistence();
+            sessionPersistence.setCookieName(pool.getSessionPersistence().getCookieName());
+            sessionPersistence.setType(pool.getSessionPersistence().getType());
+            result.setLoadBalancerSessionPersistence(sessionPersistence);
+        }
+
+        List<NeutronLoadBalancerPoolMember> loadBalancerPoolMembers = new ArrayList();
+        if (pool.getMembers() != null) {
+            for (Member member : pool.getMembers().getMember()) {
+                NeutronLoadBalancerPoolMember neutronMember = new NeutronLoadBalancerPoolMember();
+
+                neutronMember.setPoolID(pool.getUuid().getValue());
+                neutronMember.setPoolMemberID(member.getUuid().getValue());
+
+                // TODO: locate and populate remainder attributes, when its needed
+                // member.setPoolMemberAddress(xxx);
+                // member.setPoolMemberAdminStateIsUp(xxx);
+                // member.setPoolMemberProtoPort(xxx);
+                // member.setPoolMemberSubnetID(xxx);
+                // member.setPoolMemberTenantID(xxx);
+                // member.setPoolMemberWeight(xxx);
+
+                loadBalancerPoolMembers.add(neutronMember);
+            }
+        }
+        result.setLoadBalancerPoolMembers(loadBalancerPoolMembers);
+
+        return result;
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronLoadBalancerPoolMemberChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronLoadBalancerPoolMemberChangeListener.java
new file mode 100644 (file)
index 0000000..b62583f
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2015 Red Hat, 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.ovsdb.openstack.netvirt.translator.iaware.impl;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronLoadBalancerPoolMemberAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.Pools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.Pool;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.PoolKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.pool.Members;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.lbaasv2.rev150712.lbaas.attributes.pools.pool.members.Member;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronLoadBalancerPoolMemberChangeListener implements DataChangeListener, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronLoadBalancerPoolMemberChangeListener.class);
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronLoadBalancerPoolMemberChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Member> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Pools.class)
+                .child(Pool.class)
+                .child(Members.class)
+                .child(Member.class);
+        LOG.debug("Register listener for Neutron Load Balancer Pool Member model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this,
+                        AsyncDataBroker.DataChangeScope.ONE);
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+
+    @Override
+    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}", changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronLoadBalancerPoolMemberAware.class, this);
+        createPoolMember(changes, subscribers);
+        updatePoolMember(changes, subscribers);
+        deletePoolMember(changes, subscribers);
+    }
+
+    private void createPoolMember(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newPoolMember : changes.getCreatedData().entrySet()) {
+               if(newPoolMember.getValue() instanceof Member){
+                NeutronLoadBalancerPoolMember neutronLBPoolMember = fromMd(newPoolMember.getKey(), (Member) newPoolMember.getValue());
+                for (Object entry : subscribers) {
+                    INeutronLoadBalancerPoolMemberAware subscriber = (INeutronLoadBalancerPoolMemberAware) entry;
+                    subscriber.neutronLoadBalancerPoolMemberCreated(neutronLBPoolMember);
+                }
+               }
+        }
+    }
+    private void updatePoolMember(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updatePoolMember : changes.getUpdatedData().entrySet()) {
+               if(updatePoolMember.getValue() instanceof Member){
+                NeutronLoadBalancerPoolMember neutronLBPoolMember =
+                        fromMd(updatePoolMember.getKey(), (Member) updatePoolMember.getValue());
+                for(Object entry: subscribers){
+                    INeutronLoadBalancerPoolMemberAware subscriber = (INeutronLoadBalancerPoolMemberAware) entry;
+                    subscriber.neutronLoadBalancerPoolMemberUpdated(neutronLBPoolMember);
+                }
+               }
+        }
+    }
+    private void deletePoolMember(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedPoolMemberPath : changes.getRemovedPaths()) {
+               if(deletedPoolMemberPath.getTargetType().equals(Member.class)){
+                NeutronLoadBalancerPoolMember neutronLBPoolMember =
+                        fromMd(deletedPoolMemberPath, (Member) changes.getOriginalData().get(deletedPoolMemberPath));
+                for(Object entry: subscribers){
+                    INeutronLoadBalancerPoolMemberAware subscriber = (INeutronLoadBalancerPoolMemberAware) entry;
+                    subscriber.neutronLoadBalancerPoolMemberDeleted(neutronLBPoolMember);
+                }
+               }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronLoadBalancerPoolMember.java class of Neutron Northbound class.
+     * in the original location, this method is called extractFields.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronLoadBalancerPoolMember fromMd(InstanceIdentifier<?> iid, Member member) {
+        NeutronLoadBalancerPoolMember result = new NeutronLoadBalancerPoolMember();
+
+        final PoolKey poolsKey = iid.firstKeyOf(Pool.class, PoolKey.class);
+        if (poolsKey != null) {
+            result.setPoolID(poolsKey.getUuid().getValue());
+        }
+
+        result.setID(member.getUuid().getValue());
+        result.setPoolMemberAdminStateIsUp(member.isAdminStateUp());
+
+        final IpAddress memberIpAddress = member.getAddress();
+        if (memberIpAddress != null) {
+            if (memberIpAddress.getIpv4Address() != null) {
+                result.setPoolMemberAddress(memberIpAddress.getIpv4Address().getValue());
+            } else if (memberIpAddress.getIpv6Address() != null) {
+                result.setPoolMemberAddress(memberIpAddress.getIpv6Address().getValue());
+            }
+        }
+
+        result.setPoolMemberProtoPort(member.getProtocolPort());
+        result.setPoolMemberSubnetID(member.getSubnetId().getValue());
+        result.setPoolMemberTenantID(member.getTenantId().getValue());
+        result.setPoolMemberWeight(member.getWeight());
+
+        return result;
+    }
+}
+
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronNetworkChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronNetworkChangeListener.java
new file mode 100644 (file)
index 0000000..bb045b4
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork_Segment;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronNetworkAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.ext.rev150712.NetworkL3Extension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeFlat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.neutron.networks.network.Segments;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronNetworkChangeListener implements DataChangeListener, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronNetworkChangeListener.class);
+
+    private static final ImmutableBiMap<Class<? extends NetworkTypeBase>,String> NETWORK_MAP
+    = new ImmutableBiMap.Builder<Class<? extends NetworkTypeBase>,String>()
+    .put(NetworkTypeFlat.class,"flat")
+    .put(NetworkTypeGre.class,"gre")
+    .put(NetworkTypeVlan.class,"vlan")
+    .put(NetworkTypeVxlan.class,"vxlan")
+    .build();
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronNetworkChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Network> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Networks.class)
+                .child(Network.class);
+        LOG.debug("Register listener for Neutron Network model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}",changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronNetworkAware.class, this);
+        createNetwork(changes, subscribers);
+        updateNetwork(changes, subscribers);
+        deleteNetwork(changes, subscribers);
+    }
+
+    private void createNetwork(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newNetwork : changes.getCreatedData().entrySet()) {
+               if(newNetwork.getValue() instanceof Network){
+                NeutronNetwork network = fromMd((Network)newNetwork.getValue());
+                for(Object entry: subscribers){
+                    INeutronNetworkAware subscriber = (INeutronNetworkAware)entry;
+                    subscriber.neutronNetworkCreated(network);
+                }
+               }
+        }
+    }
+
+    private void updateNetwork(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updateNetwork : changes.getUpdatedData().entrySet()) {
+               if(updateNetwork.getValue() instanceof Network){
+                NeutronNetwork network = fromMd((Network)updateNetwork.getValue());
+                for(Object entry: subscribers){
+                    INeutronNetworkAware subscriber = (INeutronNetworkAware)entry;
+                    subscriber.neutronNetworkUpdated(network);
+                }
+               }
+        }
+    }
+
+    private void deleteNetwork(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedNetworkPath : changes.getRemovedPaths()) {
+               if(deletedNetworkPath.getTargetType().equals(Network.class)){
+                NeutronNetwork network = fromMd((Network)changes.getOriginalData().get(deletedNetworkPath));
+                for(Object entry: subscribers){
+                    INeutronNetworkAware subscriber = (INeutronNetworkAware)entry;
+                    subscriber.neutronNetworkDeleted(network);
+                }
+               }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronNetworkInterface.java class of Neutron Northbound class.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronNetwork fromMd(Network network) {
+        NeutronNetwork result = new NeutronNetwork();
+        result.setAdminStateUp(network.isAdminStateUp());
+        result.setNetworkName(network.getName());
+        result.setShared(network.isShared());
+        result.setStatus(network.getStatus());
+        if (network.getSubnets() != null) {
+            List<String> neutronSubnets = new ArrayList<String>();
+            for( Uuid subnet : network.getSubnets()) {
+               neutronSubnets.add(subnet.getValue());
+            }
+            result.setSubnets(neutronSubnets);
+        }
+
+        // todo remove '-' chars as tenant id doesn't use them
+        result.setTenantID(network.getTenantId().getValue());
+        result.setID(network.getUuid().getValue());
+
+        NetworkL3Extension l3Extension = network.getAugmentation(NetworkL3Extension.class);
+        result.setRouterExternal(l3Extension.isExternal());
+
+        NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
+        result.setProviderPhysicalNetwork(providerExtension.getPhysicalNetwork());
+        result.setProviderSegmentationID(providerExtension.getSegmentationId());
+        result.setProviderNetworkType(NETWORK_MAP.get(providerExtension.getNetworkType()));
+        List<NeutronNetwork_Segment> segments = new ArrayList<NeutronNetwork_Segment>();
+        if (providerExtension.getSegments() != null) {
+            for (Segments segment: providerExtension.getSegments()) {
+                NeutronNetwork_Segment neutronSegment = new NeutronNetwork_Segment();
+                neutronSegment.setProviderPhysicalNetwork(segment.getPhysicalNetwork());
+                neutronSegment.setProviderSegmentationID(segment.getSegmentationId());
+                neutronSegment.setProviderNetworkType(NETWORK_MAP.get(segment.getNetworkType()));
+                segments.add(neutronSegment);
+            }
+        }
+        result.setSegments(segments);
+        return result;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronPortChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronPortChangeListener.java
new file mode 100644 (file)
index 0000000..35bf7ff
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_AllowedAddressPairs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_ExtraDHCPOption;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_VIFDetail;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronPortAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetails;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.AllowedAddressPairs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.ExtraDhcpOpts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronPortChangeListener implements DataChangeListener, AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronPortChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Port> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Ports.class)
+                .child(Port.class);
+        LOG.debug("Register listener for Neutron Port model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}",changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronPortAware.class, this);
+        createPort(changes, subscribers);
+        updatePort(changes, subscribers);
+        deletePort(changes, subscribers);
+    }
+
+    private void createPort(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newPort : changes.getCreatedData().entrySet()) {
+               if(newPort.getValue() instanceof Port){
+                NeutronPort port = fromMd((Port)newPort.getValue());
+                for(Object entry: subscribers){
+                    INeutronPortAware subscriber = (INeutronPortAware)entry;
+                    subscriber.neutronPortCreated(port);
+                }
+               }
+        }
+    }
+
+    private void updatePort(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        Map<String, NeutronPort> originalPortMap = getChangedPorts(changes.getOriginalData());
+        for (Entry<InstanceIdentifier<?>, DataObject> updatePort : changes.getUpdatedData().entrySet()) {
+            if (updatePort.getValue() instanceof Port) {
+                NeutronPort port = fromMd((Port)updatePort.getValue());
+                NeutronPort originalPort = originalPortMap.get(port.getID());
+                if (originalPort != null) {
+                    port.setOriginalPort(originalPort);
+                } else {
+                    LOG.warn("Original Port data is missing");
+                }
+                for (Object entry: subscribers) {
+                    INeutronPortAware subscriber = (INeutronPortAware)entry;
+                    subscriber.neutronPortUpdated(port);
+                }
+            }
+        }
+    }
+
+    private void deletePort(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedPortPath : changes.getRemovedPaths()) {
+            if(deletedPortPath.getTargetType().equals(Port.class)){
+                NeutronPort port = fromMd((Port)changes.getOriginalData().get(deletedPortPath));
+                for(Object entry: subscribers){
+                    INeutronPortAware subscriber = (INeutronPortAware)entry;
+                    subscriber.neutronPortDeleted(port);
+                }
+            }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronPortInterface.java class of Neutron Northbound class.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronPort fromMd(Port port) {
+
+        NeutronPort result = new NeutronPort();
+        result.setAdminStateUp(port.isAdminStateUp());
+        if (port.getAllowedAddressPairs() != null) {
+            List<NeutronPort_AllowedAddressPairs> pairs = new ArrayList<NeutronPort_AllowedAddressPairs>();
+            for (AllowedAddressPairs mdPair : port.getAllowedAddressPairs()) {
+                NeutronPort_AllowedAddressPairs pair = new NeutronPort_AllowedAddressPairs();
+                pair.setIpAddress(mdPair.getIpAddress());
+                pair.setMacAddress(mdPair.getMacAddress());
+                pair.setPortID(mdPair.getPortId());
+                pairs.add(pair);
+            }
+            result.setAllowedAddressPairs(pairs);
+        }
+        result.setDeviceID(port.getDeviceId());
+        result.setDeviceOwner(port.getDeviceOwner());
+        if (port.getExtraDhcpOpts() != null) {
+            List<NeutronPort_ExtraDHCPOption> options = new ArrayList<NeutronPort_ExtraDHCPOption>();
+            for (ExtraDhcpOpts opt : port.getExtraDhcpOpts()) {
+                NeutronPort_ExtraDHCPOption arg = new NeutronPort_ExtraDHCPOption();
+                arg.setName(opt.getOptName());
+                arg.setValue(opt.getOptValue());
+                options.add(arg);
+            }
+            result.setExtraDHCPOptions(options);
+        }
+        if (port.getFixedIps() != null) {
+            List<Neutron_IPs> ips = new ArrayList<Neutron_IPs>();
+            for (FixedIps mdIP : port.getFixedIps()) {
+                Neutron_IPs ip = new Neutron_IPs();
+                ip.setIpAddress(String.valueOf(mdIP.getIpAddress().getValue()));
+                ip.setSubnetUUID(mdIP.getSubnetId().getValue());
+                ips.add(ip);
+            }
+            result.setFixedIPs(ips);
+        }
+        result.setMacAddress(port.getMacAddress());
+        result.setName(port.getName());
+        result.setNetworkUUID(String.valueOf(port.getNetworkId().getValue()));
+        if (port.getSecurityGroups() != null) {
+            Set<NeutronSecurityGroup> allGroups = new HashSet<NeutronSecurityGroup>();
+            NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces().fetchINeutronSecurityGroupCRUD(this);
+            INeutronSecurityGroupCRUD sgIf = interfaces.getSecurityGroupInterface();
+            for (Uuid sgUuid : port.getSecurityGroups()) {
+                allGroups.add(sgIf.getNeutronSecurityGroup(sgUuid.getValue()));
+            }
+            List<NeutronSecurityGroup> groups = new ArrayList<NeutronSecurityGroup>();
+            groups.addAll(allGroups);
+            result.setSecurityGroups(groups);
+        }
+        result.setStatus(port.getStatus());
+        if (port.getTenantId() != null) {
+            result.setTenantID(String.valueOf(port.getTenantId().getValue()).replace("-", ""));
+        }
+        result.setPortUUID(String.valueOf(port.getUuid().getValue()));
+        addExtensions(port, result);
+        return result;
+    }
+
+    protected void addExtensions(Port port, NeutronPort result) {
+        PortBindingExtension binding = port.getAugmentation(PortBindingExtension.class);
+        result.setBindinghostID(binding.getHostId());
+        if (binding.getVifDetails() != null) {
+            List<NeutronPort_VIFDetail> details = new ArrayList<NeutronPort_VIFDetail>();
+            for (VifDetails vifDetail : binding.getVifDetails()) {
+                NeutronPort_VIFDetail detail = new NeutronPort_VIFDetail();
+                detail.setPortFilter(vifDetail.isPortFilter());
+                detail.setOvsHybridPlug(vifDetail.isOvsHybridPlug());
+                details.add(detail);
+            }
+            result.setVIFDetail(details);
+        }
+        result.setBindingvifType(binding.getVifType());
+        result.setBindingvnicType(binding.getVnicType());
+    }
+
+    private  Map<String,NeutronPort> getChangedPorts(Map<InstanceIdentifier<?>, DataObject> changedData) {
+        LOG.trace("getChangedPorts:" + changedData);
+        Map<String,NeutronPort> portMap = new HashMap<String,NeutronPort>();
+        for (Map.Entry<InstanceIdentifier<?>, DataObject> changed : changedData.entrySet()) {
+            if (changed.getValue() instanceof Port) {
+                NeutronPort port = fromMd((Port)changed.getValue());
+                portMap.put(port.getID(), port);
+            }
+        }
+        return portMap;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronRouterChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronRouterChangeListener.java
new file mode 100644 (file)
index 0000000..5ad885d
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_NetworkReference;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronRouterAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.external_gateway_info.ExternalFixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronRouterChangeListener implements DataChangeListener, AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterChangeListener.class);
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronRouterChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Router> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Routers.class)
+                .child(Router.class);
+        LOG.debug("Register listener for Neutron Router model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}",changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronRouterAware.class, this);
+        createRouter(changes, subscribers);
+        updateRouter(changes, subscribers);
+        deleteRouter(changes, subscribers);
+    }
+
+    private void createRouter(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newRouter : changes.getCreatedData().entrySet()) {
+               if(newRouter.getValue() instanceof Router){
+                NeutronRouter router = fromMd((Router)newRouter.getValue());
+                for(Object entry: subscribers){
+                    INeutronRouterAware subscriber = (INeutronRouterAware)entry;
+                    subscriber.neutronRouterCreated(router);
+                }
+               }
+        }
+
+    }
+
+    private void updateRouter(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updateRouter : changes.getUpdatedData().entrySet()) {
+               if(updateRouter.getValue() instanceof Router){
+                NeutronRouter router = fromMd((Router)updateRouter.getValue());
+                for(Object entry: subscribers){
+                    INeutronRouterAware subscriber = (INeutronRouterAware)entry;
+                    subscriber.neutronRouterUpdated(router);
+                }
+               }
+        }
+    }
+
+    private void deleteRouter(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedRouterPath : changes.getRemovedPaths()) {
+               if(deletedRouterPath.getTargetType().equals(Router.class)){
+                NeutronRouter router = fromMd((Router)changes.getOriginalData().get(deletedRouterPath));
+                for(Object entry: subscribers){
+                    INeutronRouterAware subscriber = (INeutronRouterAware)entry;
+                    subscriber.neutronRouterDeleted(router);
+                }
+               }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronRouterInterface.java class of Neutron Northbound class.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronRouter fromMd(Router router) {
+        NeutronRouter result = new NeutronRouter();
+        result.setID(String.valueOf(router.getUuid().getValue()));
+        result.setName(router.getName());
+        result.setTenantID(String.valueOf(router.getTenantId().getValue()));
+        result.setAdminStateUp(router.isAdminStateUp());
+        result.setStatus(router.getStatus());
+        result.setDistributed(router.isDistributed());
+        if (router.getGatewayPortId() != null) {
+            result.setGatewayPortId(String.valueOf(router.getGatewayPortId().getValue()));
+        }
+        if (router.getRoutes() != null) {
+            List<String> routes = new ArrayList<String>();
+            for (String route : router.getRoutes()) {
+                routes.add(route);
+            }
+            result.setRoutes(routes);
+        }
+
+        if (router.getExternalGatewayInfo() != null) {
+            NeutronRouter_NetworkReference extGwInfo = new NeutronRouter_NetworkReference();
+            extGwInfo.setNetworkID(String.valueOf(router.getExternalGatewayInfo().getExternalNetworkId().getValue()));
+            extGwInfo.setEnableSNAT(router.getExternalGatewayInfo().isEnableSnat());
+            if (router.getExternalGatewayInfo().getExternalFixedIps() != null) {
+                List<Neutron_IPs> fixedIPs = new ArrayList<Neutron_IPs>();
+                for (ExternalFixedIps mdFixedIP : router.getExternalGatewayInfo().getExternalFixedIps()) {
+                     Neutron_IPs fixedIP = new Neutron_IPs();
+                     fixedIP.setSubnetUUID(String.valueOf(mdFixedIP.getSubnetId().getValue()));
+                     fixedIP.setIpAddress(String.valueOf(mdFixedIP.getIpAddress().getValue()));
+                     fixedIPs.add(fixedIP);
+                }
+                extGwInfo.setExternalFixedIPs(fixedIPs);
+            }
+            result.setExternalGatewayInfo(extGwInfo);
+        }
+
+        if (router.getInterfaces() != null) {
+            Map<String, NeutronRouter_Interface> interfaces = new HashMap<String, NeutronRouter_Interface>();
+            for (Interfaces mdInterface : router.getInterfaces()) {
+                NeutronRouter_Interface pojoInterface = new NeutronRouter_Interface();
+                String id = String.valueOf(mdInterface.getUuid().getValue());
+                pojoInterface.setID(id);
+                pojoInterface.setTenantID(String.valueOf(mdInterface.getTenantId().getValue()));
+                pojoInterface.setSubnetUUID(String.valueOf(mdInterface.getSubnetId().getValue()));
+                pojoInterface.setPortUUID(String.valueOf(mdInterface.getPortId().getValue()));
+                interfaces.put(id, pojoInterface);
+            }
+            result.setInterfaces(interfaces);
+        }
+        return result;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronSecurityGroupDataChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronSecurityGroupDataChangeListener.java
new file mode 100644 (file)
index 0000000..796d1b1
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityRuleCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityGroupAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.SecurityGroups;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroup;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronSecurityGroupDataChangeListener implements
+        DataChangeListener, AutoCloseable {
+    private static final Logger LOG = LoggerFactory
+            .getLogger(NeutronSecurityGroupDataChangeListener.class);
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronSecurityGroupDataChangeListener(DataBroker db) {
+        this.db = db;
+        InstanceIdentifier<SecurityGroup> path = InstanceIdentifier
+                .create(Neutron.class).child(SecurityGroups.class)
+                .child(SecurityGroup.class);
+        LOG.debug("Register listener for Neutron Secutiry group model data changes");
+        registration = this.db.registerDataChangeListener(
+                LogicalDatastoreType.CONFIGURATION, path, this,
+                DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}", changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(
+                INeutronSecurityGroupAware.class, this);
+        createSecurityGroup(changes, subscribers);
+        updateSecurityGroup(changes, subscribers);
+        deleteSecurityGroup(changes, subscribers);
+    }
+
+    private void createSecurityGroup(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newSecutiryGroup : changes
+                .getCreatedData().entrySet()) {
+            if (newSecutiryGroup.getValue() instanceof SecurityGroup) {
+                NeutronSecurityGroup secutiryGroup = fromMd((SecurityGroup) newSecutiryGroup
+                        .getValue());
+                for (Object entry : subscribers) {
+                    INeutronSecurityGroupAware subscriber = (INeutronSecurityGroupAware) entry;
+                    subscriber.neutronSecurityGroupCreated(secutiryGroup);
+                }
+            }
+        }
+
+    }
+
+    private void updateSecurityGroup(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updateSecurityGroup : changes
+                .getUpdatedData().entrySet()) {
+            if (updateSecurityGroup.getValue() instanceof SecurityGroup) {
+                NeutronSecurityGroup securityGroup = fromMd((SecurityGroup) updateSecurityGroup
+                        .getValue());
+                for (Object entry : subscribers) {
+                    INeutronSecurityGroupAware subscriber = (INeutronSecurityGroupAware) entry;
+                    subscriber.neutronSecurityGroupUpdated(securityGroup);
+                }
+            }
+        }
+    }
+
+    private void deleteSecurityGroup(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedSecurityGroup : changes
+                .getRemovedPaths()) {
+            if (deletedSecurityGroup.getTargetType()
+                    .equals(SecurityGroup.class)) {
+                NeutronSecurityGroup securityGroup = fromMd((SecurityGroup) changes
+                        .getOriginalData().get(deletedSecurityGroup));
+                for (Object entry : subscribers) {
+                    INeutronSecurityGroupAware subscriber = (INeutronSecurityGroupAware) entry;
+                    subscriber.neutronSecurityGroupDeleted(securityGroup);
+                }
+            }
+        }
+    }
+
+    private NeutronSecurityGroup fromMd(SecurityGroup group) {
+        NeutronSecurityGroup answer = new NeutronSecurityGroup();
+        if (group.getName() != null) {
+            answer.setSecurityGroupName(group.getName());
+        }
+        if (group.getDescription() != null) {
+            answer.setSecurityGroupDescription(group.getDescription());
+        }
+        if (group.getTenantId() != null) {
+            answer.setSecurityGroupTenantID(group.getTenantId().getValue()
+                    .replace("-", ""));
+        }
+        if (group.getSecurityRules() != null) {
+            NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+                    .fetchINeutronSecurityRuleCRUD(this);
+            INeutronSecurityRuleCRUD srCrud = interfaces
+                    .getSecurityRuleInterface();
+
+            List<NeutronSecurityRule> rules = new ArrayList<NeutronSecurityRule>();
+            for (Uuid uuid : group.getSecurityRules()) {
+                rules.add(srCrud.getNeutronSecurityRule(uuid.getValue()));
+            }
+            answer.setSecurityRules(rules);
+        }
+        if (group.getUuid() != null) {
+            answer.setID(group.getUuid().getValue());
+        }
+        return answer;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronSecurityRuleDataChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronSecurityRuleDataChangeListener.java
new file mode 100644 (file)
index 0000000..488b32d
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSecurityRuleAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolHttps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronSecurityRuleDataChangeListener implements DataChangeListener, AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityRuleDataChangeListener.class);
+
+    private static final ImmutableBiMap<Class<? extends DirectionBase>, String> DIRECTION_MAP
+            = new ImmutableBiMap.Builder<Class<? extends DirectionBase>, String>()
+            .put(DirectionEgress.class, "egress")
+            .put(DirectionIngress.class, "ingress").build();
+    private static final ImmutableBiMap<Class<? extends ProtocolBase>, String> PROTOCOL_MAP
+            = new ImmutableBiMap.Builder<Class<? extends ProtocolBase>, String>()
+            .put(ProtocolHttp.class, "HTTP")
+            .put(ProtocolHttps.class, "HTTPS")
+            .put(ProtocolIcmp.class, "ICMP")
+            .put(ProtocolTcp.class, "TCP")
+            .build();
+    private static final ImmutableBiMap<Class<? extends EthertypeBase>, String> ETHERTYPE_MAP
+            = new ImmutableBiMap.Builder<Class<? extends EthertypeBase>, String>()
+            .put(EthertypeV4.class, "v4")
+            .put(EthertypeV6.class, "v6")
+            .build();
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronSecurityRuleDataChangeListener(DataBroker db) {
+        this.db = db;
+        InstanceIdentifier<SecurityRule> path = InstanceIdentifier
+                .create(Neutron.class).child(SecurityRules.class)
+                .child(SecurityRule.class);
+        LOG.debug("Register listener for Neutron Secutiry rules model data changes");
+        registration = this.db.registerDataChangeListener(
+                LogicalDatastoreType.CONFIGURATION, path, this,
+                DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}", changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(
+                INeutronSecurityRuleAware.class, this);
+        createSecurityRule(changes, subscribers);
+        updateSecurityRule(changes, subscribers);
+        deleteSecurityRule(changes, subscribers);
+    }
+
+    private void createSecurityRule(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newSecutiryRule : changes
+                .getCreatedData().entrySet()) {
+            if (newSecutiryRule.getValue() instanceof SecurityRule) {
+                NeutronSecurityRule secutiryRule = fromMd((SecurityRule) newSecutiryRule
+                        .getValue());
+                for (Object entry : subscribers) {
+                    INeutronSecurityRuleAware subscriber = (INeutronSecurityRuleAware) entry;
+                    subscriber.neutronSecurityRuleCreated(secutiryRule);
+                }
+            }
+        }
+
+    }
+
+    private void updateSecurityRule(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updateSecurityRule : changes
+                .getUpdatedData().entrySet()) {
+            if (updateSecurityRule.getValue() instanceof SecurityRule) {
+                NeutronSecurityRule securityRule = fromMd((SecurityRule) updateSecurityRule
+                        .getValue());
+                for (Object entry : subscribers) {
+                    INeutronSecurityRuleAware subscriber = (INeutronSecurityRuleAware) entry;
+                    subscriber.neutronSecurityRuleUpdated(securityRule);
+                }
+            }
+        }
+    }
+
+    private void deleteSecurityRule(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedSecurityRule : changes
+                .getRemovedPaths()) {
+            if (deletedSecurityRule.getTargetType().equals(SecurityRule.class)) {
+                NeutronSecurityRule securityRule = fromMd((SecurityRule) changes
+                        .getOriginalData().get(deletedSecurityRule));
+                for (Object entry : subscribers) {
+                    INeutronSecurityRuleAware subscriber = (INeutronSecurityRuleAware) entry;
+                    subscriber.neutronSecurityRuleDeleted(securityRule);
+                }
+            }
+        }
+    }
+
+    private NeutronSecurityRule fromMd(SecurityRule rule) {
+        NeutronSecurityRule answer = new NeutronSecurityRule();
+        if (rule.getTenantId() != null) {
+            answer.setSecurityRuleTenantID(rule.getTenantId().getValue()
+                    .replace("-", ""));
+        }
+        if (rule.getDirection() != null) {
+            answer.setSecurityRuleDirection(DIRECTION_MAP.get(rule
+                    .getDirection()));
+        }
+        if (rule.getSecurityGroupId() != null) {
+            answer.setSecurityRuleGroupID(rule.getSecurityGroupId().getValue());
+        }
+        if (rule.getRemoteGroupId() != null) {
+            answer.setSecurityRemoteGroupID(rule.getRemoteGroupId().getValue());
+        }
+        if (rule.getRemoteIpPrefix() != null) {
+            answer.setSecurityRuleRemoteIpPrefix(rule.getRemoteIpPrefix().getIpv4Prefix()!= null?
+                    rule.getRemoteIpPrefix().getIpv4Prefix().getValue():rule.getRemoteIpPrefix().getIpv6Prefix().getValue());
+        }
+        if (rule.getProtocol() != null) {
+            answer.setSecurityRuleProtocol(PROTOCOL_MAP.get(rule.getProtocol()));
+        }
+        if (rule.getEthertype() != null) {
+            answer.setSecurityRuleEthertype(ETHERTYPE_MAP.get(rule
+                    .getEthertype()));
+        }
+        if (rule.getPortRangeMin() != null) {
+            answer.setSecurityRulePortMin(Integer.valueOf(rule
+                    .getPortRangeMin()));
+        }
+        if (rule.getPortRangeMax() != null) {
+            answer.setSecurityRulePortMax(Integer.valueOf(rule
+                    .getPortRangeMax()));
+        }
+        if (rule.getId() != null) {
+            answer.setID(rule.getId().getValue());
+        }
+        return answer;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronSubnetChangeListener.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/translator/iaware/impl/NeutronSubnetChangeListener.java
new file mode 100644 (file)
index 0000000..7f3073a
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnetIPAllocationPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronSubnetAware;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Base;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Off;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Slaac;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Stateful;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.Dhcpv6Stateless;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.AllocationPools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableBiMap;
+
+public class NeutronSubnetChangeListener implements DataChangeListener, AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronSubnetChangeListener.class);
+
+    private static final ImmutableBiMap<Class<? extends IpVersionBase>,Integer> IPV_MAP
+    = new ImmutableBiMap.Builder<Class<? extends IpVersionBase>,Integer>()
+    .put(IpVersionV4.class,Integer.valueOf(4))
+    .put(IpVersionV6.class,Integer.valueOf(6))
+    .build();
+
+    private static final ImmutableBiMap<Class<? extends Dhcpv6Base>,String> DHCPV6_MAP
+    = new ImmutableBiMap.Builder<Class<? extends Dhcpv6Base>,String>()
+    .put(Dhcpv6Off.class,"off")
+    .put(Dhcpv6Stateful.class,"dhcpv6-stateful")
+    .put(Dhcpv6Slaac.class,"slaac")
+    .put(Dhcpv6Stateless.class,"dhcpv6-stateless")
+    .build();
+
+    private ListenerRegistration<DataChangeListener> registration;
+    private DataBroker db;
+
+    public NeutronSubnetChangeListener(DataBroker db){
+        this.db = db;
+        InstanceIdentifier<Subnet> path = InstanceIdentifier
+                .create(Neutron.class)
+                .child(Subnets.class)
+                .child(Subnet.class);
+        LOG.debug("Register listener for Neutron Subnet model data changes");
+        registration =
+                this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
+
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
+        LOG.trace("Data changes : {}",changes);
+
+        Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronSubnetAware.class, this);
+        createSubnet(changes, subscribers);
+        updateSubnet(changes, subscribers);
+        deleteSubnet(changes, subscribers);
+    }
+
+    private void createSubnet(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> newSubnet : changes.getCreatedData().entrySet()) {
+               if(newSubnet.getValue() instanceof Subnet){
+                NeutronSubnet subnet = fromMd((Subnet)newSubnet.getValue());
+                for(Object entry: subscribers){
+                    INeutronSubnetAware subscriber = (INeutronSubnetAware)entry;
+                    subscriber.neutronSubnetCreated(subnet);
+                }
+               }
+        }
+    }
+
+    private void updateSubnet(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (Entry<InstanceIdentifier<?>, DataObject> updateSubnet : changes.getUpdatedData().entrySet()) {
+               if(updateSubnet.getValue() instanceof Subnet){
+                NeutronSubnet subnet = fromMd((Subnet)updateSubnet.getValue());
+                for(Object entry: subscribers){
+                    INeutronSubnetAware subscriber = (INeutronSubnetAware)entry;
+                    subscriber.neutronSubnetUpdated(subnet);
+                }
+               }
+        }
+    }
+
+    private void deleteSubnet(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
+            Object[] subscribers) {
+        for (InstanceIdentifier<?> deletedSubnetPath : changes.getRemovedPaths()) {
+               if(deletedSubnetPath.getTargetType().equals(Subnet.class)){
+                NeutronSubnet subnet = fromMd((Subnet)changes.getOriginalData().get(deletedSubnetPath));
+                for(Object entry: subscribers){
+                    INeutronSubnetAware subscriber = (INeutronSubnetAware)entry;
+                    subscriber.neutronSubnetDeleted(subnet);
+                }
+               }
+        }
+    }
+
+    /*
+     * This method is borrowed from NeutronSubnetInterface.java class of Neutron Northbound class.
+     * We will be utilizing similar code from other classes from the same package of neutron project.
+     */
+    private NeutronSubnet fromMd(Subnet subnet) {
+        NeutronSubnet result = new NeutronSubnet();
+        result.setName(subnet.getName());
+        result.setTenantID(String.valueOf(subnet.getTenantId().getValue()).replace("-",""));
+        result.setNetworkUUID(subnet.getNetworkId().getValue());
+        result.setIpVersion(IPV_MAP.get(subnet.getIpVersion()));
+        result.setCidr(subnet.getCidr());
+        result.setGatewayIP(String.valueOf(subnet.getGatewayIp().getValue()));
+        result.setIpV6RaMode(DHCPV6_MAP.get(subnet.getIpv6RaMode()));
+        result.setIpV6AddressMode(DHCPV6_MAP.get(subnet.getIpv6AddressMode()));
+        result.setEnableDHCP(subnet.isEnableDhcp());
+        if (subnet.getAllocationPools() != null) {
+            List<NeutronSubnetIPAllocationPool> allocationPools = new ArrayList<NeutronSubnetIPAllocationPool>();
+            for (AllocationPools allocationPool : subnet.getAllocationPools()) {
+                NeutronSubnetIPAllocationPool pool = new NeutronSubnetIPAllocationPool();
+                pool.setPoolStart(allocationPool.getStart());
+                pool.setPoolEnd(allocationPool.getEnd());
+                allocationPools.add(pool);
+            }
+            result.setAllocationPools(allocationPools);
+        }
+        if (subnet.getDnsNameservers() != null) {
+            List<String> dnsNameServers = new ArrayList<String>();
+            for (IpAddress dnsNameServer : subnet.getDnsNameservers()) {
+                dnsNameServers.add(String.valueOf(dnsNameServer.getValue()));
+            }
+            result.setDnsNameservers(dnsNameServers);
+        }
+        result.setID(subnet.getUuid().getValue());
+
+        // read through the ports and put the ones in this subnet into the internal
+        // myPorts object.
+       Set<NeutronPort> allPorts = new HashSet<NeutronPort>();
+        NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces()
+            .fetchINeutronPortCRUD(this);
+        INeutronPortCRUD portIf = interfaces.getPortInterface();
+        for (NeutronPort port : portIf.getAllPorts()) {
+            if (port.getFixedIPs() != null) {
+                for (Neutron_IPs ip : port.getFixedIPs()) {
+                    if (ip.getSubnetUUID().equals(result.getID())) {
+                        allPorts.add(port);
+                    }
+                }
+            }
+        }
+        List<NeutronPort> ports = new ArrayList<NeutronPort>();
+        ports.addAll(allPorts);
+        result.setPorts(ports);
+        return result;
+    }
+
+    @Override
+    public void close() throws Exception {
+        registration.close();
+    }
+
+}
index 7eade3180980b713e1b6ad4527f2d6781e4d3393..9640e603d0881896952e83739e4eb8967af05061 100644 (file)
@@ -22,9 +22,9 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.NeutronFirewall;
-import org.opendaylight.neutron.spi.NeutronFirewallPolicy;
-import org.opendaylight.neutron.spi.NeutronFirewallRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewall;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallPolicy;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFirewallRule;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.osgi.framework.ServiceReference;
index e18b7a4f4b6c64851f605d7413bfc51cb11a2b4b..a3976def3c368eb6bf697f90f7921e5d5d6ee892 100644 (file)
@@ -21,7 +21,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.opendaylight.neutron.spi.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
index 42ff6d4c266647abb18d210b5199a1fc41872bb2..806231e004bd33b3698199247a03579f43322b90 100644 (file)
@@ -31,14 +31,14 @@ import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolCRUD;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
index 4cb99948a2b5f3a507f747b68c9457de8d412d2f..52458c6e9b6161015e647111db1e458cd2181ea4 100644 (file)
@@ -30,14 +30,14 @@ import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolCRUD;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
index 4bdce6ce0c75462756faaaf2cf8b147217757437..d9c99df1157fa55764f30be120f52c55da8ee4fd 100644 (file)
@@ -30,14 +30,14 @@ import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerCRUD;
-import org.opendaylight.neutron.spi.INeutronLoadBalancerPoolCRUD;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronLoadBalancer;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPool;
-import org.opendaylight.neutron.spi.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancer;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPool;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronLoadBalancerPoolMember;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerConfiguration;
index 8890cfaa9a1d2d11f584da7fd9d12cd5337cf331..455bee9cd1426a55744066b79491acc3d0d90fcf 100644 (file)
@@ -28,8 +28,8 @@ import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
index 87a8c69243bba1a235f2350f1ff5372217581868..61b9e10d906665e1dba0b9795b1d03e9d4f2123c 100644 (file)
@@ -19,13 +19,13 @@ import java.util.Map;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSubnet;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
 import org.powermock.modules.junit4.PowerMockRunner;
 
 /**
index fda2e76005c271847d23db3cebb7e0d0b616c606..9e1e4859d5083dd310e9e6f8eb2a49c96f4f64eb 100644 (file)
@@ -26,7 +26,7 @@ import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
index b3c4525af51387f2b949f796cc0e87b781b3a60b..b00c7a50291e5b185b63524f53d311eb84514b21 100644 (file)
@@ -22,8 +22,8 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityRule;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.osgi.framework.ServiceReference;
index a004864163662f1ec79f2b463f1d7080a4114eae..c993984100a1e603c9fa2fc2851e812b6d2a4afa 100644 (file)
@@ -21,8 +21,8 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.opendaylight.neutron.spi.NeutronRouter;
-import org.opendaylight.neutron.spi.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
index 57b94a319e804dc0809a531a19f7a11d9951f8d6..707929416132628cacfeefb9b8d3d77285a36a10 100644 (file)
@@ -25,7 +25,7 @@ import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
 import org.opendaylight.ovsdb.openstack.netvirt.SouthboundEvent.Type;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
index 543a4e03085f185d11056bcb9bdfaabdcaf51348..1ca405c209c213f50c0ede992502f902ab2393c3 100644 (file)
@@ -21,7 +21,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.opendaylight.neutron.spi.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
index 8c48b2709a22ac070ccf6af9351131c287169a0a..dec0f7358e6e5f2a0ada969bf58375130711da19 100644 (file)
@@ -34,7 +34,7 @@ import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbTables;
index 442863d691cd5b03bcc63650c7ac992c963acc81..521c7c6a23d40a95fe7e81660326af9d259bfdb6 100644 (file)
@@ -35,16 +35,16 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronFloatingIP;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronRouter;
-import org.opendaylight.neutron.spi.NeutronRouter_Interface;
-import org.opendaylight.neutron.spi.NeutronSubnet;
-import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronFloatingIP;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronRouter_Interface;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.ArpProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
index a3fa51bb19e86959fa7aa3245f25dbe28d4c6cc5..1888003e88a149e10be92e7358eb31c319d052bf 100644 (file)
@@ -23,9 +23,9 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
index 70cfd6c561bfdcbbb58b0f70210a7c2fd051b3a1..5a738a6a8d476bffe987171df31c35ab89573177 100644 (file)
@@ -26,10 +26,10 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.NeutronNetwork;
-import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
 import org.opendaylight.ovsdb.openstack.netvirt.api.VlanConfigurationCache;
index d30fdacb15f4ad0a9e7c652043c89a713423b99c..7ab12eff4d64a7d62d6f5930b6811f460b2534aa 100644 (file)
@@ -21,7 +21,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
index 14bfb76a1a891dd426d5cc91efb3c62abb450993..c42e7bbe198303f045b5861d0744e04d529e2a4c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-* Copyright (C) 2014 Red Hat, Inc.
+* Copyright (C) 2014 Red Hat, 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,
index 381a4b08c11c82199974f4a1368e74f5cd2de8c0..193042726789fefa26e46b4256bc639dd36d84ac 100644 (file)
@@ -32,10 +32,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
     </scm>
     <dependencies>
-        <dependency>
-            <groupId>org.opendaylight.dlux</groupId>
-            <artifactId>loader</artifactId>
-            <version>${dlux.loader.version}</version>
+      <dependency>
+        <groupId>org.opendaylight.dlux</groupId>
+          <artifactId>loader</artifactId>
+          <version>${dlux.version}</version>
         </dependency>
         <dependency>
           <groupId>org.opendaylight.ovsdb</groupId>
index fdaafdab73e691e6983ec1776f906ac5aa6c0b86..99eede7bf183608b10ecdb517f1ea68cac3fe2c1 100644 (file)
@@ -12,7 +12,9 @@
         <property name="angularJs" value="app.ovsdb"/>
         <property name="cssDependencies">
             <list>
-                <value>src/app/ovsdb/ovsdb.css</value>
+                <value>src/app/ovsdb/css/select2.min.css</value>
+                <value>src/app/ovsdb/css/toggle-switch.css</value>
+                <value>src/app/ovsdb/css/ovsdb.css</value>
             </list>
         </property>
     </bean>
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/Graph.js b/ovsdb-ui/module/src/main/resources/ovsdb/Graph.js
new file mode 100644 (file)
index 0000000..977e75b
--- /dev/null
@@ -0,0 +1,371 @@
+define(['app/ovsdb/lib/d3.min', 'app/ovsdb/OvsCore', 'app/ovsdb/matrix', 'underscore'], function(d3, OvsCore, Geom, _) {
+  'use strict';
+
+  var root = null,
+    forceLayout = null,
+    baseBB = null,
+    nodes = null,
+    links = null,
+    nodeData = [],
+    linkData = [],
+    drag = null,
+    nodePosCache = null;
+
+  function Graph(id, width, height) {
+    var x = d3.scale.linear()
+      .domain([0, width])
+      .range([0, width]);
+
+    var y = d3.scale.linear()
+      .domain([0, height])
+      .range([height, 0]);
+
+    var tmp = d3.select(id).append("svg")
+    .attr('width', width)
+    .attr('height', height)
+    .append("svg:g")
+    .attr('class', 'layer_0');
+
+    tmp.append('svg:rect')
+    .attr('width', width)
+    .attr('height', height)
+    .attr('fill', 'white');
+
+    root = tmp.call(d3.behavior.zoom().x(x).y(y).scaleExtent([1, 6]).on("zoom", zoom))
+      .append("g");
+
+    this.matrix = new Geom.Matrix();
+
+  //  this._bg = tmp.insert('svg:polygon', ':first-child');
+  //  this._bg.attr('id', 'ttt').attr('fill', 'rgb(250, 220, 220)').attr('stroke', 'rgb(250,0,0)');
+
+    drag = d3.behavior.drag()
+      .origin(function(d) {
+        return d;
+      })
+      .on("dragstart", dragstarted.bind(this))
+      .on("drag", dragmove.bind(this))
+      .on("dragend", dragend.bind(this));
+
+    // a layout for the bridge and his link
+    forceLayout = new d3.layout.force()
+      .gravity(0.05)
+      .charge(-400)
+      .linkDistance(80)
+      .size([width, height])
+      .on('tick', this.update.bind(this));
+
+    addDefs();
+  }
+
+  function zoom() {
+    root.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
+  }
+
+  function dragstarted(d) {
+    d3.event.sourceEvent.stopPropagation();
+    forceLayout.stop();
+  }
+
+  function dragmove(d) {
+    d.x += d3.event.dx;
+    d.y += d3.event.dy;
+    d.px += d3.event.dx;
+    d.py += d3.event.dy;
+    this.update();
+  }
+
+  function dragend(d) {
+    d.fixed = true;
+    this.update();
+    forceLayout.resume();
+    baseBB = null;
+  }
+
+  // Define reusable svg item like box-shadow
+  function addDefs() {
+    // box-shadow
+    var defs = d3.select('svg').insert('svg:defs', ':first-child');
+    var filter = defs.append('svg:filter').attr('id', 'selectNode').attr('x', '-20%').attr('y', '-20%').attr('width', '140%').attr('height', '140%');
+    filter.append('feGaussianBlur').attr('stdDeviation', '2').attr('result', 'coloredBlur');
+    var femerge = filter.append('feMerge');
+    femerge.append('feMergeNode').attr('in', 'coloredBlur');
+    femerge.append('feMergeNode').attr('in', 'SourceGraphic');
+  }
+
+  function sortLink(links) {
+    links.sort(function(a,b) {
+      if (a.source > b.source) {
+        return 1;
+      } else if (a.source < b.source) {
+        return -1;
+      }
+      else {
+        if (a.target > b.target) {
+          return 1;
+        }
+        if (a.target < b.target) {
+          return -1;
+        } else {
+          return 0;
+        }
+      }
+    });
+  }
+
+  function setLinkIndexAndNum(links) {
+    _.each(links, function(link, i) {
+      if (i != 0 && links[i].source == links[i-1].source &&
+        links[i].target == links[i-1].target) {
+          links[i].linkindex = links[i-1].linkindex + 1;
+        } else {
+          links[i].linkindex = 1;
+        }
+    });
+  }
+
+  // Properties to quick access and set nodes and links
+  Object.defineProperties(Graph.prototype, {
+    links: {
+      get: function() {
+        return links;
+      },
+      set: function(value) {
+        sortLink(value);
+        setLinkIndexAndNum(value);
+
+        forceLayout.links(value);
+        links = root.selectAll('links')
+          .data(value)
+          .enter().append('svg:path')
+          .attr('class', function(d) {
+            return d.linkType;
+          })
+          .attr('fill', 'none')
+          .attr('stroke-dasharray', function(d) {
+            return d.dashArray;
+          })
+          .attr('stroke-width', function(d) {
+            return d.width;
+          })
+          .attr('stroke', function(d) {
+            return d.color;
+          });
+      }
+    },
+    nodes: {
+      get: function() {
+        return nodes;
+      },
+      set: function(value) {
+        var _this = this; // context change in callback function and we need both
+
+        forceLayout.nodes(value);
+        nodes = root.selectAll('.nodes')
+          .data(value)
+          .enter().append('svg:g')
+          .call(drag)
+          .attr('class', function(d) {
+            return (d.node instanceof OvsCore.BridgeNode) ? 'bridge' : 'switch';
+          })
+          .on('click', function(d) {
+            if (d3.event.defaultPrevented) return;
+            _this.onNodeClick(d, nodes, links, this);
+          })
+          .on("mouseover", function(d) {
+            _this.onNodeOver(d, nodes, links, this);
+          })
+          .on("mouseout", function(d) {
+            _this.onNodeOut(d, nodes, links, this);
+          });
+
+        nodes.append('text')
+          .attr('x', 0)
+          .attr('y', 30)
+          .attr('fill', 'black')
+          .attr('text-anchor', 'middle')
+          .text(function(d) {
+            if (d.node instanceof OvsCore.BridgeNode)
+              return d.node.flowInfo.ip;
+            else
+              return d.node.otherLocalIp;
+          });
+
+        //svg node
+        var layer = d3.selectAll('g.switch').append('svg:g').attr('class', 'switch').attr('transform', 'translate(-16 -16)');
+        layer.append('svg:rect').style('fill-rule', 'evenodd').attr('ry', '3.6808').attr('height', '28.901')
+          .attr('width', '28.784').style('stroke', '#002b69').attr('y', '0').attr('x', '0').style('stroke-width', "3px").style('fill', '#2a7fff');
+        layer.append('svg:path').attr('d', 'm27.043 6.2-5.0754 3.3764-.01018-2.1082-5.9209-.022.01773-2.6018 5.9031-.037.08118-2.1164z').style('fill', "#002b69");
+        layer.append('svg:path').attr('d', "m26.866 19.4-5.0754 3.3764-.01018-2.1082-5.9209-.022.01773-2.6018 5.9031-.037.08118-2.1164z").style('fill', "#002b69");
+        layer.append('svg:path').attr('d', "m3.0872 11.6 5.0754 3.3764.01018-2.1082 5.9209-.022-.01773-2.6018-5.9031-.037-.08118-2.1164z").style('fill', "#002b69");
+        layer.append('svg:path').attr('d', "m3.2639 24.8 5.0754 3.3764.01018-2.1082 5.9209-.022-.01773-2.6018-5.9031-.037-.08118-2.1164z").style('fill', "#002b69");
+
+        //svg bridge
+        var layer = d3.selectAll('g.bridge').append('svg:g').attr('transform', 'translate(-16 -16)');
+        layer.append('svg:path').style('fill', '#d40000').style('stroke', '#ff0000').style('stroke-width', '0.10413094')
+          .style('stroke-linecap', 'round') //stroke-linejoin:round
+          .attr('d', 'm 2.9656662,3.4868 c 4.8978761,7.5117 16.2156478,6.1742 21.9929178,2.0807 l 2.154019,-1.5814 -0.08265,18.1941 -2.055088,2.0313 -24.17161713,0.055 -0.0255688,-18.6893 z');
+        layer.append('svg:path').style('fill', '#ff5555').style('stroke', '#ff0000').style('stroke-width', '0.10413094')
+          .style('stroke-linecap', 'round') //stroke-linejoin:round
+          .attr('d', 'm 0.83642587,5.5637 c 4.89787603,7.5117 18.41115613,4.1109 24.18842613,0.018 l -0.06627,18.6546 -24.12215693,0 z');
+      }
+    }
+  });
+
+  // Update the node and link position on the canvas
+  Graph.prototype.update = function(e) {
+    var k = 1 , //.1 * e.alpha
+      isDragging = (e !== null)
+/*
+    if (!isDragging) {
+      k = .1 * e.alpha;
+    }
+
+    if (!isDragging) {
+      forceLayout.nodes().forEach(function(o) {
+        var i = (o.node instanceof OvsCore.OvsNode) ? 1 : 0;
+        o.y += (layerAnchor[i].y - o.y) * k;
+        o.x += (layerAnchor[i].x - o.x) * k;
+      });
+    }*/
+
+    if (links) {
+      links.attr('d', (function(d) {
+        var srcT = this.matrix.transformPoint(d.source.x, d.source.y),
+          targetT = this.matrix.transformPoint(d.target.x, d.target.y),
+          src = {x:srcT.elements[0],y:srcT.elements[1]},
+          tgt = {x:targetT.elements[0],y:targetT.elements[1]},
+          anchor1 = {}, anchor2 = {};
+
+        if (d.linkType === 'tunnel') {
+          // curve the line and arc it on a direction of a 90 degree vector
+          var perp = { x : -tgt.y, y: tgt.x};
+          var srcNorm = Math.sqrt(src.x * src.x + src.y * src.y);
+          var perpNorm = Math.sqrt(perp.x * perp.x + perp.y * perp.y);
+          var dy = (perp.y/perpNorm - src.y/srcNorm);
+          var dx = (perp.x/perpNorm - src.x/srcNorm);
+
+          anchor1 = {x: src.x - dx * 30, y: src.y - dy * 30 };
+          anchor2 = {x: tgt.x - dx * 30, y: tgt.y - dy * 30 };
+        } else {
+          // default strait line
+          anchor1 = src;
+          anchor2 = tgt;
+        }
+
+        return OvsCore.Util.String.Format('M{0},{1} C{2},{3} {4},{5} {6},{7}',
+          srcT.elements[0], srcT.elements[1],
+          anchor1.x, anchor1.y,
+          anchor2.x, anchor2.y,
+          targetT.elements[0], targetT.elements[1]
+        );
+      }).bind(this));
+    }
+
+    nodes.attr("transform", (function(d) {
+      var a = new Geom.Matrix.fromString(root.attr('transform'));
+      var tmp = Geom.Matrix.combine(a, this.matrix);
+
+      var transV = this.matrix.transformPoint(d.x, d.y);
+      var v = tmp.transformPoint(d.x, d.y);
+      d.pos = {
+        x: v.elements[0],
+        y: v.elements[1]
+      };
+      nodePosCache[d.node.nodeId] =  { pos: d.pos, fixed: d.fixed};
+      return "translate(" + transV.elements[0] + ',' + transV.elements[1] + ')';
+    }).bind(this));
+  };
+
+  Graph.prototype.setPosCache = function(cache) {
+    nodePosCache = cache;
+  };
+
+  // Apply few matrix transform to fake a perspective effet
+  Graph.prototype.applyPerspective = function(value) {
+    if (!baseBB)
+      baseBB = root.node().getBBox();
+
+    var padding = 50;
+    var persMatrix = new Geom.Matrix()
+      .translate(-(baseBB.x + baseBB.width / 2), -(baseBB.y + baseBB.height / 2))
+      .skew(-25, 0)
+      .scale(1, 0.6)
+      .translate(baseBB.x + baseBB.width / 2, baseBB.y + baseBB.height / 2);
+
+    this.matrix.transform = value ? this.matrix.transform.x(persMatrix.transform) : this.matrix.transform.x(persMatrix.transform.inverse());
+
+    var p1 = this.matrix.transformPoint(baseBB.x - padding, baseBB.y - padding);
+    var p2 = this.matrix.transformPoint(baseBB.x - padding, baseBB.y + baseBB.height + padding);
+    var p3 = this.matrix.transformPoint(baseBB.x + baseBB.width + padding, baseBB.y + baseBB.height + padding);
+    var p4 = this.matrix.transformPoint(baseBB.x + baseBB.width + padding, baseBB.y - padding);
+
+    this._bg.attr('points', OvsCore.Util.String.Format("{0},{1} {2},{3} {4},{5} {6},{7}",
+      p1.elements[0],
+      p1.elements[1],
+      //--
+      p2.elements[0],
+      p2.elements[1],
+      //--
+      p3.elements[0],
+      p3.elements[1],
+      //--
+      p4.elements[0],
+      p4.elements[1])).style('display', (value) ? 'block' : 'none');
+
+    this.update();
+  };
+
+  function positionateBaseOnCache() {
+    forceLayout.stop();
+    forceLayout.nodes().forEach(function(d) {
+      var nodeCached = nodePosCache[d.node.nodeId];
+      d.px = d.x = nodeCached.pos.x;
+      d.py = d.y = nodeCached.pos.y;
+      d.fixed = nodeCached.fixed;
+    });
+    forceLayout.resume();
+  }
+
+  // start the force layout
+  Graph.prototype.start = function() {
+    forceLayout.linkStrength(function(link) {
+      if (link.linkType === 'bridgeOvsLink') {
+        return 0;
+      }
+      return 1;
+    });
+    forceLayout.start();
+    if (_.size(nodePosCache) > 0) {
+      positionateBaseOnCache();
+    }
+  };
+
+  Graph.prototype.freeDOM = function() {
+    nodes.remove();
+    links.remove();
+    forceLayout.nodes([]);
+    forceLayout.links([]);
+  };
+
+  // Enable to manipulate attributes of the graph group node
+  Graph.prototype.attr = function(name, value) {
+    return root.attr(name, value);
+  };
+
+  // Enable the monipulate the css of the graph group node
+  Graph.prototype.style = function(name, value) {
+    return root.style(name, value);
+  };
+
+  Graph.prototype.selectAll = function(a) {
+    return root.selectAll(a);
+  };
+
+  // callback function
+  Graph.prototype.onNodeOver = _.noop;
+  Graph.prototype.onNodeOut = _.noop;
+  Graph.prototype.onNodeClick = _.noop;
+
+  return Graph;
+});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/LogicalGraph.js b/ovsdb-ui/module/src/main/resources/ovsdb/LogicalGraph.js
new file mode 100644 (file)
index 0000000..01dddbd
--- /dev/null
@@ -0,0 +1,489 @@
+define(['app/ovsdb/lib/d3.min', 'app/ovsdb/OvsCore', 'underscore'], function(d3, OvsCore, _) {
+  'use strict';
+
+  var root = null,
+    canvasWidth = -1,
+    canvasHeight = -1,
+    bbox = { x:0, y:15, width: 0, height: 0},
+    // config
+    nodeWidth = 15,
+    nodeHeight = -1,
+    defaultRouterWidth = 66,
+    defaultRouterHeight = 66,
+    networkMargin = { width: 120, height: 15},
+    routerMargin = { width: 120, height: 40},
+    vmMargin = { width: 90, height: 30},
+    defaultVmsWidth = 48,
+    defaultVmsHeight = 48,
+    ipNetworkTextMaxLength = 60,
+    networkOffset = 15,
+    linkHeight = 5,
+    // datas
+    networkData = [],
+    routerData = [],
+    vmData = [],
+    linkData = [],
+    tmpNetHolder = {},
+    // d3 layer over datas
+    d3Node = null,
+    d3Link = null,
+    d3Vm = null,
+    d3Router = null,
+    randomize = OvsCore.Util.Math.Random(42);
+
+  function LogicalGraph(id, width , height) {
+    canvasWidth = width;
+    canvasHeight = height;
+
+    nodeHeight = height - 15;
+
+    var tmp = d3.select(id).append("svg")
+    .attr('width', width)
+    .attr('height', height)
+    .append("svg:g")
+    .attr('class', 'layer_0');
+
+    tmp.append('svg:rect')
+    .attr('width', width)
+    .attr('height', height)
+    .attr('fill', 'white');
+
+    root = tmp.call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom))
+    .append("g");
+    tmp.on("dblclick.zoom", null);
+    addDefs();
+  }
+
+  // Define reusable svg item like box-shadow
+  function addDefs() {
+    // box-shadow
+    var defs = d3.select('svg').insert('svg:defs', ':first-child');
+    var filter = defs.append('svg:filter').attr('id', 'boxShadow').attr('x', '0').attr('y', '0').attr('width', '200%').attr('height', '200%');
+    filter.append('feOffset').attr('in', 'SourceAlpha').attr('result', 'offOut').attr('dx', 0).attr('dy', 0);
+    filter.append('feGaussianBlur').attr('stdDeviation', '5').attr('in','offOut').attr('result', 'blurOut');
+    filter.append('feOffset').attr('in', 'SourceGraphic').attr('in2', 'blurOut').attr('mode', 'normal');
+  }
+
+  function zoom() {
+    root.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
+  }
+
+  Object.defineProperties(LogicalGraph.prototype, {
+    networks: {
+      set: function(value) {
+        networkData = value;
+        value.forEach(function(net) {
+          routerData = routerData.concat(net.routers);
+        });
+        value.forEach(function(net) {
+          vmData = vmData.concat(net.instances);
+        });
+      }
+    }
+  });
+
+  LogicalGraph.prototype.start = function() {
+    setTopologyPosition.call(this, networkData);
+    addLinksToDom.call(this, linkData);
+    addNetWorkRouterVmsToDom.call(this, networkData, routerData, vmData);
+    update.call(this);
+  };
+
+  LogicalGraph.prototype.freeDOM = function() {
+    d3Node.remove();
+    d3Link.remove();
+    d3Vm.remove();
+    d3Router.remove();
+
+    networkData = [];
+    routerData = [];
+    vmData = [];
+    linkData = [];
+    bbox = { x:0, y:15, width: 0, height: 0};
+  };
+
+  function addLinksToDom(linksData) {
+      d3Link = root.selectAll('.llink')
+      .data(linksData).enter().append('svg:g');
+
+      d3Link.append('rect')
+      .attr('width', function(d) {
+        return d.target.x - d.source.x;
+      })
+      .attr('height', linkHeight)
+      .style('fill', function(d) {
+        return d.color;
+      });
+
+      d3Link.append('text')
+      .attr('x', 40)
+      .attr('y', -3)
+      .text(function(d) {return d.text;});
+  }
+
+  function addNetWorkRouterVmsToDom(networks, routers, vms) {
+    var ctx = this,
+      timer = null;
+
+    function getAbsPos() {
+      var elem = d3.select(this)[0][0],
+        elemAbsBBox = elem.getBoundingClientRect(),
+        parentAbsBox = d3.select('#l_graph').node().getBoundingClientRect(),
+        left = elemAbsBBox.left - parentAbsBox.left + (elemAbsBBox.right - elemAbsBBox.left),
+        top = elemAbsBBox.top  - parentAbsBox.top;
+
+      if (top < 0 ) {
+        top = 10;
+      }
+      var event = {
+         left : left,
+         top : top
+       };
+       return event;
+    }
+    d3Node = root.selectAll('.network')
+      .data(networks).enter()
+      .append('svg:g');
+    d3Router = root.selectAll('.routers')
+      .data(routers).enter()
+      .append('svg:g');
+    d3Vm = root.selectAll('.vm')
+      .data(vms).enter()
+      .append('svg:g');
+
+    // append coresponding form
+    d3Node.append('svg:rect')
+      .attr('width', nodeWidth)
+      .attr('height', nodeHeight)
+      .attr('rx', 10)
+      .attr('ry', 10)
+      .style('fill', function(d) {
+        return d.color;
+      }).on('click', function(d) {
+        if (d3.event.defaultPrevented) return;
+        timer = setTimeout(function() {
+          var e = getAbsPos.call(this);
+          ctx.onClick(e, d);
+        }.bind(this), 150);
+      }).on('dblclick', function(d) {
+        clearTimeout(timer);
+        ctx.dblClick(d);
+      });
+
+    // append the network name text
+    d3Node.append('text')
+      .attr('x', nodeWidth / 2 )
+      .attr('y', nodeHeight /2 )
+      .style('text-anchor', 'middle')
+      .style('writing-mode', 'tb')
+      .style('font-size', '12px')
+      .style('glyph-orientation-vertical', '0')
+      .text(function(d) { return d.name; });
+
+    // text info for the network ip
+    d3Node.append('text')
+      .attr('x', nodeWidth + 10)
+      .attr('y', nodeHeight - 15)
+      .attr('transform',
+        OvsCore.Util.String.Format('translate({0} {1}) rotate(-90) translate(-{0} -{1})', nodeWidth + 10, nodeHeight - 15))
+      .attr('class', 'linfolabel')
+      .text(function(d) {return d.ip;});
+
+    // vm
+    d3Vm.append('svg:image')
+      .attr('width', defaultVmsWidth)
+      .attr('height', defaultVmsHeight)
+      .attr('filter', 'url(#boxShadow)')
+      .attr('xlink:href', function(d) {
+        return d.type === 'network:dhcp' ?
+          'src/app/ovsdb/assets/dhcp.png' : 'src/app/ovsdb/assets/vm.png';
+      })
+      .on('click', function(d) {
+        if (d3.event.defaultPrevented) return;
+        timer = setTimeout(function() {
+          var e = getAbsPos.call(this);
+          ctx.onClick(e, d);
+        }.bind(this), 150);
+      }).on('dblclick', function(d) {
+        clearTimeout(timer);
+        ctx.dblClick(d);
+      });
+
+    // router
+    d3Router.append('svg:image')
+      .attr('width', defaultRouterWidth)
+      .attr('height', defaultRouterHeight)
+      .attr('xlink:href', 'src/app/ovsdb/assets/router.png')
+      .on('click', function(d) {
+        if (d3.event.defaultPrevented) return;
+        timer = setTimeout(function() {
+          var e = getAbsPos.call(this);
+          ctx.onClick(e, d);
+        }.bind(this), 150);
+      }).on('dblclick', function(d) {
+        clearTimeout(timer);
+        ctx.dblClick(d);
+      });
+
+    // router name label
+    d3Router.append('text')
+      .attr('x', defaultRouterWidth * 0.5)
+      .attr('y', defaultRouterHeight + 15)
+      .attr('text-anchor', 'middle')
+      .attr('class', 'linfolabel')
+      .text(function(d) { return d.name; });
+
+    // vm name label
+    d3Vm.append('text')
+      .attr('x', defaultVmsWidth * 0.5)
+      .attr('y', defaultVmsHeight + 15)
+      .attr('text-anchor', 'middle')
+      .attr('class', 'linfolabel')
+      .text(function(d) { return d.name; });
+
+    // vm floating ip label
+    d3Vm.append('text')
+      .attr('x', -35)
+      .attr('y', 40)
+      .attr('text-anchor', 'middle')
+      .text(function(d) {
+        return (d.floatingIp) ? d.floatingIp.ip : '';
+      });
+
+  }
+
+  function findNetworkWithRouter(router) {
+    var result = [];
+    _.each(router.interfaces, function(inter) {
+      if (inter.type === 'router_interface') {
+        var net  = tmpNetHolder[inter.networkId] || null;
+
+        if (net) {
+          result.push({network: net, interface: inter});
+        }
+      }
+    });
+
+    return result;
+  }
+
+  function positionateNetwork(network, x, y, margin) {
+    network.x = x;
+    network.y = y;
+    margin = margin || 0;
+    network.color = d3.hsl(randomize.next() * 360, 1, 0.6).toString();
+
+    // look is the network is the highest
+    bbox.height = network.y > bbox.height ? network.y : bbox.height ;
+    bbox.width = network.x > bbox.width ? network.x : bbox.width;
+
+    // get the number of "childs" (router, vm)
+    var nbRouter = network.routers.length;
+    var nbVm = network.instances.length;
+
+    if (!network.external) {
+      _.each(network.subnets, function(subnet, i) {
+        network.ip += subnet.cidr;
+        if (i < network.subnets.length -1) {
+            network.ip += ', ';
+        }
+      });
+    }
+
+    // if needed, ajust the height of the network
+    // to be able to display all children
+    ajustHeighBaseOnChilds(nbRouter, nbVm);
+
+    var py = positionateRouter(network, x + routerMargin.width, y + margin);
+
+    positionateVm(network, x + vmMargin.width, py + 35 + margin);
+    delete tmpNetHolder[network.id];
+  }
+
+  function positionateRouter(network, x, y) {
+    var px = x,
+      py = y ;
+
+    // loop over all routers
+    _.each(network.routers, function(router, i) {
+      router.x = getRouterCentroid(x, py).x ;
+      router.y = py;
+      py += getRouterMarginHeight();
+
+      if (network.external) {
+        // find network ip with the gateway ip
+        var gateway = router.externalGateway.external_fixed_ips[0].ip_address;
+        var netIp = gateway.slice(0, gateway.lastIndexOf('.')) + '.0';
+        network.ip = netIp;
+      }
+
+      // look is the router is the highest
+      bbox.height = router.y > bbox.height ? router.y : bbox.height ;
+      bbox.width = router.x > bbox.width ? router.x : bbox.width;
+
+      linkData.push({
+        source: {x: network.x + (nodeWidth * 0.5), y: router.y + (defaultRouterHeight * 0.5)},
+        target: {x: router.x + (defaultRouterWidth * 0.5), y: router.y + (nodeWidth * 0.5)},
+        color:  network.color,
+        text: router.externalGateway.external_fixed_ips[0].ip_address
+      });
+
+      // go to the next layer
+      var nets = findNetworkWithRouter(router),
+        step = defaultRouterHeight / (nets.length + 1);
+
+      _.forEach(nets, function(net, i) {
+        var netPos = getNetworkLayerPosition(bbox.width + defaultRouterWidth);
+
+        positionateNetwork(net.network, netPos.x, netPos.y);
+        linkData.push({
+          source: {x: router.x + (2 * nodeWidth), y: router.y + step * (i + 1) },
+          target: {x: net.network.x + (nodeWidth * 0.5), y: router.y + (nodeWidth * 0.5 )},
+          color: net.network.color,
+          text: net.interface.ip.ip_address
+        });
+      });
+    });
+    return py;
+  }
+
+  function positionateVm(network, x, y) {
+
+    // I do vm before router because router
+    // will step to another BUS
+    _.each(network.instances, function(vm) {
+      vm.x = x;
+      vm.y = y;
+
+      // look is the network is the highest
+      bbox.height = vm.y > bbox.height ? vm.y : bbox.height ;
+      bbox.width = vm.x > bbox.width ? vm.x : bbox.width;
+
+      y += getVmMarginHeight();
+      linkData.push({
+        source: {x: network.x + (nodeWidth * 0.5), y: vm.y + (defaultVmsHeight * 0.5 )},
+        target: {x: vm.x + (defaultVmsWidth * 0.5), y: vm.y + (nodeWidth * 0.5)},
+        color:  network.color,
+        text: vm.ip
+      });
+    });
+  }
+
+  /*
+  *  Scan the whole "BUS" to display it properly
+  * ------------------------------------------------
+  *  I build it in a virtual space, if it need to be
+  *  resize it at the end when the overal bounding
+  *  box is known
+  */
+  function setTopologyPosition(networks) {
+    _.each(networks, function(net) {
+      tmpNetHolder[net.id] = net;
+    });
+
+    var i = 0;
+    for(var key in tmpNetHolder) {
+        var margin = (i === 0) ? 5 : networkMargin.width,
+          net = tmpNetHolder[key];
+        if (net.routers.length > 0) {
+          positionateNetwork(net, bbox.x + bbox.width + margin, bbox.y);
+          ++i;
+        }
+    }
+
+    for(var key in tmpNetHolder) {
+        var margin = networkMargin.width,
+          net = tmpNetHolder[key];
+          positionateNetwork(net, bbox.x + bbox.width + margin, bbox.y);
+    }
+  }
+
+  /*
+  * Check and ajust the height for a network.
+  */
+  function ajustHeighBaseOnChilds(nbRouter, nbVm) {
+    // calculate the height for the number of childs
+    var childHeight = nbRouter * (getRouterMarginHeight()) +
+      nbVm * (getVmMarginHeight()) + ipNetworkTextMaxLength;
+
+    // if heigh bigger than the default network height resize it
+    if (childHeight > nodeHeight) {
+      nodeHeight = childHeight + networkOffset;
+    }
+  }
+
+  /*
+  * Set the view to the modal position
+  */
+  function update() {
+
+    d3Node.attr('transform', function(d) {
+      return OvsCore.Util.String.Format("translate({0}, {1})",
+        d.x, d.y
+      );
+    });
+
+    d3Router.attr('transform', function(d, i) {
+      return OvsCore.Util.String.Format("translate({0}, {1})",
+        d.x, d.y
+      );
+    });
+
+    d3Vm.attr('transform', function(d) {
+      return OvsCore.Util.String.Format("translate({0}, {1})",
+        d.x, d.y
+      );
+    });
+
+    d3Link.attr('transform', function(d) {
+      return OvsCore.Util.String.Format("translate({0}, {1})",
+        d.source.x, d.source.y
+      );
+    });
+
+    // resize the graph if bigger than the canvas
+    var bbox = root.node().getBBox();
+    if (bbox.width > canvasWidth || bbox.height > canvasHeight) {
+      var sx = (canvasWidth - 30) / bbox.width,
+        sy = (canvasHeight - 30) / bbox.height,
+        s = sx < sy ? sx : sy;
+      d3.select('.layer_0').attr('transform', 'scale(' + s + ')');
+      console.log(root.node().getBBox());
+    }
+  }
+
+  function getRouterCentroid(x, y) {
+    return {
+      x : x + defaultRouterWidth * 0.5,
+      y : y + defaultRouterHeight * 0.5
+    };
+  }
+
+  function getRouterMarginHeight() {
+    return (defaultRouterHeight + routerMargin.height);
+  }
+
+  function getVmMarginHeight() {
+    return (defaultVmsHeight + vmMargin.height);
+  }
+
+  function getNetworkLayerPosition(x) {
+    return {
+      x : x + networkMargin.width,
+      y : networkMargin.height
+    };
+  }
+
+  function getVmLayerPosition(nbRouter, x) {
+    var t =  {
+      x : x + vmMargin.width * 2,
+      y : getRoutersDim(nbRouter).height + getVmMarginHeight()
+    };
+    return t;
+  }
+
+  LogicalGraph.prototype.onClick = _.noop;
+  LogicalGraph.prototype.dblClick = _.noop;
+
+  return LogicalGraph;
+});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/OvsCore.js b/ovsdb-ui/module/src/main/resources/ovsdb/OvsCore.js
new file mode 100644 (file)
index 0000000..5d3d402
--- /dev/null
@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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
+ */
+
+define(['underscore'], function (_) {
+
+  var Topology = (function () {
+
+    function Topology(topoId) {
+      this.topoId = topoId || '';
+      this._bridgeNodes = {};
+      this._ovsdbNodes = {};
+      this._links = {};
+    }
+
+    Object.defineProperties(Topology.prototype, {
+      bridgeNodes: {
+        get: function () {
+          return this._bridgeNodes;
+        }
+      },
+      nodes: {
+        get: function() {
+          return _.extend({}, this._bridgeNodes, this._ovsdbNodes);
+        }
+      },
+      ovsdbNodes: {
+        get: function () {
+          return this._ovsdbNodes;
+        }
+      },
+      links: {
+        get: function () {
+          return this._links;
+        }
+      }
+    });
+
+    Topology.prototype.registerBridgeNode = function (bridgeNode) {
+      this._bridgeNodes[bridgeNode.nodeId] = bridgeNode;
+    };
+
+    Topology.prototype.registerOvsdbNode = function (ovsdbNode) {
+      this._ovsdbNodes[ovsdbNode.nodeId] = ovsdbNode;
+    };
+
+    Topology.prototype.registerLink = function (link) {
+      if (this._links[link.linkId]) {
+        console.warn('Two links have the same id (' + link.linkId + '), the first one will be overrided');
+      }
+      this._links[link.linkId] = link;
+    };
+
+    Topology.prototype.updateLink = function () {
+      _.each(this._links, (function (link, key) {
+        if (link instanceof Link) {
+          srcNode = _.filter(this._bridgeNodes, function(node) {
+            return node.getFLowName() === link.srcNodeId;
+          });
+          destNode = _.filter(this._bridgeNodes, function(node) {
+            return node.getFLowName() === link.destNodeId;
+          });
+          link.srcNodeId = srcNode[0].nodeId;
+          link.destNodeId = destNode[0].nodeId;
+        }
+        link.source = Object.keys(this.nodes).indexOf(link.srcNodeId);
+        link.target = Object.keys(this.nodes).indexOf(link.destNodeId);
+
+      }).bind(this));
+    };
+
+    return Topology;
+  })();
+
+  var OvsNode = (function () {
+    function OvsNode(nodeId, inetMgr, inetNode, otherLocalIp, ovsVersion) {
+      this.nodeId = nodeId;
+      this.inetMgr = inetMgr;
+      this.inetNode = inetNode;
+      this.otherLocalIp = otherLocalIp;
+      this.ovsVersion = ovsVersion;
+    }
+
+    OvsNode.prototype.showIpAdress = function() {
+      return this.otherLocalIp;
+    };
+
+    OvsNode.prototype.pretty = function() {
+      return {
+        'tabs' : ['Info'],
+        'containts' : [ {
+          'hasHeader' : false,
+          'headers' : [],
+          'datas' : [
+            { key: 'ID', value: this.nodeId},
+            { key: 'InetMgr', value: this.inetMgr},
+            { key: 'InetNode', value: this.inetNode},
+            { key: 'Local IP', value: this.otherLocalIp},
+            { key: 'OVS Version', value: this.ovsVersion}
+          ]
+        }]
+      };
+    };
+
+    return OvsNode;
+  })();
+
+  var BridgeNode = (function () {
+
+    function BridgeNode(nodeId, dpIp, name, controllerTarget, controllerConnected) {
+      this.nodeId = nodeId;
+      this.dpIp = dpIp;
+      this.name = name;
+      this.controllerTarget = controllerTarget;
+      this.controllerConnected = controllerConnected;
+      this._tpList = [];
+      this.flowInfo = {};
+      this.flowTable = [];
+    }
+
+    Object.defineProperties(BridgeNode.prototype, {
+      tPs: {
+        get: function () {
+          return this._tpList;
+        }
+      },
+    });
+
+    var dpToFlow = function (dpId) {
+      return 'openflow:' + parseInt(dpId.replace(/:/g, ''), 16);
+    };
+
+    BridgeNode.prototype.getFLowName = function () {
+      return (!this.dpIp) ? this.nodeId : dpToFlow(this.dpIp);
+    };
+
+    BridgeNode.prototype.addTerminationPoint = function (tp) {
+      this._tpList.push(tp);
+      this._tpList.sort(function(tp1, tp2) {
+        return tp1.ofPort - tp2.ofPort;
+      });
+    };
+
+    BridgeNode.prototype.addFlowTableInfo = function(flowTable) {
+      this.flowTable.push(flowTable);
+      this.flowTable.sort(function(ft1, ft2) {
+        return ft1.key - ft2.key;
+      });
+    };
+
+    BridgeNode.prototype.pretty = function() {
+      return {
+        'tabs' : [
+          'Basic Info',
+          'Ports',
+          'Flow Info',
+          'Flow Tables'
+        ],
+        'containts' : [
+          {
+            'hasHeader' : false,
+            'headers' : [],
+            'datas' : [
+              { key: 'ID', value: this.nodeId},
+              { key: 'Name', value: this.name},
+              { key: 'OpenFlow Name', value: this.getFLowName()},
+              { key: 'Controller Target', value: this.controllerTarget},
+              { key: 'Controller Connected', value: this.controllerConnected}
+            ]
+          },
+          {
+            'hasHeader' : true,
+            'header' : ['Of Port', 'Name', 'Mac', 'IFace Id',],
+            'datas' : this._tpList.map(function(s) {
+              return [s.ofPort, s.name, s.mac, s.ifaceId];
+            })
+          },
+          {
+              'hasHeader' : false,
+              'headers' : [],
+              'datas': [
+                {key : 'Manufacturer', value: this.flowInfo.manufacturer},
+                {key : 'Hardware', value: this.flowInfo.hardware},
+                {key : 'Software', value: this.flowInfo.software},
+                {key : 'Feature', value: this.flowInfo.features},
+                {key : 'Ip', value: this.flowInfo.ip}
+              ]
+          },
+          {
+            'hasHeader' : true,
+            'headers' : ['Table Id', 'Value'],
+            'datas' :this.flowTable.map(function(t) {
+              return [t.key, t.value];
+            })
+          }
+        ]
+      };
+    };
+
+    return BridgeNode;
+  })();
+
+  var TerminationPoint = (function () {
+    function TerminationPoint(name, ofPort, tpType, mac, ifaceId) {
+      this.name = name;
+      this.ofPort = ofPort;
+      this.tpType = tpType;
+      this.mac = mac || '';
+      this.ifaceId = ifaceId || '';
+    }
+    return TerminationPoint;
+  })();
+
+  var BaseLink = (function() {
+    function BaseLink(linkId, srcNodeId, destNodeId, linkType, styles) {
+      this.linkId = linkId;
+      this.srcNodeId = srcNodeId;
+      this.destNodeId = destNodeId;
+      this.linkType  = linkType;
+
+      // styling
+      styles = _.extend({}, styles);
+      this.color = styles.color;
+      this.width = styles.width || 1;
+      this.dashArray = styles.dashArray || 'None';
+
+      // d3js needed values
+      this.source = -1;
+      this.target = -1;
+    }
+    return BaseLink;
+  })();
+
+  var Link = (function () {
+    function Link(linkId, srcNodeId, destNodeId) {
+      var opt = {
+        color: 'black'
+      };
+
+      BaseLink.call(this, linkId, srcNodeId, destNodeId, 'link', opt);
+    }
+
+    Link.prototype = Object.create(BaseLink.prototype);
+    Link.prototype.constructor = Link;
+
+    return Link;
+  })();
+
+  var TunnelLink = (function() {
+    function TunnelLink(linkId, srcNodeId, destNodeId, linkType, color) {
+      var opt = {
+        color: 'green',
+        width: 2,
+        dashArray: '5,5'
+      };
+      BaseLink.call(this, linkId, srcNodeId, destNodeId, 'tunnel', opt);
+    }
+
+    TunnelLink.prototype = Object.create(BaseLink.prototype);
+    TunnelLink.prototype.constructor = TunnelLink;
+
+    return TunnelLink;
+  })();
+
+  var BridgeOvsLink = (function() {
+    function BridgeOvsLink(linkId, srcNodeId, destNodeId, linkType, color) {
+      var opt = {
+        color: 'gray',
+        dashArray: '10,10'
+      };
+      BaseLink.call(this, linkId, srcNodeId, destNodeId, 'bridgeOvsLink', opt);
+    }
+
+    BridgeOvsLink.prototype = Object.create(BaseLink.prototype);
+    BridgeOvsLink.prototype.constructor = BridgeOvsLink;
+
+    return BridgeOvsLink;
+  })();
+
+  var Util = (function() {
+    var Maths = (function() {
+      function Maths() {
+
+      }
+      // random function in javascript use timespan only
+      Maths.Random = function(nseed) {
+        var constant = Math.pow(2, 13)+1,
+          prime = 1987,
+          maximum = 1000;
+
+          if (nseed) {
+            seed = nseed;
+          }
+
+          return {
+            next : function(min, max) {
+              seed *= constant;
+              seed += prime;
+
+              return min && max ? min+seed%maximum/maximum*(max-min) : seed%maximum/maximum;
+            }
+          };
+      };
+      return Maths;
+    })();
+
+    var String = (function() {
+
+      function String() {
+
+      }
+      String.Format = function() {
+        var s = arguments[0];
+        for (var i = 0; i < arguments.length - 1; i++) {
+            var reg = new RegExp("\\{" + i + "\\}", "gm");
+            s = s.replace(reg, arguments[i + 1]);
+        }
+        return s;
+      };
+
+      return String;
+
+    })();
+    return {
+      Math: Maths,
+      String: String
+    };
+  })();
+
+  var Neutron = (function() {
+
+    var SubNet = (function() {
+      function SubNet(id, networkId, name, ipVersion, cidr, gatewayIp, tenantId) {
+        this.id = id;
+        this.networkId = networkId;
+        this.name = name;
+        this.ipVersion = ipVersion;
+        this.cidr = cidr;
+        this.gatewayIp = gatewayIp;
+        this.tenantId = tenantId;
+      }
+      return SubNet;
+    })();
+
+    var Network = (function() {
+      function Network(id, name, shared, status, external, tenantId) {
+        this.id = id;
+        this.ip = '';
+        this.name = name;
+        this.shared = shared;
+        this.status = status;
+        this.external = external;
+        this.tenantId = tenantId;
+        this.subnets = [];
+        this.instances = [];
+        this.routers = [];
+      }
+
+      Network.prototype.addSubNets = function(subnets) {
+        if(subnets) {
+          if (_.isArray(subnets)) {
+            var i = 0;
+            for (; i < subnets.length; ++i) {
+              this.subnets.push(subnets[i]);
+            }
+          }
+          else {
+            this.subnets.push(subnet);
+          }
+        }
+      };
+
+      Network.prototype.asSubnet = function(subnet) {
+        return _.every(subnet, function(sub) {
+          return _.some(this.subnets, function(s) {
+            return s.id === sub;
+          });
+        }.bind(this));
+      };
+
+      Network.prototype.pretty = function() {
+        return {
+          'tabs' : [
+            'Info',
+            'Subnets'
+          ],
+          'containts' : [
+            {
+              'hasHeader' : false,
+              'headers': [],
+              'datas' : [
+                {key : 'ID', value: this.id},
+                {key : 'Ip', value: this.ip},
+                {key : 'Name', value: this.name},
+                {key : 'Shared', value: this.shared},
+                {key : 'Status', value: this.status},
+                {key : 'External', value: this.external},
+                {key : 'Tenant Id', value: this.tenantId}
+              ]
+            },
+            {
+              'hasHeader' : true,
+              'header' : ['ID', 'Name', 'Ip Version', 'Ip', 'Gateway Ip'],
+              'datas' : this.subnets.map(function(s) {
+                return [s.id, s.name, s.ipVersion, s.cidr, s.gatewayIp];
+              })
+            }
+          ]
+        };
+      };
+
+      return Network;
+    })();
+
+    var Port = (function() {
+      function Port(id, networkId, name, tenantId, deviceId, deviceOwner, fixed_ips, mac) {
+        this.id = id;
+        this.networkId = networkId;
+        this.name = name;
+        this.tenantId = '' + tenantId || '';
+        this.deviceId = deviceId;
+        this.deviceOwner = deviceOwner;
+        this.fixed_ips = fixed_ips;
+        this.mac = mac;
+      }
+
+      Port.prototype.pretty = function() {
+        return [
+          { key: 'ID', value : this.id },
+          { key: 'Name', value: name },
+          { key: 'Tenant Id', value : this.tenantId },
+          { key: 'Device Id', value : this.deviceId },
+          { key: 'Device Owner', value : this.deviceOwner },
+          { key: 'MAC', value : this.mac }
+        ];
+      };
+
+      return Port;
+    })();
+
+    var Router = (function() {
+      function Router(id, name, status, tenantId, externalGateway) {
+        this.id = id;
+        this.name = name;
+        this.status = status;
+        this.tenantId = tenantId;
+        this.interfaces = [];
+        this.externalGateway = externalGateway;
+      }
+
+      Router.prototype.pretty = function() {
+        return {
+          'tabs' : [
+            'Info',
+            'Interfaces'
+          ],
+          'containts' : [
+            {
+              'hasHeader' : false,
+              'headers': [],
+              'datas' : [
+                { key: 'ID', value: this.id},
+                { key: 'Name', value: this.name},
+                { key: 'status', value: this.status},
+                { key: 'Tenant ID', value: this.tenantId}
+              ]
+            },
+            {
+              'hasHeader' : true,
+              'header' : ['ID', 'Type', 'Mac Address', 'Ip', 'Tenant Id'],
+              'datas' : this.interfaces.map(function(s) {
+                return [s.id, s.type, s.mac, s.ip.ip_address, s.tenantId];
+              })
+            }
+          ]
+        };
+      };
+
+      return Router;
+    })();
+
+    var Instance = (function() {
+      function Instance(id, networkId, name, ip, mac, deviceOwner, tenantId, topoInfo) {
+        this.id = id;
+        this.networkId = networkId;
+        this.name = name;
+        this.ip = ip;
+        this.mac = '' + mac;
+        this.type = deviceOwner;
+        this.tenantId = tenantId;
+        this.topoInfo = topoInfo || [];
+        this.floatingIp = {};
+      }
+
+      Instance.prototype.extractFloatingIps = function(floatingIps) {
+        var ctx = this;
+        this.floatingIp = _.find(floatingIps, function(fIp) {
+          return fIp.tenantId === ctx.tenantId &&
+            fIp.fixedIp === ctx.ip;
+        });
+      };
+
+      Instance.prototype.pretty = function() {
+        return {
+          'tabs' : [
+            'Info',
+            'Ports'
+          ],
+          'containts' : [
+            {
+              'hasHeader' : false,
+              'headers': [],
+              'datas' : [
+                { key: 'ID', value: this.id},
+                { key: "Network Id", value : this.networkId},
+                { key: 'Name', value: this.name},
+                { key: 'Ip', value: this.ip},
+                { key: 'Floating Ip', value: (this.floatingIp) ? this.floatingIp.ip : 'Not found' },
+                { key: 'MAC', value: this.mac},
+                { key: 'Type', value: this.type},
+                { key: 'Tenant ID', value: this.tenantId}
+              ]
+            },
+            {
+              'hasHeader' : true,
+              'header' : ['Name', 'Of Port', 'Mac', 'Flow', 'Ovsdb Node', 'Ovsdb Node IP'],
+              'datas' : this.topoInfo.map(function(s) {
+                return [s.name, s.ofPort, s.mac, s.bridge.getFLowName(), s.ovsNode.nodeId, s.ovsNode.showIpAdress()];
+              })
+            }
+          ]
+        };
+      };
+
+      return Instance;
+    })();
+
+    var FloatingIp =(function() {
+      function FloatingIp(id, networkId, portId, fixedIp, floatingIp, tentantId, status) {
+        this.id = id;
+        this.networkId = networkId;
+        this.portId = portId;
+        this.fixedIp = fixedIp;
+        this.ip = floatingIp;
+        this.tenantId = tentantId;
+        this.status = status;
+      }
+
+      return FloatingIp;
+    })();
+
+    return {
+      Network: Network,
+      Port: Port,
+      Instance: Instance,
+      FloatingIp: FloatingIp,
+      Router: Router,
+      SubNet: SubNet
+    };
+  })();
+
+  return {
+    OvsNode: OvsNode,
+    BridgeNode: BridgeNode,
+    TerminationPoint: TerminationPoint,
+    Topology: Topology,
+    BaseLink: BaseLink,
+    Link: Link,
+    TunnelLink: TunnelLink,
+    BridgeOvsLink:BridgeOvsLink,
+    Util:Util,
+    Neutron: Neutron
+  };
+});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/assets/dhcp.png b/ovsdb-ui/module/src/main/resources/ovsdb/assets/dhcp.png
new file mode 100644 (file)
index 0000000..82e7dae
Binary files /dev/null and b/ovsdb-ui/module/src/main/resources/ovsdb/assets/dhcp.png differ
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/assets/router.png b/ovsdb-ui/module/src/main/resources/ovsdb/assets/router.png
new file mode 100644 (file)
index 0000000..d4a82f4
Binary files /dev/null and b/ovsdb-ui/module/src/main/resources/ovsdb/assets/router.png differ
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/assets/vm.png b/ovsdb-ui/module/src/main/resources/ovsdb/assets/vm.png
new file mode 100644 (file)
index 0000000..e75572a
Binary files /dev/null and b/ovsdb-ui/module/src/main/resources/ovsdb/assets/vm.png differ
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/css/ovsdb.css b/ovsdb-ui/module/src/main/resources/ovsdb/css/ovsdb.css
new file mode 100644 (file)
index 0000000..a27e9b1
--- /dev/null
@@ -0,0 +1,220 @@
+/*\r
+ * Copyright (c) 2015 Inocybe Technologies and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+*/\r
+\r
+#errorMessage {\r
+  display: none;\r
+}\r
+.switch-light {\r
+  width: 140px;\r
+}\r
+.switch-light span > span {\r
+  color: black;\r
+}\r
+.link {\r
+  stroke: #999;\r
+  stroke-opacity: 0.8;\r
+}\r
+.form-inline > span,\r
+label {\r
+  padding-right: 15px;\r
+}\r
+#list_container {\r
+  border: 1px solid white;\r
+  background-color: #414042;\r
+  height: 600px;\r
+}\r
+#list_container label {\r
+  color: white;\r
+}\r
+svg,\r
+#list_container {\r
+  width: 100%;\r
+}\r
+svg {\r
+  border: none;\r
+  border-radius: 0;\r
+  background-image: none;\r
+  background-color: white;\r
+  height: 580px;\r
+}\r
+#list_container > .row {\r
+  margin-left: 15px;\r
+  margin-right: 15px;\r
+}\r
+.container {\r
+  padding-top: 15px;\r
+  width: 1200px;\r
+}\r
+.row {\r
+  padding-bottom: 15px;\r
+}\r
+.select2-selection__choice {\r
+  background-color: orange !important;\r
+  border-color: black !important;\r
+  color: black !important;\r
+}\r
+.select2-selection__choice > span {\r
+  color: black !important;\r
+}\r
+.select2-results {\r
+  color: black !important;\r
+}\r
+.table.table-bordered {\r
+  background-color: white;\r
+  color: black;\r
+}\r
+#graph_header {\r
+  width: 100%;\r
+  height: 20px;\r
+  background-color: white;\r
+  border-bottom: 1px solid #ccc;\r
+}\r
+.icon-fullscreen,\r
+.icon-resize-small {\r
+  margin-right: 5px;\r
+  margin-top: 2px;\r
+}\r
+.bg_rect {\r
+  fill: #FFA6A6;\r
+  opacity: .4;\r
+  stroke: #ff0000;\r
+}\r
+kbd {\r
+  color: #333;\r
+  border-radius: 3px;\r
+  padding: 2px 4px;\r
+  font-size: 90%;\r
+  background-color: #DDD;\r
+  box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.25);\r
+}\r
+.network_info {\r
+  text-align: center;\r
+  width: 170px;\r
+  height: 80px;\r
+  padding: 5px;\r
+  border-radius: 5px;\r
+  border: 1px solid black;\r
+}\r
+#network_summary {\r
+  width: auto;\r
+  height: auto;\r
+  left: 15px;\r
+  padding: 5px;\r
+}\r
+.graph_window {\r
+  position: absolute !important;\r
+  background-color: rgba(255, 255, 255, 0.7);\r
+  -webkit-box-shadow: 0px 0px 25px 0px rgba(0, 0, 0, 0.75);\r
+  -moz-box-shadow: 0px 0px 25px 0px rgba(0, 0, 0, 0.75);\r
+  box-shadow: 0px 0px 25px 0px rgba(0, 0, 0, 0.75);\r
+  padding: 5px;\r
+  z-index: 2;\r
+  border-radius: 5px;\r
+  top: 25px;\r
+  min-height: 35px;\r
+  min-width: 100px;\r
+  overflow: hidden;\r
+}\r
+#graph_summary {\r
+  width: 160px;\r
+  height: 100px;\r
+  right: 10px;\r
+}\r
+\r
+div.window_body {\r
+  height: 80%;\r
+  font-size:12px;\r
+  color:#ccc;\r
+}\r
+div.window_content {\r
+  position:relative;\r
+  max-height:350px;\r
+  height:100%;\r
+  overflow-y: auto;\r
+}\r
+div.window_header > hr {\r
+  margin-top: 0;\r
+  margin-bottom: 10px;\r
+}\r
+div.window_header > span {\r
+  width: 100%;\r
+  display: inline;\r
+}\r
+#network_table_window,\r
+#node_table_window {\r
+  width: 355px;\r
+  height: 215px;\r
+}\r
+#node_table_window {\r
+  top: 300px;\r
+  left: 25px;\r
+}\r
+#network_table_window {\r
+  top: 300px;\r
+  right: 25px;\r
+}\r
+.window-icon {\r
+  color: black;\r
+  float: right;\r
+  margin-right: 5px;\r
+}\r
+.window-icon:hover {\r
+  background-color: #ddd;\r
+  cursor: pointer;\r
+}\r
+\r
+.linfolabel {\r
+  font-size : 12px;\r
+  letter-spacing: 1px;\r
+}\r
+#tabs > ul > li > a {\r
+  color:white !important;\r
+}\r
+#tabs > ul > li.ui-state-active {\r
+  border: 1px solid white;\r
+}\r
+\r
+#tabs > ul > li.ui-state-hover > a{\r
+  color:black !important;\r
+}\r
+\r
+#tabs > ul > li > a:focus {\r
+  background-color:inherit !important;\r
+}\r
+\r
+#lDialog, #pDialog {\r
+  position:absolute;\r
+  font-size: 11px;\r
+  width: auto;\r
+  min-width: 450px;\r
+  display:none;\r
+  background-color: rgb(255, 255, 255);\r
+  border: 1px solid black;\r
+  border-radius: 10px;\r
+  height: auto;\r
+  padding: 10px;\r
+}\r
+\r
+.window_content > ul > li.ui-state-active {\r
+  border-top: 1px solid #dddddd;\r
+  border-left: 1px solid #dddddd;\r
+  border-right: 1px solid #dddddd;\r
+}\r
+\r
+.arrow-left {\r
+       width: 0;\r
+       height: 0;\r
+       border-top: 10px solid transparent;\r
+       border-bottom: 10px solid transparent;\r
+\r
+       border-right:10px solid blue;\r
+}\r
+\r
+span.selection {\r
+  font-size: 10px;\r
+}\r
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/css/select2.min.css b/ovsdb-ui/module/src/main/resources/ovsdb/css/select2.min.css
new file mode 100755 (executable)
index 0000000..1c72344
--- /dev/null
@@ -0,0 +1 @@
+.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle;}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none;}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px;}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none;}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap;}.select2-container .select2-search--inline{float:left;}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none;}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051;}.select2-results{display:block;}.select2-results__options{list-style:none;margin:0;padding:0;}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none;}.select2-results__option[aria-selected]{cursor:pointer;}.select2-container--open .select2-dropdown{left:0;}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0;}.select2-search--dropdown{display:block;padding:4px;}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box;}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none;}.select2-search--dropdown.select2-search--hide{display:none;}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0);}.select2-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px;}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px;}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999;}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px;}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0;}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left;}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto;}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default;}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none;}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px;}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%;}.select2-container--default .select2-selection--multiple .select2-selection__placeholder{color:#999;margin-top:5px;float:left;}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px;}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px;}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333;}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder{float:right;}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto;}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto;}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0;}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default;}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none;}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0;}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0;}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa;}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto;}.select2-container--default .select2-results__option[role=group]{padding:0;}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999;}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd;}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em;}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em;}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white;}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px;}.select2-container--classic .select2-selection--single{background-color:#f6f6f6;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #ffffff 50%, #eeeeee 100%);background-image:-o-linear-gradient(top, #ffffff 50%, #eeeeee 100%);background-image:linear-gradient(to bottom, #ffffff 50%, #eeeeee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb;}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px;}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px;}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999;}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);background-image:-o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);background-image:linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#cccccc', GradientType=0);}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0;}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left;}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto;}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb;}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none;}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px;}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #ffffff 0%, #eeeeee 50%);background-image:-o-linear-gradient(top, #ffffff 0%, #eeeeee 50%);background-image:linear-gradient(to bottom, #ffffff 0%, #eeeeee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eeeeee 50%, #ffffff 100%);background-image:-o-linear-gradient(top, #eeeeee 50%, #ffffff 100%);background-image:linear-gradient(to bottom, #eeeeee 50%, #ffffff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0;}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb;}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px;}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none;}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px;}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px;}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555;}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right;}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto;}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto;}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb;}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0;}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0;}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;}.select2-container--classic .select2-dropdown{background-color:white;border:1px solid transparent;}.select2-container--classic .select2-dropdown--above{border-bottom:none;}.select2-container--classic .select2-dropdown--below{border-top:none;}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto;}.select2-container--classic .select2-results__option[role=group]{padding:0;}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey;}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:white;}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px;}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb;}
\ No newline at end of file
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/css/toggle-switch.css b/ovsdb-ui/module/src/main/resources/ovsdb/css/toggle-switch.css
new file mode 100644 (file)
index 0000000..78cb2b3
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+* CSS TOGGLE SWITCHES
+* Unlicense
+*
+* Ionuț Colceriu - ghinda.net
+* https://github.com/ghinda/css-toggle-switch
+*
+*/
+/* Supported values are px, rem-calc, em-calc */
+/* Functions */
+/* Toggle Switches */
+/* Shared */
+/* Checkbox
+*/
+/* Radio Switch
+*/
+/* Hide by default
+*/
+.switch-toggle a, .switch-light span span {
+  display: none; }
+
+/* We can't test for a specific feature,
+* so we only target browsers with support for media queries.
+*/
+@media only screen {
+  /* Checkbox switch
+  */
+  .switch-light {
+    display: block;
+    min-height: 1.875em;
+    /* Outline the toggles when the inputs are focused
+  */
+    position: relative;
+    overflow: visible;
+    padding: 0;
+    margin-left: 6.25em;
+    /* Position the label over all the elements, except the slide-button (<a>)
+  * Clicking anywhere on the label will change the switch-state
+  */
+    /* Don't hide the input from screen-readers and keyboard access
+  */ }
+    .switch-light * {
+      -webkit-box-sizing: border-box;
+      -moz-box-sizing: border-box;
+      box-sizing: border-box; }
+    .switch-light a {
+      display: block;
+      -webkit-transition: all 0.2s ease-out;
+      -moz-transition: all 0.2s ease-out;
+      transition: all 0.2s ease-out; }
+    .switch-light label, .switch-light > span {
+      line-height: 1.875em;
+      vertical-align: middle; }
+    .switch-light input:focus ~ a, .switch-light input:focus + label {
+      outline: 1px dotted #888; }
+    .switch-light label {
+      position: relative;
+      z-index: 3;
+      display: block;
+      width: 100%; }
+    .switch-light input {
+      position: absolute;
+      opacity: 0;
+      z-index: 5; }
+      .switch-light input:checked ~ a {
+        right: 0%; }
+    .switch-light > span {
+      position: absolute;
+      left: -6.25em;
+      width: 100%;
+      margin: 0;
+      padding-right: 6.25em;
+      text-align: left; }
+      .switch-light > span span {
+        position: absolute;
+        top: 0;
+        left: 0;
+        z-index: 5;
+        display: block;
+        width: 50%;
+        margin-left: 6.25em;
+        text-align: center; }
+        .switch-light > span span:last-child {
+          left: 50%; }
+    .switch-light a {
+      position: absolute;
+      right: 50%;
+      top: 0;
+      z-index: 4;
+      display: block;
+      width: 50%;
+      height: 100%;
+      padding: 0; }
+
+  /* Radio switch
+  */
+  .switch-toggle {
+    display: block;
+    min-height: 1.875em;
+    /* Outline the toggles when the inputs are focused
+  */
+    position: relative;
+    display: table;
+    table-layout: fixed;
+    /* For callout panels in foundation
+  */
+    padding: 0 !important;
+    /* Generate styles for the multiple states */ }
+    .switch-toggle * {
+      -webkit-box-sizing: border-box;
+      -moz-box-sizing: border-box;
+      box-sizing: border-box; }
+    .switch-toggle a {
+      display: block;
+      -webkit-transition: all 0.2s ease-out;
+      -moz-transition: all 0.2s ease-out;
+      transition: all 0.2s ease-out; }
+    .switch-toggle label, .switch-toggle > span {
+      line-height: 1.875em;
+      vertical-align: middle; }
+    .switch-toggle input:focus ~ a, .switch-toggle input:focus + label {
+      outline: 1px dotted #888; }
+    .switch-toggle * {
+      font-size: 1em; }
+    .switch-toggle input {
+      position: absolute;
+      opacity: 0; }
+    .switch-toggle input + label {
+      position: relative;
+      z-index: 2;
+      display: table-cell;
+      width: 50%;
+      padding: 0 0.5em;
+      margin: 0;
+      text-align: center; }
+    .switch-toggle a {
+      position: absolute;
+      top: 0;
+      left: 0;
+      padding: 0;
+      z-index: 1;
+      width: 50%;
+      height: 100%; }
+    .switch-toggle input:last-of-type:checked ~ a {
+      left: 50%; }
+    .switch-toggle.switch-3 label, .switch-toggle.switch-3 a {
+      width: 33.3333333333%; }
+    .switch-toggle.switch-3 input:checked:nth-of-type(2) ~ a {
+      left: 33.3333333333%; }
+    .switch-toggle.switch-3 input:checked:last-of-type ~ a {
+      left: 66.6666666667%; }
+    .switch-toggle.switch-4 label, .switch-toggle.switch-4 a {
+      width: 25%; }
+    .switch-toggle.switch-4 input:checked:nth-of-type(2) ~ a {
+      left: 25%; }
+    .switch-toggle.switch-4 input:checked:nth-of-type(3) ~ a {
+      left: 50%; }
+    .switch-toggle.switch-4 input:checked:last-of-type ~ a {
+      left: 75%; }
+    .switch-toggle.switch-5 label, .switch-toggle.switch-5 a {
+      width: 20%; }
+    .switch-toggle.switch-5 input:checked:nth-of-type(2) ~ a {
+      left: 20%; }
+    .switch-toggle.switch-5 input:checked:nth-of-type(3) ~ a {
+      left: 40%; }
+    .switch-toggle.switch-5 input:checked:nth-of-type(4) ~ a {
+      left: 60%; }
+    .switch-toggle.switch-5 input:checked:last-of-type ~ a {
+      left: 80%; }
+
+  /* Standalone Themes */
+  /* Candy Theme
+  * Based on the "Sort Switches / Toggles (PSD)" by Ormal Clarck
+  * http://www.premiumpixels.com/freebies/sort-switches-toggles-psd/
+  */
+  .switch-candy {
+    background-color: #2d3035;
+    border-radius: 3px;
+    color: #fff;
+    font-weight: bold;
+    text-align: center;
+    text-shadow: 1px 1px 1px #191b1e;
+    box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.3), 0 1px 0 rgba(255, 255, 255, 0.2); }
+    .switch-candy label {
+      color: #fff;
+      -webkit-transition: color 0.2s ease-out;
+      -moz-transition: color 0.2s ease-out;
+      transition: color 0.2s ease-out; }
+    .switch-candy input:checked + label {
+      color: #333;
+      text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); }
+    .switch-candy a {
+      border: 1px solid #333;
+      background-color: #70c66b;
+      border-radius: 3px;
+      background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0));
+      background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0));
+      box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), inset 0 1px 1px rgba(255, 255, 255, 0.45); }
+    .switch-candy > span {
+      color: #333;
+      text-shadow: none; }
+    .switch-candy span {
+      color: #fff; }
+    .switch-candy.switch-candy-blue a {
+      background-color: #38a3d4; }
+    .switch-candy.switch-candy-yellow a {
+      background-color: #f5e560; }
+
+  /* Android Theme
+  */
+  .switch-android {
+    background-color: #464747;
+    border-radius: 1px;
+    box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0;
+    color: #fff;
+    /* Selected ON switch-light
+    */ }
+    .switch-android label {
+      color: #fff; }
+    .switch-android > span span {
+      opacity: 0;
+      margin-left: 7.1875em;
+      -webkit-transition: all 0.1s;
+      -moz-transition: all 0.1s;
+      transition: all 0.1s; }
+      .switch-android > span span:first-of-type {
+        opacity: 1; }
+    .switch-android > span span, .switch-android input + label {
+      font-size: 85%;
+      line-height: 2.15625em; }
+    .switch-android a {
+      background-color: #666;
+      border-radius: 1px;
+      box-shadow: inset rgba(255, 255, 255, 0.2) 0 1px 0, inset rgba(0, 0, 0, 0.3) 0 -1px 0; }
+    .switch-android.switch-light input:checked ~ a {
+      background-color: #0E88B1; }
+    .switch-android.switch-light input:checked ~ span span:first-of-type {
+      opacity: 0; }
+    .switch-android.switch-light input:checked ~ span span:last-of-type {
+      opacity: 1; }
+    .switch-android.switch-toggle, .switch-android > span span {
+      text-transform: uppercase; }
+
+  /* iOS Theme
+  */
+  .switch-ios.switch-light {
+    color: #868686; }
+    .switch-ios.switch-light a {
+      left: 0;
+      width: 1.875em;
+      background-color: #fff;
+      border: 1px solid #d3d3d3;
+      border-radius: 100%;
+      -webkit-transition: all 0.3s ease-out;
+      -moz-transition: all 0.3s ease-out;
+      transition: all 0.3s ease-out;
+      box-shadow: inset 0 -3px 3px rgba(0, 0, 0, 0.025), 0 1px 4px rgba(0, 0, 0, 0.15), 0 4px 4px rgba(0, 0, 0, 0.1); }
+    .switch-ios.switch-light > span span {
+      width: 100%;
+      left: 0;
+      opacity: 0; }
+      .switch-ios.switch-light > span span:first-of-type {
+        opacity: 1;
+        padding-left: 1.875em; }
+      .switch-ios.switch-light > span span:last-of-type {
+        padding-right: 1.875em; }
+    .switch-ios.switch-light > span:before {
+      content: '';
+      display: block;
+      width: 100%;
+      height: 100%;
+      position: absolute;
+      left: 6.25em;
+      top: 0;
+      background-color: #fafafa;
+      border: 1px solid #d3d3d3;
+      border-radius: 30px;
+      -webkit-transition: all 0.5s ease-out;
+      -moz-transition: all 0.5s ease-out;
+      transition: all 0.5s ease-out;
+      box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0; }
+    .switch-ios.switch-light input:checked ~ a {
+      left: 100%;
+      margin-left: -1.875em; }
+    .switch-ios.switch-light input:checked ~ span:before {
+      border-color: #53d76a;
+      box-shadow: inset 0 0 0 30px #53d76a; }
+    .switch-ios.switch-light input:checked ~ span span:first-of-type {
+      opacity: 0; }
+    .switch-ios.switch-light input:checked ~ span span:last-of-type {
+      opacity: 1;
+      color: #fff; }
+  .switch-ios.switch-toggle {
+    background-color: #fafafa;
+    border: 1px solid #d3d3d3;
+    border-radius: 30px;
+    box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0; }
+    .switch-ios.switch-toggle a {
+      background-color: #53d76a;
+      border-radius: 25px;
+      -webkit-transition: all 0.3s ease-out;
+      -moz-transition: all 0.3s ease-out;
+      transition: all 0.3s ease-out; }
+    .switch-ios.switch-toggle label {
+      color: #868686; }
+  .switch-ios input:checked + label {
+    color: #3a3a3a; }
+ }
+
+/* Bugfix for older Webkit, including mobile Webkit. Adapted from
+* http://css-tricks.com/webkit-sibling-bug/
+*/
+@media only screen and (-webkit-max-device-pixel-ratio: 2) and (max-device-width: 80em) {
+  .switch-light, .switch-toggle {
+    -webkit-animation: webkitSiblingBugfix infinite 1s; } }
+
+@-webkit-keyframes webkitSiblingBugfix {
+  from {
+    -webkit-transform: translate3d(0, 0, 0); }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0); } }
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/index.tpl.html b/ovsdb-ui/module/src/main/resources/ovsdb/index.tpl.html
deleted file mode 100644 (file)
index 3aec420..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<!--\r
- * Copyright (c) 2015 Inocybe Technologies and others.  All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
--->\r
-\r
-<div class="form-group">\r
-  <span>In progress</span>\r
-  <div id="errorMessage" class="alert alert-danger" role="alert">\r
-      {{err.message}}\r
-  </div>\r
-</div>\r
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/lib/d3.min.js b/ovsdb-ui/module/src/main/resources/ovsdb/lib/d3.min.js
new file mode 100644 (file)
index 0000000..34d5513
--- /dev/null
@@ -0,0 +1,5 @@
+!function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function e(n,t){return t>n?-1:n>t?1:n>=t?0:0/0}function r(n){return null===n?0/0:+n}function u(n){return!isNaN(n)}function i(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)<0?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)>0?u=i:r=i+1}return r}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function c(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function l(){this._=Object.create(null)}function s(n){return(n+="")===pa||n[0]===va?va+n:n}function f(n){return(n+="")[0]===va?n.slice(1):n}function h(n){return s(n)in this._}function g(n){return(n=s(n))in this._&&delete this._[n]}function p(){var n=[];for(var t in this._)n.push(f(t));return n}function v(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function m(){this._=Object.create(null)}function y(n){return n}function M(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e=0,r=da.length;r>e;++e){var u=da[e]+t;if(u in n)return u}}function b(){}function _(){}function w(n){function t(){for(var t,r=e,u=-1,i=r.length;++u<i;)(t=r[u].on)&&t.apply(this,arguments);return n}var e=[],r=new l;return t.on=function(t,u){var i,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,i=e.indexOf(o)).concat(e.slice(i+1)),r.remove(t)),u&&e.push(r.set(t,{on:u})),n)},t}function S(){ta.event.preventDefault()}function k(){for(var n,t=ta.event;n=t.sourceEvent;)t=n;return t}function E(n){for(var t=new _,e=0,r=arguments.length;++e<r;)t[arguments[e]]=w(t);return t.of=function(e,r){return function(u){try{var i=u.sourceEvent=ta.event;u.target=n,ta.event=u,t[u.type].apply(e,r)}finally{ta.event=i}}},t}function A(n){return ya(n,_a),n}function N(n){return"function"==typeof n?n:function(){return Ma(n,this)}}function C(n){return"function"==typeof n?n:function(){return xa(n,this)}}function z(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function u(){this.setAttribute(n,t)}function i(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=ta.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?i:u}function q(n){return n.trim().replace(/\s+/g," ")}function L(n){return new RegExp("(?:^|\\s+)"+ta.requote(n)+"(?:\\s+|$)","g")}function T(n){return(n+"").trim().split(/^|\s+/)}function R(n,t){function e(){for(var e=-1;++e<u;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<u;)n[e](this,r)}n=T(n).map(D);var u=n.length;return"function"==typeof t?r:e}function D(n){var t=L(n);return function(e,r){if(u=e.classList)return r?u.add(n):u.remove(n);var u=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(u)||e.setAttribute("class",q(u+" "+n))):e.setAttribute("class",q(u.replace(t," ")))}}function P(n,t,e){function r(){this.style.removeProperty(n)}function u(){this.style.setProperty(n,t,e)}function i(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?i:u}function U(n,t){function e(){delete this[n]}function r(){this[n]=t}function u(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?u:r}function j(n){function t(){var t=this.ownerDocument,e=this.namespaceURI;return e?t.createElementNS(e,n):t.createElement(n)}function e(){return this.ownerDocument.createElementNS(n.space,n.local)}return"function"==typeof n?n:(n=ta.ns.qualify(n)).local?e:t}function F(){var n=this.parentNode;n&&n.removeChild(this)}function H(n){return{__data__:n}}function O(n){return function(){return ba(this,n)}}function I(n){return arguments.length||(n=e),function(t,e){return t&&e?n(t.__data__,e.__data__):!t-!e}}function Y(n,t){for(var e=0,r=n.length;r>e;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function Z(n){return ya(n,Sa),n}function V(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t<c;);return o}}function X(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function u(){var u=c(t,ra(arguments));r.call(this),this.addEventListener(n,this[o]=u,u.$=e),u._=t}function i(){var t,e=new RegExp("^__on([^.]+)"+ta.requote(n)+"$");for(var r in this)if(t=r.match(e)){var u=this[r];this.removeEventListener(t[1],u,u.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),c=$;a>0&&(n=n.slice(0,a));var l=ka.get(n);return l&&(n=l,c=B),a?t?u:r:t?b:i}function $(n,t){return function(e){var r=ta.event;ta.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{ta.event=r}}}function B(n,t){var e=$(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function W(e){var r=".dragsuppress-"+ ++Aa,u="click"+r,i=ta.select(t(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==Ea&&(Ea="onselectstart"in e?!1:x(e.style,"userSelect")),Ea){var o=n(e).style,a=o[Ea];o[Ea]="none"}return function(n){if(i.on(r,null),Ea&&(o[Ea]=a),n){var t=function(){i.on(u,null)};i.on(u,function(){S(),t()},!0),setTimeout(t,0)}}}function J(n,e){e.changedTouches&&(e=e.changedTouches[0]);var r=n.ownerSVGElement||n;if(r.createSVGPoint){var u=r.createSVGPoint();if(0>Na){var i=t(n);if(i.scrollX||i.scrollY){r=ta.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=r[0][0].getScreenCTM();Na=!(o.f||o.e),r.remove()}}return Na?(u.x=e.pageX,u.y=e.pageY):(u.x=e.clientX,u.y=e.clientY),u=u.matrixTransform(n.getScreenCTM().inverse()),[u.x,u.y]}var a=n.getBoundingClientRect();return[e.clientX-a.left-n.clientLeft,e.clientY-a.top-n.clientTop]}function G(){return ta.event.changedTouches[0].identifier}function K(n){return n>0?1:0>n?-1:0}function Q(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function nt(n){return n>1?0:-1>n?qa:Math.acos(n)}function tt(n){return n>1?Ra:-1>n?-Ra:Math.asin(n)}function et(n){return((n=Math.exp(n))-1/n)/2}function rt(n){return((n=Math.exp(n))+1/n)/2}function ut(n){return((n=Math.exp(2*n))-1)/(n+1)}function it(n){return(n=Math.sin(n/2))*n}function ot(){}function at(n,t,e){return this instanceof at?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof at?new at(n.h,n.s,n.l):bt(""+n,_t,at):new at(n,t,e)}function ct(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,new mt(u(n+120),u(n),u(n-120))}function lt(n,t,e){return this instanceof lt?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof lt?new lt(n.h,n.c,n.l):n instanceof ft?gt(n.l,n.a,n.b):gt((n=wt((n=ta.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new lt(n,t,e)}function st(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new ft(e,Math.cos(n*=Da)*t,Math.sin(n)*t)}function ft(n,t,e){return this instanceof ft?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof ft?new ft(n.l,n.a,n.b):n instanceof lt?st(n.h,n.c,n.l):wt((n=mt(n)).r,n.g,n.b):new ft(n,t,e)}function ht(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=pt(u)*Xa,r=pt(r)*$a,i=pt(i)*Ba,new mt(dt(3.2404542*u-1.5371385*r-.4985314*i),dt(-.969266*u+1.8760108*r+.041556*i),dt(.0556434*u-.2040259*r+1.0572252*i))}function gt(n,t,e){return n>0?new lt(Math.atan2(e,t)*Pa,Math.sqrt(t*t+e*e),n):new lt(0/0,0/0,n)}function pt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function vt(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function dt(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mt(n,t,e){return this instanceof mt?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof mt?new mt(n.r,n.g,n.b):bt(""+n,mt,ct):new mt(n,t,e)}function yt(n){return new mt(n>>16,n>>8&255,255&n)}function Mt(n){return yt(n)+""}function xt(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function bt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(kt(u[0]),kt(u[1]),kt(u[2]))}return(i=Ga.get(n.toLowerCase()))?t(i.r,i.g,i.b):(null==n||"#"!==n.charAt(0)||isNaN(i=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&i)>>4,o=o>>4|o,a=240&i,a=a>>4|a,c=15&i,c=c<<4|c):7===n.length&&(o=(16711680&i)>>16,a=(65280&i)>>8,c=255&i)),t(o,a,c))}function _t(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),new at(r,u,c)}function wt(n,t,e){n=St(n),t=St(t),e=St(e);var r=vt((.4124564*n+.3575761*t+.1804375*e)/Xa),u=vt((.2126729*n+.7151522*t+.072175*e)/$a),i=vt((.0193339*n+.119192*t+.9503041*e)/Ba);return ft(116*u-16,500*(r-u),200*(u-i))}function St(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function kt(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function Et(n){return"function"==typeof n?n:function(){return n}}function At(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Nt(t,e,n,r)}}function Nt(n,t,e,r){function u(){var n,t=c.status;if(!t&&zt(c)||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return void o.error.call(i,r)}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=ta.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,l=null;return!this.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=ta.event;ta.event=n;try{o.progress.call(i,c)}finally{ta.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(l=n,i):l},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(ra(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var s in a)c.setRequestHeader(s,a[s]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},ta.rebind(i,o,"on"),null==r?i:i.get(Ct(r))}function Ct(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function zt(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function qt(){var n=Lt(),t=Tt()-n;t>24?(isFinite(t)&&(clearTimeout(tc),tc=setTimeout(qt,t)),nc=0):(nc=1,rc(qt))}function Lt(){var n=Date.now();for(ec=Ka;ec;)n>=ec.t&&(ec.f=ec.c(n-ec.t)),ec=ec.n;return n}function Tt(){for(var n,t=Ka,e=1/0;t;)t.f?t=n?n.n=t.n:Ka=t.n:(t.t<e&&(e=t.t),t=(n=t).n);return Qa=n,e}function Rt(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Dt(n,t){var e=Math.pow(10,3*ga(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function Pt(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r&&e?function(n,t){for(var u=n.length,i=[],o=0,a=r[0],c=0;u>0&&a>0&&(c+a+1>t&&(a=Math.max(1,t-c)),i.push(n.substring(u-=a,u+a)),!((c+=a+1)>t));)a=r[o=(o+1)%r.length];return i.reverse().join(e)}:y;return function(n){var e=ic.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"-",c=e[4]||"",l=e[5],s=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1,y=!0;switch(h&&(h=+h.substring(1)),(l||"0"===r&&"="===o)&&(l=r="0",o="="),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===c&&(v="0"+g.toLowerCase());case"c":y=!1;case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===c&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=oc.get(g)||Ut;var M=l&&f;return function(n){var e=d;if(m&&n%1)return"";var u=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>p){var c=ta.formatPrefix(n,h);n=c.scale(n),e=c.symbol+d}else n*=p;n=g(n,h);var x,b,_=n.lastIndexOf(".");if(0>_){var w=y?n.lastIndexOf("e"):-1;0>w?(x=n,b=""):(x=n.substring(0,w),b=n.substring(w))}else x=n.substring(0,_),b=t+n.substring(_+1);!l&&f&&(x=i(x,1/0));var S=v.length+x.length+b.length+(M?0:u.length),k=s>S?new Array(S=s-S+1).join(r):"";return M&&(x=i(k+x,k.length?s-b.length:1/0)),u+=v,n=x+b,("<"===o?u+n+k:">"===o?k+u+n:"^"===o?k.substring(0,S>>=1)+u+n+k.substring(S):u+(M?n:k+n))+e}}}function Ut(n){return n+""}function jt(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Ft(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new cc(e-1)),1),e}function i(n,e){return t(n=new cc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{cc=jt;var r=new jt;return r._=n,o(r,t,e)}finally{cc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Ht(n);return c.floor=c,c.round=Ht(r),c.ceil=Ht(u),c.offset=Ht(i),c.range=a,n}function Ht(n){return function(t,e){try{cc=jt;var r=new jt;return r._=t,n(r,e)._}finally{cc=Date}}}function Ot(n){function t(n){function t(t){for(var e,u,i,o=[],a=-1,c=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.slice(c,a)),null!=(u=sc[e=n.charAt(++a)])&&(e=n.charAt(++a)),(i=N[e])&&(e=i(t,null==u?"e"===e?" ":"0":u)),o.push(e),c=a+1);return o.push(n.slice(c,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},u=e(r,n,t,0);if(u!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var i=null!=r.Z&&cc!==jt,o=new(i?jt:cc);return"j"in r?o.setFullYear(r.y,0,r.j):"w"in r&&("W"in r||"U"in r)?(o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+(r.Z/100|0),r.M+r.Z%100,r.S,r.L),i?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var u,i,o,a=0,c=t.length,l=e.length;c>a;){if(r>=l)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=C[o in sc?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){_.lastIndex=0;var r=_.exec(t.slice(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){x.lastIndex=0;var r=x.exec(t.slice(e));return r?(n.w=b.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){E.lastIndex=0;var r=E.exec(t.slice(e));return r?(n.m=A.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.slice(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,N.c.toString(),t,r)}function c(n,t,r){return e(n,N.x.toString(),t,r)}function l(n,t,r){return e(n,N.X.toString(),t,r)}function s(n,t,e){var r=M.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{cc=jt;var t=new cc;return t._=n,r(t)}finally{cc=Date}}var r=t(n);return e.parse=function(n){try{cc=jt;var t=r.parse(n);return t&&t._}finally{cc=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ae;var M=ta.map(),x=Yt(v),b=Zt(v),_=Yt(d),w=Zt(d),S=Yt(m),k=Zt(m),E=Yt(y),A=Zt(y);p.forEach(function(n,t){M.set(n.toLowerCase(),t)});var N={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return It(n.getDate(),t,2)},e:function(n,t){return It(n.getDate(),t,2)},H:function(n,t){return It(n.getHours(),t,2)},I:function(n,t){return It(n.getHours()%12||12,t,2)},j:function(n,t){return It(1+ac.dayOfYear(n),t,3)},L:function(n,t){return It(n.getMilliseconds(),t,3)},m:function(n,t){return It(n.getMonth()+1,t,2)},M:function(n,t){return It(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return It(n.getSeconds(),t,2)},U:function(n,t){return It(ac.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return It(ac.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return It(n.getFullYear()%100,t,2)},Y:function(n,t){return It(n.getFullYear()%1e4,t,4)},Z:ie,"%":function(){return"%"}},C={a:r,A:u,b:i,B:o,c:a,d:Qt,e:Qt,H:te,I:te,j:ne,L:ue,m:Kt,M:ee,p:s,S:re,U:Xt,w:Vt,W:$t,x:c,X:l,y:Wt,Y:Bt,Z:Jt,"%":oe};return t}function It(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Yt(n){return new RegExp("^(?:"+n.map(ta.requote).join("|")+")","i")}function Zt(n){for(var t=new l,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function Vt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Xt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e));return r?(n.U=+r[0],e+r[0].length):-1}function $t(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e));return r?(n.W=+r[0],e+r[0].length):-1}function Bt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Wt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.y=Gt(+r[0]),e+r[0].length):-1}function Jt(n,t,e){return/^[+-]\d{4}$/.test(t=t.slice(e,e+5))?(n.Z=-t,e+5):-1}function Gt(n){return n+(n>68?1900:2e3)}function Kt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Qt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function ne(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function te(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function ee(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function re(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ue(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function ie(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=ga(t)/60|0,u=ga(t)%60;return e+It(r,"0",2)+It(u,"0",2)}function oe(n,t,e){hc.lastIndex=0;var r=hc.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ae(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ce(){}function le(n,t,e){var r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function se(n,t){n&&dc.hasOwnProperty(n.type)&&dc[n.type](n,t)}function fe(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++u<i;)r=n[u],t.point(r[0],r[1],r[2]);t.lineEnd()}function he(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)fe(n[e],t,1);t.polygonEnd()}function ge(){function n(n,t){n*=Da,t=t*Da/2+qa/4;var e=n-r,o=e>=0?1:-1,a=o*e,c=Math.cos(t),l=Math.sin(t),s=i*l,f=u*c+s*Math.cos(a),h=s*o*Math.sin(a);yc.add(Math.atan2(h,f)),r=n,u=c,i=l}var t,e,r,u,i;Mc.point=function(o,a){Mc.point=n,r=(t=o)*Da,u=Math.cos(a=(e=a)*Da/2+qa/4),i=Math.sin(a)},Mc.lineEnd=function(){n(t,e)}}function pe(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function ve(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function de(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function me(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function ye(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function Me(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function xe(n){return[Math.atan2(n[1],n[0]),tt(n[2])]}function be(n,t){return ga(n[0]-t[0])<Ca&&ga(n[1]-t[1])<Ca}function _e(n,t){n*=Da;var e=Math.cos(t*=Da);we(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function we(n,t,e){++xc,_c+=(n-_c)/xc,wc+=(t-wc)/xc,Sc+=(e-Sc)/xc}function Se(){function n(n,u){n*=Da;var i=Math.cos(u*=Da),o=i*Math.cos(n),a=i*Math.sin(n),c=Math.sin(u),l=Math.atan2(Math.sqrt((l=e*c-r*a)*l+(l=r*o-t*c)*l+(l=t*a-e*o)*l),t*o+e*a+r*c);bc+=l,kc+=l*(t+(t=o)),Ec+=l*(e+(e=a)),Ac+=l*(r+(r=c)),we(t,e,r)}var t,e,r;qc.point=function(u,i){u*=Da;var o=Math.cos(i*=Da);t=o*Math.cos(u),e=o*Math.sin(u),r=Math.sin(i),qc.point=n,we(t,e,r)}}function ke(){qc.point=_e}function Ee(){function n(n,t){n*=Da;var e=Math.cos(t*=Da),o=e*Math.cos(n),a=e*Math.sin(n),c=Math.sin(t),l=u*c-i*a,s=i*o-r*c,f=r*a-u*o,h=Math.sqrt(l*l+s*s+f*f),g=r*o+u*a+i*c,p=h&&-nt(g)/h,v=Math.atan2(h,g);Nc+=p*l,Cc+=p*s,zc+=p*f,bc+=v,kc+=v*(r+(r=o)),Ec+=v*(u+(u=a)),Ac+=v*(i+(i=c)),we(r,u,i)}var t,e,r,u,i;qc.point=function(o,a){t=o,e=a,qc.point=n,o*=Da;var c=Math.cos(a*=Da);r=c*Math.cos(o),u=c*Math.sin(o),i=Math.sin(a),we(r,u,i)},qc.lineEnd=function(){n(t,e),qc.lineEnd=ke,qc.point=_e}}function Ae(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function Ne(){return!0}function Ce(n,t,e,r,u){var i=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(be(e,r)){u.lineStart();for(var a=0;t>a;++a)u.point((e=n[a])[0],e[1]);return void u.lineEnd()}var c=new qe(e,n,null,!0),l=new qe(e,null,c,!1);c.o=l,i.push(c),o.push(l),c=new qe(r,n,null,!1),l=new qe(r,null,c,!0),c.o=l,i.push(c),o.push(l)}}),o.sort(t),ze(i),ze(o),i.length){for(var a=0,c=e,l=o.length;l>a;++a)o[a].e=c=!c;for(var s,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;s=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var a=0,l=s.length;l>a;++a)u.point((f=s[a])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){s=g.p.z;for(var a=s.length-1;a>=0;--a)u.point((f=s[a])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,s=g.z,p=!p}while(!g.v);u.lineEnd()}}}function ze(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r<t;)u.n=e=n[r],e.p=u,u=e;u.n=e=n[0],e.p=u}}function qe(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Le(n,t,e,r){return function(u,i){function o(t,e){var r=u(t,e);n(t=r[0],e=r[1])&&i.point(t,e)}function a(n,t){var e=u(n,t);d.point(e[0],e[1])}function c(){y.point=a,d.lineStart()}function l(){y.point=o,d.lineEnd()}function s(n,t){v.push([n,t]);var e=u(n,t);x.point(e[0],e[1])}function f(){x.lineStart(),v=[]}function h(){s(v[0][0],v[0][1]),x.lineEnd();var n,t=x.clean(),e=M.buffer(),r=e.length;if(v.pop(),p.push(v),v=null,r)if(1&t){n=e[0];var u,r=n.length-1,o=-1;if(r>0){for(b||(i.polygonStart(),b=!0),i.lineStart();++o<r;)i.point((u=n[o])[0],u[1]);i.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Te))}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:l,polygonStart:function(){y.point=s,y.lineStart=f,y.lineEnd=h,g=[],p=[]},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=l,g=ta.merge(g);var n=Fe(m,p);g.length?(b||(i.polygonStart(),b=!0),Ce(g,De,n,e,i)):n&&(b||(i.polygonStart(),b=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),b&&(i.polygonEnd(),b=!1),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},M=Re(),x=t(M),b=!1;return y}}function Te(n){return n.length>1}function Re(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:b,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function De(n,t){return((n=n.x)[0]<0?n[1]-Ra-Ca:Ra-n[1])-((t=t.x)[0]<0?t[1]-Ra-Ca:Ra-t[1])}function Pe(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?qa:-qa,c=ga(i-e);ga(c-qa)<Ca?(n.point(e,r=(r+o)/2>0?Ra:-Ra),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=qa&&(ga(e-u)<Ca&&(e-=u*Ca),ga(i-a)<Ca&&(i-=a*Ca),r=Ue(e,r,i,o),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=i,r=o),u=a},lineEnd:function(){n.lineEnd(),e=r=0/0},clean:function(){return 2-t}}}function Ue(n,t,e,r){var u,i,o=Math.sin(n-e);return ga(o)>Ca?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function je(n,t,e,r){var u;if(null==n)u=e*Ra,r.point(-qa,u),r.point(0,u),r.point(qa,u),r.point(qa,0),r.point(qa,-u),r.point(0,-u),r.point(-qa,-u),r.point(-qa,0),r.point(-qa,u);else if(ga(n[0]-t[0])>Ca){var i=n[0]<t[0]?qa:-qa;u=e*i/2,r.point(-i,u),r.point(0,u),r.point(i,u)}else r.point(t[0],t[1])}function Fe(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;yc.reset();for(var a=0,c=t.length;c>a;++a){var l=t[a],s=l.length;if(s)for(var f=l[0],h=f[0],g=f[1]/2+qa/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===s&&(d=0),n=l[d];var m=n[0],y=n[1]/2+qa/4,M=Math.sin(y),x=Math.cos(y),b=m-h,_=b>=0?1:-1,w=_*b,S=w>qa,k=p*M;if(yc.add(Math.atan2(k*_*Math.sin(w),v*x+k*Math.cos(w))),i+=S?b+_*La:b,S^h>=e^m>=e){var E=de(pe(f),pe(n));Me(E);var A=de(u,E);Me(A);var N=(S^b>=0?-1:1)*tt(A[2]);(r>N||r===N&&(E[0]||E[1]))&&(o+=S^b>=0?1:-1)}if(!d++)break;h=m,p=M,v=x,f=n}}return(-Ca>i||Ca>i&&0>yc)^1&o}function He(n){function t(n,t){return Math.cos(n)*Math.cos(t)>i}function e(n){var e,i,c,l,s;return{lineStart:function(){l=c=!1,s=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=o?v?0:u(f,h):v?u(f+(0>f?qa:-qa),h):0;if(!e&&(l=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(be(e,g)||be(p,g))&&(p[0]+=Ca,p[1]+=Ca,v=t(p[0],p[1]))),v!==c)s=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^v){var m;d&i||!(m=r(p,e,!0))||(s=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&be(e,p)||n.point(p[0],p[1]),e=p,c=v,i=d},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return s|(l&&c)<<1}}}function r(n,t,e){var r=pe(n),u=pe(t),o=[1,0,0],a=de(r,u),c=ve(a,a),l=a[0],s=c-l*l;if(!s)return!e&&n;var f=i*c/s,h=-i*l/s,g=de(o,a),p=ye(o,f),v=ye(a,h);me(p,v);var d=g,m=ve(p,d),y=ve(d,d),M=m*m-y*(ve(p,p)-1);if(!(0>M)){var x=Math.sqrt(M),b=ye(d,(-m-x)/y);if(me(b,p),b=xe(b),!e)return b;var _,w=n[0],S=t[0],k=n[1],E=t[1];w>S&&(_=w,w=S,S=_);var A=S-w,N=ga(A-qa)<Ca,C=N||Ca>A;if(!N&&k>E&&(_=k,k=E,E=_),C?N?k+E>0^b[1]<(ga(b[0]-w)<Ca?k:E):k<=b[1]&&b[1]<=E:A>qa^(w<=b[0]&&b[0]<=S)){var z=ye(d,(-m+x)/y);return me(z,p),[b,xe(z)]}}}function u(t,e){var r=o?n:qa-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=ga(i)>Ca,c=gr(n,6*Da);return Le(t,e,c,o?[0,-n]:[-qa,n-qa])}function Oe(n,t,e,r){return function(u){var i,o=u.a,a=u.b,c=o.x,l=o.y,s=a.x,f=a.y,h=0,g=1,p=s-c,v=f-l;if(i=n-c,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-c,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-l,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-l,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:c+h*p,y:l+h*v}),1>g&&(u.b={x:c+g*p,y:l+g*v}),u}}}}}}function Ie(n,t,e,r){function u(r,u){return ga(r[0]-n)<Ca?u>0?0:3:ga(r[0]-e)<Ca?u>0?2:1:ga(r[1]-t)<Ca?u>0?1:0:u>0?3:2}function i(n,t){return o(n.x,t.x)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=d[u],c=a.length,l=a[0];c>o;++o)i=a[o],l[1]<=r?i[1]>r&&Q(l,i,n)>0&&++t:i[1]<=r&&Q(l,i,n)<0&&--t,l=i;return 0!==t}function l(i,a,c,l){var s=0,f=0;if(null==i||(s=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do l.point(0===s||3===s?n:e,s>1?r:t);while((s=(s+c+4)%4)!==f)}else l.point(a[0],a[1])}function s(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){s(n,t)&&a.point(n,t)}function h(){C.point=p,d&&d.push(m=[]),S=!0,w=!1,b=_=0/0}function g(){v&&(p(y,M),x&&w&&A.rejoin(),v.push(A.buffer())),C.point=f,w&&a.lineEnd()}function p(n,t){n=Math.max(-Tc,Math.min(Tc,n)),t=Math.max(-Tc,Math.min(Tc,t));var e=s(n,t);if(d&&m.push([n,t]),S)y=n,M=t,x=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:b,y:_},b:{x:n,y:t}};N(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}b=n,_=t,w=e}var v,d,m,y,M,x,b,_,w,S,k,E=a,A=Re(),N=Oe(n,t,e,r),C={point:f,lineStart:h,lineEnd:g,polygonStart:function(){a=A,v=[],d=[],k=!0},polygonEnd:function(){a=E,v=ta.merge(v);var t=c([n,r]),e=k&&t,u=v.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),l(null,null,1,a),a.lineEnd()),u&&Ce(v,i,t,l,a),a.polygonEnd()),v=d=m=null}};return C}}function Ye(n){var t=0,e=qa/3,r=ir(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*qa/180,e=n[1]*qa/180):[t/qa*180,e/qa*180]},u}function Ze(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,tt((i-(n*n+e*e)*u*u)/(2*u))]},e}function Ve(){function n(n,t){Dc+=u*n-r*t,r=n,u=t}var t,e,r,u;Hc.point=function(i,o){Hc.point=n,t=r=i,e=u=o},Hc.lineEnd=function(){n(t,e)}}function Xe(n,t){Pc>n&&(Pc=n),n>jc&&(jc=n),Uc>t&&(Uc=t),t>Fc&&(Fc=t)}function $e(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function u(){o.push("Z")}var i=Be(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=Be(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Be(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function We(n,t){_c+=n,wc+=t,++Sc}function Je(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);kc+=o*(t+n)/2,Ec+=o*(e+r)/2,Ac+=o,We(t=n,e=r)}var t,e;Ic.point=function(r,u){Ic.point=n,We(t=r,e=u)}}function Ge(){Ic.point=We}function Ke(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);kc+=o*(r+n)/2,Ec+=o*(u+t)/2,Ac+=o,o=u*n-r*t,Nc+=o*(r+n),Cc+=o*(u+t),zc+=3*o,We(r=n,u=t)}var t,e,r,u;Ic.point=function(i,o){Ic.point=n,We(t=r=i,e=u=o)},Ic.lineEnd=function(){n(t,e)}}function Qe(n){function t(t,e){n.moveTo(t+o,e),n.arc(t,e,o,0,La)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:b};return a}function nr(n){function t(n){return(a?r:e)(n)}function e(t){return rr(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){M=0/0,S.point=i,t.lineStart()}function i(e,r){var i=pe([e,r]),o=n(e,r);u(M,x,y,b,_,w,M=o[0],x=o[1],y=e,b=i[0],_=i[1],w=i[2],a,t),t.point(M,x)}function o(){S.point=e,t.lineEnd()}function c(){r(),S.point=l,S.lineEnd=s}function l(n,t){i(f=n,h=t),g=M,p=x,v=b,d=_,m=w,S.point=i}function s(){u(M,x,y,b,_,w,g,p,f,v,d,m,a,t),S.lineEnd=o,o()}var f,h,g,p,v,d,m,y,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c
+},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,a,c,l,s,f,h,g,p,v,d,m){var y=s-t,M=f-e,x=y*y+M*M;if(x>4*i&&d--){var b=a+g,_=c+p,w=l+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),E=ga(ga(w)-1)<Ca||ga(r-h)<Ca?(r+h)/2:Math.atan2(_,b),A=n(E,k),N=A[0],C=A[1],z=N-t,q=C-e,L=M*z-y*q;(L*L/x>i||ga((y*z+M*q)/x-.5)>.3||o>a*g+c*p+l*v)&&(u(t,e,r,a,c,l,N,C,E,b/=S,_/=S,w,d,m),m.point(N,C),u(N,C,E,b,_,w,s,f,h,g,p,v,d,m))}}var i=.5,o=Math.cos(30*Da),a=16;return t.precision=function(n){return arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function tr(n){var t=nr(function(t,e){return n([t*Pa,e*Pa])});return function(n){return or(t(n))}}function er(n){this.stream=n}function rr(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function ur(n){return ir(function(){return n})()}function ir(n){function t(n){return n=a(n[0]*Da,n[1]*Da),[n[0]*h+c,l-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*Pa,n[1]*Pa]}function r(){a=Ae(o=lr(m,M,x),i);var n=i(v,d);return c=g-n[0]*h,l=p+n[1]*h,u()}function u(){return s&&(s.valid=!1,s=null),t}var i,o,a,c,l,s,f=nr(function(n,t){return n=i(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,M=0,x=0,b=Lc,_=y,w=null,S=null;return t.stream=function(n){return s&&(s.valid=!1),s=or(b(o,f(_(n)))),s.valid=!0,s},t.clipAngle=function(n){return arguments.length?(b=null==n?(w=n,Lc):He((w=+n)*Da),u()):w},t.clipExtent=function(n){return arguments.length?(S=n,_=n?Ie(n[0][0],n[0][1],n[1][0],n[1][1]):y,u()):S},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*Da,d=n[1]%360*Da,r()):[v*Pa,d*Pa]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Da,M=n[1]%360*Da,x=n.length>2?n[2]%360*Da:0,r()):[m*Pa,M*Pa,x*Pa]},ta.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function or(n){return rr(n,function(t,e){n.point(t*Da,e*Da)})}function ar(n,t){return[n,t]}function cr(n,t){return[n>qa?n-La:-qa>n?n+La:n,t]}function lr(n,t,e){return n?t||e?Ae(fr(n),hr(t,e)):fr(n):t||e?hr(t,e):cr}function sr(n){return function(t,e){return t+=n,[t>qa?t-La:-qa>t?t+La:t,e]}}function fr(n){var t=sr(n);return t.invert=sr(-n),t}function hr(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*r+a*u;return[Math.atan2(c*i-s*o,a*r-l*u),tt(s*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*i-c*o;return[Math.atan2(c*i+l*o,a*r+s*u),tt(s*r-a*u)]},e}function gr(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=pr(e,u),i=pr(e,i),(o>0?i>u:u>i)&&(u+=o*La)):(u=n+o*La,i=n-.5*c);for(var l,s=u;o>0?s>i:i>s;s-=c)a.point((l=xe([e,-r*Math.cos(s),-r*Math.sin(s)]))[0],l[1])}}function pr(n,t){var e=pe(t);e[0]-=n,Me(e);var r=nt(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Ca)%(2*Math.PI)}function vr(n,t,e){var r=ta.range(n,t-Ca,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function dr(n,t,e){var r=ta.range(n,t-Ca,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function mr(n){return n.source}function yr(n){return n.target}function Mr(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),l=u*Math.sin(n),s=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(it(r-t)+u*o*it(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*s,u=e*l+t*f,o=e*i+t*a;return[Math.atan2(u,r)*Pa,Math.atan2(o,Math.sqrt(r*r+u*u))*Pa]}:function(){return[n*Pa,t*Pa]};return p.distance=h,p}function xr(){function n(n,u){var i=Math.sin(u*=Da),o=Math.cos(u),a=ga((n*=Da)-t),c=Math.cos(a);Yc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;Zc.point=function(u,i){t=u*Da,e=Math.sin(i*=Da),r=Math.cos(i),Zc.point=n},Zc.lineEnd=function(){Zc.point=Zc.lineEnd=b}}function br(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function _r(n,t){function e(n,t){o>0?-Ra+Ca>t&&(t=-Ra+Ca):t>Ra-Ca&&(t=Ra-Ca);var e=o/Math.pow(u(t),i);return[e*Math.sin(i*n),o-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(qa/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),o=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=o-t,r=K(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Ra]},e):Sr}function wr(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return ga(u)<Ca?ar:(e.invert=function(n,t){var e=i-t;return[Math.atan2(n,e)/u,i-K(u)*Math.sqrt(n*n+e*e)]},e)}function Sr(n,t){return[n,Math.log(Math.tan(qa/4+t/2))]}function kr(n){var t,e=ur(n),r=e.scale,u=e.translate,i=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=u.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=i.apply(e,arguments);if(o===e){if(t=null==n){var a=qa*r(),c=u();i([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function Er(n,t){return[Math.log(Math.tan(qa/4+t/2)),-n]}function Ar(n){return n[0]}function Nr(n){return n[1]}function Cr(n){for(var t=n.length,e=[0,1],r=2,u=2;t>u;u++){for(;r>1&&Q(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function zr(n,t){return n[0]-t[0]||n[1]-t[1]}function qr(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Lr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],l=e[1],s=t[1]-c,f=r[1]-l,h=(a*(c-l)-f*(u-i))/(f*o-a*s);return[u+h*o,c+h*s]}function Tr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Rr(){tu(this),this.edge=this.site=this.circle=null}function Dr(n){var t=el.pop()||new Rr;return t.site=n,t}function Pr(n){Xr(n),Qc.remove(n),el.push(n),tu(n)}function Ur(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];Pr(n);for(var c=i;c.circle&&ga(e-c.circle.x)<Ca&&ga(r-c.circle.cy)<Ca;)i=c.P,a.unshift(c),Pr(c),c=i;a.unshift(c),Xr(c);for(var l=o;l.circle&&ga(e-l.circle.x)<Ca&&ga(r-l.circle.cy)<Ca;)o=l.N,a.push(l),Pr(l),l=o;a.push(l),Xr(l);var s,f=a.length;for(s=1;f>s;++s)l=a[s],c=a[s-1],Kr(l.edge,c.site,l.site,u);c=a[0],l=a[f-1],l.edge=Jr(c.site,l.site,null,u),Vr(c),Vr(l)}function jr(n){for(var t,e,r,u,i=n.x,o=n.y,a=Qc._;a;)if(r=Fr(a,o)-i,r>Ca)a=a.L;else{if(u=i-Hr(a,o),!(u>Ca)){r>-Ca?(t=a.P,e=a):u>-Ca?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var c=Dr(n);if(Qc.insert(t,c),t||e){if(t===e)return Xr(t),e=Dr(t.site),Qc.insert(c,e),c.edge=e.edge=Jr(t.site,c.site),Vr(t),void Vr(e);if(!e)return void(c.edge=Jr(t.site,c.site));Xr(t),Xr(e);var l=t.site,s=l.x,f=l.y,h=n.x-s,g=n.y-f,p=e.site,v=p.x-s,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,M=v*v+d*d,x={x:(d*y-g*M)/m+s,y:(h*M-v*y)/m+f};Kr(e.edge,l,p,x),c.edge=Jr(l,n,null,x),e.edge=Jr(n,p,null,x),Vr(t),Vr(e)}}function Fr(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var o=n.P;if(!o)return-1/0;e=o.site;var a=e.x,c=e.y,l=c-t;if(!l)return a;var s=a-r,f=1/i-1/l,h=s/l;return f?(-h+Math.sqrt(h*h-2*f*(s*s/(-2*l)-c+l/2+u-i/2)))/f+r:(r+a)/2}function Hr(n,t){var e=n.N;if(e)return Fr(e,t);var r=n.site;return r.y===t?r.x:1/0}function Or(n){this.site=n,this.edges=[]}function Ir(n){for(var t,e,r,u,i,o,a,c,l,s,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=Kc,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(a=i.edges,c=a.length,o=0;c>o;)s=a[o].end(),r=s.x,u=s.y,l=a[++o%c].start(),t=l.x,e=l.y,(ga(r-t)>Ca||ga(u-e)>Ca)&&(a.splice(o,0,new Qr(Gr(i.site,s,ga(r-f)<Ca&&p-u>Ca?{x:f,y:ga(t-f)<Ca?e:p}:ga(u-p)<Ca&&h-r>Ca?{x:ga(e-p)<Ca?t:h,y:p}:ga(r-h)<Ca&&u-g>Ca?{x:h,y:ga(t-h)<Ca?e:g}:ga(u-g)<Ca&&r-f>Ca?{x:ga(e-g)<Ca?t:f,y:g}:null),i.site,null)),++c)}function Yr(n,t){return t.angle-n.angle}function Zr(){tu(this),this.x=this.y=this.arc=this.site=this.cy=null}function Vr(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,u=n.site,i=e.site;if(r!==i){var o=u.x,a=u.y,c=r.x-o,l=r.y-a,s=i.x-o,f=i.y-a,h=2*(c*f-l*s);if(!(h>=-za)){var g=c*c+l*l,p=s*s+f*f,v=(f*g-l*p)/h,d=(c*p-s*g)/h,f=d+a,m=rl.pop()||new Zr;m.arc=n,m.site=u,m.x=v+o,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,M=tl._;M;)if(m.y<M.y||m.y===M.y&&m.x<=M.x){if(!M.L){y=M.P;break}M=M.L}else{if(!M.R){y=M;break}M=M.R}tl.insert(y,m),y||(nl=m)}}}}function Xr(n){var t=n.circle;t&&(t.P||(nl=t.N),tl.remove(t),rl.push(t),tu(t),n.circle=null)}function $r(n){for(var t,e=Gc,r=Oe(n[0][0],n[0][1],n[1][0],n[1][1]),u=e.length;u--;)t=e[u],(!Br(t,n)||!r(t)||ga(t.a.x-t.b.x)<Ca&&ga(t.a.y-t.b.y)<Ca)&&(t.a=t.b=null,e.splice(u,1))}function Br(n,t){var e=n.b;if(e)return!0;var r,u,i=n.a,o=t[0][0],a=t[1][0],c=t[0][1],l=t[1][1],s=n.l,f=n.r,h=s.x,g=s.y,p=f.x,v=f.y,d=(h+p)/2,m=(g+v)/2;if(v===g){if(o>d||d>=a)return;if(h>p){if(i){if(i.y>=l)return}else i={x:d,y:c};e={x:d,y:l}}else{if(i){if(i.y<c)return}else i={x:d,y:l};e={x:d,y:c}}}else if(r=(h-p)/(v-g),u=m-r*d,-1>r||r>1)if(h>p){if(i){if(i.y>=l)return}else i={x:(c-u)/r,y:c};e={x:(l-u)/r,y:l}}else{if(i){if(i.y<c)return}else i={x:(l-u)/r,y:l};e={x:(c-u)/r,y:c}}else if(v>g){if(i){if(i.x>=a)return}else i={x:o,y:r*o+u};e={x:a,y:r*a+u}}else{if(i){if(i.x<o)return}else i={x:a,y:r*a+u};e={x:o,y:r*o+u}}return n.a=i,n.b=e,!0}function Wr(n,t){this.l=n,this.r=t,this.a=this.b=null}function Jr(n,t,e,r){var u=new Wr(n,t);return Gc.push(u),e&&Kr(u,n,t,e),r&&Kr(u,t,n,r),Kc[n.i].edges.push(new Qr(u,n,t)),Kc[t.i].edges.push(new Qr(u,t,n)),u}function Gr(n,t,e){var r=new Wr(n,null);return r.a=t,r.b=e,Gc.push(r),r}function Kr(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function Qr(n,t,e){var r=n.a,u=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(u.x-r.x,r.y-u.y):Math.atan2(r.x-u.x,u.y-r.y)}function nu(){this._=null}function tu(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function eu(n,t){var e=t,r=t.R,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function ru(n,t){var e=t,r=t.L,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function uu(n){for(;n.L;)n=n.L;return n}function iu(n,t){var e,r,u,i=n.sort(ou).pop();for(Gc=[],Kc=new Array(n.length),Qc=new nu,tl=new nu;;)if(u=nl,i&&(!u||i.y<u.y||i.y===u.y&&i.x<u.x))(i.x!==e||i.y!==r)&&(Kc[i.i]=new Or(i),jr(i),e=i.x,r=i.y),i=n.pop();else{if(!u)break;Ur(u.arc)}t&&($r(t),Ir(t));var o={cells:Kc,edges:Gc};return Qc=tl=Gc=Kc=null,o}function ou(n,t){return t.y-n.y||t.x-n.x}function au(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function cu(n){return n.x}function lu(n){return n.y}function su(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function fu(n,t,e,r,u,i){if(!n(t,e,r,u,i)){var o=.5*(e+u),a=.5*(r+i),c=t.nodes;c[0]&&fu(n,c[0],e,r,o,a),c[1]&&fu(n,c[1],o,r,u,a),c[2]&&fu(n,c[2],e,a,o,i),c[3]&&fu(n,c[3],o,a,u,i)}}function hu(n,t,e,r,u,i,o){var a,c=1/0;return function l(n,s,f,h,g){if(!(s>i||f>o||r>h||u>g)){if(p=n.point){var p,v=t-n.x,d=e-n.y,m=v*v+d*d;if(c>m){var y=Math.sqrt(c=m);r=t-y,u=e-y,i=t+y,o=e+y,a=p}}for(var M=n.nodes,x=.5*(s+h),b=.5*(f+g),_=t>=x,w=e>=b,S=w<<1|_,k=S+4;k>S;++S)if(n=M[3&S])switch(3&S){case 0:l(n,s,f,x,b);break;case 1:l(n,x,f,h,b);break;case 2:l(n,s,b,x,g);break;case 3:l(n,x,b,h,g)}}}(n,r,u,i,o),a}function gu(n,t){n=ta.rgb(n),t=ta.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return"#"+xt(Math.round(e+i*n))+xt(Math.round(r+o*n))+xt(Math.round(u+a*n))}}function pu(n,t){var e,r={},u={};for(e in n)e in t?r[e]=mu(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function vu(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function du(n,t){var e,r,u,i=il.lastIndex=ol.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(e=il.exec(n))&&(r=ol.exec(t));)(u=r.index)>i&&(u=t.slice(i,u),a[o]?a[o]+=u:a[++o]=u),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,c.push({i:o,x:vu(e,r)})),i=ol.lastIndex;return i<t.length&&(u=t.slice(i),a[o]?a[o]+=u:a[++o]=u),a.length<2?c[0]?(t=c[0].x,function(n){return t(n)+""}):function(){return t}:(t=c.length,function(n){for(var e,r=0;t>r;++r)a[(e=c[r]).i]=e.x(n);return a.join("")})}function mu(n,t){for(var e,r=ta.interpolators.length;--r>=0&&!(e=ta.interpolators[r](n,t)););return e}function yu(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(mu(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function Mu(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function xu(n){return function(t){return 1-n(1-t)}}function bu(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function _u(n){return n*n}function wu(n){return n*n*n}function Su(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function ku(n){return function(t){return Math.pow(t,n)}}function Eu(n){return 1-Math.cos(n*Ra)}function Au(n){return Math.pow(2,10*(n-1))}function Nu(n){return 1-Math.sqrt(1-n*n)}function Cu(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/La*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*La/t)}}function zu(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function qu(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Lu(n,t){n=ta.hcl(n),t=ta.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return st(e+i*n,r+o*n,u+a*n)+""}}function Tu(n,t){n=ta.hsl(n),t=ta.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ct(e+i*n,r+o*n,u+a*n)+""}}function Ru(n,t){n=ta.lab(n),t=ta.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return ht(e+i*n,r+o*n,u+a*n)+""}}function Du(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Pu(n){var t=[n.a,n.b],e=[n.c,n.d],r=ju(t),u=Uu(t,e),i=ju(Fu(e,t,-u))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,u*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Pa,this.translate=[n.e,n.f],this.scale=[r,i],this.skew=i?Math.atan2(u,i)*Pa:0}function Uu(n,t){return n[0]*t[0]+n[1]*t[1]}function ju(n){var t=Math.sqrt(Uu(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Fu(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Hu(n,t){var e,r=[],u=[],i=ta.transform(n),o=ta.transform(t),a=i.translate,c=o.translate,l=i.rotate,s=o.rotate,f=i.skew,h=o.skew,g=i.scale,p=o.scale;return a[0]!=c[0]||a[1]!=c[1]?(r.push("translate(",null,",",null,")"),u.push({i:1,x:vu(a[0],c[0])},{i:3,x:vu(a[1],c[1])})):r.push(c[0]||c[1]?"translate("+c+")":""),l!=s?(l-s>180?s+=360:s-l>180&&(l+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:vu(l,s)})):s&&r.push(r.pop()+"rotate("+s+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:vu(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:vu(g[0],p[0])},{i:e-2,x:vu(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++i<e;)r[(t=u[i]).i]=t.x(n);return r.join("")}}function Ou(n,t){return t=(t-=n=+n)||1/t,function(e){return(e-n)/t}}function Iu(n,t){return t=(t-=n=+n)||1/t,function(e){return Math.max(0,Math.min(1,(e-n)/t))}}function Yu(n){for(var t=n.source,e=n.target,r=Vu(t,e),u=[t];t!==r;)t=t.parent,u.push(t);for(var i=u.length;e!==r;)u.splice(i,0,e),e=e.parent;return u}function Zu(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Vu(n,t){if(n===t)return n;for(var e=Zu(n),r=Zu(t),u=e.pop(),i=r.pop(),o=null;u===i;)o=u,u=e.pop(),i=r.pop();return o}function Xu(n){n.fixed|=2}function $u(n){n.fixed&=-7}function Bu(n){n.fixed|=4,n.px=n.x,n.py=n.y}function Wu(n){n.fixed&=-5}function Ju(n,t,e){var r=0,u=0;if(n.charge=0,!n.leaf)for(var i,o=n.nodes,a=o.length,c=-1;++c<a;)i=o[c],null!=i&&(Ju(i,t,e),n.charge+=i.charge,r+=i.charge*i.cx,u+=i.charge*i.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var l=t*e[n.point.index];n.charge+=n.pointCharge=l,r+=l*n.point.x,u+=l*n.point.y}n.cx=r/n.charge,n.cy=u/n.charge}function Gu(n,t){return ta.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=ri,n}function Ku(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(u=n.children)&&(r=u.length))for(var r,u;--r>=0;)e.push(u[r])}function Qu(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(i=n.children)&&(u=i.length))for(var u,i,o=-1;++o<u;)e.push(i[o]);for(;null!=(n=r.pop());)t(n)}function ni(n){return n.children}function ti(n){return n.value}function ei(n,t){return t.value-n.value}function ri(n){return ta.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function ui(n){return n.x}function ii(n){return n.y}function oi(n,t,e){n.y0=t,n.y=e}function ai(n){return ta.range(n.length)}function ci(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function li(n){for(var t,e=1,r=0,u=n[0][1],i=n.length;i>e;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function si(n){return n.reduce(fi,0)}function fi(n,t){return n+t[1]}function hi(n,t){return gi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function gi(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function pi(n){return[ta.min(n),ta.max(n)]}function vi(n,t){return n.value-t.value}function di(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function mi(n,t){n._pack_next=t,t._pack_prev=n}function yi(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function Mi(n){function t(n){s=Math.min(n.x-n.r,s),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(l=e.length)){var e,r,u,i,o,a,c,l,s=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(xi),r=e[0],r.x=-r.r,r.y=0,t(r),l>1&&(u=e[1],u.x=u.r,u.y=0,t(u),l>2))for(i=e[2],wi(r,u,i),t(i),di(r,i),r._pack_prev=i,di(i,u),u=r._pack_next,o=3;l>o;o++){wi(r,u,i=e[o]);var p=0,v=1,d=1;for(a=u._pack_next;a!==u;a=a._pack_next,v++)if(yi(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!yi(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.r<r.r?mi(r,u=a):mi(r=c,u),o--):(di(r,i),u=i,t(i))}var m=(s+f)/2,y=(h+g)/2,M=0;for(o=0;l>o;o++)i=e[o],i.x-=m,i.y-=y,M=Math.max(M,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=M,e.forEach(bi)}}function xi(n){n._pack_next=n._pack_prev=n}function bi(n){delete n._pack_next,delete n._pack_prev}function _i(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++i<o;)_i(u[i],t,e,r)}function wi(n,t,e){var r=n.r+e.r,u=t.x-n.x,i=t.y-n.y;if(r&&(u||i)){var o=t.r+e.r,a=u*u+i*i;o*=o,r*=r;var c=.5+(r-o)/(2*a),l=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+c*u+l*i,e.y=n.y+c*i-l*u}else e.x=n.x+r,e.y=n.y}function Si(n,t){return n.parent==t.parent?1:2}function ki(n){var t=n.children;return t.length?t[0]:n.t}function Ei(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function Ai(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function Ni(n){for(var t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Ci(n,t,e){return n.a.parent===t.parent?n.a:e}function zi(n){return 1+ta.max(n,function(n){return n.y})}function qi(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Li(n){var t=n.children;return t&&t.length?Li(t[0]):n}function Ti(n){var t,e=n.children;return e&&(t=e.length)?Ti(e[t-1]):n}function Ri(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Di(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Pi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Ui(n){return n.rangeExtent?n.rangeExtent():Pi(n.range())}function ji(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Fi(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Hi(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:ml}function Oi(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)u.push(e(n[o-1],n[o])),i.push(r(t[o-1],t[o]));return function(t){var e=ta.bisect(n,t,1,a)-1;return i[e](u[e](t))}}function Ii(n,t,e,r){function u(){var u=Math.min(n.length,t.length)>2?Oi:ji,c=r?Iu:Ou;return o=u(n,t,c,e),a=u(t,n,c,mu),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(Du)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Xi(n,t)},i.tickFormat=function(t,e){return $i(n,t,e)},i.nice=function(t){return Zi(n,t),u()},i.copy=function(){return Ii(n,t,e,r)},u()}function Yi(n,t){return ta.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Zi(n,t){return Fi(n,Hi(Vi(n,t)[2]))}function Vi(n,t){null==t&&(t=10);var e=Pi(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Xi(n,t){return ta.range.apply(ta,Vi(n,t))}function $i(n,t,e){var r=Vi(n,t);if(e){var u=ic.exec(e);if(u.shift(),"s"===u[8]){var i=ta.formatPrefix(Math.max(ga(r[0]),ga(r[1])));return u[7]||(u[7]="."+Bi(i.scale(r[2]))),u[8]="f",e=ta.format(u.join("")),function(n){return e(i.scale(n))+i.symbol}}u[7]||(u[7]="."+Wi(u[8],r)),e=u.join("")}else e=",."+Bi(r[2])+"f";return ta.format(e)}function Bi(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function Wi(n,t){var e=Bi(t[2]);return n in yl?Math.abs(e-Bi(Math.max(ga(t[0]),ga(t[1]))))+ +("e"!==n):e-2*("%"===n)}function Ji(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Fi(r.map(u),e?Math:xl);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=Pi(r),o=[],a=n[0],c=n[1],l=Math.floor(u(a)),s=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(s-l)){if(e){for(;s>l;l++)for(var h=1;f>h;h++)o.push(i(l)*h);o.push(i(l))}else for(o.push(i(l));l++<s;)for(var h=f-1;h>0;h--)o.push(i(l)*h);for(l=0;o[l]<a;l++);for(s=o.length;o[s-1]>c;s--);o=o.slice(l,s)}return o},o.tickFormat=function(n,t){if(!arguments.length)return Ml;arguments.length<2?t=Ml:"function"!=typeof t&&(t=ta.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return Ji(n.copy(),t,e,r)},Yi(o,n)}function Gi(n,t,e){function r(t){return n(u(t))}var u=Ki(t),i=Ki(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Xi(e,n)},r.tickFormat=function(n,t){return $i(e,n,t)},r.nice=function(n){return r.domain(Zi(e,n))},r.exponent=function(o){return arguments.length?(u=Ki(t=o),i=Ki(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return Gi(n.copy(),t,e)},Yi(r,n)}function Ki(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function Qi(n,t){function e(e){return i[((u.get(e)||("range"===t.t?u.set(e,n.push(e)):0/0))-1)%i.length]}function r(t,e){return ta.range(n.length).map(function(n){return t+e*n})}var u,i,o;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new l;for(var i,o=-1,a=r.length;++o<a;)u.has(i=r[o])||u.set(i,n.push(i));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(i=n,o=0,t={t:"range",a:arguments},e):i},e.rangePoints=function(u,a){arguments.length<2&&(a=0);var c=u[0],l=u[1],s=n.length<2?(c=(c+l)/2,0):(l-c)/(n.length-1+a);return i=r(c+s*a/2,s),o=0,t={t:"rangePoints",a:arguments},e},e.rangeRoundPoints=function(u,a){arguments.length<2&&(a=0);var c=u[0],l=u[1],s=n.length<2?(c=l=Math.round((c+l)/2),0):(l-c)/(n.length-1+a)|0;return i=r(c+Math.round(s*a/2+(l-c-(n.length-1+a)*s)/2),s),o=0,t={t:"rangeRoundPoints",a:arguments},e},e.rangeBands=function(u,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=(f-s)/(n.length-a+2*c);return i=r(s+h*c,h),l&&i.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(u,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=Math.floor((f-s)/(n.length-a+2*c));return i=r(s+Math.round((f-s-(n.length-a)*h)/2),h),l&&i.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return o},e.rangeExtent=function(){return Pi(t.a[0])},e.copy=function(){return Qi(n,t)},e.domain(n)}function no(n,t){function i(){var e=0,r=t.length;for(a=[];++e<r;)a[e-1]=ta.quantile(n,e/r);return o}function o(n){return isNaN(n=+n)?void 0:t[ta.bisect(a,n)]}var a;return o.domain=function(t){return arguments.length?(n=t.map(r).filter(u).sort(e),i()):n},o.range=function(n){return arguments.length?(t=n,i()):t},o.quantiles=function(){return a},o.invertExtent=function(e){return e=t.indexOf(e),0>e?[0/0,0/0]:[e>0?a[e-1]:n[0],e<a.length?a[e]:n[n.length-1]]},o.copy=function(){return no(n,t)},i()}function to(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(i*(t-n))))]}function u(){return i=e.length/(t-n),o=e.length-1,r}var i,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],u()):[n,t]},r.range=function(n){return arguments.length?(e=n,u()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return to(n,t,e)},u()}function eo(n,t){function e(e){return e>=e?t[ta.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return eo(n,t)},e}function ro(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Xi(n,t)},t.tickFormat=function(t,e){return $i(n,t,e)},t.copy=function(){return ro(n)},t}function uo(){return 0}function io(n){return n.innerRadius}function oo(n){return n.outerRadius}function ao(n){return n.startAngle}function co(n){return n.endAngle}function lo(n){return n&&n.padAngle}function so(n,t,e,r){return(n-e)*t-(t-r)*n>0?0:1}function fo(n,t,e,r,u){var i=n[0]-t[0],o=n[1]-t[1],a=(u?r:-r)/Math.sqrt(i*i+o*o),c=a*o,l=-a*i,s=n[0]+c,f=n[1]+l,h=t[0]+c,g=t[1]+l,p=(s+h)/2,v=(f+g)/2,d=h-s,m=g-f,y=d*d+m*m,M=e-r,x=s*g-h*f,b=(0>m?-1:1)*Math.sqrt(M*M*y-x*x),_=(x*m-d*b)/y,w=(-x*d-m*b)/y,S=(x*m+d*b)/y,k=(-x*d+m*b)/y,E=_-p,A=w-v,N=S-p,C=k-v;return E*E+A*A>N*N+C*C&&(_=S,w=k),[[_-c,w-l],[_*e/M,w*e/M]]}function ho(n){function t(t){function o(){l.push("M",i(n(s),a))}for(var c,l=[],s=[],f=-1,h=t.length,g=Et(e),p=Et(r);++f<h;)u.call(this,c=t[f],f)?s.push([+g.call(this,c,f),+p.call(this,c,f)]):s.length&&(o(),s=[]);return s.length&&o(),l.length?l.join(""):null}var e=Ar,r=Nr,u=Ne,i=go,o=i.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(u=n,t):u},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?i=n:(i=El.get(n)||go).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function go(n){return n.join("L")}function po(n){return go(n)+"Z"}function vo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&u.push("H",r[0]),u.join("")}function mo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("V",(r=n[t])[1],"H",r[0]);return u.join("")}function yo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r=n[t])[0],"V",r[1]);return u.join("")}function Mo(n,t){return n.length<4?go(n):n[1]+_o(n.slice(1,-1),wo(n,t))}function xo(n,t){return n.length<3?go(n):n[0]+_o((n.push(n[0]),n),wo([n[n.length-2]].concat(n,[n[1]]),t))}function bo(n,t){return n.length<3?go(n):n[0]+_o(n,wo(n,t))}function _o(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return go(n);var e=n.length!=t.length,r="",u=n[0],i=n[1],o=t[0],a=o,c=1;if(e&&(r+="Q"+(i[0]-2*o[0]/3)+","+(i[1]-2*o[1]/3)+","+i[0]+","+i[1],u=n[1],c=2),t.length>1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var l=2;l<t.length;l++,c++)i=n[c],a=t[l],r+="S"+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1]}if(e){var s=n[c];r+="Q"+(i[0]+2*a[0]/3)+","+(i[1]+2*a[1]/3)+","+s[0]+","+s[1]}return r}function wo(n,t){for(var e,r=[],u=(1-t)/2,i=n[0],o=n[1],a=1,c=n.length;++a<c;)e=i,i=o,o=n[a],r.push([u*(o[0]-e[0]),u*(o[1]-e[1])]);return r}function So(n){if(n.length<3)return go(n);var t=1,e=n.length,r=n[0],u=r[0],i=r[1],o=[u,u,u,(r=n[1])[0]],a=[i,i,i,r[1]],c=[u,",",i,"L",No(Cl,o),",",No(Cl,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Co(c,o,a);return n.pop(),c.push("L",r),c.join("")}function ko(n){if(n.length<4)return go(n);for(var t,e=[],r=-1,u=n.length,i=[0],o=[0];++r<3;)t=n[r],i.push(t[0]),o.push(t[1]);for(e.push(No(Cl,i)+","+No(Cl,o)),--r;++r<u;)t=n[r],i.shift(),i.push(t[0]),o.shift(),o.push(t[1]),Co(e,i,o);return e.join("")}function Eo(n){for(var t,e,r=-1,u=n.length,i=u+4,o=[],a=[];++r<4;)e=n[r%u],o.push(e[0]),a.push(e[1]);for(t=[No(Cl,o),",",No(Cl,a)],--r;++r<i;)e=n[r%u],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Co(t,o,a);return t.join("")}function Ao(n,t){var e=n.length-1;if(e)for(var r,u,i=n[0][0],o=n[0][1],a=n[e][0]-i,c=n[e][1]-o,l=-1;++l<=e;)r=n[l],u=l/e,r[0]=t*r[0]+(1-t)*(i+u*a),r[1]=t*r[1]+(1-t)*(o+u*c);return So(n)}function No(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Co(n,t,e){n.push("C",No(Al,t),",",No(Al,e),",",No(Nl,t),",",No(Nl,e),",",No(Cl,t),",",No(Cl,e))}function zo(n,t){return(t[1]-n[1])/(t[0]-n[0])}function qo(n){for(var t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=zo(u,i);++t<e;)r[t]=(o+(o=zo(u=i,i=n[t+1])))/2;return r[t]=o,r}function Lo(n){for(var t,e,r,u,i=[],o=qo(n),a=-1,c=n.length-1;++a<c;)t=zo(n[a],n[a+1]),ga(t)<Ca?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,u=e*e+r*r,u>9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function To(n){return n.length<3?go(n):n[0]+_o(n,Lo(n))}function Ro(n){for(var t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]-Ra,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Do(n){function t(t){function c(){v.push("M",a(n(m),f),s,l(n(d.reverse()),f),"Z")}for(var h,g,p,v=[],d=[],m=[],y=-1,M=t.length,x=Et(e),b=Et(u),_=e===r?function(){return g}:Et(r),w=u===i?function(){return p}:Et(i);++y<M;)o.call(this,h=t[y],y)?(d.push([g=+x.call(this,h,y),p=+b.call(this,h,y)]),m.push([+_.call(this,h,y),+w.call(this,h,y)])):d.length&&(c(),d=[],m=[]);return d.length&&c(),v.length?v.join(""):null}var e=Ar,r=Ar,u=0,i=Nr,o=Ne,a=go,c=a.key,l=a,s="L",f=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r
+},t.y=function(n){return arguments.length?(u=i=n,t):i},t.y0=function(n){return arguments.length?(u=n,t):u},t.y1=function(n){return arguments.length?(i=n,t):i},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c="function"==typeof n?a=n:(a=El.get(n)||go).key,l=a.reverse||a,s=a.closed?"M":"L",t):c},t.tension=function(n){return arguments.length?(f=n,t):f},t}function Po(n){return n.radius}function Uo(n){return[n.x,n.y]}function jo(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]-Ra;return[e*Math.cos(r),e*Math.sin(r)]}}function Fo(){return 64}function Ho(){return"circle"}function Oo(n){var t=Math.sqrt(n/qa);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Io(n){return function(){var t,e;(t=this[n])&&(e=t[t.active])&&(--t.count?delete t[t.active]:delete this[n],t.active+=.5,e.event&&e.event.interrupt.call(this,this.__data__,e.index))}}function Yo(n,t,e){return ya(n,Pl),n.namespace=t,n.id=e,n}function Zo(n,t,e,r){var u=n.id,i=n.namespace;return Y(n,"function"==typeof e?function(n,o,a){n[i][u].tween.set(t,r(e.call(n,n.__data__,o,a)))}:(e=r(e),function(n){n[i][u].tween.set(t,e)}))}function Vo(n){return null==n&&(n=""),function(){this.textContent=n}}function Xo(n){return null==n?"__transition__":"__transition_"+n+"__"}function $o(n,t,e,r,u){var i=n[e]||(n[e]={active:0,count:0}),o=i[r];if(!o){var a=u.time;o=i[r]={tween:new l,time:a,delay:u.delay,duration:u.duration,ease:u.ease,index:t},u=null,++i.count,ta.timer(function(u){function c(e){if(i.active>r)return s();var u=i[i.active];u&&(--i.count,delete i[i.active],u.event&&u.event.interrupt.call(n,n.__data__,u.index)),i.active=r,o.event&&o.event.start.call(n,n.__data__,t),o.tween.forEach(function(e,r){(r=r.call(n,n.__data__,t))&&v.push(r)}),h=o.ease,f=o.duration,ta.timer(function(){return p.c=l(e||1)?Ne:l,1},0,a)}function l(e){if(i.active!==r)return 1;for(var u=e/f,a=h(u),c=v.length;c>0;)v[--c].call(n,a);return u>=1?(o.event&&o.event.end.call(n,n.__data__,t),s()):void 0}function s(){return--i.count?delete i[r]:delete n[e],1}var f,h,g=o.delay,p=ec,v=[];return p.t=g+a,u>=g?c(u-g):void(p.c=c)},0,a)}}function Bo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function Wo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function Jo(n){return n.toISOString()}function Go(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=ta.bisect(Vl,u);return i==Vl.length?[t.year,Vi(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/Vl[i-1]<Vl[i]/u?i-1:i]:[Bl,Vi(n,e)[2]]}return r.invert=function(t){return Ko(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(Ko)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,Ko(+e+1),t).length}var i=r.domain(),o=Pi(i),a=null==n?u(o,10):"number"==typeof n&&u(o,n);return a&&(n=a[0],t=a[1]),r.domain(Fi(i,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=Ko(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=Ko(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Pi(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],Ko(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return Go(n.copy(),t,e)},Yi(r,n)}function Ko(n){return new Date(n)}function Qo(n){return JSON.parse(n.responseText)}function na(n){var t=ua.createRange();return t.selectNode(ua.body),t.createContextualFragment(n.responseText)}var ta={version:"3.5.5"},ea=[].slice,ra=function(n){return ea.call(n)},ua=this.document;if(ua)try{ra(ua.documentElement.childNodes)[0].nodeType}catch(ia){ra=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}if(Date.now||(Date.now=function(){return+new Date}),ua)try{ua.createElement("DIV").style.setProperty("opacity",0,"")}catch(oa){var aa=this.Element.prototype,ca=aa.setAttribute,la=aa.setAttributeNS,sa=this.CSSStyleDeclaration.prototype,fa=sa.setProperty;aa.setAttribute=function(n,t){ca.call(this,n,t+"")},aa.setAttributeNS=function(n,t,e){la.call(this,n,t,e+"")},sa.setProperty=function(n,t,e){fa.call(this,n,t+"",e)}}ta.ascending=e,ta.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},ta.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i;)if(null!=(r=n[u])&&r>=r){e=r;break}for(;++u<i;)null!=(r=n[u])&&e>r&&(e=r)}else{for(;++u<i;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=r;break}for(;++u<i;)null!=(r=t.call(n,n[u],u))&&e>r&&(e=r)}return e},ta.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i;)if(null!=(r=n[u])&&r>=r){e=r;break}for(;++u<i;)null!=(r=n[u])&&r>e&&(e=r)}else{for(;++u<i;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=r;break}for(;++u<i;)null!=(r=t.call(n,n[u],u))&&r>e&&(e=r)}return e},ta.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i<o;)if(null!=(r=n[i])&&r>=r){e=u=r;break}for(;++i<o;)null!=(r=n[i])&&(e>r&&(e=r),r>u&&(u=r))}else{for(;++i<o;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=u=r;break}for(;++i<o;)null!=(r=t.call(n,n[i],i))&&(e>r&&(e=r),r>u&&(u=r))}return[e,u]},ta.sum=function(n,t){var e,r=0,i=n.length,o=-1;if(1===arguments.length)for(;++o<i;)u(e=+n[o])&&(r+=e);else for(;++o<i;)u(e=+t.call(n,n[o],o))&&(r+=e);return r},ta.mean=function(n,t){var e,i=0,o=n.length,a=-1,c=o;if(1===arguments.length)for(;++a<o;)u(e=r(n[a]))?i+=e:--c;else for(;++a<o;)u(e=r(t.call(n,n[a],a)))?i+=e:--c;return c?i/c:void 0},ta.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),u=+n[r-1],i=e-r;return i?u+i*(n[r]-u):u},ta.median=function(n,t){var i,o=[],a=n.length,c=-1;if(1===arguments.length)for(;++c<a;)u(i=r(n[c]))&&o.push(i);else for(;++c<a;)u(i=r(t.call(n,n[c],c)))&&o.push(i);return o.length?ta.quantile(o.sort(e),.5):void 0},ta.variance=function(n,t){var e,i,o=n.length,a=0,c=0,l=-1,s=0;if(1===arguments.length)for(;++l<o;)u(e=r(n[l]))&&(i=e-a,a+=i/++s,c+=i*(e-a));else for(;++l<o;)u(e=r(t.call(n,n[l],l)))&&(i=e-a,a+=i/++s,c+=i*(e-a));return s>1?c/(s-1):void 0},ta.deviation=function(){var n=ta.variance.apply(this,arguments);return n?Math.sqrt(n):n};var ha=i(e);ta.bisectLeft=ha.left,ta.bisect=ta.bisectRight=ha.right,ta.bisector=function(n){return i(1===n.length?function(t,r){return e(n(t),r)}:n)},ta.shuffle=function(n,t,e){(i=arguments.length)<3&&(e=n.length,2>i&&(t=0));for(var r,u,i=e-t;i;)u=Math.random()*i--|0,r=n[i+t],n[i+t]=n[u+t],n[u+t]=r;return n},ta.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},ta.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},ta.zip=function(){if(!(r=arguments.length))return[];for(var n=-1,t=ta.min(arguments,o),e=new Array(t);++n<t;)for(var r,u=-1,i=e[n]=new Array(r);++u<r;)i[u]=arguments[u][n];return e},ta.transpose=function(n){return ta.zip.apply(ta,n)},ta.keys=function(n){var t=[];for(var e in n)t.push(e);return t},ta.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},ta.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},ta.merge=function(n){for(var t,e,r,u=n.length,i=-1,o=0;++i<u;)o+=n[i].length;for(e=new Array(o);--u>=0;)for(r=n[u],t=r.length;--t>=0;)e[--o]=r[t];return e};var ga=Math.abs;ta.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),(t-n)/e===1/0)throw new Error("infinite range");var r,u=[],i=a(ga(e)),o=-1;if(n*=i,t*=i,e*=i,0>e)for(;(r=n+e*++o)>t;)u.push(r/i);else for(;(r=n+e*++o)<t;)u.push(r/i);return u},ta.map=function(n,t){var e=new l;if(n instanceof l)n.forEach(function(n,t){e.set(n,t)});else if(Array.isArray(n)){var r,u=-1,i=n.length;if(1===arguments.length)for(;++u<i;)e.set(u,n[u]);else for(;++u<i;)e.set(t.call(n,r=n[u],u),r)}else for(var o in n)e.set(o,n[o]);return e};var pa="__proto__",va="\x00";c(l,{has:h,get:function(n){return this._[s(n)]},set:function(n,t){return this._[s(n)]=t},remove:g,keys:p,values:function(){var n=[];for(var t in this._)n.push(this._[t]);return n},entries:function(){var n=[];for(var t in this._)n.push({key:f(t),value:this._[t]});return n},size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,f(t),this._[t])}}),ta.nest=function(){function n(t,o,a){if(a>=i.length)return r?r.call(u,o):e?o.sort(e):o;for(var c,s,f,h,g=-1,p=o.length,v=i[a++],d=new l;++g<p;)(h=d.get(c=v(s=o[g])))?h.push(s):d.set(c,[s]);return t?(s=t(),f=function(e,r){s.set(e,n(t,r,a))}):(s={},f=function(e,r){s[e]=n(t,r,a)}),d.forEach(f),s}function t(n,e){if(e>=i.length)return n;var r=[],u=o[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],o=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(ta.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return o[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},ta.set=function(n){var t=new m;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},c(m,{has:h,add:function(n){return this._[s(n+="")]=!0,n},remove:g,values:p,size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,f(t))}}),ta.behavior={},ta.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r<u;)n[e=arguments[r]]=M(n,t,t[e]);return n};var da=["webkit","ms","moz","Moz","o","O"];ta.dispatch=function(){for(var n=new _,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=w(n);return n},_.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},ta.event=null,ta.requote=function(n){return n.replace(ma,"\\$&")};var ma=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ya={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},Ma=function(n,t){return t.querySelector(n)},xa=function(n,t){return t.querySelectorAll(n)},ba=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(ba=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(Ma=function(n,t){return Sizzle(n,t)[0]||null},xa=Sizzle,ba=Sizzle.matchesSelector),ta.selection=function(){return ta.select(ua.documentElement)};var _a=ta.selection.prototype=[];_a.select=function(n){var t,e,r,u,i=[];n=N(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var c=-1,l=r.length;++c<l;)(u=r[c])?(t.push(e=n.call(u,u.__data__,c,o)),e&&"__data__"in u&&(e.__data__=u.__data__)):t.push(null)}return A(i)},_a.selectAll=function(n){var t,e,r=[];n=C(n);for(var u=-1,i=this.length;++u<i;)for(var o=this[u],a=-1,c=o.length;++a<c;)(e=o[a])&&(r.push(t=ra(n.call(e,e.__data__,a,u))),t.parentNode=e);return A(r)};var wa={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};ta.ns={prefix:wa,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&(e=n.slice(0,t),n=n.slice(t+1)),wa.hasOwnProperty(e)?{space:wa[e],local:n}:n}},_a.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=ta.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},_a.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,u=-1;if(t=e.classList){for(;++u<r;)if(!t.contains(n[u]))return!1}else for(t=e.getAttribute("class");++u<r;)if(!L(n[u]).test(t))return!1;return!0}for(t in n)this.each(R(t,n[t]));return this}return this.each(R(n,t))},_a.style=function(n,e,r){var u=arguments.length;if(3>u){if("string"!=typeof n){2>u&&(e="");for(r in n)this.each(P(r,n[r],e));return this}if(2>u){var i=this.node();return t(i).getComputedStyle(i,null).getPropertyValue(n)}r=""}return this.each(P(n,e,r))},_a.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(U(t,n[t]));return this}return this.each(U(n,t))},_a.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},_a.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},_a.append=function(n){return n=j(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},_a.insert=function(n,t){return n=j(n),t=N(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},_a.remove=function(){return this.each(F)},_a.data=function(n,t){function e(n,e){var r,u,i,o=n.length,f=e.length,h=Math.min(o,f),g=new Array(f),p=new Array(f),v=new Array(o);if(t){var d,m=new l,y=new Array(o);for(r=-1;++r<o;)m.has(d=t.call(u=n[r],u.__data__,r))?v[r]=u:m.set(d,u),y[r]=d;for(r=-1;++r<f;)(u=m.get(d=t.call(e,i=e[r],r)))?u!==!0&&(g[r]=u,u.__data__=i):p[r]=H(i),m.set(d,!0);for(r=-1;++r<o;)m.get(y[r])!==!0&&(v[r]=n[r])}else{for(r=-1;++r<h;)u=n[r],i=e[r],u?(u.__data__=i,g[r]=u):p[r]=H(i);for(;f>r;++r)p[r]=H(e[r]);for(;o>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,a.push(p),c.push(g),s.push(v)}var r,u,i=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++i<o;)(u=r[i])&&(n[i]=u.__data__);return n}var a=Z([]),c=A([]),s=A([]);if("function"==typeof n)for(;++i<o;)e(r=this[i],n.call(r,r.parentNode.__data__,i));else for(;++i<o;)e(r=this[i],n);return c.enter=function(){return a},c.exit=function(){return s},c},_a.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},_a.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=O(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return A(u)},_a.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],u=r.length-1,i=r[u];--u>=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},_a.sort=function(n){n=I.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},_a.each=function(n){return Y(this,function(t,e,r){n.call(t,t.__data__,e,r)})},_a.call=function(n){var t=ra(arguments);return n.apply(t[0]=this,t),this},_a.empty=function(){return!this.node()},_a.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},_a.size=function(){var n=0;return Y(this,function(){++n}),n};var Sa=[];ta.selection.enter=Z,ta.selection.enter.prototype=Sa,Sa.append=_a.append,Sa.empty=_a.empty,Sa.node=_a.node,Sa.call=_a.call,Sa.size=_a.size,Sa.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++a<c;){r=(u=this[a]).update,o.push(t=[]),t.parentNode=u.parentNode;for(var l=-1,s=u.length;++l<s;)(i=u[l])?(t.push(r[l]=e=n.call(u.parentNode,i.__data__,l,a)),e.__data__=i.__data__):t.push(null)}return A(o)},Sa.insert=function(n,t){return arguments.length<2&&(t=V(this)),_a.insert.call(this,n,t)},ta.select=function(t){var e;return"string"==typeof t?(e=[Ma(t,ua)],e.parentNode=ua.documentElement):(e=[t],e.parentNode=n(t)),A([e])},ta.selectAll=function(n){var t;return"string"==typeof n?(t=ra(xa(n,ua)),t.parentNode=ua.documentElement):(t=n,t.parentNode=null),A([t])},_a.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(X(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(X(n,t,e))};var ka=ta.map({mouseenter:"mouseover",mouseleave:"mouseout"});ua&&ka.forEach(function(n){"on"+n in ua&&ka.remove(n)});var Ea,Aa=0;ta.mouse=function(n){return J(n,k())};var Na=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ta.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=k().changedTouches),t)for(var r,u=0,i=t.length;i>u;++u)if((r=t[u]).identifier===e)return J(n,r)},ta.behavior.drag=function(){function n(){this.on("mousedown.drag",i).on("touchstart.drag",o)}function e(n,t,e,i,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-M[0],e=r[1]-M[1],p|=n|e,M=r,g({type:"drag",x:r[0]+l[0],y:r[1]+l[1],dx:n,dy:e}))}function c(){t(h,v)&&(m.on(i+d,null).on(o+d,null),y(p&&ta.event.target===f),g({type:"dragend"}))}var l,s=this,f=ta.event.target,h=s.parentNode,g=r.of(s,arguments),p=0,v=n(),d=".drag"+(null==v?"":"-"+v),m=ta.select(e(f)).on(i+d,a).on(o+d,c),y=W(f),M=t(h,v);u?(l=u.apply(s,arguments),l=[l.x-M[0],l.y-M[1]]):l=[0,0],g({type:"dragstart"})}}var r=E(n,"drag","dragstart","dragend"),u=null,i=e(b,ta.mouse,t,"mousemove","mouseup"),o=e(G,ta.touch,y,"touchmove","touchend");return n.origin=function(t){return arguments.length?(u=t,n):u},ta.rebind(n,r,"on")},ta.touches=function(n,t){return arguments.length<2&&(t=k().touches),t?ra(t).map(function(t){var e=J(n,t);return e.identifier=t.identifier,e}):[]};var Ca=1e-6,za=Ca*Ca,qa=Math.PI,La=2*qa,Ta=La-Ca,Ra=qa/2,Da=qa/180,Pa=180/qa,Ua=Math.SQRT2,ja=2,Fa=4;ta.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=rt(v),o=i/(ja*h)*(e*ut(Ua*t+v)-et(v));return[r+o*l,u+o*s,i*e/rt(Ua*t+v)]}return[r+n*l,u+n*s,i*Math.exp(Ua*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],l=o-r,s=a-u,f=l*l+s*s,h=Math.sqrt(f),g=(c*c-i*i+Fa*f)/(2*i*ja*h),p=(c*c-i*i-Fa*f)/(2*c*ja*h),v=Math.log(Math.sqrt(g*g+1)-g),d=Math.log(Math.sqrt(p*p+1)-p),m=d-v,y=(m||Math.log(c/i))/Ua;return e.duration=1e3*y,e},ta.behavior.zoom=function(){function n(n){n.on(q,f).on(Oa+".zoom",g).on("dblclick.zoom",p).on(R,h)}function e(n){return[(n[0]-k.x)/k.k,(n[1]-k.y)/k.k]}function r(n){return[n[0]*k.k+k.x,n[1]*k.k+k.y]}function u(n){k.k=Math.max(N[0],Math.min(N[1],n))}function i(n,t){t=r(t),k.x+=n[0]-t[0],k.y+=n[1]-t[1]}function o(t,e,r,o){t.__chart__={x:k.x,y:k.y,k:k.k},u(Math.pow(2,o)),i(d=e,r),t=ta.select(t),C>0&&(t=t.transition().duration(C)),t.call(n.event)}function a(){b&&b.domain(x.range().map(function(n){return(n-k.x)/k.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-k.y)/k.k}).map(_.invert))}function c(n){z++||n({type:"zoomstart"})}function l(n){a(),n({type:"zoom",scale:k.k,translate:[k.x,k.y]})}function s(n){--z||n({type:"zoomend"}),d=null}function f(){function n(){f=1,i(ta.mouse(u),g),l(a)}function r(){h.on(L,null).on(T,null),p(f&&ta.event.target===o),s(a)}var u=this,o=ta.event.target,a=D.of(u,arguments),f=0,h=ta.select(t(u)).on(L,n).on(T,r),g=e(ta.mouse(u)),p=W(u);Dl.call(u),c(a)}function h(){function n(){var n=ta.touches(p);return g=k.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=e(n))}),n}function t(){var t=ta.event.target;ta.select(t).on(x,r).on(b,a),_.push(t);for(var e=ta.event.changedTouches,u=0,i=e.length;i>u;++u)d[e[u].identifier]=null;var c=n(),l=Date.now();if(1===c.length){if(500>l-M){var s=c[0];o(p,s,d[s.identifier],Math.floor(Math.log(k.k)/Math.LN2)+1),S()}M=l}else if(c.length>1){var s=c[0],f=c[1],h=s[0]-f[0],g=s[1]-f[1];m=h*h+g*g}}function r(){var n,t,e,r,o=ta.touches(p);Dl.call(p);for(var a=0,c=o.length;c>a;++a,r=null)if(e=o[a],r=d[e.identifier]){if(t)break;n=e,t=r}if(r){var s=(s=e[0]-n[0])*s+(s=e[1]-n[1])*s,f=m&&Math.sqrt(s/m);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+r[0])/2,(t[1]+r[1])/2],u(f*g)}M=null,i(n,t),l(v)}function a(){if(ta.event.touches.length){for(var t=ta.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var u in d)return void n()}ta.selectAll(_).on(y,null),w.on(q,f).on(R,h),E(),s(v)}var g,p=this,v=D.of(p,arguments),d={},m=0,y=".zoom-"+ta.event.changedTouches[0].identifier,x="touchmove"+y,b="touchend"+y,_=[],w=ta.select(p),E=W(p);t(),c(v),w.on(q,null).on(R,t)}function g(){var n=D.of(this,arguments);y?clearTimeout(y):(v=e(d=m||ta.mouse(this)),Dl.call(this),c(n)),y=setTimeout(function(){y=null,s(n)},50),S(),u(Math.pow(2,.002*Ha())*k.k),i(d,v),l(n)}function p(){var n=ta.mouse(this),t=Math.log(k.k)/Math.LN2;o(this,n,e(n),ta.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var v,d,m,y,M,x,b,_,w,k={x:0,y:0,k:1},A=[960,500],N=Ia,C=250,z=0,q="mousedown.zoom",L="mousemove.zoom",T="mouseup.zoom",R="touchstart.zoom",D=E(n,"zoomstart","zoom","zoomend");return Oa||(Oa="onwheel"in ua?(Ha=function(){return-ta.event.deltaY*(ta.event.deltaMode?120:1)},"wheel"):"onmousewheel"in ua?(Ha=function(){return ta.event.wheelDelta},"mousewheel"):(Ha=function(){return-ta.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=D.of(this,arguments),t=k;Tl?ta.select(this).transition().each("start.zoom",function(){k=this.__chart__||{x:0,y:0,k:1},c(n)}).tween("zoom:zoom",function(){var e=A[0],r=A[1],u=d?d[0]:e/2,i=d?d[1]:r/2,o=ta.interpolateZoom([(u-k.x)/k.k,(i-k.y)/k.k,e/k.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),a=e/r[2];this.__chart__=k={x:u-r[0]*a,y:i-r[1]*a,k:a},l(n)}}).each("interrupt.zoom",function(){s(n)}).each("end.zoom",function(){s(n)}):(this.__chart__=k,c(n),l(n),s(n))})},n.translate=function(t){return arguments.length?(k={x:+t[0],y:+t[1],k:k.k},a(),n):[k.x,k.y]},n.scale=function(t){return arguments.length?(k={x:k.x,y:k.y,k:+t},a(),n):k.k},n.scaleExtent=function(t){return arguments.length?(N=null==t?Ia:[+t[0],+t[1]],n):N},n.center=function(t){return arguments.length?(m=t&&[+t[0],+t[1]],n):m},n.size=function(t){return arguments.length?(A=t&&[+t[0],+t[1]],n):A},n.duration=function(t){return arguments.length?(C=+t,n):C},n.x=function(t){return arguments.length?(b=t,x=t.copy(),k={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),k={x:0,y:0,k:1},n):w},ta.rebind(n,D,"on")};var Ha,Oa,Ia=[0,1/0];ta.color=ot,ot.prototype.toString=function(){return this.rgb()+""},ta.hsl=at;var Ya=at.prototype=new ot;Ya.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new at(this.h,this.s,this.l/n)},Ya.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new at(this.h,this.s,n*this.l)},Ya.rgb=function(){return ct(this.h,this.s,this.l)},ta.hcl=lt;var Za=lt.prototype=new ot;Za.brighter=function(n){return new lt(this.h,this.c,Math.min(100,this.l+Va*(arguments.length?n:1)))},Za.darker=function(n){return new lt(this.h,this.c,Math.max(0,this.l-Va*(arguments.length?n:1)))},Za.rgb=function(){return st(this.h,this.c,this.l).rgb()},ta.lab=ft;var Va=18,Xa=.95047,$a=1,Ba=1.08883,Wa=ft.prototype=new ot;Wa.brighter=function(n){return new ft(Math.min(100,this.l+Va*(arguments.length?n:1)),this.a,this.b)},Wa.darker=function(n){return new ft(Math.max(0,this.l-Va*(arguments.length?n:1)),this.a,this.b)},Wa.rgb=function(){return ht(this.l,this.a,this.b)},ta.rgb=mt;var Ja=mt.prototype=new ot;Ja.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),new mt(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new mt(u,u,u)},Ja.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mt(n*this.r,n*this.g,n*this.b)},Ja.hsl=function(){return _t(this.r,this.g,this.b)},Ja.toString=function(){return"#"+xt(this.r)+xt(this.g)+xt(this.b)};var Ga=ta.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});Ga.forEach(function(n,t){Ga.set(n,yt(t))}),ta.functor=Et,ta.xhr=At(y),ta.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=Nt(n,t,null==e?r:u(e),i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(s>=l)return o;if(u)return u=!1,i;var t=s;if(34===n.charCodeAt(t)){for(var e=t;e++<l;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}s=e+2;var r=n.charCodeAt(e+1);return 13===r?(u=!0,10===n.charCodeAt(e+2)&&++s):10===r&&(u=!0),n.slice(t+1,e).replace(/""/g,'"')}for(;l>s;){var r=n.charCodeAt(s++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(s)&&(++s,++a);else if(r!==c)continue;return n.slice(t,s-a)}return n.slice(t)}for(var r,u,i={},o={},a=[],l=n.length,s=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();t&&null==(h=t(h,f++))||a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new m,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(o).join(n)].concat(t.map(function(t){return u.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},ta.csv=ta.dsv(",","text/csv"),ta.tsv=ta.dsv("      ","text/tab-separated-values");var Ka,Qa,nc,tc,ec,rc=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ta.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,f:!1,n:null};Qa?Qa.n=i:Ka=i,Qa=i,nc||(tc=clearTimeout(tc),nc=1,rc(qt))},ta.timer.flush=function(){Lt(),Tt()},ta.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var uc=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Dt);ta.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=ta.round(n,Rt(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),uc[8+e/3]};var ic=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,oc=ta.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ta.round(n,Rt(n,t))).toFixed(Math.max(0,Math.min(20,Rt(n*(1+1e-15),t))))}}),ac=ta.time={},cc=Date;jt.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){lc.setUTCDate.apply(this._,arguments)},setDay:function(){lc.setUTCDay.apply(this._,arguments)},setFullYear:function(){lc.setUTCFullYear.apply(this._,arguments)},setHours:function(){lc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){lc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){lc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){lc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){lc.setUTCSeconds.apply(this._,arguments)},setTime:function(){lc.setTime.apply(this._,arguments)}};var lc=Date.prototype;ac.year=Ft(function(n){return n=ac.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ac.years=ac.year.range,ac.years.utc=ac.year.utc.range,ac.day=Ft(function(n){var t=new cc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),ac.days=ac.day.range,ac.days.utc=ac.day.utc.range,ac.dayOfYear=function(n){var t=ac.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=ac[n]=Ft(function(n){return(n=ac.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=ac.year(n).getDay();return Math.floor((ac.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ac[n+"s"]=e.range,ac[n+"s"].utc=e.utc.range,ac[n+"OfYear"]=function(n){var e=ac.year(n).getDay();return Math.floor((ac.dayOfYear(n)+(e+t)%7)/7)}}),ac.week=ac.sunday,ac.weeks=ac.sunday.range,ac.weeks.utc=ac.sunday.utc.range,ac.weekOfYear=ac.sundayOfYear;var sc={"-":"",_:" ",0:"0"},fc=/^\s*\d+/,hc=/^%/;ta.locale=function(n){return{numberFormat:Pt(n),timeFormat:Ot(n)}};var gc=ta.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});ta.format=gc.numberFormat,ta.geo={},ce.prototype={s:0,t:0,add:function(n){le(n,this.t,pc),le(pc.s,this.s,this),this.s?this.t+=pc.t:this.s=pc.t
+},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var pc=new ce;ta.geo.stream=function(n,t){n&&vc.hasOwnProperty(n.type)?vc[n.type](n,t):se(n,t)};var vc={Feature:function(n,t){se(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++r<u;)se(e[r].geometry,t)}},dc={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){fe(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)fe(e[r],t,0)},Polygon:function(n,t){he(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)he(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,u=e.length;++r<u;)se(e[r],t)}};ta.geo.area=function(n){return mc=0,ta.geo.stream(n,Mc),mc};var mc,yc=new ce,Mc={sphere:function(){mc+=4*qa},point:b,lineStart:b,lineEnd:b,polygonStart:function(){yc.reset(),Mc.lineStart=ge},polygonEnd:function(){var n=2*yc;mc+=0>n?4*qa+n:n,Mc.lineStart=Mc.lineEnd=Mc.point=b}};ta.geo.bounds=function(){function n(n,t){M.push(x=[s=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=pe([t*Da,e*Da]);if(m){var u=de(m,r),i=[u[1],-u[0],0],o=de(i,u);Me(o),o=xe(o);var c=t-p,l=c>0?1:-1,v=o[0]*Pa*l,d=ga(c)>180;if(d^(v>l*p&&l*t>v)){var y=o[1]*Pa;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>l*p&&l*t>v)){var y=-o[1]*Pa;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t):h>=s?(s>t&&(s=t),t>h&&(h=t)):t>p?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t)}else n(t,e);m=r,p=t}function e(){b.point=t}function r(){x[0]=s,x[1]=h,b.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=ga(r)>180?r+(r>0?360:-360):r}else v=n,d=e;Mc.point(n,e),t(n,e)}function i(){Mc.lineStart()}function o(){u(v,d),Mc.lineEnd(),ga(y)>Ca&&(s=-(h=180)),x[0]=s,x[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var s,f,h,g,p,v,d,m,y,M,x,b={point:n,lineStart:e,lineEnd:r,polygonStart:function(){b.point=u,b.lineStart=i,b.lineEnd=o,y=0,Mc.polygonStart()},polygonEnd:function(){Mc.polygonEnd(),b.point=n,b.lineStart=e,b.lineEnd=r,0>yc?(s=-(h=180),f=-(g=90)):y>Ca?g=90:-Ca>y&&(f=-90),x[0]=s,x[1]=h}};return function(n){g=h=-(s=f=1/0),M=[],ta.geo.stream(n,b);var t=M.length;if(t){M.sort(c);for(var e,r=1,u=M[0],i=[u];t>r;++r)e=M[r],l(e[0],u)||l(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e);for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,s=e[0],h=u[1])}return M=x=null,1/0===s||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[s,f],[h,g]]}}(),ta.geo.centroid=function(n){xc=bc=_c=wc=Sc=kc=Ec=Ac=Nc=Cc=zc=0,ta.geo.stream(n,qc);var t=Nc,e=Cc,r=zc,u=t*t+e*e+r*r;return za>u&&(t=kc,e=Ec,r=Ac,Ca>bc&&(t=_c,e=wc,r=Sc),u=t*t+e*e+r*r,za>u)?[0/0,0/0]:[Math.atan2(e,t)*Pa,tt(r/Math.sqrt(u))*Pa]};var xc,bc,_c,wc,Sc,kc,Ec,Ac,Nc,Cc,zc,qc={sphere:b,point:_e,lineStart:Se,lineEnd:ke,polygonStart:function(){qc.lineStart=Ee},polygonEnd:function(){qc.lineStart=Se}},Lc=Le(Ne,Pe,je,[-qa,-qa/2]),Tc=1e9;ta.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=Ie(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(ta.geo.conicEqualArea=function(){return Ye(Ze)}).raw=Ze,ta.geo.albers=function(){return ta.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ta.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=ta.geo.albers(),o=ta.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=ta.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var l=i.scale(),s=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[s-.455*l,f-.238*l],[s+.455*l,f+.238*l]]).stream(c).point,r=o.translate([s-.307*l,f+.201*l]).clipExtent([[s-.425*l+Ca,f+.12*l+Ca],[s-.214*l-Ca,f+.234*l-Ca]]).stream(c).point,u=a.translate([s-.205*l,f+.212*l]).clipExtent([[s-.214*l+Ca,f+.166*l+Ca],[s-.115*l-Ca,f+.234*l-Ca]]).stream(c).point,n},n.scale(1070)};var Rc,Dc,Pc,Uc,jc,Fc,Hc={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Dc=0,Hc.lineStart=Ve},polygonEnd:function(){Hc.lineStart=Hc.lineEnd=Hc.point=b,Rc+=ga(Dc/2)}},Oc={point:Xe,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Ic={point:We,lineStart:Je,lineEnd:Ge,polygonStart:function(){Ic.lineStart=Ke},polygonEnd:function(){Ic.point=We,Ic.lineStart=Je,Ic.lineEnd=Ge}};ta.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),ta.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Rc=0,ta.geo.stream(n,u(Hc)),Rc},n.centroid=function(n){return _c=wc=Sc=kc=Ec=Ac=Nc=Cc=zc=0,ta.geo.stream(n,u(Ic)),zc?[Nc/zc,Cc/zc]:Ac?[kc/Ac,Ec/Ac]:Sc?[_c/Sc,wc/Sc]:[0/0,0/0]},n.bounds=function(n){return jc=Fc=-(Pc=Uc=1/0),ta.geo.stream(n,u(Oc)),[[Pc,Uc],[jc,Fc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||tr(n):y,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new $e:new Qe(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(ta.geo.albersUsa()).context(null)},ta.geo.transform=function(n){return{stream:function(t){var e=new er(t);for(var r in n)e[r]=n[r];return e}}},er.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},ta.geo.projection=ur,ta.geo.projectionMutator=ir,(ta.geo.equirectangular=function(){return ur(ar)}).raw=ar.invert=ar,ta.geo.rotation=function(n){function t(t){return t=n(t[0]*Da,t[1]*Da),t[0]*=Pa,t[1]*=Pa,t}return n=lr(n[0]%360*Da,n[1]*Da,n.length>2?n[2]*Da:0),t.invert=function(t){return t=n.invert(t[0]*Da,t[1]*Da),t[0]*=Pa,t[1]*=Pa,t},t},cr.invert=ar,ta.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=lr(-n[0]*Da,-n[1]*Da,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Pa,n[1]*=Pa}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=gr((t=+r)*Da,u*Da),n):t},n.precision=function(r){return arguments.length?(e=gr(t*Da,(u=+r)*Da),n):u},n.angle(90)},ta.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Da,u=n[1]*Da,i=t[1]*Da,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),l=Math.cos(u),s=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=l*s-c*f*a)*e),c*s+l*f*a)},ta.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ta.range(Math.ceil(i/d)*d,u,d).map(h).concat(ta.range(Math.ceil(l/m)*m,c,m).map(g)).concat(ta.range(Math.ceil(r/p)*p,e,p).filter(function(n){return ga(n%d)>Ca}).map(s)).concat(ta.range(Math.ceil(a/v)*v,o,v).filter(function(n){return ga(n%m)>Ca}).map(f))}var e,r,u,i,o,a,c,l,s,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(l).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],l=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),l>c&&(t=l,l=c,c=t),n.precision(y)):[[i,l],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,s=vr(a,o,90),f=dr(r,e,y),h=vr(l,c,90),g=dr(i,u,y),n):y},n.majorExtent([[-180,-90+Ca],[180,90-Ca]]).minorExtent([[-180,-80-Ca],[180,80+Ca]])},ta.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=mr,u=yr;return n.distance=function(){return ta.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},ta.geo.interpolate=function(n,t){return Mr(n[0]*Da,n[1]*Da,t[0]*Da,t[1]*Da)},ta.geo.length=function(n){return Yc=0,ta.geo.stream(n,Zc),Yc};var Yc,Zc={sphere:b,point:b,lineStart:xr,lineEnd:b,polygonStart:b,polygonEnd:b},Vc=br(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ta.geo.azimuthalEqualArea=function(){return ur(Vc)}).raw=Vc;var Xc=br(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},y);(ta.geo.azimuthalEquidistant=function(){return ur(Xc)}).raw=Xc,(ta.geo.conicConformal=function(){return Ye(_r)}).raw=_r,(ta.geo.conicEquidistant=function(){return Ye(wr)}).raw=wr;var $c=br(function(n){return 1/n},Math.atan);(ta.geo.gnomonic=function(){return ur($c)}).raw=$c,Sr.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Ra]},(ta.geo.mercator=function(){return kr(Sr)}).raw=Sr;var Bc=br(function(){return 1},Math.asin);(ta.geo.orthographic=function(){return ur(Bc)}).raw=Bc;var Wc=br(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ta.geo.stereographic=function(){return ur(Wc)}).raw=Wc,Er.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Ra]},(ta.geo.transverseMercator=function(){var n=kr(Er),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=Er,ta.geom={},ta.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=Et(e),i=Et(r),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(a.sort(zr),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var l=Cr(a),s=Cr(c),f=s[0]===l[0],h=s[s.length-1]===l[l.length-1],g=[];for(t=l.length-1;t>=0;--t)g.push(n[a[l[t]][2]]);for(t=+f;t<s.length-h;++t)g.push(n[a[s[t]][2]]);return g}var e=Ar,r=Nr;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},ta.geom.polygon=function(n){return ya(n,Jc),n};var Jc=ta.geom.polygon.prototype=[];Jc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],u=0;++t<e;)n=r,r=this[t],u+=n[1]*r[0]-n[0]*r[1];return.5*u},Jc.centroid=function(n){var t,e,r=-1,u=this.length,i=0,o=0,a=this[u-1];for(arguments.length||(n=-1/(6*this.area()));++r<u;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],i+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[i*n,o*n]},Jc.clip=function(n){for(var t,e,r,u,i,o,a=Tr(n),c=-1,l=this.length-Tr(this),s=this[l-1];++c<l;){for(t=n.slice(),n.length=0,u=this[c],i=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],qr(o,s,u)?(qr(i,s,u)||n.push(Lr(i,o,s,u)),n.push(o)):qr(i,s,u)&&n.push(Lr(i,o,s,u)),i=o;a&&n.push(n[0]),s=u}return n};var Gc,Kc,Qc,nl,tl,el=[],rl=[];Or.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Yr),t.length},Qr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},nu.prototype={insert:function(n,t){var e,r,u;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=uu(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(u=r.R,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.R&&(eu(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ru(this,r))):(u=r.L,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.L&&(ru(this,e),n=e,e=n.U),e.C=!1,r.C=!0,eu(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,u=n.U,i=n.L,o=n.R;if(e=i?o?uu(o):i:o,u?u.L===n?u.L=e:u.R=e:this._=e,i&&o?(r=e.C,e.C=n.C,e.L=i,i.U=e,e!==o?(u=e.U,e.U=n.U,n=e.R,u.L=n,e.R=o,o.U=e):(e.U=u,u=e,n=e.R)):(r=n.C,n=e),n&&(n.U=u),!r){if(n&&n.C)return void(n.C=!1);do{if(n===this._)break;if(n===u.L){if(t=u.R,t.C&&(t.C=!1,u.C=!0,eu(this,u),t=u.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,ru(this,t),t=u.R),t.C=u.C,u.C=t.R.C=!1,eu(this,u),n=this._;break}}else if(t=u.L,t.C&&(t.C=!1,u.C=!0,ru(this,u),t=u.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,eu(this,t),t=u.L),t.C=u.C,u.C=t.L.C=!1,ru(this,u),n=this._;break}t.C=!0,n=u,u=u.U}while(!n.C);n&&(n.C=!1)}}},ta.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],u=a[0][1],i=a[1][0],o=a[1][1];return iu(e(n),a).cells.forEach(function(e,a){var c=e.edges,l=e.site,s=t[a]=c.length?c.map(function(n){var t=n.start();return[t.x,t.y]}):l.x>=r&&l.x<=i&&l.y>=u&&l.y<=o?[[r,o],[i,o],[i,u],[r,u]]:[];s.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/Ca)*Ca,y:Math.round(o(n,t)/Ca)*Ca,i:t}})}var r=Ar,u=Nr,i=r,o=u,a=ul;return n?t(n):(t.links=function(n){return iu(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return iu(e(n)).cells.forEach(function(e,r){for(var u,i,o=e.site,a=e.edges.sort(Yr),c=-1,l=a.length,s=a[l-1].edge,f=s.l===o?s.r:s.l;++c<l;)u=s,i=f,s=a[c].edge,f=s.l===o?s.r:s.l,r<i.i&&r<f.i&&au(o,i,f)<0&&t.push([n[r],n[i.i],n[f.i]])}),t},t.x=function(n){return arguments.length?(i=Et(r=n),t):r},t.y=function(n){return arguments.length?(o=Et(u=n),t):u},t.clipExtent=function(n){return arguments.length?(a=null==n?ul:n,t):a===ul?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===ul?null:a&&a[1]},t)};var ul=[[-1e6,-1e6],[1e6,1e6]];ta.geom.delaunay=function(n){return ta.geom.voronoi().triangles(n)},ta.geom.quadtree=function(n,t,e,r,u){function i(n){function i(n,t,e,r,u,i,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var c=n.x,s=n.y;if(null!=c)if(ga(c-e)+ga(s-r)<.01)l(n,t,e,r,u,i,o,a);else{var f=n.point;n.x=n.y=n.point=null,l(n,f,c,s,u,i,o,a),l(n,t,e,r,u,i,o,a)}else n.x=e,n.y=r,n.point=t}else l(n,t,e,r,u,i,o,a)}function l(n,t,e,r,u,o,a,c){var l=.5*(u+a),s=.5*(o+c),f=e>=l,h=r>=s,g=h<<1|f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=su()),f?u=l:a=l,h?o=s:c=s,i(n,t,e,r,u,o,a,c)}var s,f,h,g,p,v,d,m,y,M=Et(a),x=Et(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)s=n[g],s.x<v&&(v=s.x),s.y<d&&(d=s.y),s.x>m&&(m=s.x),s.y>y&&(y=s.y),f.push(s.x),h.push(s.y);else for(g=0;p>g;++g){var b=+M(s=n[g],g),_=+x(s,g);v>b&&(v=b),d>_&&(d=_),b>m&&(m=b),_>y&&(y=_),f.push(b),h.push(_)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=su();if(k.add=function(n){i(k,n,+M(n,++g),+x(n,g),v,d,m,y)},k.visit=function(n){fu(n,k,v,d,m,y)},k.find=function(n){return hu(k,n[0],n[1],v,d,m,y)},g=-1,null==t){for(;++g<p;)i(k,n[g],f[g],h[g],v,d,m,y);--g}else n.forEach(k.add);return f=h=n=s=null,k}var o,a=Ar,c=Nr;return(o=arguments.length)?(a=cu,c=lu,3===o&&(u=e,r=t,e=t=0),i(n)):(i.x=function(n){return arguments.length?(a=n,i):a},i.y=function(n){return arguments.length?(c=n,i):c},i.extent=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],u=+n[1][1]),i):null==t?null:[[t,e],[r,u]]},i.size=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=e=0,r=+n[0],u=+n[1]),i):null==t?null:[r-t,u-e]},i)},ta.interpolateRgb=gu,ta.interpolateObject=pu,ta.interpolateNumber=vu,ta.interpolateString=du;var il=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,ol=new RegExp(il.source,"g");ta.interpolate=mu,ta.interpolators=[function(n,t){var e=typeof t;return("string"===e?Ga.has(t)||/^(#|rgb\(|hsl\()/.test(t)?gu:du:t instanceof ot?gu:Array.isArray(t)?yu:"object"===e&&isNaN(t)?pu:vu)(n,t)}],ta.interpolateArray=yu;var al=function(){return y},cl=ta.map({linear:al,poly:ku,quad:function(){return _u},cubic:function(){return wu},sin:function(){return Eu},exp:function(){return Au},circle:function(){return Nu},elastic:Cu,back:zu,bounce:function(){return qu}}),ll=ta.map({"in":y,out:xu,"in-out":bu,"out-in":function(n){return bu(xu(n))}});ta.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=cl.get(e)||al,r=ll.get(r)||y,Mu(r(e.apply(null,ea.call(arguments,1))))},ta.interpolateHcl=Lu,ta.interpolateHsl=Tu,ta.interpolateLab=Ru,ta.interpolateRound=Du,ta.transform=function(n){var t=ua.createElementNS(ta.ns.prefix.svg,"g");return(ta.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Pu(e?e.matrix:sl)})(n)},Pu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var sl={a:1,b:0,c:0,d:1,e:0,f:0};ta.interpolateTransform=Hu,ta.layout={},ta.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(Yu(n[e]));return t}},ta.layout.chord=function(){function n(){var n,l,f,h,g,p={},v=[],d=ta.range(i),m=[];for(e=[],r=[],n=0,h=-1;++h<i;){for(l=0,g=-1;++g<i;)l+=u[h][g];v.push(l),m.push(ta.range(i)),n+=l}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&m.forEach(function(n,t){n.sort(function(n,e){return a(u[t][n],u[t][e])})}),n=(La-s*i)/n,l=0,h=-1;++h<i;){for(f=l,g=-1;++g<i;){var y=d[h],M=m[y][g],x=u[y][M],b=l,_=l+=x*n;p[y+"-"+M]={index:y,subindex:M,startAngle:b,endAngle:_,value:x}}r[y]={index:y,startAngle:f,endAngle:l,value:(l-f)/n},l+=s}for(h=-1;++h<i;)for(g=h-1;++g<i;){var w=p[h+"-"+g],S=p[g+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}c&&t()}function t(){e.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,u,i,o,a,c,l={},s=0;return l.matrix=function(n){return arguments.length?(i=(u=n)&&u.length,e=r=null,l):u},l.padding=function(n){return arguments.length?(s=n,e=r=null,l):s},l.sortGroups=function(n){return arguments.length?(o=n,e=r=null,l):o},l.sortSubgroups=function(n){return arguments.length?(a=n,e=null,l):a},l.sortChords=function(n){return arguments.length?(c=n,e&&t(),l):c},l.chords=function(){return e||n(),e},l.groups=function(){return r||n(),r},l},ta.layout.force=function(){function n(n){return function(t,e,r,u){if(t.point!==n){var i=t.cx-n.x,o=t.cy-n.y,a=u-e,c=i*i+o*o;if(c>a*a/d){if(p>c){var l=t.charge/c;n.px-=i*l,n.py-=o*l}return!0}if(t.point&&c&&p>c){var l=t.pointCharge/c;n.px-=i*l,n.py-=o*l}}return!t.charge}}function t(n){n.px=ta.event.x,n.py=ta.event.y,a.resume()}var e,r,u,i,o,a={},c=ta.dispatch("start","tick","end"),l=[1,1],s=.9,f=fl,h=hl,g=-30,p=gl,v=.1,d=.64,m=[],M=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,y,x,b=m.length,_=M.length;for(e=0;_>e;++e)a=M[e],f=a.source,h=a.target,y=h.x-f.x,x=h.y-f.y,(p=y*y+x*x)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,y*=p,x*=p,h.x-=y*(d=f.weight/(h.weight+f.weight)),h.y-=x*d,f.x+=y*(d=1-d),f.y+=x*d);if((d=r*v)&&(y=l[0]/2,x=l[1]/2,e=-1,d))for(;++e<b;)a=m[e],a.x+=(y-a.x)*d,a.y+=(x-a.y)*d;if(g)for(Ju(t=ta.geom.quadtree(m),r,o),e=-1;++e<b;)(a=m[e]).fixed||t.visit(n(a));for(e=-1;++e<b;)a=m[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*s,a.y-=(a.py-(a.py=a.y))*s);c.tick({type:"tick",alpha:r})},a.nodes=function(n){return arguments.length?(m=n,a):m},a.links=function(n){return arguments.length?(M=n,a):M},a.size=function(n){return arguments.length?(l=n,a):l},a.linkDistance=function(n){return arguments.length?(f="function"==typeof n?n:+n,a):f},a.distance=a.linkDistance,a.linkStrength=function(n){return arguments.length?(h="function"==typeof n?n:+n,a):h},a.friction=function(n){return arguments.length?(s=+n,a):s},a.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,a):g},a.chargeDistance=function(n){return arguments.length?(p=n*n,a):Math.sqrt(p)},a.gravity=function(n){return arguments.length?(v=+n,a):v},a.theta=function(n){return arguments.length?(d=n*n,a):Math.sqrt(d)},a.alpha=function(n){return arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),ta.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;s>a;++a){var u=M[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,l=o.length;++a<l;)if(!isNaN(i=o[a][n]))return i;return Math.random()*r}var t,e,r,c=m.length,s=M.length,p=l[0],v=l[1];for(t=0;c>t;++t)(r=m[t]).index=t,r.weight=0;for(t=0;s>t;++t)r=M[t],"number"==typeof r.source&&(r.source=m[r.source]),"number"==typeof r.target&&(r.target=m[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;s>t;++t)u[t]=+f.call(this,M[t],t);else for(t=0;s>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;s>t;++t)i[t]=+h.call(this,M[t],t);else for(t=0;s>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=ta.behavior.drag().origin(y).on("dragstart.force",Xu).on("drag.force",t).on("dragend.force",$u)),arguments.length?void this.on("mouseover.force",Bu).on("mouseout.force",Wu).call(e):e},ta.rebind(a,c,"on")};var fl=20,hl=1,gl=1/0;ta.layout.hierarchy=function(){function n(u){var i,o=[u],a=[];for(u.depth=0;null!=(i=o.pop());)if(a.push(i),(l=e.call(n,i,i.depth))&&(c=l.length)){for(var c,l,s;--c>=0;)o.push(s=l[c]),s.parent=i,s.depth=i.depth+1;r&&(i.value=0),i.children=l}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return Qu(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),a}var t=ei,e=ni,r=ti;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&(Ku(t,function(n){n.children&&(n.value=0)}),Qu(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},ta.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,l=-1;for(r=t.value?r/t.value:0;++l<o;)n(a=i[l],e,c=a.value*r,u),e+=c}}function t(n){var e=n.children,r=0;if(e&&(u=e.length))for(var u,i=-1;++i<u;)r=Math.max(r,t(e[i]));return 1+r}function e(e,i){var o=r.call(this,e,i);return n(o[0],0,u[0],u[1]/t(o[0])),o}var r=ta.layout.hierarchy(),u=[1,1];return e.size=function(n){return arguments.length?(u=n,e):u},Gu(e,r)},ta.layout.pie=function(){function n(o){var a,c=o.length,l=o.map(function(e,r){return+t.call(n,e,r)}),s=+("function"==typeof r?r.apply(this,arguments):r),f=("function"==typeof u?u.apply(this,arguments):u)-s,h=Math.min(Math.abs(f)/c,+("function"==typeof i?i.apply(this,arguments):i)),g=h*(0>f?-1:1),p=(f-c*g)/ta.sum(l),v=ta.range(c),d=[];return null!=e&&v.sort(e===pl?function(n,t){return l[t]-l[n]}:function(n,t){return e(o[n],o[t])}),v.forEach(function(n){d[n]={data:o[n],value:a=l[n],startAngle:s,endAngle:s+=a*p+g,padAngle:h}}),d}var t=Number,e=pl,r=0,u=La,i=0;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n.padAngle=function(t){return arguments.length?(i=t,n):i},n};var pl={};ta.layout.stack=function(){function n(a,c){if(!(h=a.length))return a;var l=a.map(function(e,r){return t.call(n,e,r)}),s=l.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,s,c);l=ta.permute(l,f),s=ta.permute(s,f);var h,g,p,v,d=r.call(n,s,c),m=l[0].length;for(p=0;m>p;++p)for(u.call(n,l[0][p],v=d[p],s[0][p][1]),g=1;h>g;++g)u.call(n,l[g][p],v+=s[g-1][p][1],s[g][p][1]);return a}var t=y,e=ai,r=ci,u=oi,i=ui,o=ii;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:vl.get(t)||ai,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:dl.get(t)||ci,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var vl=ta.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(li),i=n.map(si),o=ta.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,l=[],s=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],l.push(e)):(c+=i[e],s.push(e));return s.reverse().concat(l)},reverse:function(n){return ta.range(n.length).reverse()},"default":ai}),dl=ta.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,l,s=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=l=0,e=1;h>e;++e){for(t=0,u=0;s>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];s>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,l>c&&(l=c)}for(e=0;h>e;++e)g[e]-=l;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ci});ta.layout.histogram=function(){function n(n,i){for(var o,a,c=[],l=n.map(e,this),s=r.call(this,l,i),f=u.call(this,s,l,i),i=-1,h=l.length,g=f.length-1,p=t?1:1/h;++i<g;)o=c[i]=[],o.dx=f[i+1]-(o.x=f[i]),o.y=0;if(g>0)for(i=-1;++i<h;)a=l[i],a>=s[0]&&a<=s[1]&&(o=c[ta.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=pi,u=hi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=Et(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return gi(n,t)}:Et(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},ta.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],l=u[1],s=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Qu(a,function(n){n.r=+s(n.value)}),Qu(a,Mi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/l))/2;Qu(a,function(n){n.r+=f}),Qu(a,Mi),Qu(a,function(n){n.r-=f})}return _i(a,c/2,l/2,t?1:1/Math.max(2*a.r/c,2*a.r/l)),o}var t,e=ta.layout.hierarchy().sort(vi),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},Gu(n,e)},ta.layout.tree=function(){function n(n,u){var s=o.call(this,n,u),f=s[0],h=t(f);if(Qu(h,e),h.parent.m=-h.z,Ku(h,r),l)Ku(f,i);else{var g=f,p=f,v=f;Ku(f,function(n){n.x<g.x&&(g=n),n.x>p.x&&(p=n),n.depth>v.depth&&(v=n)});var d=a(g,p)/2-g.x,m=c[0]/(p.x+a(p,g)/2+d),y=c[1]/(v.depth||1);Ku(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return s}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,o=0,a=i.length;a>o;++o)r.push((i[o]=u={_:i[o],parent:t,children:(u=i[o].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=u);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){Ni(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+a(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,o=t,c=u.parent.children[0],l=u.m,s=i.m,f=o.m,h=c.m;o=Ei(o),u=ki(u),o&&u;)c=ki(c),i=Ei(i),i.a=n,r=o.z+f-u.z-l+a(o._,u._),r>0&&(Ai(Ci(o,n,e),n,r),l+=r,s+=r),f+=o.m,l+=u.m,h+=c.m,s+=i.m;o&&!Ei(i)&&(i.t=o,i.m+=f-s),u&&!ki(c)&&(c.t=u,c.m+=l-h,e=n)}return e}function i(n){n.x*=c[0],n.y=n.depth*c[1]}var o=ta.layout.hierarchy().sort(null).value(null),a=Si,c=[1,1],l=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(l=null==(c=t)?i:null,n):l?null:c},n.nodeSize=function(t){return arguments.length?(l=null==(c=t)?null:i,n):l?c:null},Gu(n,o)},ta.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],l=0;Qu(c,function(n){var t=n.children;t&&t.length?(n.x=qi(t),n.y=zi(t)):(n.x=o?l+=e(n,o):0,n.y=0,o=n)});var s=Li(c),f=Ti(c),h=s.x-e(s,f)/2,g=f.x+e(f,s)/2;return Qu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=ta.layout.hierarchy().sort(null).value(null),e=Si,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Gu(n,t)},ta.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++u<i;)r=(e=n[u]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,l=f(e),s=[],h=i.slice(),p=1/0,v="slice"===g?l.dx:"dice"===g?l.dy:"slice-dice"===g?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/e.value),s.area=0;(c=h.length)>0;)s.push(o=h[c-1]),s.area+=o.area,"squarify"!==g||(a=r(s,v))<=p?(h.pop(),p=a):(s.area-=s.pop().area,u(s,v,l,!1),v=Math.min(l.dx,l.dy),s.length=s.area=0,p=1/0);s.length&&(u(s,v,l,!0),s.length=s.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(i>e&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,l=e.y,s=t?c(n.area/t):0;if(t==e.dx){for((r||s>e.dy)&&(s=e.dy);++i<o;)u=n[i],u.x=a,u.y=l,u.dy=s,a+=u.dx=Math.min(e.x+e.dx-a,s?c(u.area/s):0);u.z=!0,u.dx+=e.x+e.dx-a,e.y+=s,e.dy-=s}else{for((r||s>e.dx)&&(s=e.dx);++i<o;)u=n[i],u.x=a,u.y=l,u.dx=s,l+=u.dy=Math.min(e.y+e.dy-l,s?c(u.area/s):0);u.z=!1,u.dy+=e.y+e.dy-l,e.x+=s,e.dx-=s}}function i(r){var u=o||a(r),i=u[0];return i.x=0,i.y=0,i.dx=l[0],i.dy=l[1],o&&a.revalue(i),n([i],i.dx*i.dy/i.value),(o?e:t)(i),h&&(o=u),u}var o,a=ta.layout.hierarchy(),c=Math.round,l=[1,1],s=null,f=Ri,h=!1,g="squarify",p=.5*(1+Math.sqrt(5));
+return i.size=function(n){return arguments.length?(l=n,i):l},i.padding=function(n){function t(t){var e=n.call(i,t,t.depth);return null==e?Ri(t):Di(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return Di(t,n)}if(!arguments.length)return s;var r;return f=null==(s=n)?Ri:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,i},i.round=function(n){return arguments.length?(c=n?Math.round:Number,i):c!=Number},i.sticky=function(n){return arguments.length?(h=n,o=null,i):h},i.ratio=function(n){return arguments.length?(p=n,i):p},i.mode=function(n){return arguments.length?(g=n+"",i):g},Gu(i,a)},ta.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=ta.random.normal.apply(ta,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ta.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},ta.scale={};var ml={floor:y,ceil:y};ta.scale.linear=function(){return Ii([0,1],[0,1],mu,!1)};var yl={s:1,g:1,p:1,r:1,e:1};ta.scale.log=function(){return Ji(ta.scale.linear().domain([0,1]),10,!0,[1,10])};var Ml=ta.format(".0e"),xl={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ta.scale.pow=function(){return Gi(ta.scale.linear(),1,[0,1])},ta.scale.sqrt=function(){return ta.scale.pow().exponent(.5)},ta.scale.ordinal=function(){return Qi([],{t:"range",a:[[]]})},ta.scale.category10=function(){return ta.scale.ordinal().range(bl)},ta.scale.category20=function(){return ta.scale.ordinal().range(_l)},ta.scale.category20b=function(){return ta.scale.ordinal().range(wl)},ta.scale.category20c=function(){return ta.scale.ordinal().range(Sl)};var bl=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(Mt),_l=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(Mt),wl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(Mt),Sl=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(Mt);ta.scale.quantile=function(){return no([],[])},ta.scale.quantize=function(){return to(0,1,[0,1])},ta.scale.threshold=function(){return eo([.5],[0,1])},ta.scale.identity=function(){return ro([0,1])},ta.svg={},ta.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),l=Math.max(0,+r.apply(this,arguments)),s=o.apply(this,arguments)-Ra,f=a.apply(this,arguments)-Ra,h=Math.abs(f-s),g=s>f?0:1;if(n>l&&(p=l,l=n,n=p),h>=Ta)return t(l,g)+(n?t(n,1-g):"")+"Z";var p,v,d,m,y,M,x,b,_,w,S,k,E=0,A=0,N=[];if((m=(+c.apply(this,arguments)||0)/2)&&(d=i===kl?Math.sqrt(n*n+l*l):+i.apply(this,arguments),g||(A*=-1),l&&(A=tt(d/l*Math.sin(m))),n&&(E=tt(d/n*Math.sin(m)))),l){y=l*Math.cos(s+A),M=l*Math.sin(s+A),x=l*Math.cos(f-A),b=l*Math.sin(f-A);var C=Math.abs(f-s-2*A)<=qa?0:1;if(A&&so(y,M,x,b)===g^C){var z=(s+f)/2;y=l*Math.cos(z),M=l*Math.sin(z),x=b=null}}else y=M=0;if(n){_=n*Math.cos(f-E),w=n*Math.sin(f-E),S=n*Math.cos(s+E),k=n*Math.sin(s+E);var q=Math.abs(s-f+2*E)<=qa?0:1;if(E&&so(_,w,S,k)===1-g^q){var L=(s+f)/2;_=n*Math.cos(L),w=n*Math.sin(L),S=k=null}}else _=w=0;if((p=Math.min(Math.abs(l-n)/2,+u.apply(this,arguments)))>.001){v=l>n^g?0:1;var T=null==S?[_,w]:null==x?[y,M]:Lr([y,M],[S,k],[x,b],[_,w]),R=y-T[0],D=M-T[1],P=x-T[0],U=b-T[1],j=1/Math.sin(Math.acos((R*P+D*U)/(Math.sqrt(R*R+D*D)*Math.sqrt(P*P+U*U)))/2),F=Math.sqrt(T[0]*T[0]+T[1]*T[1]);if(null!=x){var H=Math.min(p,(l-F)/(j+1)),O=fo(null==S?[_,w]:[S,k],[y,M],l,H,g),I=fo([x,b],[_,w],l,H,g);p===H?N.push("M",O[0],"A",H,",",H," 0 0,",v," ",O[1],"A",l,",",l," 0 ",1-g^so(O[1][0],O[1][1],I[1][0],I[1][1]),",",g," ",I[1],"A",H,",",H," 0 0,",v," ",I[0]):N.push("M",O[0],"A",H,",",H," 0 1,",v," ",I[0])}else N.push("M",y,",",M);if(null!=S){var Y=Math.min(p,(n-F)/(j-1)),Z=fo([y,M],[S,k],n,-Y,g),V=fo([_,w],null==x?[y,M]:[x,b],n,-Y,g);p===Y?N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",V[1],"A",n,",",n," 0 ",g^so(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-g," ",Z[1],"A",Y,",",Y," 0 0,",v," ",Z[0]):N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",Z[0])}else N.push("L",_,",",w)}else N.push("M",y,",",M),null!=x&&N.push("A",l,",",l," 0 ",C,",",g," ",x,",",b),N.push("L",_,",",w),null!=S&&N.push("A",n,",",n," 0 ",q,",",1-g," ",S,",",k);return N.push("Z"),N.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var e=io,r=oo,u=uo,i=kl,o=ao,a=co,c=lo;return n.innerRadius=function(t){return arguments.length?(e=Et(t),n):e},n.outerRadius=function(t){return arguments.length?(r=Et(t),n):r},n.cornerRadius=function(t){return arguments.length?(u=Et(t),n):u},n.padRadius=function(t){return arguments.length?(i=t==kl?kl:Et(t),n):i},n.startAngle=function(t){return arguments.length?(o=Et(t),n):o},n.endAngle=function(t){return arguments.length?(a=Et(t),n):a},n.padAngle=function(t){return arguments.length?(c=Et(t),n):c},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Ra;return[Math.cos(t)*n,Math.sin(t)*n]},n};var kl="auto";ta.svg.line=function(){return ho(y)};var El=ta.map({linear:go,"linear-closed":po,step:vo,"step-before":mo,"step-after":yo,basis:So,"basis-open":ko,"basis-closed":Eo,bundle:Ao,cardinal:bo,"cardinal-open":Mo,"cardinal-closed":xo,monotone:To});El.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Al=[0,2/3,1/3,0],Nl=[0,1/3,2/3,0],Cl=[0,1/6,2/3,1/6];ta.svg.line.radial=function(){var n=ho(Ro);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},mo.reverse=yo,yo.reverse=mo,ta.svg.area=function(){return Do(y)},ta.svg.area.radial=function(){var n=Do(Ro);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ta.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),l=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+u(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)-Ra,s=l.call(n,u,r)-Ra;return{r:i,a0:o,a1:s,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(s),i*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>qa)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=mr,o=yr,a=Po,c=ao,l=co;return n.radius=function(t){return arguments.length?(a=Et(t),n):a},n.source=function(t){return arguments.length?(i=Et(t),n):i},n.target=function(t){return arguments.length?(o=Et(t),n):o},n.startAngle=function(t){return arguments.length?(c=Et(t),n):c},n.endAngle=function(t){return arguments.length?(l=Et(t),n):l},n},ta.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=mr,e=yr,r=Uo;return n.source=function(e){return arguments.length?(t=Et(e),n):t},n.target=function(t){return arguments.length?(e=Et(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ta.svg.diagonal.radial=function(){var n=ta.svg.diagonal(),t=Uo,e=n.projection;return n.projection=function(n){return arguments.length?e(jo(t=n)):t},n},ta.svg.symbol=function(){function n(n,r){return(zl.get(t.call(this,n,r))||Oo)(e.call(this,n,r))}var t=Ho,e=Fo;return n.type=function(e){return arguments.length?(t=Et(e),n):t},n.size=function(t){return arguments.length?(e=Et(t),n):e},n};var zl=ta.map({circle:Oo,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Ll)),e=t*Ll;return"M0,"+-t+"L"+e+",0 0,"+t+" "+-e+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ta.svg.symbolTypes=zl.keys();var ql=Math.sqrt(3),Ll=Math.tan(30*Da);_a.transition=function(n){for(var t,e,r=Tl||++Ul,u=Xo(n),i=[],o=Rl||{time:Date.now(),ease:Su,delay:0,duration:250},a=-1,c=this.length;++a<c;){i.push(t=[]);for(var l=this[a],s=-1,f=l.length;++s<f;)(e=l[s])&&$o(e,s,u,r,o),t.push(e)}return Yo(i,u,r)},_a.interrupt=function(n){return this.each(null==n?Dl:Io(Xo(n)))};var Tl,Rl,Dl=Io(Xo()),Pl=[],Ul=0;Pl.call=_a.call,Pl.empty=_a.empty,Pl.node=_a.node,Pl.size=_a.size,ta.transition=function(n,t){return n&&n.transition?Tl?n.transition(t):n:ta.selection().transition(n)},ta.transition.prototype=Pl,Pl.select=function(n){var t,e,r,u=this.id,i=this.namespace,o=[];n=N(n);for(var a=-1,c=this.length;++a<c;){o.push(t=[]);for(var l=this[a],s=-1,f=l.length;++s<f;)(r=l[s])&&(e=n.call(r,r.__data__,s,a))?("__data__"in r&&(e.__data__=r.__data__),$o(e,s,i,u,r[i][u]),t.push(e)):t.push(null)}return Yo(o,i,u)},Pl.selectAll=function(n){var t,e,r,u,i,o=this.id,a=this.namespace,c=[];n=C(n);for(var l=-1,s=this.length;++l<s;)for(var f=this[l],h=-1,g=f.length;++h<g;)if(r=f[h]){i=r[a][o],e=n.call(r,r.__data__,h,l),c.push(t=[]);for(var p=-1,v=e.length;++p<v;)(u=e[p])&&$o(u,p,a,o,i),t.push(u)}return Yo(c,a,o)},Pl.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=O(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return Yo(u,this.namespace,this.id)},Pl.tween=function(n,t){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(n):Y(this,null==t?function(t){t[r][e].tween.remove(n)}:function(u){u[r][e].tween.set(n,t)})},Pl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Hu:mu,a=ta.ns.qualify(n);return Zo(this,"attr."+n,t,a.local?i:u)},Pl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=ta.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Pl.style=function(n,e,r){function u(){this.style.removeProperty(n)}function i(e){return null==e?u:(e+="",function(){var u,i=t(this).getComputedStyle(this,null).getPropertyValue(n);return i!==e&&(u=mu(i,e),function(t){this.style.setProperty(n,u(t),r)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(e="");for(r in n)this.style(r,n[r],e);return this}r=""}return Zo(this,"style."+n,e,i)},Pl.styleTween=function(n,e,r){function u(u,i){var o=e.call(this,u,i,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),r)}}return arguments.length<3&&(r=""),this.tween("style."+n,u)},Pl.text=function(n){return Zo(this,"text",n,Vo)},Pl.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Pl.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=ta.ease.apply(ta,arguments)),Y(this,function(r){r[e][t].ease=n}))},Pl.delay=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].delay:Y(this,"function"==typeof n?function(r,u,i){r[e][t].delay=+n.call(r,r.__data__,u,i)}:(n=+n,function(r){r[e][t].delay=n}))},Pl.duration=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].duration:Y(this,"function"==typeof n?function(r,u,i){r[e][t].duration=Math.max(1,n.call(r,r.__data__,u,i))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Pl.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var u=Rl,i=Tl;try{Tl=e,Y(this,function(t,u,i){Rl=t[r][e],n.call(t,t.__data__,u,i)})}finally{Rl=u,Tl=i}}else Y(this,function(u){var i=u[r][e];(i.event||(i.event=ta.dispatch("start","end","interrupt"))).on(n,t)});return this},Pl.transition=function(){for(var n,t,e,r,u=this.id,i=++Ul,o=this.namespace,a=[],c=0,l=this.length;l>c;c++){a.push(n=[]);for(var t=this[c],s=0,f=t.length;f>s;s++)(e=t[s])&&(r=e[o][u],$o(e,s,o,i,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Yo(a,o,i)},ta.svg.axis=function(){function n(n){n.each(function(){var n,l=ta.select(this),s=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):y:t,p=l.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Ca),d=ta.transition(p.exit()).style("opacity",Ca).remove(),m=ta.transition(p.order()).style("opacity",1),M=Math.max(u,0)+o,x=Ui(f),b=l.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),ta.transition(b));v.append("line"),v.append("text");var w,S,k,E,A=v.select("line"),N=m.select("line"),C=p.select("text").text(g),z=v.select("text"),q=m.select("text"),L="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=Bo,w="x",k="y",S="x2",E="y2",C.attr("dy",0>L?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+L*i+"V0H"+x[1]+"V"+L*i)):(n=Wo,w="y",k="x",S="y2",E="x2",C.attr("dy",".32em").style("text-anchor",0>L?"end":"start"),_.attr("d","M"+L*i+","+x[0]+"H0V"+x[1]+"H"+L*i)),A.attr(E,L*u),z.attr(k,L*M),N.attr(S,0).attr(E,L*u),q.attr(w,0).attr(k,L*M),f.rangeBand){var T=f,R=T.rangeBand()/2;s=f=function(n){return T(n)+R}}else s.rangeBand?s=f:d.call(n,f,s);v.call(n,s,f),m.call(n,f,f)})}var t,e=ta.scale.linear(),r=jl,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Fl?t+"":jl,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var jl="bottom",Fl={top:1,right:1,bottom:1,left:1};ta.svg.brush=function(){function n(t){t.each(function(){var t=ta.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",i).on("touchstart.brush",i),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(v,y);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Hl[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var c,f=ta.transition(t),h=ta.transition(o);l&&(c=Ui(l),h.attr("x",c[0]).attr("width",c[1]-c[0]),r(f)),s&&(c=Ui(s),h.attr("y",c[0]).attr("height",c[1]-c[0]),u(f)),e(f)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+f[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",f[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1]-f[0])}function u(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function i(){function i(){32==ta.event.keyCode&&(C||(M=null,q[0]-=f[1],q[1]-=h[1],C=2),S())}function v(){32==ta.event.keyCode&&2==C&&(q[0]+=f[1],q[1]+=h[1],C=0,S())}function d(){var n=ta.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(ta.event.altKey?(M||(M=[(f[0]+f[1])/2,(h[0]+h[1])/2]),q[0]=f[+(n[0]<M[0])],q[1]=h[+(n[1]<M[1])]):M=null),A&&m(n,l,0)&&(r(k),t=!0),N&&m(n,s,1)&&(u(k),t=!0),t&&(e(k),w({type:"brush",mode:C?"move":"resize"}))}function m(n,t,e){var r,u,i=Ui(t),c=i[0],l=i[1],s=q[e],v=e?h:f,d=v[1]-v[0];return C&&(c-=s,l-=d+s),r=(e?p:g)?Math.max(c,Math.min(l,n[e])):n[e],C?u=(r+=s)+d:(M&&(s=Math.max(c,Math.min(l,2*M[e]-r))),r>s?(u=r,r=s):u=s),v[0]!=r||v[1]!=u?(e?a=null:o=null,v[0]=r,v[1]=u,!0):void 0}function y(){d(),k.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ta.select("body").style("cursor",null),L.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),z(),w({type:"brushend"})}var M,x,b=this,_=ta.select(ta.event.target),w=c.of(b,arguments),k=ta.select(b),E=_.datum(),A=!/^(n|s)$/.test(E)&&l,N=!/^(e|w)$/.test(E)&&s,C=_.classed("extent"),z=W(b),q=ta.mouse(b),L=ta.select(t(b)).on("keydown.brush",i).on("keyup.brush",v);if(ta.event.changedTouches?L.on("touchmove.brush",d).on("touchend.brush",y):L.on("mousemove.brush",d).on("mouseup.brush",y),k.interrupt().selectAll("*").interrupt(),C)q[0]=f[0]-q[0],q[1]=h[0]-q[1];else if(E){var T=+/w$/.test(E),R=+/^n/.test(E);x=[f[1-T]-q[0],h[1-R]-q[1]],q[0]=f[T],q[1]=h[R]}else ta.event.altKey&&(M=q.slice());k.style("pointer-events","none").selectAll(".resize").style("display",null),ta.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var o,a,c=E(n,"brushstart","brush","brushend"),l=null,s=null,f=[0,0],h=[0,0],g=!0,p=!0,v=Ol[0];return n.event=function(n){n.each(function(){var n=c.of(this,arguments),t={x:f,y:h,i:o,j:a},e=this.__chart__||t;this.__chart__=t,Tl?ta.select(this).transition().each("start.brush",function(){o=e.i,a=e.j,f=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=yu(f,t.x),r=yu(h,t.y);return o=a=null,function(u){f=t.x=e(u),h=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(l=t,v=Ol[!l<<1|!s],n):l},n.y=function(t){return arguments.length?(s=t,v=Ol[!l<<1|!s],n):s},n.clamp=function(t){return arguments.length?(l&&s?(g=!!t[0],p=!!t[1]):l?g=!!t:s&&(p=!!t),n):l&&s?[g,p]:l?g:s?p:null},n.extent=function(t){var e,r,u,i,c;return arguments.length?(l&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),o=[e,r],l.invert&&(e=l(e),r=l(r)),e>r&&(c=e,e=r,r=c),(e!=f[0]||r!=f[1])&&(f=[e,r])),s&&(u=t[0],i=t[1],l&&(u=u[1],i=i[1]),a=[u,i],s.invert&&(u=s(u),i=s(i)),u>i&&(c=u,u=i,i=c),(u!=h[0]||i!=h[1])&&(h=[u,i])),n):(l&&(o?(e=o[0],r=o[1]):(e=f[0],r=f[1],l.invert&&(e=l.invert(e),r=l.invert(r)),e>r&&(c=e,e=r,r=c))),s&&(a?(u=a[0],i=a[1]):(u=h[0],i=h[1],s.invert&&(u=s.invert(u),i=s.invert(i)),u>i&&(c=u,u=i,i=c))),l&&s?[[e,u],[r,i]]:l?[e,r]:s&&[u,i])},n.clear=function(){return n.empty()||(f=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!l&&f[0]==f[1]||!!s&&h[0]==h[1]},ta.rebind(n,c,"on")};var Hl={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ol=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Il=ac.format=gc.timeFormat,Yl=Il.utc,Zl=Yl("%Y-%m-%dT%H:%M:%S.%LZ");Il.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Jo:Zl,Jo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Jo.toString=Zl.toString,ac.second=Ft(function(n){return new cc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ac.seconds=ac.second.range,ac.seconds.utc=ac.second.utc.range,ac.minute=Ft(function(n){return new cc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ac.minutes=ac.minute.range,ac.minutes.utc=ac.minute.utc.range,ac.hour=Ft(function(n){var t=n.getTimezoneOffset()/60;return new cc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ac.hours=ac.hour.range,ac.hours.utc=ac.hour.utc.range,ac.month=Ft(function(n){return n=ac.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ac.months=ac.month.range,ac.months.utc=ac.month.utc.range;var Vl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Xl=[[ac.second,1],[ac.second,5],[ac.second,15],[ac.second,30],[ac.minute,1],[ac.minute,5],[ac.minute,15],[ac.minute,30],[ac.hour,1],[ac.hour,3],[ac.hour,6],[ac.hour,12],[ac.day,1],[ac.day,2],[ac.week,1],[ac.month,1],[ac.month,3],[ac.year,1]],$l=Il.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",Ne]]),Bl={range:function(n,t,e){return ta.range(Math.ceil(n/e)*e,+t,e).map(Ko)},floor:y,ceil:y};Xl.year=ac.year,ac.scale=function(){return Go(ta.scale.linear(),Xl,$l)};var Wl=Xl.map(function(n){return[n[0].utc,n[1]]}),Jl=Yl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",Ne]]);Wl.year=ac.year.utc,ac.scale.utc=function(){return Go(ta.scale.linear(),Wl,Jl)},ta.text=At(function(n){return n.responseText}),ta.json=function(n,t){return Nt(n,"application/json",Qo,t)},ta.html=function(n,t){return Nt(n,"text/html",na,t)},ta.xml=At(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(ta):"object"==typeof module&&module.exports&&(module.exports=ta),this.d3=ta}();
\ No newline at end of file
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/lib/select2.full.min.js b/ovsdb-ui/module/src/main/resources/ovsdb/lib/select2.full.min.js
new file mode 100755 (executable)
index 0000000..59d8c1a
--- /dev/null
@@ -0,0 +1,3 @@
+/*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){var b=function(){if(a&&a.fn&&a.fn.select2&&a.fn.select2.amd)var b=a.fn.select2.amd;var b;return function(){if(!b||!b.requirejs){b?c=b:b={};var a,c,d;!function(b){function e(a,b){return u.call(a,b)}function f(a,b){var c,d,e,f,g,h,i,j,k,l,m,n=b&&b.split("/"),o=s.map,p=o&&o["*"]||{};if(a&&"."===a.charAt(0))if(b){for(n=n.slice(0,n.length-1),a=a.split("/"),g=a.length-1,s.nodeIdCompat&&w.test(a[g])&&(a[g]=a[g].replace(w,"")),a=n.concat(a),k=0;k<a.length;k+=1)if(m=a[k],"."===m)a.splice(k,1),k-=1;else if(".."===m){if(1===k&&(".."===a[2]||".."===a[0]))break;k>0&&(a.splice(k-1,2),k-=2)}a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if((n||p)&&o){for(c=a.split("/"),k=c.length;k>0;k-=1){if(d=c.slice(0,k).join("/"),n)for(l=n.length;l>0;l-=1)if(e=o[n.slice(0,l).join("/")],e&&(e=e[d])){f=e,h=k;break}if(f)break;!i&&p&&p[d]&&(i=p[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function g(a,c){return function(){return n.apply(b,v.call(arguments,0).concat([a,c]))}}function h(a){return function(b){return f(b,a)}}function i(a){return function(b){q[a]=b}}function j(a){if(e(r,a)){var c=r[a];delete r[a],t[a]=!0,m.apply(b,c)}if(!e(q,a)&&!e(t,a))throw new Error("No "+a);return q[a]}function k(a){var b,c=a?a.indexOf("!"):-1;return c>-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function l(a){return function(){return s&&s.config&&s.config[a]||{}}}var m,n,o,p,q={},r={},s={},t={},u=Object.prototype.hasOwnProperty,v=[].slice,w=/\.js$/;o=function(a,b){var c,d=k(a),e=d[0];return a=d[1],e&&(e=f(e,b),c=j(e)),e?a=c&&c.normalize?c.normalize(a,h(b)):f(a,b):(a=f(a,b),d=k(a),e=d[0],a=d[1],e&&(c=j(e))),{f:e?e+"!"+a:a,n:a,pr:e,p:c}},p={require:function(a){return g(a)},exports:function(a){var b=q[a];return"undefined"!=typeof b?b:q[a]={}},module:function(a){return{id:a,uri:"",exports:q[a],config:l(a)}}},m=function(a,c,d,f){var h,k,l,m,n,s,u=[],v=typeof d;if(f=f||a,"undefined"===v||"function"===v){for(c=!c.length&&d.length?["require","exports","module"]:c,n=0;n<c.length;n+=1)if(m=o(c[n],f),k=m.f,"require"===k)u[n]=p.require(a);else if("exports"===k)u[n]=p.exports(a),s=!0;else if("module"===k)h=u[n]=p.module(a);else if(e(q,k)||e(r,k)||e(t,k))u[n]=j(k);else{if(!m.p)throw new Error(a+" missing "+k);m.p.load(m.n,g(f,!0),i(k),{}),u[n]=q[k]}l=d?d.apply(q[a],u):void 0,a&&(h&&h.exports!==b&&h.exports!==q[a]?q[a]=h.exports:l===b&&s||(q[a]=l))}else a&&(q[a]=d)},a=c=n=function(a,c,d,e,f){if("string"==typeof a)return p[a]?p[a](c):j(o(a,c).f);if(!a.splice){if(s=a,s.deps&&n(s.deps,s.callback),!c)return;c.splice?(a=c,c=d,d=null):a=b}return c=c||function(){},"function"==typeof d&&(d=e,e=f),e?m(b,a,c,d):setTimeout(function(){m(b,a,c,d)},4),n},n.config=function(a){return n(a)},a._defined=q,d=function(a,b,c){b.splice||(c=b,b=[]),e(q,a)||e(r,a)||(r[a]=[a,b,c])},d.amd={jQuery:!0}}(),b.requirejs=a,b.require=c,b.define=d}}(),b.define("almond",function(){}),b.define("jquery",[],function(){var b=a||$;return null==b&&console&&console.error&&console.error("Select2: An instance of jQuery or a jQuery-compatible library was not found. Make sure that you are including jQuery before Select2 on your web page."),b}),b.define("select2/utils",["jquery"],function(a){function b(a){var b=a.prototype,c=[];for(var d in b){var e=b[d];"function"==typeof e&&"constructor"!==d&&c.push(d)}return c}var c={};c.Extend=function(a,b){function c(){this.constructor=a}var d={}.hasOwnProperty;for(var e in b)d.call(b,e)&&(a[e]=b[e]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},c.Decorate=function(a,c){function d(){var b=Array.prototype.unshift,d=c.prototype.constructor.length,e=a.prototype.constructor;d>0&&(b.call(arguments,a.prototype.constructor),e=c.prototype.constructor),e.apply(this,arguments)}function e(){this.constructor=d}var f=b(c),g=b(a);c.displayName=a.displayName,d.prototype=new e;for(var h=0;h<g.length;h++){var i=g[h];d.prototype[i]=a.prototype[i]}for(var j=(function(a){var b=function(){};a in d.prototype&&(b=d.prototype[a]);var e=c.prototype[a];return function(){var a=Array.prototype.unshift;return a.call(arguments,b),e.apply(this,arguments)}}),k=0;k<f.length;k++){var l=f[k];d.prototype[l]=j(l)}return d};var d=function(){this.listeners={}};return d.prototype.on=function(a,b){this.listeners=this.listeners||{},a in this.listeners?this.listeners[a].push(b):this.listeners[a]=[b]},d.prototype.trigger=function(a){var b=Array.prototype.slice;this.listeners=this.listeners||{},a in this.listeners&&this.invoke(this.listeners[a],b.call(arguments,1)),"*"in this.listeners&&this.invoke(this.listeners["*"],arguments)},d.prototype.invoke=function(a,b){for(var c=0,d=a.length;d>c;c++)a[c].apply(this,b)},c.Observable=d,c.generateChars=function(a){for(var b="",c=0;a>c;c++){var d=Math.floor(36*Math.random());b+=d.toString(36)}return b},c.bind=function(a,b){return function(){a.apply(b,arguments)}},c._convertData=function(a){for(var b in a){var c=b.split("-"),d=a;if(1!==c.length){for(var e=0;e<c.length;e++){var f=c[e];f=f.substring(0,1).toLowerCase()+f.substring(1),f in d||(d[f]={}),e==c.length-1&&(d[f]=a[b]),d=d[f]}delete a[b]}}return a},c.hasScroll=function(b,c){var d=a(c),e=c.style.overflowX,f=c.style.overflowY;return e!==f||"hidden"!==f&&"visible"!==f?"scroll"===e||"scroll"===f?!0:d.innerHeight()<c.scrollHeight||d.innerWidth()<c.scrollWidth:!1},c.escapeMarkup=function(a){var b={"\\":"&#92;","&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#47;"};return"string"!=typeof a?a:String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})},c.appendMany=function(b,c){if("1.7"===a.fn.jquery.substr(0,3)){var d=a();a.map(c,function(a){d=d.add(a)}),c=d}b.append(c)},c}),b.define("select2/results",["jquery","./utils"],function(a,b){function c(a,b,d){this.$element=a,this.data=d,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<ul class="select2-results__options" role="tree"></ul>');return this.options.get("multiple")&&b.attr("aria-multiselectable","true"),this.$results=b,b},c.prototype.clear=function(){this.$results.empty()},c.prototype.displayMessage=function(b){var c=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var d=a('<li role="treeitem" class="select2-results__option"></li>'),e=this.options.get("translations").get(b.message);d.append(c(e(b.args))),this.$results.append(d)},c.prototype.append=function(a){this.hideLoading();var b=[];if(null==a.results||0===a.results.length)return void(0===this.$results.children().length&&this.trigger("results:message",{message:"noResults"}));a.results=this.sort(a.results);for(var c=0;c<a.results.length;c++){var d=a.results[c],e=this.option(d);b.push(e)}this.$results.append(b)},c.prototype.position=function(a,b){var c=b.find(".select2-results");c.append(a)},c.prototype.sort=function(a){var b=this.options.get("sorter");return b(a)},c.prototype.setClasses=function(){var b=this;this.data.current(function(c){var d=a.map(c,function(a){return a.id.toString()}),e=b.$results.find(".select2-results__option[aria-selected]");e.each(function(){var b=a(this),c=a.data(this,"data"),e=""+c.id;null!=c.element&&c.element.selected||null==c.element&&a.inArray(e,d)>-1?b.attr("aria-selected","true"):b.attr("aria-selected","false")});var f=e.filter("[aria-selected=true]");f.length>0?f.first().trigger("mouseenter"):e.first().trigger("mouseenter")})},c.prototype.showLoading=function(a){this.hideLoading();var b=this.options.get("translations").get("searching"),c={disabled:!0,loading:!0,text:b(a)},d=this.option(c);d.className+=" loading-results",this.$results.prepend(d)},c.prototype.hideLoading=function(){this.$results.find(".loading-results").remove()},c.prototype.option=function(b){var c=document.createElement("li");c.className="select2-results__option";var d={role:"treeitem","aria-selected":"false"};b.disabled&&(delete d["aria-selected"],d["aria-disabled"]="true"),null==b.id&&delete d["aria-selected"],null!=b._resultId&&(c.id=b._resultId),b.title&&(c.title=b.title),b.children&&(d.role="group",d["aria-label"]=b.text,delete d["aria-selected"]);for(var e in d){var f=d[e];c.setAttribute(e,f)}if(b.children){var g=a(c),h=document.createElement("strong");h.className="select2-results__group";{a(h)}this.template(b,h);for(var i=[],j=0;j<b.children.length;j++){var k=b.children[j],l=this.option(k);i.push(l)}var m=a("<ul></ul>",{"class":"select2-results__options select2-results__options--nested"});m.append(i),g.append(h),g.append(m)}else this.template(b,c);return a.data(c,"data",b),c},c.prototype.bind=function(b){var c=this,d=b.id+"-results";this.$results.attr("id",d),b.on("results:all",function(a){c.clear(),c.append(a.data),b.isOpen()&&c.setClasses()}),b.on("results:append",function(a){c.append(a.data),b.isOpen()&&c.setClasses()}),b.on("query",function(a){c.showLoading(a)}),b.on("select",function(){b.isOpen()&&c.setClasses()}),b.on("unselect",function(){b.isOpen()&&c.setClasses()}),b.on("open",function(){c.$results.attr("aria-expanded","true"),c.$results.attr("aria-hidden","false"),c.setClasses(),c.ensureHighlightVisible()}),b.on("close",function(){c.$results.attr("aria-expanded","false"),c.$results.attr("aria-hidden","true"),c.$results.removeAttr("aria-activedescendant")}),b.on("results:toggle",function(){var a=c.getHighlightedResults();0!==a.length&&a.trigger("mouseup")}),b.on("results:select",function(){var a=c.getHighlightedResults();if(0!==a.length){var b=a.data("data");"true"==a.attr("aria-selected")?c.trigger("close"):c.trigger("select",{data:b})}}),b.on("results:previous",function(){var a=c.getHighlightedResults(),b=c.$results.find("[aria-selected]"),d=b.index(a);if(0!==d){var e=d-1;0===a.length&&(e=0);var f=b.eq(e);f.trigger("mouseenter");var g=c.$results.offset().top,h=f.offset().top,i=c.$results.scrollTop()+(h-g);0===e?c.$results.scrollTop(0):0>h-g&&c.$results.scrollTop(i)}}),b.on("results:next",function(){var a=c.getHighlightedResults(),b=c.$results.find("[aria-selected]"),d=b.index(a),e=d+1;if(!(e>=b.length)){var f=b.eq(e);f.trigger("mouseenter");var g=c.$results.offset().top+c.$results.outerHeight(!1),h=f.offset().top+f.outerHeight(!1),i=c.$results.scrollTop()+h-g;0===e?c.$results.scrollTop(0):h>g&&c.$results.scrollTop(i)}}),b.on("results:focus",function(a){a.element.addClass("select2-results__option--highlighted")}),b.on("results:message",function(a){c.displayMessage(a)}),a.fn.mousewheel&&this.$results.on("mousewheel",function(a){var b=c.$results.scrollTop(),d=c.$results.get(0).scrollHeight-c.$results.scrollTop()+a.deltaY,e=a.deltaY>0&&b-a.deltaY<=0,f=a.deltaY<0&&d<=c.$results.height();e?(c.$results.scrollTop(0),a.preventDefault(),a.stopPropagation()):f&&(c.$results.scrollTop(c.$results.get(0).scrollHeight-c.$results.height()),a.preventDefault(),a.stopPropagation())}),this.$results.on("mouseup",".select2-results__option[aria-selected]",function(b){var d=a(this),e=d.data("data");return"true"===d.attr("aria-selected")?void(c.options.get("multiple")?c.trigger("unselect",{originalEvent:b,data:e}):c.trigger("close")):void c.trigger("select",{originalEvent:b,data:e})}),this.$results.on("mouseenter",".select2-results__option[aria-selected]",function(){var b=a(this).data("data");c.getHighlightedResults().removeClass("select2-results__option--highlighted"),c.trigger("results:focus",{data:b,element:a(this)})})},c.prototype.getHighlightedResults=function(){var a=this.$results.find(".select2-results__option--highlighted");return a},c.prototype.destroy=function(){this.$results.remove()},c.prototype.ensureHighlightVisible=function(){var a=this.getHighlightedResults();if(0!==a.length){var b=this.$results.find("[aria-selected]"),c=b.index(a),d=this.$results.offset().top,e=a.offset().top,f=this.$results.scrollTop()+(e-d),g=e-d;f-=2*a.outerHeight(!1),2>=c?this.$results.scrollTop(0):(g>this.$results.outerHeight()||0>g)&&this.$results.scrollTop(f)}},c.prototype.template=function(b,c){var d=this.options.get("templateResult"),e=this.options.get("escapeMarkup"),f=d(b);null==f?c.style.display="none":"string"==typeof f?c.innerHTML=e(f):a(c).append(f)},c}),b.define("select2/keys",[],function(){var a={BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46};return a}),b.define("select2/selection/base",["jquery","../utils","../keys"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,b.Observable),d.prototype.render=function(){var b=a('<span class="select2-selection" role="combobox" aria-autocomplete="list" aria-haspopup="true" aria-expanded="false"></span>');return this._tabindex=0,null!=this.$element.data("old-tabindex")?this._tabindex=this.$element.data("old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),b.attr("title",this.$element.attr("title")),b.attr("tabindex",this._tabindex),this.$selection=b,b},d.prototype.bind=function(a){var b=this,d=(a.id+"-container",a.id+"-results");this.container=a,this.$selection.on("focus",function(a){b.trigger("focus",a)}),this.$selection.on("blur",function(a){b.trigger("blur",a)}),this.$selection.on("keydown",function(a){b.trigger("keypress",a),a.which===c.SPACE&&a.preventDefault()}),a.on("results:focus",function(a){b.$selection.attr("aria-activedescendant",a.data._resultId)}),a.on("selection:update",function(a){b.update(a.data)}),a.on("open",function(){b.$selection.attr("aria-expanded","true"),b.$selection.attr("aria-owns",d),b._attachCloseHandler(a)}),a.on("close",function(){b.$selection.attr("aria-expanded","false"),b.$selection.removeAttr("aria-activedescendant"),b.$selection.removeAttr("aria-owns"),b.$selection.focus(),b._detachCloseHandler(a)}),a.on("enable",function(){b.$selection.attr("tabindex",b._tabindex)}),a.on("disable",function(){b.$selection.attr("tabindex","-1")})},d.prototype._attachCloseHandler=function(b){a(document.body).on("mousedown.select2."+b.id,function(b){var c=a(b.target),d=c.closest(".select2"),e=a(".select2.select2-container--open");e.each(function(){var b=a(this);if(this!=d[0]){var c=b.data("element");c.select2("close")}})})},d.prototype._detachCloseHandler=function(b){a(document.body).off("mousedown.select2."+b.id)},d.prototype.position=function(a,b){var c=b.find(".selection");c.append(a)},d.prototype.destroy=function(){this._detachCloseHandler(this.container)},d.prototype.update=function(){throw new Error("The `update` method must be defined in child classes.")},d}),b.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(a,b,c){function d(){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--single"),a.html('<span class="select2-selection__rendered"></span><span class="select2-selection__arrow" role="presentation"><b role="presentation"></b></span>'),a},d.prototype.bind=function(a){var b=this;d.__super__.bind.apply(this,arguments);var c=a.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",c),this.$selection.attr("aria-labelledby",c),this.$selection.on("mousedown",function(a){1===a.which&&b.trigger("toggle",{originalEvent:a})}),this.$selection.on("focus",function(){}),this.$selection.on("blur",function(){}),a.on("selection:update",function(a){b.update(a.data)})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a){var b=this.options.get("templateSelection"),c=this.options.get("escapeMarkup");return c(b(a))},d.prototype.selectionContainer=function(){return a("<span></span>")},d.prototype.update=function(a){if(0===a.length)return void this.clear();var b=a[0],c=this.display(b),d=this.$selection.find(".select2-selection__rendered");d.empty().append(c),d.prop("title",b.title||b.text)},d}),b.define("select2/selection/multiple",["jquery","./base","../utils"],function(a,b,c){function d(){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--multiple"),a.html('<ul class="select2-selection__rendered"></ul>'),a},d.prototype.bind=function(){var b=this;d.__super__.bind.apply(this,arguments),this.$selection.on("click",function(a){b.trigger("toggle",{originalEvent:a})}),this.$selection.on("click",".select2-selection__choice__remove",function(c){var d=a(this),e=d.parent(),f=e.data("data");b.trigger("unselect",{originalEvent:c,data:f})})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a){var b=this.options.get("templateSelection"),c=this.options.get("escapeMarkup");return c(b(a))},d.prototype.selectionContainer=function(){var b=a('<li class="select2-selection__choice"><span class="select2-selection__choice__remove" role="presentation">&times;</span></li>');return b},d.prototype.update=function(a){if(this.clear(),0!==a.length){for(var b=[],d=0;d<a.length;d++){var e=a[d],f=this.display(e),g=this.selectionContainer();g.append(f),g.prop("title",e.title||e.text),g.data("data",e),b.push(g)}var h=this.$selection.find(".select2-selection__rendered");c.appendMany(h,b)}},d}),b.define("select2/selection/placeholder",["../utils"],function(){function a(a,b,c){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c)}return a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.createPlaceholder=function(a,b){var c=this.selectionContainer();return c.html(this.display(b)),c.addClass("select2-selection__placeholder").removeClass("select2-selection__choice"),c},a.prototype.update=function(a,b){var c=1==b.length&&b[0].id!=this.placeholder.id,d=b.length>1;if(d||c)return a.call(this,b);this.clear();var e=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(e)},a}),b.define("select2/selection/allowClear",["jquery","../keys"],function(a,b){function c(){}return c.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(a){d._handleClear(a)}),b.on("keypress",function(a){d._handleKeyboardClear(a,b)})},c.prototype._handleClear=function(a,b){if(!this.options.get("disabled")){var c=this.$selection.find(".select2-selection__clear");if(0!==c.length){b.stopPropagation();for(var d=c.data("data"),e=0;e<d.length;e++){var f={data:d[e]};if(this.trigger("unselect",f),f.prevented)return}this.$element.val(this.placeholder.id).trigger("change"),this.trigger("toggle")}}},c.prototype._handleKeyboardClear=function(a,c,d){d.isOpen()||(c.which==b.DELETE||c.which==b.BACKSPACE)&&this._handleClear(c)},c.prototype.update=function(b,c){if(b.call(this,c),!(this.$selection.find(".select2-selection__placeholder").length>0||0===c.length)){var d=a('<span class="select2-selection__clear">&times;</span>');d.data("data",c),this.$selection.find(".select2-selection__rendered").prepend(d)}},c}),b.define("select2/selection/search",["jquery","../utils","../keys"],function(a,b,c){function d(a,b,c){a.call(this,b,c)}return d.prototype.render=function(b){var c=a('<li class="select2-search select2-search--inline"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="textbox" /></li>');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus()}),b.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val(""),e.$search.focus()}),b.on("enable",function(){e.$search.prop("disabled",!1)}),b.on("disable",function(){e.$search.prop("disabled",!0)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e.trigger("blur",a)}),this.$selection.on("keydown",".select2-search--inline",function(a){a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented();var b=a.which;if(b===c.BACKSPACE&&""===e.$search.val()){var d=e.$searchContainer.prev(".select2-selection__choice");if(d.length>0){var f=d.data("data");e.searchRemoveChoice(f),a.preventDefault()}}}),this.$selection.on("input",".select2-search--inline",function(){e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input",".select2-search--inline",function(a){e.handleSearch(a)})},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.trigger("open"),this.$search.val(b.text+" ")},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{var b=this.$search.val().length+1;a=.75*b+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){var a={"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"};return a}),b.define("select2/data/base",["../utils"],function(a){function b(){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),d+=null!=c.id?"-"+c.id.toString():"-"+a.generateChars(4)},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change");if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f<a.length;f++){var g=a[f].id;-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")});else{var d=a.id;this.$element.val(d),this.$element.trigger("change")}},d.prototype.unselect=function(a){var b=this;if(this.$element.prop("multiple"))return a.selected=!1,c(a.element).is("option")?(a.element.selected=!1,void this.$element.trigger("change")):void this.current(function(d){for(var e=[],f=0;f<d.length;f++){var g=d[f].id;g!==a.id&&-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")})},d.prototype.bind=function(a){var b=this;this.container=a,a.on("select",function(a){b.select(a.data)}),a.on("unselect",function(a){b.unselect(a.data)})},d.prototype.destroy=function(){this.$element.find("*").each(function(){c.removeData(this,"data")})},d.prototype.query=function(a,b){var d=[],e=this,f=this.$element.children();f.each(function(){var b=c(this);if(b.is("option")||b.is("optgroup")){var f=e.item(b),g=e.matches(a,f);null!==g&&d.push(g)}}),b({results:d})},d.prototype.addOptions=function(a){b.appendMany(this.$element,a)},d.prototype.option=function(a){var b;a.children?(b=document.createElement("optgroup"),b.label=a.text):(b=document.createElement("option"),void 0!==b.textContent?b.textContent=a.text:b.innerText=a.text),a.id&&(b.value=a.id),a.disabled&&(b.disabled=!0),a.selected&&(b.selected=!0),a.title&&(b.title=a.title);var d=c(b),e=this._normalizeItem(a);return e.element=b,c.data(b,"data",e),d},d.prototype.item=function(a){var b={};
+if(b=c.data(a[0],"data"),null!=b)return b;if(a.is("option"))b={id:a.val(),text:a.text(),disabled:a.prop("disabled"),selected:a.prop("selected"),title:a.prop("title")};else if(a.is("optgroup")){b={text:a.prop("label"),children:[],title:a.prop("title")};for(var d=a.children("option"),e=[],f=0;f<d.length;f++){var g=c(d[f]),h=this.item(g);e.push(h)}b.children=e}return b=this._normalizeItem(b),b.element=a[0],c.data(a[0],"data",b),b},d.prototype._normalizeItem=function(a){c.isPlainObject(a)||(a={id:a,text:a}),a=c.extend({},{text:""},a);var b={selected:!1,disabled:!1};return null!=a.id&&(a.id=a.id.toString()),null!=a.text&&(a.text=a.text.toString()),null==a._resultId&&a.id&&null!=this.container&&(a._resultId=this.generateResultId(this.container,a)),c.extend({},b,a)},d.prototype.matches=function(a,b){var c=this.options.get("matcher");return c(a,b)},d}),b.define("select2/data/array",["./select","../utils","jquery"],function(a,b,c){function d(a,b){var c=b.get("data")||[];d.__super__.constructor.call(this,a,b),this.addOptions(this.convertToOptions(c))}return b.Extend(d,a),d.prototype.select=function(a){var b=this.$element.find("option").filter(function(b,c){return c.value==a.id.toString()});0===b.length&&(b=this.option(a),this.addOptions(b)),d.__super__.select.call(this,a)},d.prototype.convertToOptions=function(a){function d(a){return function(){return c(this).val()==a.id}}for(var e=this,f=this.$element.find("option"),g=f.map(function(){return e.item(c(this)).id}).get(),h=[],i=0;i<a.length;i++){var j=this._normalizeItem(a[i]);if(c.inArray(j.id,g)>=0){var k=f.filter(d(j)),l=this.item(k),m=(c.extend(!0,{},l,j),this.option(l));k.replaceWith(m)}else{var n=this.option(j);if(j.children){var o=this.convertToOptions(j.children);b.appendMany(n,o)}h.push(n)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(b,c){this.ajaxOptions=this._applyDefaults(c.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),a.__super__.constructor.call(this,b,c)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return{q:a.term}},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url(a)),"function"==typeof f.data&&(f.data=f.data(a)),this.ajaxOptions.delay&&""!==a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");if(void 0!==f&&(this.createTag=f),b.call(this,c,d),a.isArray(e))for(var g=0;g<e.length;g++){var h=e[g],i=this._normalizeItem(h),j=this.option(i);this.$element.append(j)}}return b.prototype.query=function(a,b,c){function d(a,f){for(var g=a.results,h=0;h<g.length;h++){var i=g[h],j=null!=i.children&&!d({results:i.children},!0),k=i.text===b.term;if(k||j)return f?!1:(a.data=g,void c(a))}if(f)return!0;var l=e.createTag(b);if(null!=l){var m=e.option(l);m.attr("data-select2-tag",!0),e.addOptions([m]),e.insertTag(g,l)}a.results=g,c(a)}var e=this;return this._removeOldTags(),null==b.term||null!=b.page?void a.call(this,b,c):void a.call(this,b,d)},b.prototype.createTag=function(b,c){var d=a.trim(c.term);return""===d?null:{id:d,text:d}},b.prototype.insertTag=function(a,b,c){b.unshift(c)},b.prototype._removeOldTags=function(){var b=(this._lastTag,this.$element.find("option[data-select2-tag]"));b.each(function(){this.selected||a(this).remove()})},b}),b.define("select2/data/tokenizer",["jquery"],function(a){function b(a,b,c){var d=c.get("tokenizer");void 0!==d&&(this.tokenizer=d),a.call(this,b,c)}return b.prototype.bind=function(a,b,c){a.call(this,b,c),this.$search=b.dropdown.$search||b.selection.$search||c.find(".select2-search__field")},b.prototype.query=function(a,b,c){function d(a){e.select(a)}var e=this;b.term=b.term||"";var f=this.tokenizer(b,this.options,d);f.term!==b.term&&(this.$search.length&&(this.$search.val(f.term),this.$search.focus()),b.term=f.term),a.call(this,b,c)},b.prototype.tokenizer=function(b,c,d,e){for(var f=d.get("tokenSeparators")||[],g=c.term,h=0,i=this.createTag||function(a){return{id:a.term,text:a.term}};h<g.length;){var j=g[h];if(-1!==a.inArray(j,f)){var k=g.substr(0,h),l=a.extend({},c,{term:k}),m=i(l);e(m),g=g.substr(h+1)||"",h=0}else h++}return{term:g}},b}),b.define("select2/data/minimumInputLength",[],function(){function a(a,b,c){this.minimumInputLength=c.get("minimumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){return b.term=b.term||"",b.term.length<this.minimumInputLength?void this.trigger("results:message",{message:"inputTooShort",args:{minimum:this.minimumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumInputLength",[],function(){function a(a,b,c){this.maximumInputLength=c.get("maximumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){return b.term=b.term||"",this.maximumInputLength>0&&b.term.length>this.maximumInputLength?void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;return d.maximumSelectionLength>0&&f>=d.maximumSelectionLength?void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}}):void a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<span class="select2-dropdown"><span class="select2-results"></span></span>');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.position=function(){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a){function b(){}return b.prototype.render=function(b){var c=b.call(this),d=a('<span class="select2-search select2-search--dropdown"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="textbox" /></span>');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){var b=e.showSearch(a);b?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},b.prototype.handleSearch=function(){if(!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},b.prototype.showSearch=function(){return!0},b}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){var c=e.$results.offset().top+e.$results.outerHeight(!1),d=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1);c+50>=d&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a('<li class="option load-more" role="treeitem"></li>'),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(a,b,c){this.$dropdownParent=c.get("dropdownParent")||document.body,a.call(this,b,c)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a("<span></span>"),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c){var d=this,e="scroll.select2."+c.id,f="resize.select2."+c.id,g="orientationchange.select2."+c.id,h=this.$container.parents().filter(b.hasScroll);h.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),h.on(e,function(){var b=a(this).data("select2-scroll-position");a(this).scrollTop(b.y)}),a(window).on(e+" "+f+" "+g,function(){d._positionDropdown(),d._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c){var d="scroll.select2."+c.id,e="resize.select2."+c.id,f="orientationchange.select2."+c.id,g=this.$container.parents().filter(b.hasScroll);g.off(d),a(window).off(d+" "+e+" "+f)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=(this.$container.position(),this.$container.offset());f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.top<f.top-h.height,k=i.bottom>f.bottom+h.height,l={left:f.left,top:g.bottom};c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){this.$dropdownContainer.width();var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d<b.length;d++){var e=b[d];e.children?c+=a(e.children):c++}return c}function b(a,b,c,d){this.minimumResultsForSearch=c.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),a.call(this,b,c,d)}return b.prototype.showSearch=function(b,c){return a(c.data.results)<this.minimumResultsForSearch?!1:b.call(this,c)},b}),b.define("select2/dropdown/selectOnClose",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("close",function(){d._handleSelectOnClose()})},a.prototype._handleSelectOnClose=function(){var a=this.getHighlightedResults();a.length<1||this.trigger("select",{data:a.data("data")})},a}),b.define("select2/dropdown/closeOnSelect",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("select",function(a){d._selectTriggered(a)}),b.on("unselect",function(a){d._selectTriggered(a)})},a.prototype._selectTriggered=function(a,b){var c=b.originalEvent;c&&c.ctrlKey||this.trigger("close")},a}),b.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(a){var b=a.input.length-a.maximum,c="Please delete "+b+" character";return 1!=b&&(c+="s"),c},inputTooShort:function(a){var b=a.minimum-a.input.length,c="Please enter "+b+" or more characters";return c},loadingMore:function(){return"Loading more results…"},maximumSelected:function(a){var b="You can only select "+a.maximum+" item";return 1!=a.maximum&&(b+="s"),b},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),b.define("select2/defaults",["jquery","require","./results","./selection/single","./selection/multiple","./selection/placeholder","./selection/allowClear","./selection/search","./selection/eventRelay","./utils","./translation","./diacritics","./data/select","./data/array","./data/ajax","./data/tags","./data/tokenizer","./data/minimumInputLength","./data/maximumInputLength","./data/maximumSelectionLength","./dropdown","./dropdown/search","./dropdown/hidePlaceholder","./dropdown/infiniteScroll","./dropdown/attachBody","./dropdown/minimumResultsForSearch","./dropdown/selectOnClose","./dropdown/closeOnSelect","./i18n/en"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C){function D(){this.reset()}D.prototype.apply=function(l){if(l=a.extend({},this.defaults,l),null==l.dataAdapter){if(l.dataAdapter=null!=l.ajax?o:null!=l.data?n:m,l.minimumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),(null!=l.tokenSeparators||null!=l.tokenizer)&&(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.selectionAdapter=l.multiple?e:d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L<K.length;L++){var M=K[L],N={};try{N=k.loadPath(M)}catch(O){try{M=this.defaults.amdLanguageBase+M,N=k.loadPath(M)}catch(P){l.debug&&window.console&&console.warn&&console.warn('Select2: The language file for "'+M+'" could not be automatically loaded. A fallback will be used instead.');continue}}J.extend(N)}l.translations=J}else{var Q=k.loadPath(this.defaults.amdLanguageBase+"en"),R=new k(l.language);R.extend(Q),l.translations=R}return l},D.prototype.reset=function(){function b(a){function b(a){return l[a]||a}return a.replace(/[^\u0000-\u007E]/g,b)}function c(d,e){if(""===a.trim(d.term))return e;if(e.children&&e.children.length>0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){var h=e.children[g],i=c(d,h);null==i&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var j=b(e.text).toUpperCase(),k=b(d.term).toUpperCase();return j.indexOf(k)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)};var E=new D;return E}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(this.options.dir=a.prop("dir")?a.prop("dir"):a.closest("[dir]").prop("dir")?a.closest("[dir]").prop("dir"):"ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return 0>=e?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;i>h;h+=1){var j=g[h].replace(/\s/g,""),k=j.match(c);if(null!==k&&k.length>=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this._sync=c.bind(this._syncAttributes,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._sync);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._sync)}),this._observer.observe(this.$element[0],{attributes:!0,subtree:!1})):this.$element[0].addEventListener&&this.$element[0].addEventListener("DOMAttrModified",b._sync,!1)},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("focus",function(){a.$container.addClass("select2-container--focus")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open"),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ENTER?(a.trigger("results:select"),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle"),b.preventDefault()):c===d.UP?(a.trigger("results:previous"),b.preventDefault()):c===d.DOWN?(a.trigger("results:next"),b.preventDefault()):(c===d.ESC||c===d.TAB)&&(a.close(),b.preventDefault()):(c===d.ENTER||c===d.SPACE||(c===d.DOWN||c===d.UP)&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable")):this.trigger("enable")},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||(this.trigger("query",{}),this.trigger("open"))},e.prototype.close=function(){this.isOpen()&&this.trigger("close")},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),(null==a||0===a.length)&&(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._sync),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&this.$element[0].removeEventListener("DOMAttrModified",this._sync,!1),this._sync=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null},e.prototype.render=function(){var b=a('<span class="select2 select2-container"><span class="selection"></span><span class="dropdown-wrapper" aria-hidden="true"></span></span>');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("select2/compat/utils",["jquery"],function(a){function b(b,c,d){var e,f,g=[];e=a.trim(b.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each(function(){0===this.indexOf("select2-")&&g.push(this)})),e=a.trim(c.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each(function(){0!==this.indexOf("select2-")&&(f=d(this),null!=f&&g.push(f))})),b.attr("class",g.join(" "))}return{syncCssClasses:b}}),b.define("select2/compat/containerCss",["jquery","./utils"],function(a,b){function c(){return null}function d(){}return d.prototype.render=function(d){var e=d.call(this),f=this.options.get("containerCssClass")||"";a.isFunction(f)&&(f=f(this.$element));var g=this.options.get("adaptContainerCssClass");if(g=g||c,-1!==f.indexOf(":all:")){f=f.replace(":all","");var h=g;g=function(a){var b=h(a);return null!=b?b+" "+a:a}}var i=this.options.get("containerCss")||{};return a.isFunction(i)&&(i=i(this.$element)),b.syncCssClasses(e,this.$element,g),e.css(i),e.addClass(f),e},d}),b.define("select2/compat/dropdownCss",["jquery","./utils"],function(a,b){function c(){return null}function d(){}return d.prototype.render=function(d){var e=d.call(this),f=this.options.get("dropdownCssClass")||"";a.isFunction(f)&&(f=f(this.$element));var g=this.options.get("adaptDropdownCssClass");if(g=g||c,-1!==f.indexOf(":all:")){f=f.replace(":all","");var h=g;g=function(a){var b=h(a);return null!=b?b+" "+a:a}}var i=this.options.get("dropdownCss")||{};return a.isFunction(i)&&(i=i(this.$element)),b.syncCssClasses(e,this.$element,g),e.css(i),e.addClass(f),e},d}),b.define("select2/compat/initSelection",["jquery"],function(a){function b(a,b,c){c.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `initSelection` option has been deprecated in favor of a custom data adapter that overrides the `current` method. This method is now called multiple times instead of a single time when the instance is initialized. Support will be removed for the `initSelection` option in future versions of Select2"),this.initSelection=c.get("initSelection"),this._isInitialized=!1,a.call(this,b,c)}return b.prototype.current=function(b,c){var d=this;return this._isInitialized?void b.call(this,c):void this.initSelection.call(null,this.$element,function(b){d._isInitialized=!0,a.isArray(b)||(b=[b]),c(b)})},b}),b.define("select2/compat/inputData",["jquery"],function(a){function b(a,b,c){this._currentData=[],this._valueSeparator=c.get("valueSeparator")||",","hidden"===b.prop("type")&&c.get("debug")&&console&&console.warn&&console.warn("Select2: Using a hidden input with Select2 is no longer supported and may stop working in the future. It is recommended to use a `<select>` element instead."),a.call(this,b,c)}return b.prototype.current=function(b,c){function d(b,c){var e=[];return b.selected||-1!==a.inArray(b.id,c)?(b.selected=!0,e.push(b)):b.selected=!1,b.children&&e.push.apply(e,d(b.children,c)),e}for(var e=[],f=0;f<this._currentData.length;f++){var g=this._currentData[f];e.push.apply(e,d(g,this.$element.val().split(this._valueSeparator)))}c(e)},b.prototype.select=function(b,c){if(this.options.get("multiple")){var d=this.$element.val();d+=this._valueSeparator+c.id,this.$element.val(d),this.$element.trigger("change")}else this.current(function(b){a.map(b,function(a){a.selected=!1})}),this.$element.val(c.id),this.$element.trigger("change")},b.prototype.unselect=function(a,b){var c=this;b.selected=!1,this.current(function(a){for(var d=[],e=0;e<a.length;e++){var f=a[e];
+b.id!=f.id&&d.push(f.id)}c.$element.val(d.join(c._valueSeparator)),c.$element.trigger("change")})},b.prototype.query=function(a,b,c){for(var d=[],e=0;e<this._currentData.length;e++){var f=this._currentData[e],g=this.matches(b,f);null!==g&&d.push(g)}c({results:d})},b.prototype.addOptions=function(b,c){var d=a.map(c,function(b){return a.data(b[0],"data")});this._currentData.push.apply(this._currentData,d)},b}),b.define("select2/compat/matcher",["jquery"],function(a){function b(b){function c(c,d){var e=a.extend(!0,{},d);if(null==c.term||""===a.trim(c.term))return e;if(d.children){for(var f=d.children.length-1;f>=0;f--){var g=d.children[f],h=b(c.term,g.text,g);h||e.children.splice(f,1)}if(e.children.length>0)return e}return b(c.term,d.text,d)?e:null}return c}return b}),b.define("select2/compat/query",[],function(){function a(a,b,c){c.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `query` option has been deprecated in favor of a custom data adapter that overrides the `query` method. Support will be removed for the `query` option in future versions of Select2."),a.call(this,b,c)}return a.prototype.query=function(a,b,c){b.callback=c;var d=this.options.get("query");d.call(null,b)},a}),b.define("select2/dropdown/attachContainer",[],function(){function a(a,b,c){a.call(this,b,c)}return a.prototype.position=function(a,b,c){var d=c.find(".dropdown-wrapper");d.append(b),b.addClass("select2-dropdown--below"),c.addClass("select2-container--below")},a}),b.define("select2/dropdown/stopPropagation",[],function(){function a(){}return a.prototype.bind=function(a,b,c){a.call(this,b,c);var d=["blur","change","click","dblclick","focus","focusin","focusout","input","keydown","keyup","keypress","mousedown","mouseenter","mouseleave","mousemove","mouseover","mouseup","search","touchend","touchstart"];this.$dropdown.on(d.join(" "),function(a){a.stopPropagation()})},a}),b.define("select2/selection/stopPropagation",[],function(){function a(){}return a.prototype.bind=function(a,b,c){a.call(this,b,c);var d=["blur","change","click","dblclick","focus","focusin","focusout","input","keydown","keyup","keypress","mousedown","mouseenter","mouseleave","mousemove","mouseover","mouseup","search","touchend","touchstart"];this.$selection.on(d.join(" "),function(a){a.stopPropagation()})},a}),b.define("jquery.select2",["jquery","require","./select2/core","./select2/defaults"],function(a,b,c,d){if(b("jquery.mousewheel"),null==a.fn.select2){var e=["open","close","destroy"];a.fn.select2=function(b){if(b=b||{},"object"==typeof b)return this.each(function(){{var d=a.extend({},b,!0);new c(a(this),d)}}),this;if("string"==typeof b){var d=this.data("select2");null==d&&window.console&&console.error&&console.error("The select2('"+b+"') method was called on an element that is not using Select2.");var f=Array.prototype.slice.call(arguments,1),g=d[b](f);return a.inArray(b,e)>-1?this:g}throw new Error("Invalid arguments for Select2: "+b)}}return null==a.fn.select2.defaults&&(a.fn.select2.defaults=d),c}),function(c){"function"==typeof b.define&&b.define.amd?b.define("jquery.mousewheel",["jquery"],c):"object"==typeof exports?module.exports=c:c(a)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})}),{define:b.define,require:b.require}}(),c=b.require("jquery.select2");return a.fn.select2.amd=b,c});
\ No newline at end of file
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/lib/sylvester.js b/ovsdb-ui/module/src/main/resources/ovsdb/lib/sylvester.js
new file mode 100755 (executable)
index 0000000..3e83bee
--- /dev/null
@@ -0,0 +1 @@
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 17={3i:\'0.1.3\',16:1e-6};l v(){}v.23={e:l(i){8(i<1||i>7.4.q)?w:7.4[i-1]},2R:l(){8 7.4.q},1u:l(){8 F.1x(7.2u(7))},24:l(a){9 n=7.4.q;9 V=a.4||a;o(n!=V.q){8 1L}J{o(F.13(7.4[n-1]-V[n-1])>17.16){8 1L}}H(--n);8 2x},1q:l(){8 v.u(7.4)},1b:l(a){9 b=[];7.28(l(x,i){b.19(a(x,i))});8 v.u(b)},28:l(a){9 n=7.4.q,k=n,i;J{i=k-n;a(7.4[i],i+1)}H(--n)},2q:l(){9 r=7.1u();o(r===0){8 7.1q()}8 7.1b(l(x){8 x/r})},1C:l(a){9 V=a.4||a;9 n=7.4.q,k=n,i;o(n!=V.q){8 w}9 b=0,1D=0,1F=0;7.28(l(x,i){b+=x*V[i-1];1D+=x*x;1F+=V[i-1]*V[i-1]});1D=F.1x(1D);1F=F.1x(1F);o(1D*1F===0){8 w}9 c=b/(1D*1F);o(c<-1){c=-1}o(c>1){c=1}8 F.37(c)},1m:l(a){9 b=7.1C(a);8(b===w)?w:(b<=17.16)},34:l(a){9 b=7.1C(a);8(b===w)?w:(F.13(b-F.1A)<=17.16)},2k:l(a){9 b=7.2u(a);8(b===w)?w:(F.13(b)<=17.16)},2j:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x+V[i-1]})},2C:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x-V[i-1]})},22:l(k){8 7.1b(l(x){8 x*k})},x:l(k){8 7.22(k)},2u:l(a){9 V=a.4||a;9 i,2g=0,n=7.4.q;o(n!=V.q){8 w}J{2g+=7.4[n-1]*V[n-1]}H(--n);8 2g},2f:l(a){9 B=a.4||a;o(7.4.q!=3||B.q!=3){8 w}9 A=7.4;8 v.u([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},2A:l(){9 m=0,n=7.4.q,k=n,i;J{i=k-n;o(F.13(7.4[i])>F.13(m)){m=7.4[i]}}H(--n);8 m},2Z:l(x){9 a=w,n=7.4.q,k=n,i;J{i=k-n;o(a===w&&7.4[i]==x){a=i+1}}H(--n);8 a},3g:l(){8 S.2X(7.4)},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(y){8(F.13(y-x)<=17.16)?x:y})},1o:l(a){o(a.K){8 a.1o(7)}9 V=a.4||a;o(V.q!=7.4.q){8 w}9 b=0,2b;7.28(l(x,i){2b=x-V[i-1];b+=2b*2b});8 F.1x(b)},3a:l(a){8 a.1h(7)},2T:l(a){8 a.1h(7)},1V:l(t,a){9 V,R,x,y,z;2S(7.4.q){27 2:V=a.4||a;o(V.q!=2){8 w}R=S.1R(t).4;x=7.4[0]-V[0];y=7.4[1]-V[1];8 v.u([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);1I;27 3:o(!a.U){8 w}9 C=a.1r(7).4;R=S.1R(t,a.U).4;x=7.4[0]-C[0];y=7.4[1]-C[1];z=7.4[2]-C[2];8 v.u([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);1I;2P:8 w}},1t:l(a){o(a.K){9 P=7.4.2O();9 C=a.1r(P).4;8 v.u([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}1d{9 Q=a.4||a;o(7.4.q!=Q.q){8 w}8 7.1b(l(x,i){8 Q[i-1]+(Q[i-1]-x)})}},1N:l(){9 V=7.1q();2S(V.4.q){27 3:1I;27 2:V.4.19(0);1I;2P:8 w}8 V},2n:l(){8\'[\'+7.4.2K(\', \')+\']\'},26:l(a){7.4=(a.4||a).2O();8 7}};v.u=l(a){9 V=25 v();8 V.26(a)};v.i=v.u([1,0,0]);v.j=v.u([0,1,0]);v.k=v.u([0,0,1]);v.2J=l(n){9 a=[];J{a.19(F.2F())}H(--n);8 v.u(a)};v.1j=l(n){9 a=[];J{a.19(0)}H(--n);8 v.u(a)};l S(){}S.23={e:l(i,j){o(i<1||i>7.4.q||j<1||j>7.4[0].q){8 w}8 7.4[i-1][j-1]},33:l(i){o(i>7.4.q){8 w}8 v.u(7.4[i-1])},2E:l(j){o(j>7.4[0].q){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][j-1])}H(--n);8 v.u(a)},2R:l(){8{2D:7.4.q,1p:7.4[0].q}},2D:l(){8 7.4.q},1p:l(){8 7.4[0].q},24:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(7.4.q!=M.q||7.4[0].q!=M[0].q){8 1L}9 b=7.4.q,15=b,i,G,10=7.4[0].q,j;J{i=15-b;G=10;J{j=10-G;o(F.13(7.4[i][j]-M[i][j])>17.16){8 1L}}H(--G)}H(--b);8 2x},1q:l(){8 S.u(7.4)},1b:l(a){9 b=[],12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;b[i]=[];J{j=10-G;b[i][j]=a(7.4[i][j],i+1,j+1)}H(--G)}H(--12);8 S.u(b)},2i:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4.q==M.q&&7.4[0].q==M[0].q)},2j:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x+M[i-1][j-1]})},2C:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x-M[i-1][j-1]})},2B:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4[0].q==M.q)},22:l(a){o(!a.4){8 7.1b(l(x){8 x*a})}9 b=a.1u?2x:1L;9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2B(M)){8 w}9 d=7.4.q,15=d,i,G,10=M[0].q,j;9 e=7.4[0].q,4=[],21,20,c;J{i=15-d;4[i]=[];G=10;J{j=10-G;21=0;20=e;J{c=e-20;21+=7.4[i][c]*M[c][j]}H(--20);4[i][j]=21}H(--G)}H(--d);9 M=S.u(4);8 b?M.2E(1):M},x:l(a){8 7.22(a)},32:l(a,b,c,d){9 e=[],12=c,i,G,j;9 f=7.4.q,1p=7.4[0].q;J{i=c-12;e[i]=[];G=d;J{j=d-G;e[i][j]=7.4[(a+i-1)%f][(b+j-1)%1p]}H(--G)}H(--12);8 S.u(e)},31:l(){9 a=7.4.q,1p=7.4[0].q;9 b=[],12=1p,i,G,j;J{i=1p-12;b[i]=[];G=a;J{j=a-G;b[i][j]=7.4[j][i]}H(--G)}H(--12);8 S.u(b)},1y:l(){8(7.4.q==7.4[0].q)},2A:l(){9 m=0,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(F.13(7.4[i][j])>F.13(m)){m=7.4[i][j]}}H(--G)}H(--12);8 m},2Z:l(x){9 a=w,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(7.4[i][j]==x){8{i:i+1,j:j+1}}}H(--G)}H(--12);8 w},30:l(){o(!7.1y){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][i])}H(--n);8 v.u(a)},1K:l(){9 M=7.1q(),1c;9 n=7.4.q,k=n,i,1s,1n=7.4[0].q,p;J{i=k-n;o(M.4[i][i]==0){2e(j=i+1;j<k;j++){o(M.4[j][i]!=0){1c=[];1s=1n;J{p=1n-1s;1c.19(M.4[i][p]+M.4[j][p])}H(--1s);M.4[i]=1c;1I}}}o(M.4[i][i]!=0){2e(j=i+1;j<k;j++){9 a=M.4[j][i]/M.4[i][i];1c=[];1s=1n;J{p=1n-1s;1c.19(p<=i?0:M.4[j][p]-M.4[i][p]*a)}H(--1s);M.4[j]=1c}}}H(--n);8 M},3h:l(){8 7.1K()},2z:l(){o(!7.1y()){8 w}9 M=7.1K();9 a=M.4[0][0],n=M.4.q-1,k=n,i;J{i=k-n+1;a=a*M.4[i][i]}H(--n);8 a},3f:l(){8 7.2z()},2y:l(){8(7.1y()&&7.2z()===0)},2Y:l(){o(!7.1y()){8 w}9 a=7.4[0][0],n=7.4.q-1,k=n,i;J{i=k-n+1;a+=7.4[i][i]}H(--n);8 a},3e:l(){8 7.2Y()},1Y:l(){9 M=7.1K(),1Y=0;9 a=7.4.q,15=a,i,G,10=7.4[0].q,j;J{i=15-a;G=10;J{j=10-G;o(F.13(M.4[i][j])>17.16){1Y++;1I}}H(--G)}H(--a);8 1Y},3d:l(){8 7.1Y()},2W:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}9 T=7.1q(),1p=T.4[0].q;9 b=T.4.q,15=b,i,G,10=M[0].q,j;o(b!=M.q){8 w}J{i=15-b;G=10;J{j=10-G;T.4[i][1p+j]=M[i][j]}H(--G)}H(--b);8 T},2w:l(){o(!7.1y()||7.2y()){8 w}9 a=7.4.q,15=a,i,j;9 M=7.2W(S.I(a)).1K();9 b,1n=M.4[0].q,p,1c,2v;9 c=[],2c;J{i=a-1;1c=[];b=1n;c[i]=[];2v=M.4[i][i];J{p=1n-b;2c=M.4[i][p]/2v;1c.19(2c);o(p>=15){c[i].19(2c)}}H(--b);M.4[i]=1c;2e(j=0;j<i;j++){1c=[];b=1n;J{p=1n-b;1c.19(M.4[j][p]-M.4[i][p]*M.4[j][i])}H(--b);M.4[j]=1c}}H(--a);8 S.u(c)},3c:l(){8 7.2w()},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(p){8(F.13(p-x)<=17.16)?x:p})},2n:l(){9 a=[];9 n=7.4.q,k=n,i;J{i=k-n;a.19(v.u(7.4[i]).2n())}H(--n);8 a.2K(\'\\n\')},26:l(a){9 i,4=a.4||a;o(1g(4[0][0])!=\'1f\'){9 b=4.q,15=b,G,10,j;7.4=[];J{i=15-b;G=4[i].q;10=G;7.4[i]=[];J{j=10-G;7.4[i][j]=4[i][j]}H(--G)}H(--b);8 7}9 n=4.q,k=n;7.4=[];J{i=k-n;7.4.19([4[i]])}H(--n);8 7}};S.u=l(a){9 M=25 S();8 M.26(a)};S.I=l(n){9 a=[],k=n,i,G,j;J{i=k-n;a[i]=[];G=k;J{j=k-G;a[i][j]=(i==j)?1:0}H(--G)}H(--n);8 S.u(a)};S.2X=l(a){9 n=a.q,k=n,i;9 M=S.I(n);J{i=k-n;M.4[i][i]=a[i]}H(--n);8 M};S.1R=l(b,a){o(!a){8 S.u([[F.1H(b),-F.1G(b)],[F.1G(b),F.1H(b)]])}9 d=a.1q();o(d.4.q!=3){8 w}9 e=d.1u();9 x=d.4[0]/e,y=d.4[1]/e,z=d.4[2]/e;9 s=F.1G(b),c=F.1H(b),t=1-c;8 S.u([[t*x*x+c,t*x*y-s*z,t*x*z+s*y],[t*x*y+s*z,t*y*y+c,t*y*z-s*x],[t*x*z-s*y,t*y*z+s*x,t*z*z+c]])};S.3b=l(t){9 c=F.1H(t),s=F.1G(t);8 S.u([[1,0,0],[0,c,-s],[0,s,c]])};S.39=l(t){9 c=F.1H(t),s=F.1G(t);8 S.u([[c,0,s],[0,1,0],[-s,0,c]])};S.38=l(t){9 c=F.1H(t),s=F.1G(t);8 S.u([[c,-s,0],[s,c,0],[0,0,1]])};S.2J=l(n,m){8 S.1j(n,m).1b(l(){8 F.2F()})};S.1j=l(n,m){9 a=[],12=n,i,G,j;J{i=n-12;a[i]=[];G=m;J{j=m-G;a[i][j]=0}H(--G)}H(--12);8 S.u(a)};l 14(){}14.23={24:l(a){8(7.1m(a)&&7.1h(a.K))},1q:l(){8 14.u(7.K,7.U)},2U:l(a){9 V=a.4||a;8 14.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.U)},1m:l(a){o(a.W){8 a.1m(7)}9 b=7.U.1C(a.U);8(F.13(b)<=17.16||F.13(b-F.1A)<=17.16)},1o:l(a){o(a.W){8 a.1o(7)}o(a.U){o(7.1m(a)){8 7.1o(a.K)}9 N=7.U.2f(a.U).2q().4;9 A=7.K.4,B=a.K.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,D=7.U.4;9 b=P[0]-A[0],2a=P[1]-A[1],29=(P[2]||0)-A[2];9 c=F.1x(b*b+2a*2a+29*29);o(c===0)8 0;9 d=(b*D[0]+2a*D[1]+29*D[2])/c;9 e=1-d*d;8 F.13(c*F.1x(e<0?0:e))}},1h:l(a){9 b=7.1o(a);8(b!==w&&b<=17.16)},2T:l(a){8 a.1h(7)},1v:l(a){o(a.W){8 a.1v(7)}8(!7.1m(a)&&7.1o(a)<=17.16)},1U:l(a){o(a.W){8 a.1U(7)}o(!7.1v(a)){8 w}9 P=7.K.4,X=7.U.4,Q=a.K.4,Y=a.U.4;9 b=X[0],1z=X[1],1B=X[2],1T=Y[0],1S=Y[1],1M=Y[2];9 c=P[0]-Q[0],2s=P[1]-Q[1],2r=P[2]-Q[2];9 d=-b*c-1z*2s-1B*2r;9 e=1T*c+1S*2s+1M*2r;9 f=b*b+1z*1z+1B*1B;9 g=1T*1T+1S*1S+1M*1M;9 h=b*1T+1z*1S+1B*1M;9 k=(d*g/f+h*e)/(g-h*h);8 v.u([P[0]+k*b,P[1]+k*1z,P[2]+k*1B])},1r:l(a){o(a.U){o(7.1v(a)){8 7.1U(a)}o(7.1m(a)){8 w}9 D=7.U.4,E=a.U.4;9 b=D[0],1l=D[1],1k=D[2],1P=E[0],1O=E[1],1Q=E[2];9 x=(1k*1P-b*1Q),y=(b*1O-1l*1P),z=(1l*1Q-1k*1O);9 N=v.u([x*1Q-y*1O,y*1P-z*1Q,z*1O-x*1P]);9 P=11.u(a.K,N);8 P.1U(7)}1d{9 P=a.4||a;o(7.1h(P)){8 v.u(P)}9 A=7.K.4,D=7.U.4;9 b=D[0],1l=D[1],1k=D[2],1w=A[0],18=A[1],1a=A[2];9 x=b*(P[1]-18)-1l*(P[0]-1w),y=1l*((P[2]||0)-1a)-1k*(P[1]-18),z=1k*(P[0]-1w)-b*((P[2]||0)-1a);9 V=v.u([1l*x-1k*z,1k*y-b*x,b*z-1l*y]);9 k=7.1o(P)/V.1u();8 v.u([P[0]+V.4[0]*k,P[1]+V.4[1]*k,(P[2]||0)+V.4[2]*k])}},1V:l(t,a){o(1g(a.U)==\'1f\'){a=14.u(a.1N(),v.k)}9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,D=7.U.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 14.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*D[0]+R[0][1]*D[1]+R[0][2]*D[2],R[1][0]*D[0]+R[1][1]*D[1]+R[1][2]*D[2],R[2][0]*D[0]+R[2][1]*D[1]+R[2][2]*D[2]])},1t:l(a){o(a.W){9 A=7.K.4,D=7.U.4;9 b=A[0],18=A[1],1a=A[2],2N=D[0],1l=D[1],1k=D[2];9 c=7.K.1t(a).4;9 d=b+2N,2h=18+1l,2o=1a+1k;9 Q=a.1r([d,2h,2o]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2h)-c[1],Q[2]+(Q[2]-2o)-c[2]];8 14.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 14.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.U)}},1Z:l(a,b){a=v.u(a);b=v.u(b);o(a.4.q==2){a.4.19(0)}o(b.4.q==2){b.4.19(0)}o(a.4.q>3||b.4.q>3){8 w}9 c=b.1u();o(c===0){8 w}7.K=a;7.U=v.u([b.4[0]/c,b.4[1]/c,b.4[2]/c]);8 7}};14.u=l(a,b){9 L=25 14();8 L.1Z(a,b)};14.X=14.u(v.1j(3),v.i);14.Y=14.u(v.1j(3),v.j);14.Z=14.u(v.1j(3),v.k);l 11(){}11.23={24:l(a){8(7.1h(a.K)&&7.1m(a))},1q:l(){8 11.u(7.K,7.W)},2U:l(a){9 V=a.4||a;8 11.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.W)},1m:l(a){9 b;o(a.W){b=7.W.1C(a.W);8(F.13(b)<=17.16||F.13(F.1A-b)<=17.16)}1d o(a.U){8 7.W.2k(a.U)}8 w},2k:l(a){9 b=7.W.1C(a.W);8(F.13(F.1A/2-b)<=17.16)},1o:l(a){o(7.1v(a)||7.1h(a)){8 0}o(a.K){9 A=7.K.4,B=a.K.4,N=7.W.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;8 F.13((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},1h:l(a){o(a.W){8 w}o(a.U){8(7.1h(a.K)&&7.1h(a.K.2j(a.U)))}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=F.13(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));8(b<=17.16)}},1v:l(a){o(1g(a.U)==\'1f\'&&1g(a.W)==\'1f\'){8 w}8!7.1m(a)},1U:l(a){o(!7.1v(a)){8 w}o(a.U){9 A=a.K.4,D=a.U.4,P=7.K.4,N=7.W.4;9 b=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);8 v.u([A[0]+D[0]*b,A[1]+D[1]*b,A[2]+D[2]*b])}1d o(a.W){9 c=7.W.2f(a.W).2q();9 N=7.W.4,A=7.K.4,O=a.W.4,B=a.K.4;9 d=S.1j(2,2),i=0;H(d.2y()){i++;d=S.u([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}9 e=d.2w().4;9 x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];9 y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];9 f=[e[0][0]*x+e[0][1]*y,e[1][0]*x+e[1][1]*y];9 g=[];2e(9 j=1;j<=3;j++){g.19((i==j)?0:f[(j+(5-i)%3)%3])}8 14.u(g,c)}},1r:l(a){9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];8 v.u([P[0]+N[0]*b,P[1]+N[1]*b,(P[2]||0)+N[2]*b])},1V:l(t,a){9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,N=7.W.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 11.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},1t:l(a){o(a.W){9 A=7.K.4,N=7.W.4;9 b=A[0],18=A[1],1a=A[2],2M=N[0],2L=N[1],2Q=N[2];9 c=7.K.1t(a).4;9 d=b+2M,2p=18+2L,2m=1a+2Q;9 Q=a.1r([d,2p,2m]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2p)-c[1],Q[2]+(Q[2]-2m)-c[2]];8 11.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 11.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.W)}},1Z:l(a,b,c){a=v.u(a);a=a.1N();o(a===w){8 w}b=v.u(b);b=b.1N();o(b===w){8 w}o(1g(c)==\'1f\'){c=w}1d{c=v.u(c);c=c.1N();o(c===w){8 w}}9 d=a.4[0],18=a.4[1],1a=a.4[2];9 e=b.4[0],1W=b.4[1],1X=b.4[2];9 f,1i;o(c!==w){9 g=c.4[0],2l=c.4[1],2t=c.4[2];f=v.u([(1W-18)*(2t-1a)-(1X-1a)*(2l-18),(1X-1a)*(g-d)-(e-d)*(2t-1a),(e-d)*(2l-18)-(1W-18)*(g-d)]);1i=f.1u();o(1i===0){8 w}f=v.u([f.4[0]/1i,f.4[1]/1i,f.4[2]/1i])}1d{1i=F.1x(e*e+1W*1W+1X*1X);o(1i===0){8 w}f=v.u([b.4[0]/1i,b.4[1]/1i,b.4[2]/1i])}7.K=a;7.W=f;8 7}};11.u=l(a,b,c){9 P=25 11();8 P.1Z(a,b,c)};11.2I=11.u(v.1j(3),v.k);11.2H=11.u(v.1j(3),v.i);11.2G=11.u(v.1j(3),v.j);11.36=11.2I;11.35=11.2H;11.3j=11.2G;9 $V=v.u;9 $M=S.u;9 $L=14.u;9 $P=11.u;',62,206,'||||elements|||this|return|var||||||||||||function|||if||length||||create|Vector|null|||||||||Math|nj|while||do|anchor||||||||Matrix||direction||normal||||kj|Plane|ni|abs|Line|ki|precision|Sylvester|A2|push|A3|map|els|else||undefined|typeof|contains|mod|Zero|D3|D2|isParallelTo|kp|distanceFrom|cols|dup|pointClosestTo|np|reflectionIn|modulus|intersects|A1|sqrt|isSquare|X2|PI|X3|angleFrom|mod1|C2|mod2|sin|cos|break|C3|toRightTriangular|false|Y3|to3D|E2|E1|E3|Rotation|Y2|Y1|intersectionWith|rotate|v12|v13|rank|setVectors|nc|sum|multiply|prototype|eql|new|setElements|case|each|PA3|PA2|part|new_element|round|for|cross|product|AD2|isSameSizeAs|add|isPerpendicularTo|v22|AN3|inspect|AD3|AN2|toUnitVector|PsubQ3|PsubQ2|v23|dot|divisor|inverse|true|isSingular|determinant|max|canMultiplyFromLeft|subtract|rows|col|random|ZX|YZ|XY|Random|join|N2|N1|D1|slice|default|N3|dimensions|switch|liesIn|translate|snapTo|augment|Diagonal|trace|indexOf|diagonal|transpose|minor|row|isAntiparallelTo|ZY|YX|acos|RotationZ|RotationY|liesOn|RotationX|inv|rk|tr|det|toDiagonalMatrix|toUpperTriangular|version|XZ'.split('|'),0,{}))
\ No newline at end of file
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/matrix.js b/ovsdb-ui/module/src/main/resources/ovsdb/matrix.js
new file mode 100644 (file)
index 0000000..97e82f6
--- /dev/null
@@ -0,0 +1,72 @@
+define(['app/ovsdb/lib/sylvester'], function() {
+  function Transform(a, b, c, d , e, f) {
+    if (a)
+    this.transform = $M([
+      [a, b, c],
+      [d, e, f],
+      [0, 0, 1]
+    ]);
+    else
+      this.transform = Matrix.I(3);
+  }
+
+  Transform.fromString = function(string) {
+    if(!string) {
+      return new Transform();
+    }
+    var g = document.createElementNS("http://www.w3.org/2000/svg", 'g');
+    g.setAttribute('transform', string);
+    var t = g.transform.baseVal.consolidate();
+    var m = t.matrix;
+    return new Transform(m.a, m.b, m.c, m.d, m.e, m.f);
+  }
+
+  Transform.combine = function(ma, mb) {
+    var t = new Transform();
+    t.transform = ma.transform.x(mb.transform);
+    return t;
+  }
+
+  Transform.prototype.translate = function(tx, ty) {
+    this.transform = $M([[1, 0, tx], [0, 1, ty], [0, 0, 1]]).x(this.transform);
+    return this;
+  };
+
+  Transform.prototype.rotate = function(deg) {
+    var rad = parseFloat(deg) * (Math.PI/180),
+    cos = Math.cos(rad),
+    sin = Math.sin(rad);
+
+    this.transform = $M([[cos, -sin, 0], [sin, cos, 0], [0, 0, 1]]).x(this.transform);
+    return this;
+  };
+
+  Transform.prototype.scale = function(x, y) {
+    var x = x,
+    y = y || x;
+
+    this.transform = $M([[x, 0, 0], [0, y, 0], [0, 0, 1]]).x(this.transform);
+    return this;
+  };
+
+  Transform.prototype.skew = function(x, y) {
+    var alpha = Math.tan(parseFloat(x) * (Math.PI/180)),
+     betha = Math.tan(parseFloat(y) * (Math.PI/180));
+
+    this.transform = $M([[1, alpha, 0], [betha, 1, 0], [0, 0, 1]]).x(this.transform);
+    return this;
+  };
+
+  Transform.prototype.transformPoint = function(x, y) {
+    var v = $V([x, y, 1]);
+    return this.transform.x(v);
+  };
+
+  Transform.prototype.toString = function() {
+    return this.transform.inspect();
+  }
+
+  return {
+    Matrix: Transform // Matrix function name already used by Sylvester
+  };
+});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/mocks/ovsdb.controller.js b/ovsdb-ui/module/src/main/resources/ovsdb/mocks/ovsdb.controller.js
deleted file mode 100644 (file)
index 1cca4f3..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-define([], function() {
-  
-});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/mocks/ovsdb.module.js b/ovsdb-ui/module/src/main/resources/ovsdb/mocks/ovsdb.module.js
deleted file mode 100644 (file)
index f68d28b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-define([], function() {
-  var ovsdb = angular.module('app.ovsdb', []);
-
-  ovsdb.register = {
-    controller: ovsdb.controller,
-    service: ovsdb.service,
-    factory: ovsdb.factory
-  };
-
-  return ovsdb;
-
-})
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/mocks/ovsdb.services.js b/ovsdb-ui/module/src/main/resources/ovsdb/mocks/ovsdb.services.js
deleted file mode 100644 (file)
index 1cca4f3..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-define([], function() {
-  
-});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.constant.js b/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.constant.js
new file mode 100644 (file)
index 0000000..cc1441d
--- /dev/null
@@ -0,0 +1,64 @@
+define(['app/ovsdb/ovsdb.module'], function(ovsdb) {
+
+  ovsdb.register.constant('nodeIdentifier', {
+    IP: 'ip',
+    ID: 'node-id',
+    REMOTE_PORT: 'remote-port',
+    SRC_NODE: 'source-node',
+    DEST_NODE: 'dest-node',
+    SRC_TP: 'source-tp',
+    DEST_TP: 'dest-tp',
+    ADDRESSES: 'addresses'
+  });
+
+  ovsdb.register.constant('ovsNodeKeys', {
+    NODE_ID: 'node-id',
+    CONNECTION_INFO: 'ovsdb:connection-info',
+    OVS_VERSION: 'ovsdb:ovs-version',
+    LOCAL_IP: 'local-ip',
+    LOCAL_PORT: 'local-port',
+    REMOTE_IP: 'remote-ip',
+    REMOTE_PORT: 'remote-port',
+    OTHER_CONFIG: 'ovsdb:openvswitch-other-configs',
+    OTHER_CONFIG_KEY: 'other-config-key',
+    OTHER_CONFIG_VALUE: 'other-config-value'
+  });
+
+  ovsdb.register.constant('bridgeNodeKeys', {
+    NODE_ID: 'node-id',
+    CONTROLLER_ENTRY: 'ovsdb:controller-entry',
+    TARGET: 'target',
+    IS_CONNECTED: 'is-connected',
+    DATA_PATH: 'ovsdb:datapath-id',
+    BRIDGE_NAME: 'ovsdb:bridge-name',
+    TP: 'termination-point'
+  });
+
+  ovsdb.register.constant('tpKeys', {
+    NAME: 'ovsdb:name',
+    OF_PORT: 'ovsdb:ofport',
+    INTERFACE_TYPE: 'ovsdb:interface-type',
+    ATTACHED_MAC: 'attached-mac',
+    IFACE_ID: 'iface-id',
+    EXTERNAL_KEY_ID: 'external-id-key',
+    EXTERNAL_KEY_VALUE: 'external-id-value'
+  });
+
+  ovsdb.register.constant('flowInfoKeys', {
+    FEATURE: 'flow-node-inventory:switch-features',
+    SOFTWARE: 'flow-node-inventory:software',
+    HARDWARE: 'flow-node-inventory:hardware',
+    MANUFACTURER: 'flow-node-inventory:manufacturer',
+    IP: 'flow-node-inventory:ip-address',
+    TABLE: 'flow-node-inventory:table'
+  });
+
+  ovsdb.register.constant('linkIdentifier', {
+    SRC: 'source',
+    l3_unicast: 'l3-unicast-igp-topology:igp-link-attributes',
+    overlay_tunnel_type: 'overlay:tunnel-type',
+    supported_link: 'supporting-link',
+    ID: 'link-id',
+    DEST: 'destination'
+  });
+});
index 5982a06eaa14cb9b4309f9d7a2d726ac70b6e182..4aac68f04d264adbed8bd4a126fb13c5347eb6ac 100644 (file)
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
  * and is available at http://www.eclipse.org/legal/epl-v10.html\r
  */\r
-\r
-define(['jquery', 'app/ovsdb/ovsdb.module','app/ovsdb/ovsdb.services'], function($, ovsdb) {\r
+define(['jquery', 'underscore', 'app/ovsdb/ovsdb.module', 'app/ovsdb/OvsCore', 'app/ovsdb/ovsdb.directives', 'app/ovsdb/ovsdb.services', 'app/ovsdb/lib/select2.full.min'], function ($, _, ovsdb, OvsCore) {\r
   'use strict';\r
 \r
-  var RootOvsdbCtrl = function($rootScope) {\r
-      $rootScope['section_logo'] = 'logo_ovsdb';\r
-  };\r
-  RootOvsdbCtrl.$inject = ['$rootScope'];\r
+  var RootOvsdbCtrl = function ($rootScope, cssInjector) {\r
+    $rootScope['section_logo'] = 'logo_ovsdb';\r
+    cssInjector.add('src/app/ovsdb/css/select2.min.css');\r
+    cssInjector.add('src/app/ovsdb/css/toggle-switch.css');\r
 \r
-  var BaseOvsdbCtrl = function($scope) {\r
-      $scope['err'] = {\r
-        "message": "",\r
-        "tag": "",\r
-        "type": ""\r
-      };\r
+    cssInjector.add('src/app/ovsdb/css/ovsdb.css');\r
+  };\r
+  RootOvsdbCtrl.$inject = ['$rootScope', 'cssInjector'];\r
 \r
-      $scope.showError = function() {\r
-        $('#errorMessage').fadeIn().delay(3000).fadeOut();\r
-      };\r
+  var BaseOvsdbCtrl = function ($scope) {\r
+    $scope.err = {\r
+      "message": "",\r
+      "tag": "",\r
+      "type": ""\r
+    };\r
+    $scope.showError = function () {\r
+      $('#errorMessage').fadeIn().delay(3000).fadeOut();\r
+    };\r
   };\r
   BaseOvsdbCtrl.$inject = ['$scope'];\r
 \r
-  var OvsdbCtrl = function($scope, TopologyNetworkSvc) {\r
-      BaseOvsdbCtrl.call(this, $scope);\r
+  var OvsdbCtrl = function ($q, $scope, TopologySvc, NeutronSvc, OvsUtil) {\r
+    BaseOvsdbCtrl.call(this, $scope);\r
+    var lgraphDataDefer = $q.defer(),\r
+      physDataDefer = $q.defer(),\r
+      filterTenant = {\r
+        bridgeIds : [''],\r
+        ovsdbIds : ['']\r
+      },\r
+      filterSubnet = {\r
+        bridgeIds : [''],\r
+        ovsdbIds : ['']\r
+      };\r
+\r
+    $scope.dataPromise = physDataDefer.promise;\r
+    $scope.lgraphIsReadyPromise = lgraphDataDefer.promise;\r
+    $scope.canvasWidth = $('#tabs').width();\r
+    $scope.canvasHeight = 580;\r
+\r
+    $scope.dialogData = ['d'];\r
+\r
+    $scope.tenants = [];\r
+    $scope.subnets = [];\r
+    $scope.selectedTenant = '';\r
+    $scope.selectedSubnet = '';\r
+\r
+    $scope.toggleLayer = function () {\r
+      $scope.rotateGraph($scope.opt.layer);\r
+    };\r
+\r
+    $scope.resizeGraph = function () {\r
+      var $row = $('#ovsdb_contain > div.row:first');\r
+      var h = $row.height();\r
+      $row.data('ph', h);\r
+      $row.fadeOut();\r
+      $('#nv_graph > svg').animate({\r
+        height: '+=' + h\r
+      });\r
+    };\r
+\r
+    $scope.minimizeGraph = function () {\r
+      var $row = $('#ovsdb_contain > div.row:first');\r
+      var h = $row.data('ph');\r
+      $row.fadeIn();\r
+      $('#nv_graph > svg').animate({\r
+        height: '-=' + h\r
+      });\r
+    };\r
+\r
+    function applyFilter(inverse) {\r
+      var bridgeIds = _.uniq(filterTenant.bridgeIds.concat(filterSubnet.bridgeIds));\r
+      var ovsdbIds = _.uniq(filterTenant.ovsdbIds.concat(filterSubnet.ovsdbIds));\r
+      $scope.filterNode(bridgeIds, '.bridge');\r
+      $scope.filterNode(ovsdbIds, '.switch');\r
+      $scope.filterLink();\r
+    }\r
+\r
+    function removeFilter() {\r
+      $scope.filterNode([''], '.bridge', false);\r
+      $scope.filterNode([''], '.switch', false);\r
+      $scope.filterLink();\r
+    }\r
+\r
+    $scope.fiterByTenant = function() {\r
+      if ($scope.selectedTenant) {\r
+        var tenant = $scope.selectedTenant;\r
+        OvsUtil.extractLogicalByTenant(tenant.id).then(function(result) {\r
+          var bridgeId = result[0],\r
+            ovsdbId = result[1];\r
+\r
+          filterTenant.bridgeIds = _.uniq(filterTenant.bridgeIds.concat(bridgeId));\r
+          filterTenant.ovsdbIds = _.uniq(filterTenant.ovsdbIds.concat(ovsdbId));\r
+          applyFilter();\r
+        });\r
+      } else {\r
+        filterTenant.bridgeIds = [''];\r
+        filterTenant.ovsdbIds = [''];\r
+        applyFilter();\r
+      }\r
+    };\r
+\r
+    $scope.filterBySubnet = function() {\r
+      if (!_.isEmpty($scope.selectedSubnet)) {\r
+        var subnets = _.map($scope.selectedSubnet, function(d) {\r
+          return d.id;\r
+        });\r
+        OvsUtil.extractLogicalBySubnet(subnets).then(function(result) {\r
+          var bridgeId = result[0],\r
+            ovsdbId = result[1];\r
+            filterSubnet.bridgeIds = _.uniq(filterSubnet.bridgeIds.concat(bridgeId));\r
+            filterSubnet.ovsdbIds = _.uniq(filterSubnet.ovsdbIds.concat(ovsdbId));\r
+            applyFilter();\r
+        });\r
+      } else {\r
+        filterSubnet.bridgeIds = [''];\r
+        filterSubnet.ovsdbIds = [''];\r
+        applyFilter();\r
+      }\r
+    };\r
+\r
+    $scope.onNodeClick = function (d, nodes, links) {\r
+      $scope.pDialogData = d.node.pretty();\r
+      $scope.$apply();\r
+    };\r
+\r
+    $('#tenantSelect').select2({\r
+      width: "200",\r
+      minimumResultsForSearch: Infinity\r
+    }).next().children('span').children('span').css('width', '200'); //hack to have the arrow with the same background\r
+\r
+    $("#tagPicker").select2({\r
+      width: "230",\r
+    });\r
+\r
+    var $tabs = $('#tabs').tabs({selected: 0});\r
+\r
+    $scope.goToPhysicalView = function(d) {\r
+      $tabs.tabs("option", "active", 1);\r
+      $('#tenantSelect').val(d.tenantId).change();\r
+\r
+      if ( d instanceof OvsCore.Neutron.Network) {\r
+        $('#tagPicker').val(d.subnets.map(function(d){return d.id;})).change();\r
+      }\r
+    };\r
+\r
+    OvsUtil.getLogicalTopology().then(function(networks) {\r
+      var tenantList = NeutronSvc.getAllTenants();\r
+      _.each(tenantList, function(t) {\r
+        $scope.tenants.push({id : t, name: t});\r
+      });\r
+      NeutronSvc.getSubNets().then(function(subHash) {\r
+        $scope.subnets = _.values(subHash).map(function(n) { return n[0]; });\r
+      });\r
+\r
+      lgraphDataDefer.resolve(networks);\r
+    });\r
+\r
+    TopologySvc.getTopologies().then(function(d) {\r
+      physDataDefer.resolve(d);\r
+    });\r
 \r
   };\r
-  OvsdbCtrl.$inject = ['$scope', 'TopologyNetworkSvc'];\r
+\r
+  OvsdbCtrl.$inject = ['$q', '$scope', 'TopologySvc', 'NeutronSvc', 'OvsUtil'];\r
   OvsdbCtrl.prototype = Object.create(BaseOvsdbCtrl.prototype);\r
 \r
   ovsdb.register.controller('RootOvsdbCtrl', RootOvsdbCtrl);\r
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.css b/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.css
deleted file mode 100644 (file)
index 4f7c162..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright (c) 2015 Inocybe Technologies 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
-*/
-
-#errorMessage {
-    display:none;
-}
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.directives.js b/ovsdb-ui/module/src/main/resources/ovsdb/ovsdb.directives.js
new file mode 100644 (file)
index 0000000..57299d0
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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
+ */
+define(['app/ovsdb/ovsdb.module', 'app/ovsdb/lib/d3.min', 'app/ovsdb/Graph', 'app/ovsdb/LogicalGraph','app/ovsdb/OvsCore', 'underscore', 'jquery', 'jquery-ui'], function (ovsdb, d3, Graph, LogicalGraph, OvsCore, _, $) {
+  'use strict';
+
+  ovsdb.register.directive('logicalGraph', function() {
+    return {
+      restrict: 'EA',
+      scope: false,
+      link : function (scope, elem, attr) {
+        var lgraph = null,
+        tabCreated = false,
+        width = scope.canvasWidth, //ele[0].clientWidth,
+        height = scope.canvasHeight;
+
+        scope.lDialogData = {};
+
+        scope.lgraphIsReadyPromise.then(function(ltopo) {
+          if (!lgraph) {
+            lgraph = new LogicalGraph(elem[0], width, height);
+          }
+
+          lgraph.networks = ltopo;
+
+          lgraph.start();
+
+          lgraph.onClick = function(e, d) {
+            var dialogId = '#lDialog';
+            scope.lDialogData = d.pretty();
+            scope.$apply();
+
+            if (!tabCreated) {
+              $(dialogId).tabs();
+              $(dialogId).draggable({
+                containment: 'parent',
+                cancel:'.window_content'
+              });
+              tabCreated = true;
+            } else {
+              $(dialogId).tabs('refresh');
+            }
+
+            var $dia = $(dialogId);
+            $dia.css('left', e.left + 30);
+            $dia.css('top', e.top + 35);
+            $dia.show();
+
+          };
+
+          lgraph.dblClick = function(d) {
+            scope.goToPhysicalView(d);
+          };
+        });
+        scope.hideLogicalDialog = function() {
+            $('#lDialog').tabs("option", "active", 0)
+            .hide();
+        };
+        elem.on('$destroy', function () {
+          if (lgraph) {
+            lgraph.freeDOM();
+          }
+        });
+      }
+    };
+  });
+
+  ovsdb.register.directive('physicalGraph', function (CacheFactory) {
+    return {
+      restrict: 'EA',
+      scope: false,
+      //templateUrl: 'src/app/ovsdb/views/graph_header.tpl.html',
+      link: function (scope, ele, attr) {
+
+        var graph = null,
+          tabCreated = false,
+          width = scope.canvasWidth,
+          height = scope.canvasHeight;
+
+        scope.reset = function () {
+          var transform = d3.transform(vis.attr('transform')),
+            ix = d3.interpolate(x.domain(), [-width / 2, width / 2]),
+            iy = d3.interpolate(y.domain(), [-height / 2, height / 2]),
+            px = x.domain(ix(1)),
+            py = y.domain(iy(1));
+
+          vis.transition().duration(750).call(zoom.x(px).y(py).scale(1).event);
+        };
+
+        scope.dataPromise.then(function (topo) {
+          if (!graph) {
+            console.log('physical graph created');
+            graph = new Graph(ele[0], width, height);
+          }
+          var nodes = _.clone(topo.nodes);
+          var links = _.clone(topo.links);
+
+          graph.setPosCache(CacheFactory.getCacheObj('nodePos'));
+
+          graph.links = _.values(links);
+          graph.nodes = _.map(nodes, function (value) {
+            return {
+              node: value
+            };
+          });
+          graph.start();
+
+          scope.nbOpenFlowSwitch = _.size(topo.bridgeNodes);
+          scope.nbOvsNode = _.size(topo.ovsdbNodes);
+
+          var linkedByIndex = {};
+          _.each(topo.flowLinks, function (d) {
+            linkedByIndex[d.source + ',' + d.target] = true;
+          });
+
+          function isConnected(a, b) {
+            return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
+          }
+
+          function hasConnections(a) {
+            for (var property in linkedByIndex) {
+              var s = property.split(",");
+              if ((s[0] == a.index || s[1] == a.index) && linkedByIndex[property])
+                return true;
+            }
+            return false;
+          }
+
+          graph.onNodeOver = function (d, nodes, links) {
+            nodes.selectAll('.switch > rect').style("stroke", function (o) {
+              return isConnected(d, o) ? "blue" : "black";
+            });
+
+            links.style("stroke", function (o) {
+                return ((o.source.index == d.index || o.target.index == d.index) && o.linkType != 'tunnel')  ? "blue" : o.color;
+            });
+          };
+
+          graph.onNodeOut = function (d, nodes, links) {
+            nodes.selectAll('.switch > rect').style("stroke", "black");
+            links.style("stroke", function(o) { return o.color; });
+          };
+
+          graph.onNodeClick = function (d, nodes, links, ctx) {
+            /*var node = d3.select(ctx);
+            d3.select('.node_selected').classed('node_selected', false).attr('filter', 'none');
+            node.classed('node_selected', true).attr('filter', 'url(#selectNode)');*/
+            scope.onNodeClick(d);
+            var dialogId = '#pDialog',
+              $dia = $(dialogId);
+
+            if (!tabCreated) {
+              $(dialogId).tabs();
+              $(dialogId).draggable({
+                containment: 'parent',
+                cancel:'.window_content'
+              });
+              tabCreated = true;
+            } else {
+              $(dialogId).tabs('refresh');
+            }
+
+            $dia.css('left', /*e.left + */30);
+            $dia.css('top', /*e.top + */35);
+            $dia.show();
+          };
+
+        });
+
+        ele.on('$destroy', function() {
+          graph.freeDOM();
+        });
+
+        scope.hidePhysicalDialog = function() {
+          $('#pDialog').tabs("option", "active", 0)
+          .hide();
+        };
+
+        scope.rotateGraph = function (value) {
+          var b = value ? 1 : -1;
+          graphs.applyPerspective(value);
+          graphs.update();
+          $('path.tunnel').toggle();
+        };
+
+        scope.filterNode = function(nodeIds, tags, exclude) {
+          exclude = (exclude === null) ? true : exclude;
+          var nodes = d3.selectAll(tags);
+          nodes.each(function(d) {
+              if (nodeIds.indexOf(d.node.nodeId) < 0) {
+                d.hidden = exclude;
+              } else {
+                d.hidden = !exclude;
+              }
+            });
+          nodes.transition().duration(200).style('opacity', function(d) {
+              return d.hidden ? '0.3' : '1';
+          });
+
+        };
+
+        scope.filterLink = function() {
+          var links = d3.selectAll(".tunnel, .link, .bridgeOvsLink");
+
+          links.each(function(d, i) {
+            d.hidden = d.source.hidden || d.target.hidden;
+          });
+          links.transition().duration(200).style('opacity', function(d) {
+              return d.hidden ? '0.3' : '1';
+          });
+        };
+      }
+    };
+  });
+
+});
index d9cbb5fffbde85e05e03efc478027beeeaccd0d3..4bad2bb534fafc8cabff7278eb119b8f564f05ac 100644 (file)
@@ -12,12 +12,34 @@ define(['angularAMD', 'app/routingConfig', 'Restangular', 'angular-translate', '
   var ovsdb = angular.module('app.ovsdb', ['app.core', 'pascalprecht.translate', 'ui.router.state', 'restangular', 'config']);\r
   ovsdb.register = ovsdb; // for unit test\r
 \r
-  ovsdb.config(function($stateProvider, $compileProvider, $controllerProvider, $provide, NavHelperProvider) {\r
+  // Filter to access neutron opendaylight.\r
+  // This factory need to be to avoid circular dependencies.\r
+  ovsdb.factory('NeutronInterceptor', ['$q', '$window', 'Base64', function($q, $window, Base64) {\r
+    return {\r
+      request : function(config) {\r
+          // Use AAA basic authentication\r
+        if (config.url.indexOf('controller/nb/v2') != -1) {\r
+          config.headers = config.headers || {};\r
+          if ($window.sessionStorage.odlUser && $window.sessionStorage.odlPass) {\r
+            var encoded = Base64.encode('admin' + ':' + 'admin');\r
+            config.headers.Authorization = 'Basic ' + encoded;\r
+          }\r
+        }\r
+        return config;\r
+      },\r
+      response : function(response) {\r
+        return response || $q.when(response);\r
+      }\r
+    };\r
+  }]);\r
+\r
+  ovsdb.config(function($stateProvider, $compileProvider, $controllerProvider, $provide, $httpProvider, NavHelperProvider) {\r
     ovsdb.register = {\r
       controller : $controllerProvider.register,\r
       directive : $compileProvider.directive,\r
       factory : $provide.factory,\r
-      service : $provide.service\r
+      service : $provide.service,\r
+      constant: $provide.constant\r
 \r
     };\r
 \r
@@ -25,10 +47,10 @@ define(['angularAMD', 'app/routingConfig', 'Restangular', 'angular-translate', '
     NavHelperProvider.addToMenu('Ovsdb', {\r
      "link" : "#/ovsdb/index",\r
      "active" : "main.ovsdb.*",\r
-     "title" : "OVSDB",\r
+     "title" : "Network Virtualization",\r
      "icon" : "icon-sitemap",\r
      "page" : {\r
-        "title" : "OVSDB",\r
+        "title" : "NetWork Virtualization",\r
         "description" : "OVSDB"\r
      }\r
     });\r
@@ -39,7 +61,7 @@ define(['angularAMD', 'app/routingConfig', 'Restangular', 'angular-translate', '
       abstract: true,\r
       views : {\r
         'content' : {\r
-          templateUrl: 'src/app/ovsdb/root.tpl.html',\r
+          templateUrl: 'src/app/ovsdb/views/root.tpl.html',\r
           controller: 'RootOvsdbCtrl'\r
         }\r
       }\r
@@ -50,11 +72,13 @@ define(['angularAMD', 'app/routingConfig', 'Restangular', 'angular-translate', '
       access: access.admin,\r
       views: {\r
         '': {\r
-          templateUrl: 'src/app/ovsdb/index.tpl.html',\r
+          templateUrl: 'src/app/ovsdb/views/index.tpl.html',\r
           controller: 'OvsdbCtrl'\r
         }\r
       }\r
     });\r
+\r
+    $httpProvider.interceptors.push('NeutronInterceptor');\r
   });\r
 \r
   return ovsdb;\r
index c144f78e7aeaecd48941886d78d2ea1c7d519a61..29fc85755d3566e26adb0949257d31d11325f2f8 100644 (file)
-/*\r
- * Copyright (c) 2015 Inocybe Technologies and others.  All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-\r
-define(['app/ovsdb/ovsdb.module'],function(ovsdb) {\r
-  'use strict';\r
-\r
-  ovsdb.register.factory('TopologyNetworkRestangular', function(Restangular, ENV) {\r
-    return Restangular.withConfig(function(RestangularConfig) {\r
-      RestangularConfig.setBaseUrl(ENV.getBaseURL("AD_SAL"));\r
-    });\r
-  });\r
-\r
-  ovsdb.register.factory('TopologyNetworkSvc', function(TopologyNetworkRestangular) {\r
-    var svc = {\r
-      base: function(name) {\r
-        return TopologyNetworkRestangular.one('restconf', name).one('network-topology:network-topology');\r
-      },\r
-      data : null\r
-    };\r
-\r
-    svc.getCurrentData = function() {\r
-      return svc.data;\r
-    };\r
-\r
-    svc.getTopologiesIds = function() {\r
-      svc.data = svc.base('operational').getList();\r
-      return svc.data;\r
-    };\r
-\r
-    svc.getConfigNode = function(topologyId, nodeId) {\r
-      return svc.base('config').one('topology', topologyId).one('node', nodeId).get();\r
-    };\r
-\r
-    svc.addConfigNode = function(topologyId, nodeId, data) {\r
-      return svc.base('config').one('topology', topologyId).one('node').put(nodeId, data);\r
-    };\r
-\r
-    svc.addConfigBridge = function(topologyId, nodeId, data) {\r
-        return svc.base('config').one('topology', topologyId).put(nodeId, data);\r
-    };\r
-\r
-    svc.removeConfigNode = function(topologyId, nodeId) {\r
-      return svc.base('config').one('topology', topologyId).one('node', nodeId).remove();\r
-    };\r
-\r
-    svc.addTerminationPointConfig = function(topologyId, nodeId, terminationId, data) {\r
-      return svc.base('config').one('topology', topologyId).one('node', nodeId).one('termination-point').put(terminationId, data);\r
-    };\r
-\r
-    svc.getTerminationPointConfig = function(topologyId, nodeId, terminationId) {\r
-      return svc.base('config').one('topology', topologyId).one('node', nodeId).one('termination-point', terminationId).get();\r
-    };\r
-\r
-    svc.removeTerminationPointConfig = function(topologyId, nodeId, terminationId) {\r
-      return svc.base('config').one('topology', topologyId).one('node', nodeId).one('termination-point', terminationId).remove();\r
-    };\r
-    return svc;\r
-  });\r
-\r
-\r
-  ovsdb.register.factory('TopologyNetworkFactory', function() {\r
-\r
-    var factory = {\r
-        createOvsdbNodeObject: function(nodeId, nodePort, nodeRemoteIp) {\r
-            return {\r
-                "network-topology:node": [\r
-                    {\r
-                        "node-id": nodeId,\r
-                        "connection-info": {\r
-                            "ovsdb:remote-port": nodePort,\r
-                            "ovsdb:remote-ip": nodeRemoteIp\r
-                        }\r
-                    }\r
-                ]\r
-            };\r
-        },\r
-        createConfigNode: function(nodeId, bridgeName,datapathId, protocolEntries, controllerEntries, managedBy) {\r
-            var configNode = {\r
-                "network-topology:node": [\r
-                    {\r
-                        "node-id": nodeId,\r
-                        "ovsdb:bridge-name": bridgeName,\r
-                        "ovsdb:datapath-id": datapathId,\r
-                        "ovsdb:protocol-entry": [ ],\r
-                        "ovsdb:controller-entry": [ ],\r
-                        "ovsdb:managed-by": managedBy\r
-                    }\r
-                ]\r
-            };\r
-\r
-            for (var protocolEntry in protocolEntries) {\r
-                configNode[0]['ovsdb:protocal-entry'].push({\r
-                    "protocol": protocolEntry\r
-                });\r
-            }\r
-\r
-            for (var controllerEntry in controllerEntries) {\r
-                configNode[0]['ovsdb:controller-entry'].push({\r
-                    "protocol" : controllerEntry\r
-                });\r
-            }\r
-\r
-            return configNode;\r
-\r
-        },\r
-        createEndPoint: function(ovsdb_options, name, interface_type, tp_id, vlan_tag, trunks, vlan_mode) {\r
-            var termination_point = {\r
-                "network-topology:termination-point": [\r
-                    {\r
-                        "ovsdb:options": [ ],\r
-                        "ovsdb:name": name,\r
-                        "ovsdb:interface-type": interface_type,\r
-                        "tp-id": tp_id,\r
-                        "vlan-tag": vlan_tag,\r
-                        "trunks": [ ],\r
-                        "vlan-mode":vlan_mode\r
-                    }\r
-                ]\r
-            };\r
-\r
-            for (var ovsdb_option in ovsdb_options) {\r
-                   termination_point[0]['ovsdb:options'].push({\r
-                        "ovsdb:option": ovsdb_option.option,\r
-                        "ovsdb:value" : ovsdb_option.value\r
-                   });\r
-            }\r
-\r
-            for (var trunk in trunks) {\r
-                termination_point[0]['trunks'].push({\r
-                    "trunk":trunk\r
-                });\r
-            }\r
-\r
-            return termination_point;\r
-        }\r
-    };\r
-\r
-    return factory;\r
-\r
-  });\r
-\r
-});\r
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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
+ */
+define(['app/ovsdb/ovsdb.module', 'app/ovsdb/OvsCore', 'underscore', 'app/ovsdb/ovsdb.constant'], function(ovsdb, OvsCore, _) {
+  'use strict';
+
+  ovsdb.register.factory('OvsdbRestangular', ['Restangular', 'ENV', function(Restangular, ENV) {
+    return Restangular.withConfig(function(RestangularConfig) {
+      RestangularConfig.setBaseUrl(ENV.getBaseURL("MD_SAL"));
+    });
+  }]);
+
+  // nbv2 support depricated in dlux
+  ovsdb.register.factory('NeutronRestangular', ['Restangular', function(Restangular) {
+    return Restangular.withConfig(function(RestangularConfig) {
+      RestangularConfig.setBaseUrl('http://localhost:8080/controller/nb/v2/neutron');
+    });
+  }]);
+
+  ovsdb.register.factory('CacheFactory', function($q) {
+    var svc = {},
+      ovsCache = {};
+    /*BUG : Using the persistant cache make the physical
+     * graph links to stop reacting with the force layout
+     * algorithm. The current behavior is to use the cache
+     * only the pile up the datas.
+     */
+    svc.obtainDataFromCache = function(key, fn, ctx) {
+      var cacheDefer = $q.defer();
+
+      if (angular.isUndefined(ovsCache[key])) {
+        fn.call(ctx, function(data) {
+            ovsCache[key] = {
+              obj : data,
+              timestamp : Date.now() + 2000//300000 // 5 mintues
+            };
+            cacheDefer.resolve(data);
+        });
+      } else {
+        var cacheObj = ovsCache[key];
+        if (cacheObj.timestamp < Date.now() ||  _.isEmpty(cacheObj.obj)) {
+          fn.call(ctx, function(data) {
+              ovsCache[key] = {
+                obj : data,
+                timestamp : Date.now() + 2000//300000 // 5 mintues
+              };
+              cacheDefer.resolve(data);
+          });
+        } else {
+          cacheDefer.resolve(cacheObj.obj);
+        }
+      }
+
+      return cacheDefer.promise;
+    };
+
+    svc.getCacheObj = function(key) {
+      if (angular.isUndefined(ovsCache[key])) {
+        ovsCache[key] = {};
+      }
+      return ovsCache[key];
+    };
+
+    return svc;
+  });
+
+  var TopologySvc = function(OvsdbRestangular, nodeIdentifier, ovsNodeKeys, bridgeNodeKeys, tpKeys, flowInfoKeys, linkIdentifier, $q, $http, CacheFactory) {
+    var svc = {
+      base: function(type) {
+        return OvsdbRestangular.one('restconf').one(type);
+      }
+    };
+
+    function parseOvsdbNode(node) {
+      var inetMgr = '',
+        inetNode = '',
+        otherLocalIp = '',
+        otherInfo = null,
+        connectionInfo = null;
+
+      connectionInfo = node[ovsNodeKeys.CONNECTION_INFO];
+      otherInfo = node[ovsNodeKeys.OTHER_CONFIG];
+
+      if (_.isObject(connectionInfo)) {
+        inetMgr = connectionInfo[ovsNodeKeys.LOCAL_IP] + ':' + connectionInfo[ovsNodeKeys.LOCAL_PORT];
+        inetNode = connectionInfo[ovsNodeKeys.REMOTE_IP] + ':' + connectionInfo[ovsNodeKeys.REMOTE_PORT];
+      }
+
+      if (_.isArray(otherInfo)) {
+        _.each(otherInfo, function(value) {
+          if (value[ovsNodeKeys.OTHER_CONFIG_KEY] === 'local_ip') {
+            otherLocalIp = value[ovsNodeKeys.OTHER_CONFIG_VALUE];
+          }
+        });
+      }
+
+      return new OvsCore.OvsNode(node[ovsNodeKeys.NODE_ID], inetMgr, inetNode, otherLocalIp, node[ovsNodeKeys.OVS_VERSION]);
+    }
+
+    function parseBridgeNode(node) {
+      var bridgeNode = null,
+        controllerTarget = '',
+        controllerConnected = false,
+        tp = node[bridgeNodeKeys.TP],
+        controllerEntries = node[bridgeNodeKeys.CONTROLLER_ENTRY];
+
+      _.each(controllerEntries, function(value) {
+        controllerTarget = value[bridgeNodeKeys.TARGET];
+        controllerEntries = value[bridgeNodeKeys.IS_CONNECTED];
+        return false; // break the anonymus function
+      });
+
+      bridgeNode = new OvsCore.BridgeNode(node[bridgeNodeKeys.NODE_ID], node[bridgeNodeKeys.DATA_PATH], node[bridgeNodeKeys.BRIDGE_NAME], controllerTarget, controllerConnected);
+
+      _.each(tp, function(value) {
+        var tp = parseBridgeTP(value);
+
+        if (tp.ofPort == '65534' && (tp.name === 'br-ex' || tp.name === 'br-int')) {
+          return;
+        } else {
+          bridgeNode.addTerminationPoint(tp);
+        }
+
+      });
+
+      return bridgeNode;
+    }
+
+    function parseBridgeTP(tp) {
+      var mac = '',
+        ifaceId = '',
+        extInfo = tp['ovsdb:port-external-ids'] || tp['ovsdb:interface-external-ids'];
+
+      _.each(extInfo, function(ext) {
+        if (ext[tpKeys.EXTERNAL_KEY_ID] === tpKeys.ATTACHED_MAC) {
+          mac = ext[tpKeys.EXTERNAL_KEY_VALUE];
+        }
+        if (ext[tpKeys.EXTERNAL_KEY_ID] === tpKeys.IFACE_ID) {
+          ifaceId = ext[tpKeys.EXTERNAL_KEY_VALUE] || '';
+        }
+      });
+
+      return new OvsCore.TerminationPoint(tp[tpKeys.NAME], tp[tpKeys.OF_PORT], tp[tpKeys.INTERFACE_TYPE], mac, ifaceId);
+    }
+
+    function fetchTopology(cb) {
+      var invNodeDefer = this.base('operational').one('opendaylight-inventory:nodes').getList();
+      var netTopoDefer = this.base('operational').one('network-topology:network-topology').getList();
+
+      // be sure all data are loaded
+      $q.all([invNodeDefer, netTopoDefer]).then(function(values) {
+          var invNode = values[0],
+            netTopo = values[1],
+            index_hash = [],
+            i = 0;
+
+          // check if the data look fine in network topology
+          if (!netTopo || !netTopo['network-topology'] || !netTopo['network-topology'].topology) {
+            throw new Error('Invalid json format while parsing network-topology');
+          }
+
+          // check if the data look fine in inventory node
+          if (!invNode || !invNode.nodes || !invNode.nodes.node) {
+            throw new Error('Invalid JSON format while parsing inventory-node');
+          }
+
+          // get all topologies and start looping
+          var topologies = netTopo['network-topology'].topology,
+            nodes = invNode.nodes.node,
+            topo = new OvsCore.Topology();
+
+          _.each(topologies, function(topology, topo_index) {
+            if (!topology.hasOwnProperty('topology-id')) {
+              throw new Error('Invalide JSON format, no topology-id for the topology [' + topo_index + ']');
+            }
+
+            // if there no node it will be an empty array so noop
+            (topology.node || []).forEach(function(node) {
+              if (!node[nodeIdentifier.ID]) {
+                throw new Error('Unexpected node : undefined ' + nodeIdentifier.ID + ' key');
+              }
+              index_hash[node[nodeIdentifier.ID]] = i++;
+
+              if (node['ovsdb:bridge-name']) {
+                //bridge Node
+                topo.registerBridgeNode(parseBridgeNode(node));
+              } else if (node['ovsdb:connection-info']) {
+                // obsvdb Node
+                topo.registerOvsdbNode(parseOvsdbNode(node));
+              }
+            });
+
+            // if there no link it will be an empty array so noop
+            (topology.link || []).forEach(function(link) {
+
+              var source = link[linkIdentifier.SRC]['source-node'],
+                dest = link[linkIdentifier.DEST]['dest-node'];
+
+              topo.registerLink(new OvsCore.Link(link[linkIdentifier.ID], source, dest));
+            });
+
+          });
+
+          _.each(nodes, function(node, index) {
+            if (!node.id) {
+              return;
+            }
+
+            var bridgeId = node.id;
+
+            var bridgeNode = _.filter(topo.bridgeNodes, function(bridgeNode) {
+              return bridgeNode.getFLowName() === bridgeId;
+            })[0];
+
+            // match info for bridge node
+            if (bridgeNode) {
+              bridgeNode.flowInfo.features = node[flowInfoKeys.FEATURE];
+              bridgeNode.flowInfo.software = node[flowInfoKeys.SOFTWARE];
+              bridgeNode.flowInfo.hardware = node[flowInfoKeys.HARDWARE];
+              bridgeNode.flowInfo.manufacturer = node[flowInfoKeys.MANUFACTURER];
+              bridgeNode.flowInfo.ip = node[flowInfoKeys.IP];
+
+              _.each(node[flowInfoKeys.TABLE], function(entry) {
+                if (!_.isUndefined(entry.id)) {
+                    _.each(entry.flow, function(flow) {
+                    bridgeNode.addFlowTableInfo({ key: flow.table_id, value: flow.id});
+                  });
+                }
+              });
+            }
+          });
+
+          // show relation between ovsNode and switch with a link
+          _.each(topo.ovsdbNodes, function(node, index) {
+            var bridges = _.filter(topo.bridgeNodes, function(bnode) {
+              return bnode.nodeId.indexOf(node.nodeId) > -1;
+            });
+            _.each(bridges, function(bridge) {
+              var size = _.size(topo.links),
+                link = new OvsCore.BridgeOvsLink(++size, node.nodeId, bridge.nodeId);
+              topo.registerLink(link);
+            });
+          });
+
+          function findVxlan(bridgeNode) {
+            var tunnels = [];
+
+            _.each(bridgeNode, function(node) {
+              var ovsdbNode = _.find(topo.ovsdbNodes, function(oNode) {
+                return node.nodeId.indexOf(oNode.nodeId) > -1;
+              });
+              if (!ovsdbNode) {
+                return false;
+              }
+              _.each(node.tPs, function(tp, index) {
+                if (tp.name.indexOf('vxlan-') > -1) {
+                  tunnels.push({
+                    port : tp,
+                    bridge : node,
+                    ovsIp : ovsdbNode.otherLocalIp || ovsdbNode.inetMgr
+                  });
+                }
+              });
+            });
+
+            return tunnels;
+          }
+
+          // extract all tunnel paired with their bridge
+          var tunnels = findVxlan(topo.bridgeNodes);
+          // loop over all pairs
+          _.each(tunnels, function(tunnel, index) {
+            var currIp = tunnel.ovsIp,
+              destIp = tunnel.port.name.replace('vxlan-', ''),
+              linkedBridge = _.find(tunnels.slice(index), function(t) {
+                var vxlanIp =  t.port.name.replace('vxlan-', '');
+                return vxlanIp === currIp;
+              });
+
+              if (linkedBridge) {
+                  topo.registerLink(new OvsCore.TunnelLink(tunnel.port.name + linkedBridge.port.name, tunnel.bridge.nodeId, linkedBridge.bridge.nodeId));
+              }
+          });
+
+          topo.updateLink();
+          cb(topo);
+        },
+        function(err) {
+          throw err;
+        }
+      );
+    }
+
+    svc.getTopologies = function() {
+      return CacheFactory.obtainDataFromCache('topologies', fetchTopology, this);
+    };
+
+    return svc;
+  };
+  TopologySvc.$inject = ['OvsdbRestangular', 'nodeIdentifier', 'ovsNodeKeys', 'bridgeNodeKeys', 'tpKeys', 'flowInfoKeys', 'linkIdentifier', '$q', '$http', 'CacheFactory'];
+
+  var NeutronSvc = function(NeutronRestangular, CacheFactory, $q, $http) {
+    var svc = {
+      base: function(type) {
+        return NeutronRestangular.one(type);
+      }
+    },
+    tenant_hash = {};
+
+    function fetchSubNetworks(cb) {
+      var subnetskDefer = svc.base('subnets').getList();
+      subnetskDefer.then(function(data) {
+        var subnets = data,
+          subnetHash = {};
+
+        if (!subnets || !subnets.subnets) {
+          throw new Error('Invalid format from neutron subnets');
+        }
+
+        _.each(subnets.subnets, function(subnet) {
+            if (!subnetHash[subnet.network_id]) {
+              subnetHash[subnet.network_id] = [];
+            }
+            tenant_hash[subnet.tenant_id] = {};
+            subnetHash[subnet.network_id].push(new OvsCore.Neutron.SubNet(
+              subnet.id,
+              subnet.network_id,
+              subnet.name,
+              subnet.ip_version,
+              subnet.cidr,
+              subnet.gateway_ip,
+              subnet.tenant_id
+            ));
+        });
+        cb(subnetHash);
+      });
+    }
+
+    function fetchNetworks(cb) {
+      var networkDefer = svc.base('networks').getList();
+      var subnetskDefer = svc.getSubNets();
+
+      $q.all([subnetskDefer, networkDefer]).then(function(datas) {
+        var subnetsHash = datas[0],
+          networks = datas[1],
+          networkArray = [];
+
+        if (!networks || !networks.networks) {
+          throw new Error('Invalid format from neutron networks');
+        }
+
+        _.each(networks.networks, function(network) {
+          var net = new OvsCore.Neutron.Network(
+            network.id,
+            network.name,
+            network.shared,
+            network.status,
+            network['router:external'],
+            network.tenant_id
+          );
+          tenant_hash[net.tenantId] = {};
+          net.addSubNets(subnetsHash[net.id]);
+          networkArray.push(net);
+        });
+          cb(networkArray);
+      });
+    }
+
+    function fetchRouters(cb) {
+      var routerDefer = svc.base('routers').getList();
+      routerDefer.then(function(data) {
+        var routers = data.routers,
+          routerArray = [];
+
+        if (!routers) {
+          throw new Error('Invalid format from neutron routers');
+        }
+        _.each(routers, function(router) {
+            var id = router.id,
+            name = router.name,
+            status = router.status,
+            tenantId = router.tenant_id,
+            extGateWayInfo = router.external_gateway_info;
+            tenant_hash[tenantId] = {};
+            routerArray.push(new OvsCore.Neutron.Router(
+              id, name, status, tenantId, extGateWayInfo
+            ));
+        });
+        cb(routerArray);
+      });
+    }
+
+    function fetchPorts(cb) {
+      var portDefer = svc.base('ports').getList();
+      portDefer.then(function(data){
+        var ports = data.ports,
+          portArray = [];
+
+        if (!ports) {
+          throw new Error('Invalid format from neutron ports');
+        }
+        _.each(ports, function(port) {
+          tenant_hash[port.tenant_id] = {};
+          portArray.push(new OvsCore.Neutron.Port(
+            port.id,
+            port.network_id,
+            port.name,
+            port.tenant_id,
+            port.device_id,
+            port.device_owner,
+            port.fixed_ips,
+            port.mac_address
+          ));
+        });
+        cb(portArray);
+      });
+    }
+
+    function fetchFloatingIps(cb) {
+      var floatingIpDefer = svc.base('floatingips').getList();
+      floatingIpDefer.then(function(data) {
+        var floatingIps = data.floatingips,
+          floatingIpArray = [];
+
+        if (!floatingIps) {
+          throw new Error('Invalid format from neutron floatingIps');
+        }
+
+        _.each(floatingIps, function(fIp) {
+          tenant_hash[fIp.tenant_id] = {};
+          floatingIpArray.push(new OvsCore.Neutron.FloatingIp(
+            fIp.id,
+            fIp.floating_network_id,
+            fIp.port_id,
+            fIp.fixed_ip_address,
+            fIp.floating_ip_address,
+            fIp.tenant_id,
+            fIp.status
+          ));
+        });
+
+        cb(floatingIpArray);
+      });
+    }
+
+    svc.getNetworks = function() {
+        return CacheFactory.obtainDataFromCache('networks', fetchNetworks, this);
+    };
+
+    svc.getSubNets = function() {
+      return CacheFactory.obtainDataFromCache('subnet', fetchSubNetworks, this);
+    };
+
+    svc.getPorts = function() {
+      return CacheFactory.obtainDataFromCache('ports', fetchPorts, this);
+    };
+
+    svc.getRouters = function() {
+      return CacheFactory.obtainDataFromCache('routers', fetchRouters, this);
+    };
+
+    svc.getFloatingIps = function() {
+      return CacheFactory.obtainDataFromCache('floatingips', fetchFloatingIps, this);
+    };
+
+    svc.getAllTenants = function() {
+      return Object.keys(tenant_hash);
+    };
+
+    return svc;
+  };
+  NeutronSvc.$inject = ['NeutronRestangular', 'CacheFactory', '$q', '$http'];
+
+  var OvsUtil = function(NeutronSvc, TopologySvc, CacheFactory, $q) {
+    var svc = {};
+
+    function findOvsdbNodeForBridge(ovsdbNodes, bridge) {
+      return _.find(ovsdbNodes, function(node) {
+        return bridge.nodeId.indexOf(node.nodeId) > -1;
+      });
+    }
+
+    function pileUpTopologyData(cb) {
+      var networksDefer = NeutronSvc.getNetworks(),
+        routersDefer = NeutronSvc.getRouters(),
+        portsDefer = NeutronSvc.getPorts(),
+        floatingDefer = NeutronSvc.getFloatingIps(),
+        netTopoDefer = TopologySvc.getTopologies();
+
+      $q.all([networksDefer, routersDefer, portsDefer, floatingDefer, netTopoDefer]).then(function (datas) {
+        var networks = datas[0],
+         routers = datas[1],
+         ports = datas[2],
+         floatingIps = datas[3],
+         topo = datas[4];
+
+        // match ports with elements
+         _.each(ports, function(port) {
+           port.topoInfo = [];
+           // corelate port.topoInfo data with network topology termination point
+           _.each(topo.bridgeNodes, function(bridge) {
+             _.each(bridge.tPs, function(tp) {
+               if (tp.ifaceId === port.id) {
+                 port.topoInfo.push({
+                   name : tp.name,
+                   ofPort : tp.ofPort,
+                   mac : bridge.dpIp,
+                   bridge : bridge,
+                   ovsNode : findOvsdbNodeForBridge(topo.ovsdbNodes, bridge)
+                 });
+               }
+             });
+           });
+
+           switch(port.deviceOwner) {
+             case 'network:router_gateway':
+             case 'network:router_interface':
+              var router = _.find(routers, function(r) { return r.id === port.deviceId; });
+              if (router) {
+                router.interfaces.push({
+                  id: port.id,
+                  networkId : port.networkId,
+                  ip : port.fixed_ips[0],
+                  mac : port.mac,
+                  type: port.deviceOwner.replace('network:', ''),
+                  tenantId : port.tenantId,
+                  topoInfo: port.topoInfo
+                });
+              }
+              break;
+            case 'compute:None':
+            case 'compute:nova':
+            case 'network:dhcp':
+              var network = _.find(networks, function(n) { return n.id === port.networkId;}),
+                inst = null;
+
+              if (network) {
+                inst = new OvsCore.Neutron.Instance(port.id,  port.networkId,
+                  port.name, port.fixed_ips[0].ip_address, port.mac,
+                  port.deviceOwner, port.tenantId, port.topoInfo );
+
+                inst.extractFloatingIps(floatingIps);
+                network.instances.push(inst);
+              }
+              break;
+           }
+
+         });
+
+         // find all routers for a specific network
+         _.each(networks, function(network) {
+           network.routers = _.filter(routers, function(router) {
+             return network.id === router.externalGateway.network_id;
+           });
+
+           // order instance by ip
+           network.instances.sort(function(a, b) {
+             var ipA = a.ip.slice(a.ip.lastIndexOf('.') + 1),
+               ipB = b.ip.slice(b.ip.lastIndexOf('.') + 1);
+               return ipA - ipB;
+           });
+         });
+
+         cb(networks);
+      });
+    }
+
+    svc.getLogicalTopology = function() {
+      return CacheFactory.obtainDataFromCache('logicalTopology', pileUpTopologyData, this);
+    };
+
+    svc.extractLogicalByTenant = function(tenantId, subSet) {
+      var lTopoDefer = svc.getLogicalTopology(),
+        resultDefer = $q.defer();
+      lTopoDefer.then(function() {
+        var ports = CacheFactory.getCacheObj('ports').obj,
+          filteredPorts = _.filter(ports, function(p) {
+            return p.tenantId === tenantId;
+          });
+
+        if (!_.isEmpty(filteredPorts)) {
+          var bridgeHash = {};
+          _.each(filteredPorts, function(p) {
+            if (!_.isEmpty(p.topoInfo) && !bridgeHash[p.topoInfo[0].bridge.nodeId]) {
+              bridgeHash[p.topoInfo[0].bridge.nodeId] = {};
+            }
+          });
+          var ovsdbHash = {};
+          _.each(filteredPorts, function(p) {
+            if (!_.isEmpty(p.topoInfo) && !ovsdbHash[p.topoInfo[0].ovsNode.nodeId]) {
+              ovsdbHash[p.topoInfo[0].ovsNode.nodeId] = {};
+            }
+          });
+
+          resultDefer.resolve([Object.keys(bridgeHash), Object.keys(ovsdbHash)]);
+        } else {
+          resultDefer.resolve([], []);
+        }
+      });
+      return resultDefer.promise;
+    };
+
+    svc.extractLogicalBySubnet = function(subnets, subSet) {
+      var lTopoDefer = svc.getLogicalTopology(),
+        resultDefer = $q.defer();
+      lTopoDefer.then(function() {
+        var ports = CacheFactory.getCacheObj('ports').obj,
+          networks = CacheFactory.getCacheObj('networks').obj;
+
+        var filteredPorts = _.filter(ports, function(p) {
+          var net = _.find(networks, function(d) {
+            return d.id === p.networkId;
+          });
+
+          return net.asSubnet(subnets);
+        });
+        if (!_.isEmpty(filteredPorts)) {
+          var bridgeHash = {};
+          _.each(filteredPorts, function(p) {
+            if (!_.isEmpty(p.topoInfo) && !bridgeHash[p.topoInfo[0].bridge.nodeId]) {
+              bridgeHash[p.topoInfo[0].bridge.nodeId] = {};
+            }
+          });
+          var ovsdbHash = {};
+          _.each(filteredPorts, function(p) {
+            if (!_.isEmpty(p.topoInfo) && !ovsdbHash[p.topoInfo[0].ovsNode.nodeId]) {
+              ovsdbHash[p.topoInfo[0].ovsNode.nodeId] = {};
+            }
+          });
+          resultDefer.resolve([Object.keys(bridgeHash), Object.keys(ovsdbHash)]);
+        } else {
+          resultDefer.resolve([], []);
+        }
+      });
+      return resultDefer.promise;
+    };
+
+    return svc;
+  };
+
+  OvsUtil.$inject = ['NeutronSvc', 'TopologySvc', 'CacheFactory', '$q'];
+
+  ovsdb.register.factory('TopologySvc', TopologySvc);
+  ovsdb.register.factory('NeutronSvc', NeutronSvc);
+  ovsdb.register.factory('OvsUtil', OvsUtil);
+});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/spec/ovsdb.spec.js b/ovsdb-ui/module/src/main/resources/ovsdb/spec/ovsdb.spec.js
deleted file mode 100644 (file)
index 713b9a6..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-define(['ovsdb/ovsdb.controller'], function() {
-  describe('A fake test', function() {
-    it('Should be retuning true', function() {
-      expect(true).toBe(true);
-    });
-  });
-});
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/views/graph_header.tpl.html b/ovsdb-ui/module/src/main/resources/ovsdb/views/graph_header.tpl.html
new file mode 100644 (file)
index 0000000..93a7b6e
--- /dev/null
@@ -0,0 +1,11 @@
+<!-- <div id="graph_header">
+  <span style="color:black; margin-left:15px;">Network Visualizer</span>
+  <i class="icon-fullscreen" style="float:right;" ng-click="resizeGraph()"></i>
+  <i class="icon-resize-small icon-2" style="float:right" ng-click="minimizeGraph()"></i>
+</div>
+-->
+
+<div id="graph_summary" data-option="false" data-title="Network Summary" nv-window style="text-align:center;">
+  <p style="font-style:italic;">{{nbOpenFlowSwitch}} brides
+    <br/> {{nbOvsNode}} switch</p>
+</div>
diff --git a/ovsdb-ui/module/src/main/resources/ovsdb/views/index.tpl.html b/ovsdb-ui/module/src/main/resources/ovsdb/views/index.tpl.html
new file mode 100644 (file)
index 0000000..ff0c104
--- /dev/null
@@ -0,0 +1,124 @@
+<!--\r
+ * Copyright (c) 2015 Inocybe Technologies and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+-->\r
+<div id="ovsdb_contain">\r
+<!--\r
+<div class="row">\r
+  <div class="col-md-2 form-inline">\r
+    <label class="switch-light well">\r
+      <input type="checkbox" ng-model="opt.layer" ng-change="toggleLayer();">\r
+      <span>\r
+        Layer 3\r
+        <span>Off</span>\r
+        <span>On</span>\r
+      </span>\r
+\r
+      <a  class="btn btn-orange"></a>\r
+    </label>\r
+  </div>\r
+  <div class="col-md-2 form-inline">\r
+    <label class="switch-light well">\r
+      <input type="checkbox" ng-model="opt.underlay" ng-change="toggleUnderlay();">\r
+      <span>\r
+        Underlay\r
+        <span>Off</span>\r
+        <span>On</span>\r
+      </span>\r
+\r
+      <a class="btn btn-orange"></a>\r
+    </label>\r
+  </div>\r
+</div>\r
+-->\r
+<div class="row">\r
+  <div class="col-md-12">\r
+    <div id="tabs" >\r
+      <ul class="nav nav-tabs tabsHeader" style="margin-bottom:15px;">\r
+        <li><a href="#logical_view">Logical View</a></li>\r
+        <li><a href="#2d_view">2D View</a></li>\r
+        <li><a href="#3d_view">3D View</a></li>\r
+      </ul>\r
+      <div id="logical_view" style="background-color:white; position:relative;">\r
+        <div id="l_graph" style="position:relative; height:580px;" logical-graph ></div>\r
+\r
+        <div id="lDialog" class="ovsDialog arrow-left">\r
+          <div style="height:10px;">\r
+            <i data-ng-click="hideLogicalDialog()" class="window-icon icon-remove"></i>\r
+          </div>\r
+          <div class="window_content">\r
+            <ul class="nav nav-tabs tabsHeader">\r
+              <li ng-repeat="tab in lDialogData.tabs track by $index" >\r
+                <a href="#lDialogTab_{{$index}}" class="active">{{tab}}</a>\r
+              </li>\r
+            </ul>\r
+            <div ng-repeat="tabContaint in lDialogData.containts track by $index" id="lDialogTab_{{$index}}">\r
+              <table ng-if="!tabContaint.hasHeader" class="table table-bordered" style="margin-bottom:0;">\r
+                <tr ng-repeat="info in tabContaint.datas track by $index">\r
+                  <td > {{info.key}} </td> <td> {{ info.value }} </td>\r
+                </tr>\r
+              </table>\r
+              <table ng-if="tabContaint.hasHeader" class="table table-bordered" style="margin-bottom:0;">\r
+                <tr>\r
+                  <th ng-repeat=" h in tabContaint.header track by $index">{{h}}</th>\r
+                </tr>\r
+                <tr ng-repeat="item in tabContaint.datas track by $index">\r
+                  <td ng-repeat="value in item track by $index"> {{ value }} </td>\r
+                </tr>\r
+              </table>\r
+            </div>\r
+          </div>\r
+        </div>\r
+\r
+      </div>\r
+      <div id="2d_view">\r
+        <div class="row">\r
+          <div class="col-md-4 col-md-offset-1 form-inline">\r
+            <span>Tenant</span>\r
+            <select id="tenantSelect" ng-model="selectedTenant" ng-change="fiterByTenant()"  ng-options="tenant.name for tenant in tenants track by tenant.id">\r
+              <option value="">---All---</option>\r
+            </select>\r
+          </div>\r
+          <div class="col-md-4 form-inline">\r
+            <span>Subnet</span>\r
+            <select id="tagPicker" multiple="multiple" ng-model="selectedSubnet" ng-change="filterBySubnet()" ng-options="subnet.name for subnet in subnets track by subnet.id">\r
+            </select>\r
+          </div>\r
+        </div>\r
+        <div id="nv_graph" style="position:relative; height:580px;" physical-graph></div>\r
+        <div id="pDialog" class="ovsDialog arrow-left">\r
+            <div style="height:10px">\r
+              <i data-ng-click="hidePhysicalDialog()" class="window-icon icon-remove"></i>\r
+            </div>\r
+          <div class="window_content">\r
+            <ul class="nav nav-tabs tabsHeader">\r
+              <li ng-repeat="tab in pDialogData.tabs track by $index" >\r
+                <a href="#pDialogTab_{{$index}}" class="active">{{tab}}</a>\r
+              </li>\r
+            </ul>\r
+            <div ng-repeat="tabContaint in pDialogData.containts track by $index" id="pDialogTab_{{$index}}">\r
+              <table ng-if="!tabContaint.hasHeader" class="table table-bordered" style="margin-bottom:0;">\r
+                <tr ng-repeat="info in tabContaint.datas track by $index">\r
+                  <td > {{info.key}} </td> <td> {{ info.value }} </td>\r
+                </tr>\r
+              </table>\r
+              <table ng-if="tabContaint.hasHeader" class="table table-bordered" style="margin-bottom:0;">\r
+                <tr>\r
+                  <th ng-repeat=" h in tabContaint.header track by $index">{{h}}</th>\r
+                </tr>\r
+                <tr ng-repeat="item in tabContaint.datas track by $index">\r
+                  <td ng-repeat="value in item track by $index"> {{ value }} </td>\r
+                </tr>\r
+              </table>\r
+            </div>\r
+          </div>\r
+        </div>\r
+\r
+      </div>\r
+    <!--  <div id="3d_view">\r
+    </div> -->\r
+  </div><!-- tab -->\r
+</div>\r
similarity index 97%
rename from ovsdb-ui/module/src/main/resources/ovsdb/root.tpl.html
rename to ovsdb-ui/module/src/main/resources/ovsdb/views/root.tpl.html
index 1340df593b99f45109bb1a2baeb0ce0d4ca45980..9e3cf154b7ae9245357b9a9b5652290a717d5f62 100644 (file)
@@ -1,8 +1,8 @@
-<!--
-* Copyright (c) 2015 Inocybe Technologies 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
--->
-<div class="main" ui-view></div>
+<!--\r
+* Copyright (c) 2015 Inocybe Technologies and others.  All rights reserved.\r
+*\r
+* This program and the accompanying materials are made available under the\r
+* terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+* and is available at http://www.eclipse.org/legal/epl-v10.html\r
+-->\r
+<div class="main" ui-view></div>\r
diff --git a/resources/commons/NetvirtSfc.json.postman_collection b/resources/commons/NetvirtSfc.json.postman_collection
new file mode 100644 (file)
index 0000000..f73f0cb
--- /dev/null
@@ -0,0 +1,189 @@
+{
+    "id": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+    "name": "NetvirtSfc",
+    "requests": [
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n    \"access-lists\": {\n        \"acl\": [\n            {\n                \"acl-name\": \"http-acl\",\n                \"access-list-entries\": {\n                    \"ace\": [\n                        {\n                            \"rule-name\": \"http-rule\",\n                            \"matches\": {\n                                \"destination-port-range\": {\n                                    \"lower-port\": \"80\",\n                                    \"upper-port\": \"80\"\n                                }\n                            },\n                            \"actions\": {\n                                \"netvirt-sfc-acl:redirect-sfc\": \"acl\"\n                            }\n                        }\n                    ]\n                }\n            }\n        ]\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Content-Type: application/json\n",
+            "id": "19b44f74-e2ea-9267-50af-ad79b6309859",
+            "method": "PUT",
+            "name": "ietf-acl redirect-sfc",
+            "time": 1445298337983,
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists",
+            "version": 2
+        },
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n    \"service-function-forwarders\": {\n        \"service-function-forwarder\": [\n            {\n                \"name\": \"SFF1\",\n                \"service-node\": \"OVSDB2\",\n                \"service-function-forwarder-ovs:ovs-bridge\": {\n                    \"bridge-name\": \"sw2\"\n                },\n                \"service-function-dictionary\": [\n                    {\n                        \"name\": \"firewall-72\",\n                        \"type\": \"service-function-type:firewall\",\n                        \"sff-sf-data-plane-locator\": {\n                            \"port\": 6633,\n                            \"ip\": \"192.168.50.71\",\n                             \"transport\": \"service-locator:vxlan-gpe\"\n                        }\n                    }\n                ],\n                \"sff-data-plane-locator\": [\n                    {\n                        \"name\": \"sfc-tun2\",\n                        \"data-plane-locator\": {\n                            \"transport\": \"service-locator:vxlan-gpe\",\n                            \"port\": 6633,\n                            \"ip\": \"192.168.50.71\"\n                        },\n                        \"service-function-forwarder-ovs:ovs-options\": {\n                            \"remote-ip\": \"flow\",\n                            \"dst-port\": \"6633\",\n                            \"key\": \"flow\",\n                            \"nsp\": \"flow\",\n                            \"nsi\": \"flow\",\n                            \"nshc1\": \"flow\",\n                            \"nshc2\": \"flow\",\n                            \"nshc3\": \"flow\",\n                            \"nshc4\": \"flow\"\n                        }\n                    }\n                ]\n            },\n            {\n                \"name\": \"SFF2\",\n                \"service-node\": \"OVSDB2\",\n                \"service-function-forwarder-ovs:ovs-bridge\": {\n                    \"bridge-name\": \"sw4\"\n                },\n                \"service-function-dictionary\": [\n                    {\n                        \"name\": \"dpi-74\",\n                        \"type\": \"service-function-type:dpi\",\n                        \"sff-sf-data-plane-locator\": {\n                            \"port\": 6633,\n                            \"ip\": \"192.168.50.73\",\n                             \"transport\": \"service-locator:vxlan-gpe\"\n                        }\n                    }\n                ],\n                \"sff-data-plane-locator\": [\n                    {\n                        \"name\": \"sfc-tun4\",\n                        \"data-plane-locator\": {\n                            \"transport\": \"service-locator:vxlan-gpe\",\n                            \"port\": 6633,\n                            \"ip\": \"192.168.50.73\"\n                        },\n                        \"service-function-forwarder-ovs:ovs-options\": {\n                            \"remote-ip\": \"flow\",\n                            \"dst-port\": \"6633\",\n                            \"key\": \"flow\",\n                            \"nsp\": \"flow\",\n                            \"nsi\": \"flow\",\n                            \"nshc1\": \"flow\",\n                            \"nshc2\": \"flow\",\n                            \"nshc3\": \"flow\",\n                            \"nshc4\": \"flow\"\n                        }\n                    }\n                ]\n            }\n        ]\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "id": "1b067065-f0d5-d871-28cf-5e7e195eb463",
+            "method": "PUT",
+            "name": "service-function-forwarders",
+            "time": 1445302610648,
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/service-function-forwarder:service-function-forwarders",
+            "version": 2
+        },
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n    \"access-lists\": {\n        \"acl\": [\n            {\n                \"acl-name\": \"http-acl\",\n                \"access-list-entries\": {\n                    \"ace\": [\n                        {\n                            \"rule-name\": \"http-rule\",\n                            \"matches\": {\n                                \"destination-port-range\": {\n                                    \"lower-port\": \"80\",\n                                    \"upper-port\": \"80\"\n                                }\n                            },\n                            \"actions\": {\n                                \"permit\": \"true\"\n\n                            }\n                        }\n                    ]\n                }\n            }\n        ]\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Content-Type: application/json\n",
+            "id": "62e3b4d9-2672-e2bd-25c9-70bfb6771026",
+            "method": "PUT",
+            "name": "ietf-acl",
+            "time": 1445298397905,
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists",
+            "version": 2
+        },
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n    \"classifiers\": {\n        \"classifier\": [\n            {\n                \"name\": \"http-classifier\",\n                \"acl\": \"http-acl\",\n                \"sffs\": {\n                    \"sff\": [\n                        {\n                            \"name\": \"sff1\"\n                        }\n                    ]\n                }\n            }\n        ]\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+            "id": "718ed9fd-f7f3-3862-4a53-b12d83c880ae",
+            "method": "PUT",
+            "name": "Classifier",
+            "time": 1444924721709,
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/netvirt-sfc-classifier:classifiers",
+            "version": 2
+        },
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n    \"access-lists\": {\n        \"acl\": [\n            {\n                \"acl-name\": \"http-acl\",\n                \"access-list-entries\": {\n                    \"ace\": [\n                        {\n                            \"rule-name\": \"http-rule\",\n                            \"matches\": {\n                                \"destination-port-range\": {\n                                    \"lower-port\": \"80\",\n                                    \"upper-port\": \"80\"\n                                }\n                            },\n                            \"actions\": {\n                                \"permit\": {}\n                            }\n                        }\n                    ]\n                }\n            }\n        ]\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Content-Type: application/json\n",
+            "id": "7412ee0c-b116-5cf1-0646-efa65f0da784",
+            "method": "GET",
+            "name": "ietf-acl",
+            "responses": [],
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists",
+            "version": 2
+        },
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n    \"classifiers\": {\n        \"classifier\": [\n            {\n                \"name\": \"http-classifier\",\n                \"acl\": \"http-acl\",\n                \"sffs\": {\n                    \"sff\": [\n                        {\n                            \"name\": \"sff1\"\n                        }\n                    ]\n                }\n            }\n        ]\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+            "id": "76b32432-5a24-9d6d-8ba2-76eb816411af",
+            "method": "DELETE",
+            "name": "Classifier",
+            "responses": [],
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/netvirt-sfc-classifier:classifiers",
+            "version": 2
+        },
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n    \"access-lists\": {\n        \"acl\": [\n            {\n                \"acl-name\": \"http-acl\",\n                \"access-list-entries\": {\n                    \"ace\": [\n                        {\n                            \"rule-name\": \"http-rule\",\n                            \"matches\": {\n                                \"destination-port-range\": {\n                                    \"lower-port\": \"80\",\n                                    \"upper-port\": \"80\"\n                                }\n                            },\n                            \"actions\": {\n                                \"netvirt-sfc-acl:redirect-sfc\": \"acl\"\n                            }\n                        }\n                    ]\n                }\n            }\n        ]\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Content-Type: application/json\n",
+            "id": "99dc6bb5-f01a-64cd-a024-c333fdf82643",
+            "method": "DELETE",
+            "name": "ietf-acl redirect-sfc",
+            "responses": [],
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/ietf-access-control-list:access-lists",
+            "version": 2
+        },
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n\t\"sfc\": {\n        \"name\": \"sfc1\"\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "id": "9d418a4b-197d-47c2-e85f-e68f6b5f5c40",
+            "method": "GET",
+            "name": "Sfc",
+            "responses": [],
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/netvirt-sfc:sfc/",
+            "version": 2
+        },
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n    \"classifiers\": {\n        \"classifier\": [\n            {\n                \"name\": \"http-classifier\",\n                \"acl\": \"http-acl\",\n                \"sffs\": {\n                    \"sff\": [\n                        {\n                            \"name\": \"sff1\"\n                        }\n                    ]\n                }\n            }\n        ]\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+            "id": "b2d13061-80e0-ad8f-d0e6-d6939ea2b0a4",
+            "method": "GET",
+            "name": "Classifier",
+            "responses": [],
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/netvirt-sfc-classifier:classifiers",
+            "version": 2
+        },
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n    \"service-functions\": {\n        \"service-function\": [\n            {\n                \"name\": \"firewall-72\",\n                \"ip-mgmt-address\": \"192.168.50.72\",\n                \"type\": \"service-function-type:firewall\",\n                \"nsh-aware\": \"true\",\n                \"sf-data-plane-locator\": [\n                    {\n                        \"name\": \"2\",\n                        \"port\": 6633,\n                        \"ip\": \"192.168.50.72\",\n                        \"transport\": \"service-locator:vxlan-gpe\",\n                        \"service-function-forwarder\": \"SFF1\"\n                    }\n                ]\n            },\n            {\n                \"name\": \"dpi-74\",\n                \"ip-mgmt-address\": \"192.168.50.74\",\n                \"type\": \"service-function-type:dpi\",\n                \"nsh-aware\": \"true\",\n                \"sf-data-plane-locator\": [\n                    {\n                        \"name\": \"3\",\n                        \"port\": 6633,\n                        \"ip\": \"192.168.50.74\",\n                        \"transport\": \"service-locator:vxlan-gpe\",\n                        \"service-function-forwarder\": \"SFF2\"\n                    }\n                ]\n            }\n        ]\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "id": "bf4f1148-5192-fd7d-3026-5a11668db75d",
+            "method": "PUT",
+            "name": "service-functions",
+            "time": 1445302596335,
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/service-function:service-functions",
+            "version": 2
+        },
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n    \"service-function-forwarders\": {\n        \"service-function-forwarder\": [\n            {\n                \"name\": \"SFF1\",\n                \"service-node\": \"OVSDB2\",\n                \"service-function-forwarder-ovs:ovs-bridge\": {\n                    \"bridge-name\": \"sw2\"\n                },\n                \"service-function-dictionary\": [\n                    {\n                        \"name\": \"firewall-72\",\n                        \"type\": \"service-function-type:firewall\",\n                        \"sff-sf-data-plane-locator\": {\n                            \"port\": 6633,\n                            \"ip\": \"192.168.50.71\",\n                             \"transport\": \"service-locator:vxlan-gpe\"\n                        }\n                    }\n                ],\n                \"sff-data-plane-locator\": [\n                    {\n                        \"name\": \"sfc-tun2\",\n                        \"data-plane-locator\": {\n                            \"transport\": \"service-locator:vxlan-gpe\",\n                            \"port\": 6633,\n                            \"ip\": \"192.168.50.71\"\n                        },\n                        \"service-function-forwarder-ovs:ovs-options\": {\n                            \"remote-ip\": \"flow\",\n                            \"dst-port\": \"6633\",\n                            \"key\": \"flow\",\n                            \"nsp\": \"flow\",\n                            \"nsi\": \"flow\",\n                            \"nshc1\": \"flow\",\n                            \"nshc2\": \"flow\",\n                            \"nshc3\": \"flow\",\n                            \"nshc4\": \"flow\"\n                        }\n                    }\n                ]\n            },\n            {\n                \"name\": \"SFF2\",\n                \"service-node\": \"OVSDB2\",\n                \"service-function-forwarder-ovs:ovs-bridge\": {\n                    \"bridge-name\": \"sw4\"\n                },\n                \"service-function-dictionary\": [\n                    {\n                        \"name\": \"dpi-74\",\n                        \"type\": \"service-function-type:dpi\",\n                        \"sff-sf-data-plane-locator\": {\n                            \"port\": 6633,\n                            \"ip\": \"192.168.50.73\",\n                             \"transport\": \"service-locator:vxlan-gpe\"\n                        }\n                    }\n                ],\n                \"sff-data-plane-locator\": [\n                    {\n                        \"name\": \"sfc-tun4\",\n                        \"data-plane-locator\": {\n                            \"transport\": \"service-locator:vxlan-gpe\",\n                            \"port\": 6633,\n                            \"ip\": \"192.168.50.73\"\n                        },\n                        \"service-function-forwarder-ovs:ovs-options\": {\n                            \"remote-ip\": \"flow\",\n                            \"dst-port\": \"6633\",\n                            \"key\": \"flow\",\n                            \"nsp\": \"flow\",\n                            \"nsi\": \"flow\",\n                            \"nshc1\": \"flow\",\n                            \"nshc2\": \"flow\",\n                            \"nshc3\": \"flow\",\n                            \"nshc4\": \"flow\"\n                        }\n                    }\n                ]\n            }\n        ]\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "id": "e6542ed1-832c-71c9-fe74-2d25c9e7f7ad",
+            "method": "GET",
+            "name": "service-function-forwarders",
+            "responses": [],
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/service-function-forwarder:service-function-forwarders",
+            "version": 2
+        },
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n\t\"sfc\": {\n        \"name\": \"sfc1\"\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "id": "ea1c70a0-6528-862c-cabc-a9b187d483c7",
+            "method": "PUT",
+            "name": "Sfc",
+            "responses": [],
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/netvirt-sfc:sfc/",
+            "version": 2
+        },
+        {
+            "collectionId": "bc172f70-35df-2cdf-50a4-8ad09b8f17a2",
+            "data": "{\n    \"service-functions\": {\n        \"service-function\": [\n            {\n                \"name\": \"firewall-72\",\n                \"ip-mgmt-address\": \"192.168.50.72\",\n                \"type\": \"service-function-type:firewall\",\n                \"nsh-aware\": \"true\",\n                \"sf-data-plane-locator\": [\n                    {\n                        \"name\": \"2\",\n                        \"port\": 6633,\n                        \"ip\": \"192.168.50.72\",\n                        \"transport\": \"service-locator:vxlan-gpe\",\n                        \"service-function-forwarder\": \"SFF1\"\n                    }\n                ]\n            },\n            {\n                \"name\": \"dpi-74\",\n                \"ip-mgmt-address\": \"192.168.50.74\",\n                \"type\": \"service-function-type:dpi\",\n                \"nsh-aware\": \"true\",\n                \"sf-data-plane-locator\": [\n                    {\n                        \"name\": \"3\",\n                        \"port\": 6633,\n                        \"ip\": \"192.168.50.74\",\n                        \"transport\": \"service-locator:vxlan-gpe\",\n                        \"service-function-forwarder\": \"SFF2\"\n                    }\n                ]\n            }\n        ]\n    }\n}",
+            "dataMode": "raw",
+            "description": "",
+            "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+            "id": "fff50fa7-aa2d-71a4-db49-4ea10b82937e",
+            "method": "GET",
+            "name": "service-functions",
+            "responses": [],
+            "timestamp": 0,
+            "url": "http://localhost:8181/restconf/config/service-function:service-functions",
+            "version": 2
+        }
+    ],
+    "timestamp": 1444922427094
+}
index 98de4d5babab88c807d0a487fbcb5d7e658bd0bf..25cf72cccfcd29a3282a6e2e0d7d567127c018c9 100644 (file)
@@ -27,4 +27,4 @@ Contents
 
 - 3-Node-Cluster-Setup-Environment-Variables.postman_environment : Postman environment file that defines variables for Restconf request for southbound plugin running in 3 node cluster environment
 
-
+- NetvirtSfc.json.postman_collection : Collection of REST-APIs to interact with Netvirt-Sfc.
index 714ff69e854e6030e62e0cc84ee4f8d7ea7a7f5b..2fe9a04593a1c208f3a1803f99d29a349e4f2d68 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2014 Red Hat, Inc.
+ *  Copyright (C) 2014 Red Hat, 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,
index 72fcc9252b335f82ecbd57c96abc07b745f5ce07..32adb5dd8e2abcfd659a1c89550ecb5635cfdf7d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2014 Red Hat, Inc.
+ *  Copyright (C) 2014 Red Hat, 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,
index a13e15c422fa0c2bb235b7ea5570166d7b5c8a6e..0b388af8c5a70d2967ab3355149cd0ee95df9096 100644 (file)
@@ -16,6 +16,7 @@ import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipC
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
@@ -77,7 +78,18 @@ public class SouthboundProvider implements BindingAwareProvider, AutoCloseable {
         //register instance entity to get the ownership of the provider
         Entity instanceEntity = new Entity(ENTITY_TYPE, ENTITY_TYPE);
         try {
+            Optional<EntityOwnershipState> ownershipStateOpt = entityOwnershipService.getOwnershipState(instanceEntity);
             registration = entityOwnershipService.registerCandidate(instanceEntity);
+            if (ownershipStateOpt.isPresent()) {
+                EntityOwnershipState ownershipState = ownershipStateOpt.get();
+                if (ownershipState.hasOwner() && !ownershipState.isOwner()) {
+                    if (ovsdbConnection == null) {
+                        ovsdbConnection = new OvsdbConnectionService();
+                        ovsdbConnection.registerConnectionListener(cm);
+                        ovsdbConnection.startOvsdbManager(SouthboundConstants.DEFAULT_OVSDB_PORT);
+                    }
+                }
+            }
         } catch (CandidateAlreadyRegisteredException e) {
             LOG.warn("OVSDB Southbound Provider instance entity {} was already "
                     + "registered for {} ownership", instanceEntity, e);
index 4116ebb8a0d7768f1720d77fc849498860e076bb..f15be017d2e1906e689524c88a697ff841c6310b 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound;
 
 import static org.junit.Assert.assertEquals;
index 9cbb99dc30b269365d87b0ac914cf276ea0c8da2..cbfe4c2b6543a4f6396ce106e4068e22201c80dc 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound;
 
 import static org.junit.Assert.assertEquals;
index f9a8239cd89cfe0b5aa8062419a1fa98d88c14a6..209301c58d78d97b58540bd31cfdf6042f62c339 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound;
 
 import static org.junit.Assert.assertEquals;
index 3025fddeada47cde9f49500933f4d48ca30d3e0b..469bd723400f1db1e6c3bab2e295dfe83e452245 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound;
 
 import static org.junit.Assert.assertEquals;
index 055d74f6ddcd9ba56119ed4813a1d3eaa9cd0c91..7a8f5714ccb144e379aa36a86fb7f0a4af3467d4 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound;
 
 import static org.mockito.Matchers.any;
index 8be119607c07488c45694d6315ff0534aaac97f4..c51f18873d46758139181d7736aafb3265e16ff4 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound;
 import static org.junit.Assert.assertEquals;
 
index 26168a6c8e036fac1356edafa4dedf9537a1115e..546e004b55cf23ae3ebdd452ae71d6058fd17493 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound;
 
 import static org.junit.Assert.assertEquals;
index cb7ed423f2da33f4dd58d4292c0f641daf94da16..662fbcd6e397ea2ad5f14fee2706e83aa66a976c 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound;
 
 import static org.mockito.Matchers.any;
@@ -20,6 +28,7 @@ import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipC
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
@@ -74,6 +83,8 @@ public class SouthboundProviderTest {
 
         when(entityOwnershipService.registerListener(anyString(), any(EntityOwnershipListener.class))).thenReturn(mock(EntityOwnershipListenerRegistration.class));
         when(entityOwnershipService.registerCandidate(any(Entity.class))).thenReturn(registration);
+        EntityOwnershipState entityOwnershipState = mock(EntityOwnershipState.class);
+        when(entityOwnershipService.getOwnershipState(any(Entity.class))).thenReturn(Optional.of(entityOwnershipState));
 
         southboundProvider.onSessionInitiated(session);
 
index 457230b4ffe6a9f872c6fa9a6444970163cf2768..a6844344e0d697819b2dc9bce3f595e64f256e38 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
index d3176ccad7d2464aaeeeaaa2d5cc1abec569303e..e6045b9cf48d1b088a484fce48cfc6fc40dfc9fa 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
 
 import static org.junit.Assert.assertEquals;
index 7b24ed4f45d433d05d8f55ca1a0b826619bf3901..be5f1b20c5b446c7cad5da8c13f4ef206ecaccb2 100644 (file)
@@ -1,6 +1,13 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
 
-import static org.junit.Assert.*;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
index a2030af6519ba8e504bc280092db31c76532ffc5..faa2329269e40c111b6c7112c082bda36453095e 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
 
 import static org.mockito.Matchers.any;
index f1cbd989295cb66a2c097de55fa9b1667f766a95..9bdd0085686748030090c26c3cc7835bd78b9459 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
 
 import static org.junit.Assert.assertEquals;
index 55de9697d706d1b35f7aff662ea3ec8bc5cc8bf9..22a28bfec92dc548dd8c12e44ae113d80cfd4ef5 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
 
 import static org.junit.Assert.assertEquals;
index 7a3944d9054d04bebbfd7bbddd323066a34a6a23..a0b5b934163aa170b7d58d655d384065191426df 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
 
 import static org.junit.Assert.assertEquals;
index a15fd3030ba6c0663fd85fd5f2d8384dc0d98683..aabf249594baa62ab3681756e08756db5bf92bcb 100644 (file)
@@ -1,8 +1,20 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
 
-import static org.junit.Assert.*;
-import static org.mockito.Matchers.*;
-import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -22,7 +34,6 @@ import org.opendaylight.ovsdb.lib.notation.Column;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
-import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
 import org.opendaylight.ovsdb.schema.openvswitch.Manager;
 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
 import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
index 4a8aa7ecfef5fdd6e21ffb21746164f1cd50d3e1..7ffeb5270a1000344b4fb5a604d3a0dad9abaadf 100644 (file)
@@ -1,8 +1,20 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
 
-import static org.junit.Assert.*;
-import static org.mockito.Matchers.*;
-import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -20,16 +32,12 @@ import org.opendaylight.ovsdb.lib.notation.Column;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
-import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
-import org.opendaylight.ovsdb.schema.openvswitch.Controller;
 import org.opendaylight.ovsdb.schema.openvswitch.Manager;
 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
 import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
 import org.opendaylight.ovsdb.southbound.SouthboundUtil;
 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.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntryKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
@@ -38,7 +46,6 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.powermock.api.mockito.PowerMockito;
-import org.powermock.api.support.membermodification.MemberMatcher;
 import org.powermock.api.support.membermodification.MemberModifier;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
index 834e23d357ee1790889f31ecee8b71ce9649acb2..5fac43c07410742918e23778e27b4165dcbcc845 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
 
 import static org.junit.Assert.assertEquals;
index 29aaa16c645d3c3d3cee60652d8098480f7fbefc..696c365327c449edcdf719e257c0b7e349be0e17 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
 
 import static org.junit.Assert.*;
diff --git a/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbPortRemoveCommandTest.java b/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbPortRemoveCommandTest.java
new file mode 100644 (file)
index 0000000..5175faf
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.Column;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
+import org.opendaylight.ovsdb.schema.openvswitch.Port;
+import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
+import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+@PrepareForTest({TyperUtils.class, SouthboundMapper.class, InstanceIdentifier.class})
+@RunWith(PowerMockRunner.class)
+public class OvsdbPortRemoveCommandTest {
+    private static final String PORT_NAME = "port0";
+    private OvsdbPortRemoveCommand ovsdbPortRemoveCommand;
+
+    @Before
+    public void setUp() throws Exception {
+        ovsdbPortRemoveCommand = PowerMockito.mock(OvsdbPortRemoveCommand.class, Mockito.CALLS_REAL_METHODS);
+    }
+
+    @Test
+    public void testOvsdbPortRemoveCommandTest() {
+        OvsdbConnectionInstance key = mock(OvsdbConnectionInstance.class);
+        TableUpdates updates = mock(TableUpdates.class);
+        DatabaseSchema dbSchema = mock(DatabaseSchema.class);
+        OvsdbPortRemoveCommand ovsdbPortRemoveCommand1 = new OvsdbPortRemoveCommand(key, updates, dbSchema);
+        assertEquals(key, Whitebox.getInternalState(ovsdbPortRemoveCommand1, "key"));
+        assertEquals(updates, Whitebox.getInternalState(ovsdbPortRemoveCommand1, "updates"));
+        assertEquals(dbSchema, Whitebox.getInternalState(ovsdbPortRemoveCommand1, "dbSchema"));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testExecute() throws Exception {
+        ReadWriteTransaction transaction = mock(ReadWriteTransaction.class);
+        when(ovsdbPortRemoveCommand.getUpdates()).thenReturn(mock(TableUpdates.class));
+        when(ovsdbPortRemoveCommand.getDbSchema()).thenReturn(mock(DatabaseSchema.class));
+        PowerMockito.mockStatic(TyperUtils.class);
+        UUID uuid = mock(UUID.class);
+        Map<UUID, Port> portRemovedRows = new HashMap<>();
+        Port port = mock(Port.class);
+        portRemovedRows.put(uuid, port);
+        when(TyperUtils.extractRowsRemoved(eq(Port.class), any(TableUpdates.class), any(DatabaseSchema.class))).thenReturn(portRemovedRows);
+        Map<UUID, Bridge> bridgeUpdatedRows = new HashMap<>();
+        Bridge updatedBridgeData = mock(Bridge.class);
+        bridgeUpdatedRows.put(uuid, updatedBridgeData);
+        when(TyperUtils.extractRowsUpdated(eq(Bridge.class), any(TableUpdates.class), any(DatabaseSchema.class))).thenReturn(bridgeUpdatedRows);
+        Map<UUID, Bridge> bridgeUpdatedOldRows = new HashMap<>();
+        Bridge oldBridgeData = mock(Bridge.class);
+        bridgeUpdatedOldRows.put(uuid, oldBridgeData);
+        when(TyperUtils.extractRowsOld(eq(Bridge.class), any(TableUpdates.class), any(DatabaseSchema.class))).thenReturn(bridgeUpdatedOldRows);
+
+        Column<GenericTableSchema, Set<UUID>> column = mock(Column.class);
+        when(oldBridgeData.getPortsColumn()).thenReturn(column);
+        Set<UUID> setUUID = new HashSet<>();
+        setUUID.add(uuid);
+        when(column.getData()).thenReturn(setUUID);
+
+        Column<GenericTableSchema, UUID> uuidColumn = mock(Column.class);
+        when(port.getUuidColumn()).thenReturn(uuidColumn);
+        when(uuidColumn.getData()).thenReturn(uuid);
+
+        when(port.getName()).thenReturn(PORT_NAME);
+        PowerMockito.mockStatic(SouthboundMapper.class);
+        InstanceIdentifier<Node> nodeIID = mock(InstanceIdentifier.class);
+        when(ovsdbPortRemoveCommand.getOvsdbConnectionInstance()).thenReturn(mock(OvsdbConnectionInstance.class));
+        when(SouthboundMapper.createInstanceIdentifier(any(OvsdbConnectionInstance.class), any(Bridge.class))).thenReturn(nodeIID);
+        MemberModifier.suppress(MemberModifier.methodsDeclaredIn(InstanceIdentifier.class));
+        doNothing().when(transaction).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+
+        ovsdbPortRemoveCommand.execute(transaction);
+        verify(transaction).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+    }
+}
diff --git a/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbPortUpdateCommandTest.java b/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbPortUpdateCommandTest.java
new file mode 100644 (file)
index 0000000..ac7658c
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.Column;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
+import org.opendaylight.ovsdb.schema.openvswitch.Interface;
+import org.opendaylight.ovsdb.schema.openvswitch.Port;
+import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
+import org.opendaylight.ovsdb.southbound.SouthboundConstants;
+import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+import org.opendaylight.ovsdb.southbound.SouthboundUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeInternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbPortInterfaceAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbPortInterfaceAttributes.VlanMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceOtherConfigs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceOtherConfigsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortExternalIdsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortOtherConfigs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortOtherConfigsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.TrunksBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberMatcher;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+@PrepareForTest({TyperUtils.class, OvsdbPortUpdateCommand.class, SouthboundUtil.class, SouthboundMapper.class})
+@RunWith(PowerMockRunner.class)public class OvsdbPortUpdateCommandTest {
+
+    private static final String OTHER_CONFIG_KEY = "key";
+    private static final String OTHER_CONFIG_VALUE = "value";
+    private static final String EXTERNAL_ID_KEY = "key";
+    private static final String EXTERNAL_ID_VALUE = "value";
+    private static final String INTERFACE_NAME = "interface_name";
+    private static final String VLAN_MODE_ACCESS = "access";
+    private static final String OVSDB_INTERFACE_TYPE = "internal";
+    private static final String PORT_NAME = "port_name";
+    private static final String TP_NAME = "tp_name";
+    private static final String TERMINATION_POINT_NAME = "termination_point_name";
+
+    private Map<UUID, Port> portUpdatedRows;
+    private Map<UUID, Port> portOldRows;
+    private Map<UUID, Interface> interfaceUpdatedRows;
+    private Map<UUID, Interface> interfaceOldRows;
+    private Map<UUID, Bridge> bridgeUpdatedRows;
+    private OvsdbPortUpdateCommand ovsdbPortUpdateCommand;
+
+    @Before
+    public void setUp() throws Exception {
+        ovsdbPortUpdateCommand = PowerMockito.mock(OvsdbPortUpdateCommand.class, Mockito.CALLS_REAL_METHODS);
+    }
+
+    @Test
+    public void testOvsdbPortUpdateCommand() throws Exception {
+        OvsdbConnectionInstance key = mock(OvsdbConnectionInstance.class);
+        TableUpdates updates = mock(TableUpdates.class);
+        DatabaseSchema dbSchema = mock(DatabaseSchema.class);
+
+        PowerMockito.mockStatic(TyperUtils.class);
+        PowerMockito.when(TyperUtils.extractRowsUpdated(Port.class, updates, dbSchema)).thenReturn(portUpdatedRows);
+        PowerMockito.when(TyperUtils.extractRowsOld(Port.class, updates, dbSchema)).thenReturn(portOldRows);
+        PowerMockito.when(TyperUtils.extractRowsUpdated(Interface.class, updates, dbSchema)).thenReturn(interfaceUpdatedRows);
+        PowerMockito.when(TyperUtils.extractRowsOld(Interface.class, updates, dbSchema)).thenReturn(interfaceOldRows);
+        PowerMockito.when(TyperUtils.extractRowsUpdated(Bridge.class, updates, dbSchema)).thenReturn(bridgeUpdatedRows);
+
+        OvsdbPortUpdateCommand ovsdbPortUpdateCommand1 = new OvsdbPortUpdateCommand(key, updates, dbSchema);
+        assertEquals(portUpdatedRows, Whitebox.getInternalState(ovsdbPortUpdateCommand1, "portUpdatedRows"));
+        assertEquals(portOldRows, Whitebox.getInternalState(ovsdbPortUpdateCommand1, "portOldRows"));
+        assertEquals(dbSchema, Whitebox.getInternalState(ovsdbPortUpdateCommand1, "dbSchema"));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testExecute() throws Exception {
+        ReadWriteTransaction transaction= mock(ReadWriteTransaction.class);
+        portUpdatedRows = new HashMap<>();
+        interfaceOldRows = new HashMap<>();
+        portUpdatedRows.put(mock(UUID.class), mock(Port.class));
+        interfaceOldRows.put(mock(UUID.class), mock(Interface.class));
+        MemberModifier.field(OvsdbPortUpdateCommand.class, "portUpdatedRows").set(ovsdbPortUpdateCommand, portUpdatedRows);
+        MemberModifier.field(OvsdbPortUpdateCommand.class, "interfaceOldRows").set(ovsdbPortUpdateCommand, interfaceOldRows);
+
+        OvsdbConnectionInstance ovsdbConnectionInstance = mock(OvsdbConnectionInstance.class);
+        when(ovsdbPortUpdateCommand.getOvsdbConnectionInstance()).thenReturn(ovsdbConnectionInstance);
+        InstanceIdentifier<Node> connectionIId = mock(InstanceIdentifier.class);
+        when(ovsdbConnectionInstance.getInstanceIdentifier()).thenReturn(connectionIId);
+
+        //case 1: portUpdatedRows & interfaceOldRows not null, not empty
+        Optional<Node> node = mock(Optional.class);
+        PowerMockito.doReturn(node).when(ovsdbPortUpdateCommand, "readNode", any(ReadWriteTransaction.class), any(InstanceIdentifier.class));
+        when(node.isPresent()).thenReturn(true);
+        when(node.get()).thenReturn(mock(Node.class));
+        PowerMockito.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateTerminationPoints", ReadWriteTransaction.class, Node.class));
+        ovsdbPortUpdateCommand.execute(transaction);
+        verify(ovsdbConnectionInstance).getInstanceIdentifier();
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateTerminationPoints", any(ReadWriteTransaction.class), any(Node.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUpdateTerminationPoints() throws Exception {
+        ReadWriteTransaction transaction = mock(ReadWriteTransaction.class);
+        Node node = mock(Node.class);
+
+        portUpdatedRows = new HashMap<>();
+        Port port = mock(Port.class);
+        UUID uuid = mock(UUID.class);
+        portUpdatedRows.put(uuid, port);
+        MemberModifier.field(OvsdbPortUpdateCommand.class, "portUpdatedRows").set(ovsdbPortUpdateCommand, portUpdatedRows);
+        Column<GenericTableSchema, String> bridgeColumn = mock(Column.class);
+        when(port.getNameColumn()).thenReturn(bridgeColumn);
+        when(bridgeColumn.getData()).thenReturn(TERMINATION_POINT_NAME);
+
+        Optional<InstanceIdentifier<Node>> bridgeIid = mock(Optional.class);
+        PowerMockito.doReturn(bridgeIid).when(ovsdbPortUpdateCommand, "getTerminationPointBridge", any(UUID.class));
+
+        //bridgeIid.isPresent() is true
+        when(bridgeIid.isPresent()).thenReturn(true);
+        when(bridgeIid.get()).thenReturn(mock(InstanceIdentifier.class));
+        NodeId bridgeId = mock(NodeId.class);
+        PowerMockito.mockStatic(SouthboundMapper.class);
+        PowerMockito.when(SouthboundMapper.createManagedNodeId(any(InstanceIdentifier.class))).thenReturn(bridgeId);
+
+        PowerMockito.whenNew(TpId.class).withAnyArguments().thenReturn(mock(TpId.class));
+        TerminationPointKey tpKey = mock(TerminationPointKey.class);
+        PowerMockito.whenNew(TerminationPointKey.class).withAnyArguments().thenReturn(tpKey);
+        TerminationPointBuilder tpBuilder = mock(TerminationPointBuilder.class);
+        PowerMockito.whenNew(TerminationPointBuilder.class).withNoArguments().thenReturn(tpBuilder);
+        when(tpBuilder.setKey(any(TerminationPointKey.class))).thenReturn(tpBuilder);
+        when(tpKey.getTpId()).thenReturn(mock(TpId.class));
+        when(tpBuilder.setTpId(any(TpId.class))).thenReturn(tpBuilder);
+        InstanceIdentifier<TerminationPoint> tpPath = mock(InstanceIdentifier.class);
+        PowerMockito.doReturn(tpPath).when(ovsdbPortUpdateCommand, "getInstanceIdentifier", any(InstanceIdentifier.class), any(Port.class));
+
+        OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        PowerMockito.whenNew(OvsdbTerminationPointAugmentationBuilder.class).withNoArguments().thenReturn(tpAugmentationBuilder);
+        PowerMockito.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "buildTerminationPoint", OvsdbTerminationPointAugmentationBuilder.class, Port.class));
+
+        Column<GenericTableSchema, Set<UUID>> interfacesColumn = mock(Column.class);
+        when(port.getInterfacesColumn()).thenReturn(interfacesColumn);
+        Set<UUID> setUUID = new HashSet<>();
+        UUID interfaceUUID = mock(UUID.class);
+        setUUID.add(interfaceUUID);
+        when(interfacesColumn.getData()).thenReturn(setUUID);
+
+        interfaceUpdatedRows = new HashMap<>();
+        interfaceOldRows = new HashMap<>();
+        Interface iface = mock(Interface.class);
+        interfaceUpdatedRows.put(interfaceUUID, iface);
+        Interface interfaceUpdate = mock(Interface.class);
+        interfaceUpdatedRows.put(uuid, interfaceUpdate);
+        interfaceOldRows.put(interfaceUUID, iface);
+        MemberModifier.field(OvsdbPortUpdateCommand.class, "interfaceUpdatedRows").set(ovsdbPortUpdateCommand, interfaceUpdatedRows);
+        MemberModifier.field(OvsdbPortUpdateCommand.class, "interfaceOldRows").set(ovsdbPortUpdateCommand, interfaceOldRows);
+        PowerMockito.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "buildTerminationPoint", OvsdbTerminationPointAugmentationBuilder.class, Interface.class));
+
+        when(tpAugmentationBuilder.build()).thenReturn(mock(OvsdbTerminationPointAugmentation.class));
+        when(tpBuilder.addAugmentation(eq(OvsdbTerminationPointAugmentation.class), any(OvsdbTerminationPointAugmentation.class))).thenReturn(tpBuilder);
+        when(tpBuilder.build()).thenReturn(mock(TerminationPoint.class));
+        portOldRows = new HashMap<>();
+        portOldRows.put(uuid, port);
+        MemberModifier.field(OvsdbPortUpdateCommand.class, "portOldRows").set(ovsdbPortUpdateCommand, portOldRows);
+        doNothing().when(transaction).merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(TerminationPoint.class));
+        doNothing().when(transaction).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(TerminationPoint.class));
+
+        Column<GenericTableSchema, String> interfaceColumn = mock(Column.class);
+        when(interfaceUpdate.getNameColumn()).thenReturn(interfaceColumn);
+        when(interfaceColumn.getData()).thenReturn(INTERFACE_NAME);
+
+        PowerMockito.doReturn(bridgeIid).when(ovsdbPortUpdateCommand, "getTerminationPointBridge", any(ReadWriteTransaction.class), any(Node.class), anyString());
+        PowerMockito.when(SouthboundMapper.createManagedNodeId(any(InstanceIdentifier.class))).thenReturn(bridgeId);
+        PowerMockito.whenNew(TopologyKey.class).withAnyArguments().thenReturn(mock(TopologyKey.class));
+        PowerMockito.whenNew(NodeKey.class).withAnyArguments().thenReturn(mock(NodeKey.class));
+
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateTerminationPoints", transaction, node);
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("getInstanceIdentifier", any(OvsdbTerminationPointAugmentationBuilder.class), any(Port.class));
+        verify(transaction, times(2)).merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(TerminationPoint.class));
+    }
+
+    @Test
+    public void testBuildTerminationPoint() throws Exception {
+        OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        Port portUpdate = mock(Port.class);
+        when(portUpdate.getName()).thenReturn(PORT_NAME);
+        when(portUpdate.getUuid()).thenReturn(mock(UUID.class));
+        PowerMockito.whenNew(Uuid.class).withAnyArguments().thenReturn(mock(Uuid.class));
+        when(tpAugmentationBuilder.setName(anyString())).thenReturn(tpAugmentationBuilder);
+        when(tpAugmentationBuilder.setPortUuid(any(Uuid.class))).thenReturn(tpAugmentationBuilder);
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updatePort", Port.class, OvsdbTerminationPointAugmentationBuilder.class));
+
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "buildTerminationPoint", tpAugmentationBuilder, portUpdate);
+        verify(tpAugmentationBuilder).setName(anyString());
+        verify(tpAugmentationBuilder).setPortUuid(any(Uuid.class));
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updatePort", any(Port.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+    }
+
+    @Test
+    public void testBuildTerminationPoint1() throws Exception {
+        OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        Interface interfaceUpdate = mock(Interface.class);
+        when(interfaceUpdate.getName()).thenReturn(INTERFACE_NAME);
+        when(interfaceUpdate.getUuid()).thenReturn(mock(UUID.class));
+        PowerMockito.whenNew(Uuid.class).withAnyArguments().thenReturn(mock(Uuid.class));
+        when(tpAugmentationBuilder.setName(anyString())).thenReturn(tpAugmentationBuilder);
+        when(tpAugmentationBuilder.setInterfaceUuid(any(Uuid.class))).thenReturn(tpAugmentationBuilder);
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateInterfaces", Interface.class, OvsdbTerminationPointAugmentationBuilder.class));
+
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "buildTerminationPoint", tpAugmentationBuilder, interfaceUpdate);
+        verify(tpAugmentationBuilder).setName(anyString());
+        verify(tpAugmentationBuilder).setInterfaceUuid(any(Uuid.class));
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateInterfaces", any(Interface.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testReadNode() throws Exception {
+        ReadWriteTransaction transaction = mock(ReadWriteTransaction.class);
+        InstanceIdentifier<Node> nodePath = mock(InstanceIdentifier.class);
+        Optional<Node> node = mock(Optional.class);
+        CheckedFuture<Optional<Node>, ReadFailedException> checkedFuture = mock(CheckedFuture.class);
+        when(transaction.read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class))).thenReturn(checkedFuture);
+        when(checkedFuture.checkedGet()).thenReturn(node);
+        assertEquals(node, Whitebox.invokeMethod(ovsdbPortUpdateCommand, "readNode", transaction, nodePath));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGetTerminationPointBridge() throws Exception {
+        UUID portUUID = mock(UUID.class);
+        bridgeUpdatedRows = new HashMap<UUID, Bridge>();
+        UUID bridgeUUID = mock(UUID.class);
+        Bridge bridge = mock(Bridge.class);
+        bridgeUpdatedRows.put(bridgeUUID, bridge);
+        MemberModifier.field(OvsdbPortUpdateCommand.class, "bridgeUpdatedRows").set(ovsdbPortUpdateCommand, bridgeUpdatedRows);
+
+        Column<GenericTableSchema, Set<UUID>> column = mock(Column.class);
+        when(bridge.getPortsColumn()).thenReturn(column);
+        Set<UUID> set = new HashSet<>();
+        set.add(portUUID);
+        when(column.getData()).thenReturn(set);
+
+        PowerMockito.mockStatic(SouthboundMapper.class);
+        when(ovsdbPortUpdateCommand.getOvsdbConnectionInstance()).thenReturn(mock(OvsdbConnectionInstance.class));
+        InstanceIdentifier<Node> nodeIid = mock(InstanceIdentifier.class);
+        PowerMockito.when(SouthboundMapper.createInstanceIdentifier(any(OvsdbConnectionInstance.class), any(Bridge.class))).thenReturn(nodeIid);
+
+        Optional<InstanceIdentifier<Node>> testResult = Optional.of(nodeIid);
+        assertEquals(testResult, Whitebox.invokeMethod(ovsdbPortUpdateCommand, "getTerminationPointBridge", portUUID));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGetTerminationPointBridge1() throws Exception {
+        ReadWriteTransaction transaction = mock(ReadWriteTransaction.class);
+        Node node = mock(Node.class);
+        OvsdbNodeAugmentation ovsdbNode = mock(OvsdbNodeAugmentation.class);
+        when(node.getAugmentation(OvsdbNodeAugmentation.class)).thenReturn(ovsdbNode);
+        List<ManagedNodeEntry> managedNodes = new ArrayList<>();
+        ManagedNodeEntry managedNodeEntry = mock(ManagedNodeEntry.class);
+        managedNodes.add(managedNodeEntry);
+        when(ovsdbNode.getManagedNodeEntry()).thenReturn(managedNodes);
+
+        Node managedNode = mock(Node.class);
+        OvsdbBridgeRef ovsdbBridgeRef = mock(OvsdbBridgeRef.class);
+        when(managedNodeEntry.getBridgeRef()).thenReturn(ovsdbBridgeRef);
+        InstanceIdentifier<Node> iidNode = mock(InstanceIdentifier.class);
+        when((InstanceIdentifier<Node>) ovsdbBridgeRef.getValue()).thenReturn(iidNode);
+        Optional<Node> optionalNode = Optional.of(managedNode);
+        PowerMockito.doReturn(optionalNode).when(ovsdbPortUpdateCommand, "readNode", any(ReadWriteTransaction.class), any(InstanceIdentifier.class));
+
+        TerminationPointBuilder tpBuilder = mock(TerminationPointBuilder.class);
+        PowerMockito.whenNew(TerminationPointBuilder.class).withNoArguments().thenReturn(tpBuilder);
+        PowerMockito.whenNew(TpId.class).withAnyArguments().thenReturn(mock(TpId.class));
+        PowerMockito.whenNew(TerminationPointKey.class).withAnyArguments().thenReturn(mock(TerminationPointKey.class));
+        when(tpBuilder.setKey(any(TerminationPointKey.class))).thenReturn(tpBuilder);
+
+        List<TerminationPoint> terminationPointList = new ArrayList<>();
+        TerminationPoint terminationPoint = mock(TerminationPoint.class);
+        terminationPointList.add(terminationPoint);
+        when(tpBuilder.build()).thenReturn(terminationPoint);
+        when(managedNode.getTerminationPoint()).thenReturn(terminationPointList);
+
+        when(managedNode.getAugmentation(OvsdbBridgeAugmentation.class)).thenReturn(mock(OvsdbBridgeAugmentation.class));
+
+        Optional<InstanceIdentifier<Node>> testResult = Optional.of(iidNode);
+        Optional<InstanceIdentifier<Node>>  result = Whitebox.invokeMethod(ovsdbPortUpdateCommand, "getTerminationPointBridge", transaction, node, TP_NAME);
+        assertEquals(testResult, result);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUpdateInterfaces() throws Exception {
+        Interface interfaceUpdate = mock(Interface.class);
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        Column<GenericTableSchema, String> typeColumn = mock(Column.class);
+        when(interfaceUpdate.getTypeColumn()).thenReturn(typeColumn);
+        when(typeColumn.getData()).thenReturn(OVSDB_INTERFACE_TYPE);
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateInterface", Interface.class, String.class, OvsdbTerminationPointAugmentationBuilder.class));
+
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateInterfaces", interfaceUpdate, ovsdbTerminationPointBuilder);
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateInterface", any(Interface.class), anyString(), any(OvsdbTerminationPointAugmentationBuilder.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUpdateInterface() throws Exception {
+        Interface interf = mock(Interface.class);
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        when(interf.getUuid()).thenReturn(mock(UUID.class));
+        PowerMockito.whenNew(Uuid.class).withAnyArguments().thenReturn(mock(Uuid.class));
+        when(ovsdbTerminationPointBuilder.setInterfaceUuid(any(Uuid.class))).thenReturn(ovsdbTerminationPointBuilder);
+        PowerMockito.mockStatic(SouthboundMapper.class);
+        PowerMockito.when(SouthboundMapper.createInterfaceType(anyString())).thenAnswer(new Answer<Class<? extends InterfaceTypeBase>>() {
+            public Class<? extends InterfaceTypeBase> answer(
+                    InvocationOnMock invocation) throws Throwable {
+                return (Class<? extends InterfaceTypeBase>) InterfaceTypeInternal.class;
+            }
+        });
+        when(ovsdbTerminationPointBuilder.setInterfaceType(any(Class.class))).thenReturn(ovsdbTerminationPointBuilder);
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateOfPort", Interface.class, OvsdbTerminationPointAugmentationBuilder.class));
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateOfPortRequest", Interface.class, OvsdbTerminationPointAugmentationBuilder.class));
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateInterfaceExternalIds", Interface.class, OvsdbTerminationPointAugmentationBuilder.class));
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateOptions", Interface.class, OvsdbTerminationPointAugmentationBuilder.class));
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateInterfaceOtherConfig", Interface.class, OvsdbTerminationPointAugmentationBuilder.class));
+
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateInterface", interf, OVSDB_INTERFACE_TYPE, ovsdbTerminationPointBuilder);
+        verify(ovsdbTerminationPointBuilder).setInterfaceUuid(any(Uuid.class));
+        verify(ovsdbTerminationPointBuilder).setInterfaceType(any(Class.class));
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateOfPort", any(Interface.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateOfPortRequest", any(Interface.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateInterfaceExternalIds", any(Interface.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateOptions", any(Interface.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateInterfaceOtherConfig", any(Interface.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+    }
+
+    @Test
+    public void testUpdatePort() throws Exception {
+        Port port = mock(Port.class);
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateVlan", Port.class, OvsdbTerminationPointAugmentationBuilder.class));
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateVlanTrunks", Port.class, OvsdbTerminationPointAugmentationBuilder.class));
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updateVlanMode", Port.class, OvsdbTerminationPointAugmentationBuilder.class));
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updatePortExternalIds", Port.class, OvsdbTerminationPointAugmentationBuilder.class));
+        MemberModifier.suppress(MemberMatcher.method(OvsdbPortUpdateCommand.class, "updatePortOtherConfig", Port.class, OvsdbTerminationPointAugmentationBuilder.class));
+
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updatePort", port, ovsdbTerminationPointBuilder);
+
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateVlan", any(Port.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateVlanTrunks", any(Port.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updateVlanMode", any(Port.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updatePortExternalIds", any(Port.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+        PowerMockito.verifyPrivate(ovsdbPortUpdateCommand).invoke("updatePortOtherConfig", any(Port.class), any(OvsdbTerminationPointAugmentationBuilder.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUpdateVlan() throws Exception {
+        Port port = mock(Port.class);
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        Column<GenericTableSchema, Set<Long>> column = mock(Column.class);
+        when(port.getTagColumn()).thenReturn(column);
+        Set<Long> vlanId = new HashSet<>();
+        vlanId.add((long) 808);
+        when(column.getData()).thenReturn(vlanId);
+        PowerMockito.whenNew(VlanId.class).withAnyArguments().thenReturn(mock(VlanId.class));
+        when(ovsdbTerminationPointBuilder.setVlanTag(any(VlanId.class))).thenReturn(ovsdbTerminationPointBuilder);
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateVlan", port, ovsdbTerminationPointBuilder);
+        verify(ovsdbTerminationPointBuilder).setVlanTag(any(VlanId.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUpdateVlanTrunks() throws Exception {
+        Port port = mock(Port.class);
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        Column<GenericTableSchema, Set<Long>> column = mock(Column.class);
+        when(port.getTrunksColumn()).thenReturn(column);
+        Set<Long> portTrunks = new HashSet<>();
+        portTrunks.add((long) 300);
+        when(column.getData()).thenReturn(portTrunks);
+
+        TrunksBuilder trunksBuilder = mock(TrunksBuilder.class);
+        PowerMockito.whenNew(TrunksBuilder.class).withNoArguments().thenReturn(trunksBuilder);
+        PowerMockito.whenNew(VlanId.class).withAnyArguments().thenReturn(mock(VlanId.class));
+        when(trunksBuilder.setTrunk(any(VlanId.class))).thenReturn(trunksBuilder);
+        when(ovsdbTerminationPointBuilder.setTrunks(any(List.class))).thenReturn(ovsdbTerminationPointBuilder);
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateVlanTrunks", port, ovsdbTerminationPointBuilder);
+        verify(trunksBuilder).setTrunk(any(VlanId.class));
+        verify(ovsdbTerminationPointBuilder).setTrunks(any(List.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUpdateVlanMode() throws Exception {
+        Port port = mock(Port.class);
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        Column<GenericTableSchema, Set<String>> column = mock(Column.class);
+        when(port.getVlanModeColumn()).thenReturn(column);
+        Set<String> set = new HashSet<>();
+        set.add(VLAN_MODE_ACCESS);
+        when(column.getData()).thenReturn(set);
+        when(ovsdbTerminationPointBuilder.setVlanMode(OvsdbPortInterfaceAttributes.VlanMode.Access)).thenReturn(ovsdbTerminationPointBuilder);
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateVlanMode", port, ovsdbTerminationPointBuilder);
+        verify(ovsdbTerminationPointBuilder).setVlanMode(any(VlanMode.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUpdateOfPort() throws Exception {
+        Interface interf = mock(Interface.class);
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        Set<Long> ofPorts = new HashSet<>();
+        ofPorts.add((long) 10000);
+        Column<GenericTableSchema, Set<Long>> column = mock(Column.class);
+        when(interf.getOpenFlowPortColumn()).thenReturn(column);
+        when(column.getData()).thenReturn(ofPorts);
+        when(ovsdbTerminationPointBuilder.setOfport(any(Long.class))).thenReturn(ovsdbTerminationPointBuilder);
+        when(interf.getName()).thenReturn(INTERFACE_NAME);
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateOfPort", interf, ovsdbTerminationPointBuilder);
+        verify(ovsdbTerminationPointBuilder).setOfport(any(Long.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUpdateOfPortRequest() throws Exception {
+        Interface interf = mock(Interface.class);
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        Set<Long> ofPortRequests = new HashSet<>();
+        ofPortRequests.add((long) 10000);
+        Column<GenericTableSchema, Set<Long>> column = mock(Column.class);
+        when(interf.getOpenFlowPortRequestColumn()).thenReturn(column);
+        when(column.getData()).thenReturn(ofPortRequests);
+        when(ovsdbTerminationPointBuilder.setOfportRequest(any(Integer.class))).thenReturn(ovsdbTerminationPointBuilder);
+        when(interf.getName()).thenReturn(INTERFACE_NAME);
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateOfPortRequest", interf, ovsdbTerminationPointBuilder);
+        verify(ovsdbTerminationPointBuilder).setOfportRequest(any(Integer.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUpdateInterfaceExternalIds() throws Exception {
+        Interface interf = mock(Interface.class);
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
+        when(interf.getExternalIdsColumn()).thenReturn(column);
+        Map<String, String> map = new HashMap<>();
+        when(column.getData()).thenReturn(map);
+        map.put(EXTERNAL_ID_KEY, EXTERNAL_ID_VALUE);
+        when(column.getData()).thenReturn(map);
+
+        InterfaceExternalIdsBuilder interfaceExternalIdsBuilder = mock(InterfaceExternalIdsBuilder.class);
+        PowerMockito.whenNew(InterfaceExternalIdsBuilder.class).withNoArguments().thenReturn(interfaceExternalIdsBuilder);
+
+        when(interfaceExternalIdsBuilder.setExternalIdKey(anyString())).thenReturn(interfaceExternalIdsBuilder);
+        when(interfaceExternalIdsBuilder.setExternalIdValue(anyString())).thenReturn(interfaceExternalIdsBuilder);
+        when(interfaceExternalIdsBuilder.build()).thenReturn(mock(InterfaceExternalIds.class));
+        when(ovsdbTerminationPointBuilder.setInterfaceExternalIds(any(List.class))).thenReturn(ovsdbTerminationPointBuilder);
+
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateInterfaceExternalIds", interf, ovsdbTerminationPointBuilder);
+        verify(interfaceExternalIdsBuilder).setExternalIdKey(anyString());
+        verify(interfaceExternalIdsBuilder).setExternalIdValue(anyString());
+
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUpdatePortExternalIds() throws Exception {
+        Port port = mock(Port.class);
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
+        when(port.getExternalIdsColumn()).thenReturn(column);
+        Map<String, String> map = new HashMap<>();
+        when(column.getData()).thenReturn(map);
+        map.put(EXTERNAL_ID_KEY, EXTERNAL_ID_VALUE);
+        when(column.getData()).thenReturn(map);
+
+        PortExternalIdsBuilder portExternalIdsBuilder = mock(PortExternalIdsBuilder.class);
+        PowerMockito.whenNew(PortExternalIdsBuilder.class).withNoArguments().thenReturn(portExternalIdsBuilder);
+
+        when(portExternalIdsBuilder.setExternalIdKey(anyString())).thenReturn(portExternalIdsBuilder);
+        when(portExternalIdsBuilder.setExternalIdValue(anyString())).thenReturn(portExternalIdsBuilder);
+        when(portExternalIdsBuilder.build()).thenReturn(mock(PortExternalIds.class));
+        when(ovsdbTerminationPointBuilder.setPortExternalIds(any(List.class))).thenReturn(ovsdbTerminationPointBuilder);
+
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updatePortExternalIds", port, ovsdbTerminationPointBuilder);
+        verify(portExternalIdsBuilder).setExternalIdKey(anyString());
+        verify(portExternalIdsBuilder).setExternalIdValue(anyString());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUpdatePortOtherConfig() throws Exception {
+        Port port = mock(Port.class);
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
+        when(port.getOtherConfigColumn()).thenReturn(column);
+        Map<String, String> map = new HashMap<>();
+        map.put(OTHER_CONFIG_KEY, OTHER_CONFIG_VALUE);
+        when(column.getData()).thenReturn(map);
+
+        PortOtherConfigsBuilder portOtherConfigsBuilder = mock(PortOtherConfigsBuilder.class);
+        PowerMockito.whenNew(PortOtherConfigsBuilder.class).withNoArguments().thenReturn(portOtherConfigsBuilder);
+
+        when(portOtherConfigsBuilder.setOtherConfigKey(anyString())).thenReturn(portOtherConfigsBuilder);
+        when(portOtherConfigsBuilder.setOtherConfigValue(anyString())).thenReturn(portOtherConfigsBuilder);
+        when(portOtherConfigsBuilder.build()).thenReturn(mock(PortOtherConfigs.class));
+        when(ovsdbTerminationPointBuilder.setInterfaceOtherConfigs(any(List.class))).thenReturn(ovsdbTerminationPointBuilder);
+
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updatePortOtherConfig", port, ovsdbTerminationPointBuilder);
+        verify(portOtherConfigsBuilder).setOtherConfigKey(anyString());
+        verify(portOtherConfigsBuilder).setOtherConfigValue(anyString());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUpdateInterfaceOtherConfig() throws Exception {
+        Interface interf = mock(Interface.class);
+        OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointBuilder = mock(OvsdbTerminationPointAugmentationBuilder.class);
+        Map<String, String> interfaceOtherConfigMap = new HashMap<>();
+        interfaceOtherConfigMap.put(OTHER_CONFIG_KEY, OTHER_CONFIG_VALUE);
+        Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
+        when(interf.getOtherConfigColumn()).thenReturn(column);
+        when(column.getData()).thenReturn(interfaceOtherConfigMap);
+
+        InterfaceOtherConfigsBuilder interfaceOtherConfigsBuilder = mock(InterfaceOtherConfigsBuilder.class);
+        PowerMockito.whenNew(InterfaceOtherConfigsBuilder.class).withNoArguments().thenReturn(interfaceOtherConfigsBuilder);
+
+        when(interfaceOtherConfigsBuilder.setOtherConfigKey(anyString())).thenReturn(interfaceOtherConfigsBuilder);
+        when(interfaceOtherConfigsBuilder.setOtherConfigValue(anyString())).thenReturn(interfaceOtherConfigsBuilder);
+        when(interfaceOtherConfigsBuilder.build()).thenReturn(mock(InterfaceOtherConfigs.class));
+        when(ovsdbTerminationPointBuilder.setInterfaceOtherConfigs(any(List.class))).thenReturn(ovsdbTerminationPointBuilder);
+
+        Whitebox.invokeMethod(ovsdbPortUpdateCommand, "updateInterfaceOtherConfig", interf, ovsdbTerminationPointBuilder);
+        verify(interfaceOtherConfigsBuilder).setOtherConfigKey(anyString());
+        verify(interfaceOtherConfigsBuilder).setOtherConfigValue(anyString());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGetInstanceIdentifier() throws Exception {
+        InstanceIdentifier<Node> bridgeIid = mock(InstanceIdentifier.class);
+        Port port = mock(Port.class);
+        Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
+        when(port.getExternalIdsColumn()).thenReturn(column);
+        Map<String, String> map = new HashMap<>();
+        map.put(SouthboundConstants.IID_EXTERNAL_ID_KEY, "opendaylight-iid");
+        when(column.getData()).thenReturn(map);
+
+        PowerMockito.mockStatic(SouthboundUtil.class);
+        InstanceIdentifier<TerminationPoint> terminationPointIId = mock(InstanceIdentifier.class);
+        PowerMockito.when((InstanceIdentifier<TerminationPoint>) SouthboundUtil.deserializeInstanceIdentifier(anyString())).thenReturn(terminationPointIId);
+        assertEquals(terminationPointIId, Whitebox.invokeMethod(ovsdbPortUpdateCommand, "getInstanceIdentifier", bridgeIid, port));
+    }
+}
\ No newline at end of file
diff --git a/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/TransactionInvokerImplTest.java b/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/transactions/md/TransactionInvokerImplTest.java
new file mode 100644 (file)
index 0000000..0060341
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2015 Inocybe Technologies 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.ovsdb.southbound.transactions.md;
+
+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.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+@PrepareForTest({TransactionInvokerImpl.class})
+@RunWith(PowerMockRunner.class)
+public class TransactionInvokerImplTest {
+    private static final int QUEUE_SIZE = 10000;
+    @Mock private BindingTransactionChain chain;
+    @Mock private DataBroker db;
+    private BlockingQueue<TransactionCommand> inputQueue = new LinkedBlockingQueue<TransactionCommand>(QUEUE_SIZE);
+    private BlockingQueue<ReadWriteTransaction> successfulTransactionQueue
+        = new LinkedBlockingQueue<ReadWriteTransaction>(QUEUE_SIZE);
+    private BlockingQueue<AsyncTransaction<?, ?>> failedTransactionQueue
+        = new LinkedBlockingQueue<AsyncTransaction<?, ?>>(QUEUE_SIZE);
+    @Mock private ExecutorService executor;
+    private Map<ReadWriteTransaction,TransactionCommand> transactionToCommand
+        = new HashMap<ReadWriteTransaction,TransactionCommand>();
+    private List<ReadWriteTransaction> pendingTransactions = new ArrayList<ReadWriteTransaction>();
+    private TransactionInvokerImpl transactionInvokerImpl;
+
+    @Before
+    public void setUp() throws Exception {
+        transactionInvokerImpl = PowerMockito.mock(TransactionInvokerImpl.class, Mockito.CALLS_REAL_METHODS);
+        MemberModifier.field(TransactionInvokerImpl.class, "chain").set(transactionInvokerImpl, chain);
+        MemberModifier.field(TransactionInvokerImpl.class, "db").set(transactionInvokerImpl, db);
+    }
+
+    @Test
+    public void testTransactionInvokerImpl() throws Exception {
+        MemberModifier.field(TransactionInvokerImpl.class, "inputQueue").set(transactionInvokerImpl, inputQueue);
+        when(db.createTransactionChain(any(TransactionChainListener.class))).thenReturn(mock(BindingTransactionChain.class));
+        TransactionInvokerImpl transactionInvokerImpl1 = new TransactionInvokerImpl(db);
+        verify(db).createTransactionChain(any(TransactionChainListener.class));
+        assertNotNull(Whitebox.getInternalState(transactionInvokerImpl1, "executor"));
+    }
+
+    @Test
+    public void testInvoke() throws Exception {
+        MemberModifier.field(TransactionInvokerImpl.class, "inputQueue").set(transactionInvokerImpl, inputQueue);
+        TransactionCommand command = mock(TransactionCommand.class);
+        transactionInvokerImpl.invoke(command);
+        BlockingQueue<TransactionCommand> testInputQueue = Whitebox.getInternalState(transactionInvokerImpl, "inputQueue");
+        assertTrue(testInputQueue.contains(command));
+    }
+
+    @Test
+    public void testOnTransactionChainFailed() throws Exception {
+        MemberModifier.field(TransactionInvokerImpl.class, "failedTransactionQueue").set(transactionInvokerImpl, failedTransactionQueue);
+        TransactionChain<?, ?> chain = mock(TransactionChain.class);
+        AsyncTransaction<?, ?> transaction = mock(AsyncTransaction.class);
+        Throwable cause = mock(Throwable.class);
+        transactionInvokerImpl.onTransactionChainFailed(chain, transaction, cause);
+        BlockingQueue<AsyncTransaction<?, ?>> testFailedTransactionQueue = Whitebox.getInternalState(transactionInvokerImpl, "failedTransactionQueue");
+        assertTrue(testFailedTransactionQueue.contains(transaction));
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Test
+    public void testExtractResubmitCommands() throws Exception {
+        AsyncTransaction<?, ?> transaction = mock(ReadWriteTransaction.class);
+        failedTransactionQueue.put(transaction);
+        MemberModifier.field(TransactionInvokerImpl.class, "failedTransactionQueue").set(transactionInvokerImpl, failedTransactionQueue);
+
+        AsyncTransaction tx1 = mock(ReadWriteTransaction.class);
+        AsyncTransaction tx2 = mock(ReadWriteTransaction.class);
+        pendingTransactions.add((ReadWriteTransaction) tx1);
+        pendingTransactions.add((ReadWriteTransaction) transaction);
+        pendingTransactions.add((ReadWriteTransaction) tx2);
+        MemberModifier.field(TransactionInvokerImpl.class, "pendingTransactions").set(transactionInvokerImpl, pendingTransactions);
+
+        List<ReadWriteTransaction> transactions= new ArrayList<ReadWriteTransaction>();
+        transactions.add((ReadWriteTransaction) tx1);
+
+        TransactionCommand txCommand = mock(TransactionCommand.class);
+        transactionToCommand.put((ReadWriteTransaction) tx1, txCommand);
+        transactionToCommand.put((ReadWriteTransaction) tx2, txCommand);
+        transactionToCommand.put((ReadWriteTransaction) transaction, txCommand);
+        MemberModifier.field(TransactionInvokerImpl.class, "transactionToCommand").set(transactionInvokerImpl, transactionToCommand);
+        PowerMockito.suppress(MemberModifier.method(TransactionInvokerImpl.class, "resetTransactionQueue"));
+
+        List<TransactionCommand> testCommands = new ArrayList<TransactionCommand>();
+        testCommands.add(txCommand);
+
+        assertEquals(testCommands, Whitebox.invokeMethod(transactionInvokerImpl, "extractResubmitCommands"));
+    }
+
+    @Test
+    public void testResetTransactionQueue() throws Exception {
+        doNothing().when(chain).close();
+        when(db.createTransactionChain(any(TransactionInvokerImpl.class))).thenReturn(chain);
+
+        failedTransactionQueue.add(mock(AsyncTransaction.class));
+        MemberModifier.field(TransactionInvokerImpl.class, "pendingTransactions").set(transactionInvokerImpl, pendingTransactions);
+        MemberModifier.field(TransactionInvokerImpl.class, "transactionToCommand").set(transactionInvokerImpl, transactionToCommand);
+        MemberModifier.field(TransactionInvokerImpl.class, "failedTransactionQueue").set(transactionInvokerImpl, failedTransactionQueue);
+        MemberModifier.field(TransactionInvokerImpl.class, "successfulTransactionQueue").set(transactionInvokerImpl, successfulTransactionQueue);
+
+        Whitebox.invokeMethod(transactionInvokerImpl, "resetTransactionQueue");
+        assertNotNull(Whitebox.getInternalState(transactionInvokerImpl, "pendingTransactions"));
+        assertNotNull(Whitebox.getInternalState(transactionInvokerImpl, "transactionToCommand"));
+        BlockingQueue<AsyncTransaction<?, ?>> testFailedTransactionQueue = Whitebox.getInternalState(transactionInvokerImpl, "failedTransactionQueue");
+        assertEquals(0, testFailedTransactionQueue.size());
+    }
+
+    @Test
+    public void testRecordPendingTransaction() throws Exception {
+        TransactionCommand command = mock(TransactionCommand.class);
+        ReadWriteTransaction transaction= mock(ReadWriteTransaction.class);
+        MemberModifier.field(TransactionInvokerImpl.class, "pendingTransactions").set(transactionInvokerImpl, pendingTransactions);
+        MemberModifier.field(TransactionInvokerImpl.class, "transactionToCommand").set(transactionInvokerImpl, transactionToCommand);
+        Whitebox.invokeMethod(transactionInvokerImpl, "recordPendingTransaction", command, transaction);
+
+        List<ReadWriteTransaction> testPendingTransactions = Whitebox.getInternalState(transactionInvokerImpl, "pendingTransactions");
+        assertEquals(1, testPendingTransactions.size());
+
+        Map<ReadWriteTransaction, TransactionCommand> testTransactionToCommand = Whitebox.getInternalState(transactionInvokerImpl, "transactionToCommand");
+        assertEquals(1, testTransactionToCommand.size());
+    }
+
+    @Test
+    public void testExtractCommands() throws Exception {
+        List<TransactionCommand> commands = new ArrayList<>();
+        PowerMockito.doReturn(commands).when(transactionInvokerImpl, "extractResubmitCommands");
+
+        List<TransactionCommand> resubmitCommands = new ArrayList<>();
+        resubmitCommands.add(mock(TransactionCommand.class));
+        PowerMockito.doReturn(resubmitCommands).when(transactionInvokerImpl, "extractCommandsFromQueue");
+
+        List<TransactionCommand> testCommands = new ArrayList<>();
+        testCommands.addAll(resubmitCommands);
+
+        assertEquals(testCommands, Whitebox.invokeMethod(transactionInvokerImpl, "extractCommands"));
+    }
+
+    @Test
+    public void testExtractCommandsFromQueue() throws Exception {
+        TransactionCommand command = mock(TransactionCommand.class);
+        inputQueue.add(command);
+        MemberModifier.field(TransactionInvokerImpl.class, "inputQueue").set(transactionInvokerImpl, inputQueue);
+        List<TransactionCommand> testResult = new ArrayList<TransactionCommand>();
+        testResult.add(command);
+        assertEquals(testResult, Whitebox.invokeMethod(transactionInvokerImpl, "extractCommandsFromQueue"));
+    }
+
+    @Test
+    public void testForgetSuccessfulTransactions() throws Exception {
+        ReadWriteTransaction transaction = mock(ReadWriteTransaction.class);
+        successfulTransactionQueue.add(transaction);
+        pendingTransactions.add(transaction);
+        transactionToCommand.put(transaction, mock(TransactionCommand.class));
+        MemberModifier.field(TransactionInvokerImpl.class, "successfulTransactionQueue").set(transactionInvokerImpl, successfulTransactionQueue);
+        MemberModifier.field(TransactionInvokerImpl.class, "pendingTransactions").set(transactionInvokerImpl, pendingTransactions);
+        MemberModifier.field(TransactionInvokerImpl.class, "transactionToCommand").set(transactionInvokerImpl, transactionToCommand);
+
+        Whitebox.invokeMethod(transactionInvokerImpl, "forgetSuccessfulTransactions");
+
+        List<ReadWriteTransaction> testPendingTransactions = Whitebox.getInternalState(transactionInvokerImpl, "pendingTransactions");
+        Map<ReadWriteTransaction, TransactionCommand> testTransactionToCommand = Whitebox.getInternalState(transactionInvokerImpl, "transactionToCommand");
+        assertTrue(testPendingTransactions.isEmpty());
+        assertTrue(testTransactionToCommand.isEmpty());
+    }
+
+    @Test
+    public void testClose() throws Exception {
+        MemberModifier.field(TransactionInvokerImpl.class, "executor").set(transactionInvokerImpl, executor);
+        doNothing().when(executor).shutdown();
+        transactionInvokerImpl.close();
+        verify(executor).shutdown();
+    }
+}
index f70e36eb284427084fb01a315a96b4ecbf2d1832..edfcee9744b1c84d8dc351f201e5da0f6f7f2be6 100644 (file)
@@ -19,17 +19,15 @@ import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRunti
 
 import com.google.common.collect.ImmutableBiMap;
 import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
 import java.io.File;
+import java.lang.reflect.Array;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
@@ -103,6 +101,7 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
+import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.Option;
@@ -124,11 +123,10 @@ import org.slf4j.LoggerFactory;
 @RunWith(PaxExam.class)
 @ExamReactorStrategy(PerClass.class)
 public class SouthboundIT extends AbstractMdsalTestBase {
-    private static final String EXPECTED_VALUES_KEY = "ExpectedValuesKey";
-    private static final String INPUT_VALUES_KEY = "InputValuesKey";
     private static final String NETDEV_DP_TYPE = "netdev";
     private static final Logger LOG = LoggerFactory.getLogger(SouthboundIT.class);
     private static final int OVSDB_UPDATE_TIMEOUT = 1000;
+    private static final String FORMAT_STR = "%s_%s_%d";
     public static final int NUM_THREADS = 4;
     private static String addressStr;
     private static String portStr;
@@ -366,7 +364,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                 .create(NetworkTopology.class)
                 .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
                 .child(Node.class,
-                        createNodeKey(connectionInfo.getRemoteIp(),connectionInfo.getRemotePort()));
+                        createNodeKey(connectionInfo.getRemoteIp(), connectionInfo.getRemotePort()));
     }
 
     private Node getOvsdbNode(final ConnectionInfo connectionInfo) {
@@ -873,562 +871,319 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
     }
 
-    /*
-     * Generates the test cases involved in testing PortExternalIds.  See inline comments for descriptions of
-     * the particular cases considered.
-     *
-     * The return value is a Map in the form (K,V)=(testCaseName,testCase).
-     * - testCaseName is a String
-     * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
-     *     either corresponding INPUT port external_ids, or EXPECTED port external_ids
-     *     INPUT    is the List we use when calling
-     *              <code>TerminationPointAugmentationBuilder.setPortExternalIds()</code>
-     *     EXPECTED is the List we expect to receive after calling
-     *              <code>TerminationPointAugmentationBuilder.getPortExternalIds()</code>
-     */
-    private Map<String, Map<String, List<PortExternalIds>>> generatePortExternalIdsTestCases() {
-        Map<String, Map<String, List<PortExternalIds>>> testMap = new HashMap<>();
+    private interface KeyValueBuilder<T> {
+        T build(String testName, String key, String value);
+        T[] build(String testName, int count, String key, String value);
+        void reset();
+    }
 
-        final String PORT_EXTERNAL_ID_KEY = "PortExternalIdKey";
-        final String PORT_EXTERNAL_ID_VALUE = "PortExternalIdValue";
-        final String FORMAT_STR = "%s_%s_%d";
-        final String GOOD_KEY = "GoodKey";
-        final String GOOD_VALUE = "GoodValue";
-        final String NO_VALUE_FOR_KEY = "NoValueForKey";
-        final String NO_KEY_FOR_VALUE = "NoKeyForValue";
+    private abstract static class BaseKeyValueBuilder<T> implements KeyValueBuilder<T> {
+        private static final int COUNTER_START = 0;
+        private int counter = COUNTER_START;
+        private final Class<T> builtClass;
 
-        // Test Case 1:  TestOneExternalId
-        // Test Type:    Positive
-        // Description:  Create a termination point with one PortExternalIds
-        // Expected:     A port is created with the single external_ids specified below
-        final String testOneExternalIdName = "TestOneExternalId";
-        int externalIdCounter = 0;
-        List<PortExternalIds> oneExternalId = Lists.newArrayList(
-                (new PortExternalIdsBuilder()
-                        .setExternalIdKey(String.format(FORMAT_STR, testOneExternalIdName,
-                                PORT_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setExternalIdValue(String.format(FORMAT_STR, testOneExternalIdName,
-                                PORT_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()));
-        Map<String,List<PortExternalIds>> testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, oneExternalId);
-        testCase.put(INPUT_VALUES_KEY, oneExternalId);
-        testMap.put(testOneExternalIdName, testCase);
-
-        // Test Case 2:  TestFiveExternalId
-        // Test Type:    Positive
-        // Description:  Create a termination point with multiple (five) PortExternalIds
-        // Expected:     A port is created with the five external_ids specified below
-        final String testFiveExternalIdName = "TestFiveExternalId";
-        externalIdCounter = 0;
-        List<PortExternalIds> fiveExternalId = Lists.newArrayList(
-                (new PortExternalIdsBuilder()
-                        .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                PORT_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                PORT_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()),
-                (new PortExternalIdsBuilder()
-                        .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                PORT_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                PORT_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()),
-                (new PortExternalIdsBuilder()
-                        .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                PORT_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                PORT_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()),
-                (new PortExternalIdsBuilder()
-                        .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                PORT_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                PORT_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()),
-                (new PortExternalIdsBuilder()
-                        .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                PORT_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                PORT_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()));
-        testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, fiveExternalId);
-        testCase.put(INPUT_VALUES_KEY, fiveExternalId);
-        testMap.put(testFiveExternalIdName, testCase);
-
-        // Test Case 3:  TestOneGoodExternalIdOneMalformedExternalIdValue
-        // Test Type:    Negative
-        // Description:
-        //     One perfectly fine PortExternalId
-        //        (TestOneGoodExternalIdOneMalformedExternalIdValue_PortExternalIdKey_1,
-        //        TestOneGoodExternalIdOneMalformedExternalId_PortExternalIdValue_1)
-        //     and one malformed PortExternalId which only has key specified
-        //        (TestOneGoodExternalIdOneMalformedExternalIdValue_NoValueForKey_2,
-        //        UNSPECIFIED)
-        // Expected:     A port is created without any external_ids
-        final String testOneGoodExternalIdOneMalformedExternalIdValueName =
-                "TestOneGoodExternalIdOneMalformedExternalIdValue";
-        externalIdCounter = 0;
-        PortExternalIds oneGood = new PortExternalIdsBuilder()
-                .setExternalIdKey(String.format(FORMAT_STR, testOneGoodExternalIdOneMalformedExternalIdValueName,
-                        GOOD_KEY, ++externalIdCounter))
-                .setExternalIdValue(String.format(FORMAT_STR,
-                        testOneGoodExternalIdOneMalformedExternalIdValueName,
-                        GOOD_VALUE, externalIdCounter))
-                .build();
-        PortExternalIds oneBad = new PortExternalIdsBuilder()
-                .setExternalIdKey(String.format(FORMAT_STR,
-                        testOneGoodExternalIdOneMalformedExternalIdValueName, NO_VALUE_FOR_KEY, ++externalIdCounter))
-                .build();
-        List<PortExternalIds> oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
-        List<PortExternalIds> oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodExternalIdOneMalformedExternalIdValueName, testCase);
-
-        // Test Case 4:  TestOneGoodExternalIdOneMalformedExternalIdKey
-        // Test Type:    Negative
-        // Description:
-        //     One perfectly fine PortExternalId
-        //        (TestOneGoodExternalIdOneMalformedExternalIdValue_PortExternalIdKey_1,
-        //        TestOneGoodExternalIdOneMalformedExternalId_PortExternalIdValue_1)
-        //     and one malformed PortExternalId which only has key specified
-        //        (UNSPECIFIED,
-        //        TestOneGoodExternalIdOneMalformedExternalIdKey_NoKeyForValue_2)
-        // Expected:     A port is created without any external_ids
-        final String testOneGoodExternalIdOneMalformedExternalIdKeyName =
-                "TestOneGoodExternalIdOneMalformedExternalIdKey";
-        externalIdCounter = 0;
-        oneGood = new PortExternalIdsBuilder()
-                .setExternalIdKey(String.format(FORMAT_STR, testOneGoodExternalIdOneMalformedExternalIdKeyName,
-                        GOOD_KEY, ++externalIdCounter))
-                .setExternalIdValue(String.format(FORMAT_STR,
-                        testOneGoodExternalIdOneMalformedExternalIdKeyName,
-                        GOOD_VALUE, externalIdCounter))
-                .build();
-        oneBad = new PortExternalIdsBuilder()
-                .setExternalIdKey(String.format(FORMAT_STR,
-                        testOneGoodExternalIdOneMalformedExternalIdKeyName, NO_KEY_FOR_VALUE, ++externalIdCounter))
-                .build();
-        oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
-        oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodExternalIdOneMalformedExternalIdKeyName, testCase);
+        protected abstract Builder<T> builder();
 
-        return testMap;
-    }
+        protected abstract void setKey(Builder<T> builder, String key);
 
-    /*
-     * @see <code>SouthboundIT.testCRUDPortExternalIds()</code>
-     * This is helper test method to compare a test "set" of BridgeExternalIds against an expected "set"
-     */
-    private void assertExpectedPortExternalIdsExist( List<PortExternalIds> expected,
-                                                     List<PortExternalIds> test ) {
+        protected abstract void setValue(Builder<T> builder, String value);
 
-        if (expected != null) {
-            for (PortExternalIds expectedExternalId : expected) {
-                Assert.assertTrue(test.contains(expectedExternalId));
+        @SuppressWarnings("unchecked")
+        private BaseKeyValueBuilder() {
+            builtClass = (Class<T>) this.getClass().getSuperclass().getTypeParameters()[0].getClass();
+        }
+
+        @Override
+        public final T build(final String testName, final String key, final String value) {
+            final Builder<T> builder = builder();
+            this.counter++;
+            if (key != null) {
+                setKey(builder, String.format(FORMAT_STR, testName, key, this.counter));
+            }
+            if (value != null) {
+                setValue(builder, String.format(FORMAT_STR, testName, value, this.counter));
             }
+            return builder.build();
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public final T[] build(final String testName, final int count, final String key, final String value) {
+            final T[] instances = (T[]) Array.newInstance(builtClass, count);
+            for (int idx = 0; idx < count; idx++) {
+                instances[idx] = build(testName, key, value);
+            }
+            return instances;
+        }
+
+        @Override
+        public final void reset() {
+            this.counter = COUNTER_START;
         }
     }
 
-    /*
-     * Tests the CRUD operations for <code>Port</code>
-     * <code>external_ids</code>.
-     *
-     * @see <code>SouthboundIT.generatePortExternalIdsTestCases()</code> for
-     * specific test case information
-     */
-    @Test
-    public void testCRUDTerminationPointPortExternalIds()
-            throws InterruptedException, ExecutionException {
+    private static final class SouthboundPortExternalIdsBuilder extends BaseKeyValueBuilder<PortExternalIds> {
+        @Override
+        protected Builder<PortExternalIds> builder() {
+            return new PortExternalIdsBuilder();
+        }
 
-        final String TEST_PREFIX = "CRUDTPPortExternalIds";
+        @Override
+        protected void setKey(Builder<PortExternalIds> builder, String key) {
+            ((PortExternalIdsBuilder) builder).setExternalIdKey(key);
+        }
 
-        ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
-        connectOvsdbNode(connectionInfo);
+        @Override
+        protected void setValue(Builder<PortExternalIds> builder, String value) {
+            ((PortExternalIdsBuilder) builder).setExternalIdValue(value);
+        }
+    }
 
-        // updateFromTestCases represent the original test case value.
-        // updateToTestCases represent the new value after the update has been
-        // performed.
-        Map<String, Map<String, List<PortExternalIds>>> updateFromTestCases =
-                generatePortExternalIdsTestCases();
-        Map<String, Map<String, List<PortExternalIds>>> updateToTestCases =
-                generatePortExternalIdsTestCases();
-        Map<String, List<PortExternalIds>> updateFromTestCase;
-        List<PortExternalIds> updateFromInputExternalIds;
-        List<PortExternalIds> updateFromExpectedExternalIds;
-        Map<String, List<PortExternalIds>> updateToTestCase;
-        List<PortExternalIds> updateToInputExternalIds;
-        List<PortExternalIds> updateToExpectedExternalIds;
-        String testBridgeName;
-        String testPortName;
+    private static final class SouthboundInterfaceExternalIdsBuilder extends BaseKeyValueBuilder<InterfaceExternalIds> {
+        @Override
+        protected Builder<InterfaceExternalIds> builder() {
+            return new InterfaceExternalIdsBuilder();
+        }
 
-        int counter = 1;
-        // multihreads the test using NUM_THREADS
-        ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
-        for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
-            updateFromTestCase = updateFromTestCases.get(
-                    updateFromTestCaseKey);
-            updateFromInputExternalIds = updateFromTestCase.get(
-                    INPUT_VALUES_KEY);
-            updateFromExpectedExternalIds = updateFromTestCase.get(
-                    EXPECTED_VALUES_KEY);
-            for (String testCaseKey : updateToTestCases.keySet()) {
-                testPortName = testBridgeName = String.format("%s_%s_%d",
-                        TEST_PREFIX, testCaseKey, counter);
-                counter += 1;
-                updateToTestCase = updateToTestCases.get(testCaseKey);
-                updateToInputExternalIds = updateToTestCase.get(
-                        INPUT_VALUES_KEY);
-                updateToExpectedExternalIds = updateToTestCase.get(
-                        EXPECTED_VALUES_KEY);
-                TestCRUDTerminationPointPortExternalIdsRunnable testRunnable =
-                        new TestCRUDTerminationPointPortExternalIdsRunnable(
-                                connectionInfo, testBridgeName, testPortName,
-                                updateFromInputExternalIds,
-                                updateFromExpectedExternalIds,
-                                updateToInputExternalIds,
-                                updateToExpectedExternalIds);
-                executor.submit(testRunnable);
-            }
+        @Override
+        protected void setKey(Builder<InterfaceExternalIds> builder, String key) {
+            ((InterfaceExternalIdsBuilder) builder).setExternalIdKey(key);
+        }
+
+        @Override
+        protected void setValue(Builder<InterfaceExternalIds> builder, String value) {
+            ((InterfaceExternalIdsBuilder) builder).setExternalIdValue(value);
         }
-        executor.shutdown();
-        executor.awaitTermination(5, TimeUnit.MINUTES);
-        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
     }
 
-    class TestCRUDTerminationPointPortExternalIdsRunnable implements Runnable {
-        ConnectionInfo connectionInfo;
-        String testBridgeName;
-        String testPortName;
-        List<PortExternalIds> updateFromInputExternalIds;
-        List<PortExternalIds> updateFromExpectedExternalIds;
-        List<PortExternalIds> updateToInputExternalIds;
-        List<PortExternalIds> updateToExpectedExternalIds;
-
-        public TestCRUDTerminationPointPortExternalIdsRunnable(
-                ConnectionInfo connectionInfo,
-                String testBridgeName, String testPortName,
-                List<PortExternalIds> updateFromInputExternalIds,
-                List<PortExternalIds> updateFromExpectedExternalIds,
-                List<PortExternalIds> updateToInputExternalIds,
-                List<PortExternalIds> updateToExpectedExternalIds) {
+    private static final class SouthboundOptionsBuilder extends BaseKeyValueBuilder<Options> {
+        @Override
+        protected Builder<Options> builder() {
+            return new OptionsBuilder();
+        }
 
-            this.connectionInfo = connectionInfo;
-            this.testBridgeName = testBridgeName;
-            this.testPortName = testPortName;
-            this.updateFromInputExternalIds = updateFromInputExternalIds;
-            this.updateFromExpectedExternalIds = updateFromExpectedExternalIds;
-            this.updateToInputExternalIds = updateToInputExternalIds;
-            this.updateToExpectedExternalIds = updateToExpectedExternalIds;
+        @Override
+        protected void setKey(Builder<Options> builder, String key) {
+            ((OptionsBuilder) builder).setOption(key);
         }
 
         @Override
-        public void run() {
-            try {
-                test();
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
+        protected void setValue(Builder<Options> builder, String value) {
+            ((OptionsBuilder) builder).setValue(value);
         }
+    }
 
-        private void test() throws InterruptedException {
+    private static final class SouthboundInterfaceOtherConfigsBuilder extends BaseKeyValueBuilder<InterfaceOtherConfigs> {
+        @Override
+        protected Builder<InterfaceOtherConfigs> builder() {
+            return new InterfaceOtherConfigsBuilder();
+        }
 
-            final int TERMINATION_POINT_TEST_INDEX = 0;
-            // CREATE: Create the test bridge
-            Assert.assertTrue(addBridge(connectionInfo, null,
-                    testBridgeName, null, true,
-                    SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
-                    true, null, null, null, null));
-            NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
-                    connectionInfo, new OvsdbBridgeName(testBridgeName)));
-            OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
-                    createGenericOvsdbTerminationPointAugmentationBuilder();
-            tpCreateAugmentationBuilder.setName(testPortName);
-            tpCreateAugmentationBuilder.setPortExternalIds(updateFromInputExternalIds);
-            Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
+        @Override
+        protected void setKey(Builder<InterfaceOtherConfigs> builder, String key) {
+            ((InterfaceOtherConfigsBuilder) builder).setOtherConfigKey(key);
+        }
 
-            // READ: Read the test port and ensure changes are propagated to the CONFIGURATION data store,
-            // then repeat for OPERATIONAL data store
-            OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-            List<PortExternalIds> updateFromConfigurationExternalIds =
-                    updateFromConfigurationTerminationPointAugmentation
-                            .getPortExternalIds();
-            assertExpectedPortExternalIdsExist(updateFromExpectedExternalIds, updateFromConfigurationExternalIds);
-            OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmenation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-            List<PortExternalIds> updateFromOperationalExternalIds = updateFromOperationalTerminationPointAugmenation
-                    .getPortExternalIds();
-            assertExpectedPortExternalIdsExist(updateFromExpectedExternalIds, updateFromOperationalExternalIds);
+        @Override
+        protected void setValue(Builder<InterfaceOtherConfigs> builder, String value) {
+            ((InterfaceOtherConfigsBuilder) builder).setOtherConfigValue(value);
+        }
+    }
 
-            // UPDATE:  update the external_ids
-            testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
-            OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
-                    new OvsdbTerminationPointAugmentationBuilder();
-            tpUpdateAugmentationBuilder.setPortExternalIds(updateToInputExternalIds);
-            InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
-            NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
-            NodeId portUpdateNodeId = createManagedNodeId(portIid);
-            portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
-            TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
-            tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
-            tpUpdateBuilder.addAugmentation(
-                    OvsdbTerminationPointAugmentation.class,
-                    tpUpdateAugmentationBuilder.build());
-            portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
-            boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
-                    portIid, portUpdateNodeBuilder.build());
-            Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-            Assert.assertTrue(result);
+    private static final class SouthboundPortOtherConfigsBuilder extends BaseKeyValueBuilder<PortOtherConfigs> {
+        @Override
+        protected Builder<PortOtherConfigs> builder() {
+            return new PortOtherConfigsBuilder();
+        }
 
-            // READ: the test port and ensure changes are propagated to the CONFIGURATION data store,
-            // then repeat for OPERATIONAL data store
-            OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-            List<PortExternalIds> updateToConfigurationExternalIds = updateToConfigurationTerminationPointAugmentation
-                    .getPortExternalIds();
-            assertExpectedPortExternalIdsExist(updateToExpectedExternalIds, updateToConfigurationExternalIds);
-            assertExpectedPortExternalIdsExist(updateFromExpectedExternalIds, updateToConfigurationExternalIds);
-            OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-            List<PortExternalIds> updateToOperationalExternalIds =
-                    updateToOperationalTerminationPointAugmentation.getPortExternalIds();
-            if (updateFromExpectedExternalIds != null) {
-                assertExpectedPortExternalIdsExist(updateToExpectedExternalIds, updateToOperationalExternalIds);
-                assertExpectedPortExternalIdsExist(updateFromExpectedExternalIds, updateToOperationalExternalIds);
-            }
+        @Override
+        protected void setKey(Builder<PortOtherConfigs> builder, String key) {
+            ((PortOtherConfigsBuilder) builder).setOtherConfigKey(key);
+        }
 
-            // DELETE
-            Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
+        @Override
+        protected void setValue(Builder<PortOtherConfigs> builder, String value) {
+            ((PortOtherConfigsBuilder) builder).setOtherConfigValue(value);
         }
     }
 
+    private static final class SouthboundBridgeOtherConfigsBuilder extends BaseKeyValueBuilder<BridgeOtherConfigs> {
+        @Override
+        protected Builder<BridgeOtherConfigs> builder() {
+            return new BridgeOtherConfigsBuilder();
+        }
 
+        @Override
+        protected void setKey(Builder<BridgeOtherConfigs> builder, String key) {
+            ((BridgeOtherConfigsBuilder) builder).setBridgeOtherConfigKey(key);
+        }
+
+        @Override
+        protected void setValue(Builder<BridgeOtherConfigs> builder, String value) {
+            ((BridgeOtherConfigsBuilder) builder).setBridgeOtherConfigValue(value);
+        }
+    }
+
+    private static final class SouthboundBridgeExternalIdsBuilder extends BaseKeyValueBuilder<BridgeExternalIds> {
+        @Override
+        protected Builder<BridgeExternalIds> builder() {
+            return new BridgeExternalIdsBuilder();
+        }
+
+        @Override
+        protected void setKey(Builder<BridgeExternalIds> builder, String key) {
+            ((BridgeExternalIdsBuilder) builder).setBridgeExternalIdKey(key);
+        }
+
+        @Override
+        protected void setValue(Builder<BridgeExternalIds> builder, String value) {
+            ((BridgeExternalIdsBuilder) builder).setBridgeExternalIdValue(value);
+        }
+    }
 
     /*
-     * Generates the test cases involved in testing InterfaceExternalIds.  See inline comments for descriptions of
+     * Generates the test cases involved in testing key-value-based data.  See inline comments for descriptions of
      * the particular cases considered.
-     *
-     * The return value is a Map in the form (K,V)=(testCaseName,testCase).
-     * - testCaseName is a String
-     * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
-     *     either corresponding INPUT interface external_ids, or EXPECTED interface external_ids
-     *     INPUT    is the List we use when calling
-     *              <code>TerminationPointAugmentationBuilder.setInterfaceExternalIds()</code>
-     *     EXPECTED is the List we expect to receive after calling
-     *              <code>TerminationPointAugmentationBuilder.getInterfaceExternalIds()</code>
      */
-    private Map<String, Map<String, List<InterfaceExternalIds>>> generateInterfaceExternalIdsTestCases() {
-        Map<String, Map<String, List<InterfaceExternalIds>>> testMap = new HashMap<>();
+    private static <T> List<SouthboundTestCase<T>> generateKeyValueTestCases(
+            KeyValueBuilder<T> builder, String idKey, String idValue) {
+        List<SouthboundTestCase<T>> testCases = new ArrayList<>();
 
-        final String INTERFACE_EXTERNAL_ID_KEY = "IntExternalIdKey";
-        final String INTERFACE_EXTERNAL_ID_VALUE = "IntExternalIdValue";
-        final String FORMAT_STR = "%s_%s_%d";
         final String GOOD_KEY = "GoodKey";
         final String GOOD_VALUE = "GoodValue";
         final String NO_VALUE_FOR_KEY = "NoValueForKey";
         final String NO_KEY_FOR_VALUE = "NoKeyForValue";
 
-        // Test Case 1:  TestOneExternalId
+        // Test Case 1:  TestOne
         // Test Type:    Positive
-        // Description:  Create a termination point with one InterfaceExternalIds
-        // Expected:     A termination point is created with the single external_ids specified below
-        final String testOneExternalIdName = "TestOneExternalId";
-        int externalIdCounter = 0;
-        List<InterfaceExternalIds> oneExternalId = Lists.newArrayList(
-                (new InterfaceExternalIdsBuilder()
-                        .setExternalIdKey(String.format(FORMAT_STR, testOneExternalIdName,
-                                INTERFACE_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setExternalIdValue(String.format(FORMAT_STR, testOneExternalIdName,
-                                INTERFACE_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()));
-        Map<String,List<InterfaceExternalIds>> testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, oneExternalId);
-        testCase.put(INPUT_VALUES_KEY, oneExternalId);
-        testMap.put(testOneExternalIdName, testCase);
-
-        // Test Case 2:  TestFiveExternalId
+        // Description:  Create a termination point with one value
+        // Expected:     A port is created with the single value specified below
+        final String testOneName = "TestOne";
+        testCases.add(new SouthboundTestCaseBuilder<T>()
+                .name(testOneName)
+                .input(builder.build(testOneName, idKey, idValue))
+                .expectInputAsOutput()
+                .build());
+        builder.reset();
+
+        // Test Case 2:  TestFive
         // Test Type:    Positive
-        // Description:  Create a termination point with multiple (five) InterfaceExternalIds
-        // Expected:     A termination point is created with the five external_ids specified below
-        final String testFiveExternalIdName = "TestFiveExternalId";
-        externalIdCounter = 0;
-        List<InterfaceExternalIds> fiveExternalId = Lists.newArrayList(
-                (new InterfaceExternalIdsBuilder()
-                        .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                INTERFACE_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                INTERFACE_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()),
-                (new InterfaceExternalIdsBuilder()
-                        .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                INTERFACE_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                INTERFACE_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()),
-                (new InterfaceExternalIdsBuilder()
-                        .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                INTERFACE_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                INTERFACE_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()),
-                (new InterfaceExternalIdsBuilder()
-                        .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                INTERFACE_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                INTERFACE_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()),
-                (new InterfaceExternalIdsBuilder()
-                        .setExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                INTERFACE_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                INTERFACE_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()));
-        testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, fiveExternalId);
-        testCase.put(INPUT_VALUES_KEY, fiveExternalId);
-        testMap.put(testFiveExternalIdName, testCase);
-
-        // Test Case 3:  TestOneGoodExternalIdOneMalformedExternalIdValue
+        // Description:  Create a termination point with multiple (five) values
+        // Expected:     A port is created with the five values specified below
+        final String testFiveName = "TestFive";
+        testCases.add(new SouthboundTestCaseBuilder<T>()
+                .name(testFiveName)
+                .input(builder.build(testFiveName, 5, idKey, idValue))
+                .expectInputAsOutput()
+                .build());
+        builder.reset();
+
+        // Test Case 3:  TestOneGoodOneMalformedValue
         // Test Type:    Negative
         // Description:
-        //     One perfectly fine InterfaceExternalId
-        //        (TestOneGoodExternalIdOneMalformedExternalIdValue_IntExternalIdKey_1,
-        //        TestOneGoodExternalIdOneMalformedExternalId_IntExternalIdValue_1)
-        //     and one malformed PortExternalId which only has key specified
-        //        (TestOneGoodExternalIdOneMalformedExternalIdValue_NoValueForKey_2,
+        //     One perfectly fine input
+        //        (TestOneGoodOneMalformedValue_GoodKey_1,
+        //        TestOneGoodOneMalformedValue_GoodValue_1)
+        //     and one malformed input which only has key specified
+        //        (TestOneGoodOneMalformedValue_NoValueForKey_2,
         //        UNSPECIFIED)
-        // Expected:     A termination point is created without any external_ids
-        final String testOneGoodExternalIdOneMalformedExternalIdValueName =
-                "TestOneGoodExternalIdOneMalformedExternalIdValue";
-        externalIdCounter = 0;
-        InterfaceExternalIds oneGood = new InterfaceExternalIdsBuilder()
-                .setExternalIdKey(String.format(FORMAT_STR, testOneGoodExternalIdOneMalformedExternalIdValueName,
-                        GOOD_KEY, ++externalIdCounter))
-                .setExternalIdValue(String.format(FORMAT_STR,
-                        testOneGoodExternalIdOneMalformedExternalIdValueName,
-                        GOOD_VALUE, externalIdCounter))
-                .build();
-        InterfaceExternalIds oneBad = new InterfaceExternalIdsBuilder()
-                .setExternalIdKey(String.format(FORMAT_STR,
-                        testOneGoodExternalIdOneMalformedExternalIdValueName, NO_VALUE_FOR_KEY, ++externalIdCounter))
-                .build();
-        List<InterfaceExternalIds> oneGoodOneBadInput = Lists.newArrayList(
-                oneGood, oneBad);
-        List<InterfaceExternalIds> oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodExternalIdOneMalformedExternalIdValueName, testCase);
-
-        // Test Case 4:  TestOneGoodExternalIdOneMalformedExternalIdKey
+        // Expected:     A port is created without any values
+        final String testOneGoodOneMalformedValueName = "TestOneGoodOneMalformedValue";
+        testCases.add(new SouthboundTestCaseBuilder<T>()
+                .name(testOneGoodOneMalformedValueName)
+                .input(
+                        builder.build(testOneGoodOneMalformedValueName, GOOD_KEY, GOOD_VALUE),
+                        builder.build(testOneGoodOneMalformedValueName, NO_VALUE_FOR_KEY, null)
+                )
+                .expect()
+                .build());
+        builder.reset();
+
+        // Test Case 4:  TestOneGoodOneMalformedKey
         // Test Type:    Negative
         // Description:
-        //     One perfectly fine InterfaceExternalId
-        //        (TestOneGoodExternalIdOneMalformedExternalIdValue_IntExternalIdKey_1,
-        //        TestOneGoodExternalIdOneMalformedExternalId_IntExternalIdValue_1)
-        //     and one malformed BridgeExternalId which only has key specified
+        //     One perfectly fine input
+        //        (TestOneGoodOneMalformedKey_GoodKey_1,
+        //        TestOneGoodOneMalformedKey_GoodValue_1)
+        //     and one malformed input which only has value specified
         //        (UNSPECIFIED,
-        //        TestOneGoodExternalIdOneMalformedExternalIdKey_NoKeyForValue_2)
-        // Expected:     A termination point is created without any external_ids
-        final String testOneGoodExternalIdOneMalformedExternalIdKeyName =
-                "TestOneGoodExternalIdOneMalformedExternalIdKey";
-        externalIdCounter = 0;
-        oneGood = new InterfaceExternalIdsBuilder()
-                .setExternalIdKey(String.format(FORMAT_STR, testOneGoodExternalIdOneMalformedExternalIdKeyName,
-                        GOOD_KEY, ++externalIdCounter))
-                .setExternalIdValue(String.format(FORMAT_STR,
-                        testOneGoodExternalIdOneMalformedExternalIdKeyName,
-                        GOOD_VALUE, externalIdCounter))
-                .build();
-        oneBad = new InterfaceExternalIdsBuilder()
-                .setExternalIdKey(String.format(FORMAT_STR,
-                        testOneGoodExternalIdOneMalformedExternalIdKeyName, NO_KEY_FOR_VALUE, ++externalIdCounter))
-                .build();
-        oneGoodOneBadInput = Lists.newArrayList(
-                oneGood, oneBad);
-        oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodExternalIdOneMalformedExternalIdKeyName, testCase);
+        //        TestOneGoodOneMalformedKey_NoKeyForValue_2)
+        // Expected:     A port is created without any values
+        final String testOneGoodOneMalformedKeyName = "TestOneGoodOneMalformedKey";
+        testCases.add(new SouthboundTestCaseBuilder<T>()
+                .name(testOneGoodOneMalformedKeyName)
+                .input(
+                        builder.build(testOneGoodOneMalformedKeyName, GOOD_KEY, GOOD_VALUE),
+                        builder.build(testOneGoodOneMalformedKeyName, null, NO_KEY_FOR_VALUE)
+                )
+                .expect()
+                .build());
+        builder.reset();
 
-        return testMap;
+        return testCases;
     }
 
     /*
-     * @see <code>SouthboundIT.testCRUDInterfaceExternalIds()</code>
-     * This is helper test method to compare a test "set" of InterfaceExternalIds against an expected "set"
+     * Generates the test cases involved in testing PortExternalIds.  See inline comments for descriptions of
+     * the particular cases considered.
      */
-    private void assertExpectedInterfaceExternalIdsExist( List<InterfaceExternalIds> expected,
-                                                          List<InterfaceExternalIds> test ) {
-
-        if (expected != null) {
-            for (InterfaceExternalIds expectedExternalId : expected) {
-                Assert.assertTrue(test.contains(expectedExternalId));
-            }
-        }
+    private List<SouthboundTestCase<PortExternalIds>> generatePortExternalIdsTestCases() {
+        return generateKeyValueTestCases(new SouthboundPortExternalIdsBuilder(), "PortExternalIdKey",
+                "PortExternalIdValue");
     }
 
     /*
-     * Tests the CRUD operations for <code>Interface</code> <code>external_ids</code>.
+     * Tests the CRUD operations for <code>Port</code>
+     * <code>external_ids</code>.
      *
-     * @see <code>SouthboundIT.generateInterfaceExternalIdsTestCases()</code> for specific test case information
+     * @see <code>SouthboundIT.generatePortExternalIdsTestCases()</code> for
+     * specific test case information
      */
     @Test
-    public void testCRUDTerminationPointInterfaceExternalIds() throws InterruptedException, ExecutionException {
-        final String TEST_PREFIX = "CRUDTPInterfaceExternalIds";
+    public void testCRUDTerminationPointPortExternalIds()
+            throws InterruptedException, ExecutionException {
+
+        final String TEST_PREFIX = "CRUDTPPortExternalIds";
 
         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
         connectOvsdbNode(connectionInfo);
 
-        // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
-        // the update has been performed.
-        Map<String, Map<String, List<InterfaceExternalIds>>> updateFromTestCases =
-                generateInterfaceExternalIdsTestCases();
-        Map<String, Map<String, List<InterfaceExternalIds>>> updateToTestCases =
-                generateInterfaceExternalIdsTestCases();
-        Map<String, List<InterfaceExternalIds>> updateFromTestCase;
-        List<InterfaceExternalIds> updateFromInputExternalIds;
-        List<InterfaceExternalIds> updateFromExpectedExternalIds;
-        Map<String, List<InterfaceExternalIds>> updateToTestCase;
-        List<InterfaceExternalIds> updateToInputExternalIds;
-        List<InterfaceExternalIds> updateToExpectedExternalIds;
+        // updateFromTestCases represent the original test case value.
+        // updateToTestCases represent the new value after the update has been
+        // performed.
+        List<SouthboundTestCase<PortExternalIds>> updateFromTestCases = generatePortExternalIdsTestCases();
+        List<SouthboundTestCase<PortExternalIds>> updateToTestCases = generatePortExternalIdsTestCases();
         String testBridgeName;
         String testPortName;
 
         int counter = 1;
         // multihreads the test using NUM_THREADS
         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
-        for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
-            updateFromTestCase = updateFromTestCases.get(updateFromTestCaseKey);
-            updateFromInputExternalIds = updateFromTestCase.get(INPUT_VALUES_KEY);
-            updateFromExpectedExternalIds = updateFromTestCase.get(EXPECTED_VALUES_KEY);
-            for (String testCaseKey : updateToTestCases.keySet()) {
-                testPortName = testBridgeName = String.format("%s_%s_%d", TEST_PREFIX, testCaseKey, counter);
+        for (SouthboundTestCase<PortExternalIds> fromTestCase : updateFromTestCases) {
+            for (SouthboundTestCase<PortExternalIds> toTestCase : updateToTestCases) {
+                testPortName = testBridgeName = String.format(FORMAT_STR,
+                        TEST_PREFIX, toTestCase.name, counter);
                 counter += 1;
-                updateToTestCase = updateToTestCases.get(testCaseKey);
-                updateToInputExternalIds = updateToTestCase.get(INPUT_VALUES_KEY);
-                updateToExpectedExternalIds = updateToTestCase.get(EXPECTED_VALUES_KEY);
-
-                TestCRUDTerminationPointInterfaceExternalIdsRunnable testRunnable =
-                        new TestCRUDTerminationPointInterfaceExternalIdsRunnable(
-                                connectionInfo, testBridgeName, testPortName,
-                                updateFromInputExternalIds,
-                                updateFromExpectedExternalIds,
-                                updateToInputExternalIds,
-                                updateToExpectedExternalIds);
-                executor.submit(testRunnable);
+                executor.submit(new TestCRUDTerminationPointRunnable<>(
+                        new SouthboundTestHelper<PortExternalIds>() {
+                            @Override
+                            public List<PortExternalIds> readValues(
+                                    OvsdbTerminationPointAugmentation augmentation) {
+                                return augmentation.getPortExternalIds();
+                            }
+
+                            @Override
+                            public void writeValues(
+                                    OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
+                                    List<PortExternalIds> updateFromInput) {
+                                augmentationBuilder.setPortExternalIds(updateFromInput);
+                            }
+                        },
+                        connectionInfo, testBridgeName, testPortName,
+                        fromTestCase.inputValues,
+                        fromTestCase.expectedValues,
+                        toTestCase.inputValues,
+                        toTestCase.expectedValues));
             }
         }
         executor.shutdown();
@@ -1436,337 +1191,231 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
     }
 
-    class TestCRUDTerminationPointInterfaceExternalIdsRunnable implements Runnable {
-
-        ConnectionInfo connectionInfo;
-        String testBridgeName;
-        String testPortName;
-        List<InterfaceExternalIds> updateFromInputExternalIds;
-        List<InterfaceExternalIds> updateFromExpectedExternalIds;
-        List<InterfaceExternalIds> updateToInputExternalIds;
-        List<InterfaceExternalIds> updateToExpectedExternalIds;
-
-        TestCRUDTerminationPointInterfaceExternalIdsRunnable(
-                ConnectionInfo connectionInfo, String testBridgeName,
-                String testPortName,
-                List<InterfaceExternalIds> updateFromInputExternalIds,
-                List<InterfaceExternalIds> updateFromExpectedExternalIds,
-                List<InterfaceExternalIds> updateToInputExternalIds,
-                List<InterfaceExternalIds> updateToExpectedExternalIds) {
+    /**
+     * Southbound test helper. Classes implementing this interface are used to provide concrete access to the input and
+     * output of the underlying augmentation for the type being managed.
+     *
+     * @param <T> The type of data used for the test case.
+     */
+    private interface SouthboundTestHelper<T> {
+        /**
+         * Read the values from the augmentation. These would usually be checked against the expected values provided
+         * for the test case.
+         *
+         * @param augmentation The augmentation to read from.
+         * @return The values read.
+         */
+        List<T> readValues(OvsdbTerminationPointAugmentation augmentation);
+
+        /**
+         * Write the values to the augmentation (via its builder). This would usually be used to apply the input values
+         * provided for the test case.
+         *
+         * @param augmentationBuilder The augmentation builder.
+         * @param values The values to write.
+         */
+        void writeValues(OvsdbTerminationPointAugmentationBuilder augmentationBuilder, List<T> values);
+    }
 
+    /**
+     * <p>
+     * Test runner used to apply a suite of create/read/update/delete tests. Each instance of a runner expects:
+     * </p>
+     * <ul>
+     * <li>a helper used to manipulate the appropriate data structures in the termination point augmentation (see
+     * {@link SouthboundTestHelper});</li>
+     * <li>connection information for the southbound;</li>
+     * <li>a name to use for the test bridge (this allows multiple tests to be conducted in parallel against different
+     * bridges);</li>
+     * <li>a name to use for the test port;</li>
+     * <li>the initial input values to use for the termination point augmentation;</li>
+     * <li>the initial expected values to check the augmentation against;</li>
+     * <li>the target input values to update the terminal point to;</li>
+     * <li>the target expected values to check the augmentation point against.</li>
+     * </ul>
+     * <p>The following tests are performed:</p>
+     * <ol>
+     * <li>the bridge is added;</li>
+     * <li>the termination point is added, with the provided initial input values;</li>
+     * <li>the termination point is read from the <em>configuration</em> data store, and checked against the provided
+     * initial expected values;</li>
+     * <li>the termination point is read from the <em>operational</em> data store, and checked against the provided
+     * initial expected values;</li>
+     * <li>the termination point is updated by merging the provided target input values;</li>
+     * <li>the termination point is read from the <em>configuration</em> data store, and checked against the provided
+     * initial <b>and</b> target expected values;</li>
+     * <li>the termination point is read from the <em>operational</em> data store, and checked against the provided
+     * initial <b>and</b> target expected values;</li>
+     * <li>the bridge is deleted.</li>
+     * </ol>
+     *
+     * @param <T> The type of data used for the test case.
+     */
+    private final class TestCRUDTerminationPointRunnable<T> implements Runnable {
+        private final SouthboundTestHelper<T> helper;
+        private final ConnectionInfo connectionInfo;
+        private final String testBridgeName;
+        private final String testPortName;
+        private final List<T> updateFromInput;
+        private final List<T> updateFromExpected;
+        private final List<T> updateToInput;
+        private final List<T> updateToExpected;
+
+        private TestCRUDTerminationPointRunnable(
+                SouthboundTestHelper<T> helper, ConnectionInfo connectionInfo, String testBridgeName,
+                String testPortName, List<T> updateFromInput, List<T> updateFromExpected, List<T> updateToInput,
+                List<T> updateToExpected) {
+            this.helper = helper;
             this.connectionInfo = connectionInfo;
             this.testBridgeName = testBridgeName;
             this.testPortName = testPortName;
-            this.updateFromInputExternalIds = updateFromInputExternalIds;
-            this.updateFromExpectedExternalIds = updateFromExpectedExternalIds;
-            this.updateToInputExternalIds = updateToInputExternalIds;
-            this.updateToExpectedExternalIds = updateToExpectedExternalIds;
+            this.updateFromInput = updateFromInput;
+            this.updateFromExpected = updateFromExpected;
+            this.updateToInput = updateToInput;
+            this.updateToExpected = updateToExpected;
         }
 
         @Override
         public void run() {
             try {
-                test();
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-
-        public void test() throws InterruptedException {
-
-            final int TERMINATION_POINT_TEST_INDEX = 0;
-            // CREATE: Create the test interface
-            Assert.assertTrue(addBridge(connectionInfo, null,
-                    testBridgeName, null, true, SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
-                    true, null, null, null, null));
-            NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
-                    connectionInfo, new OvsdbBridgeName(testBridgeName)));
-            OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
-                    createGenericOvsdbTerminationPointAugmentationBuilder();
-            tpCreateAugmentationBuilder.setName(testPortName);
-            tpCreateAugmentationBuilder.setInterfaceExternalIds(updateFromInputExternalIds);
-            Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
-
-            // READ: Read the test interface and ensure changes are propagated to the CONFIGURATION data store,
-            // then repeat for OPERATIONAL data store
-            OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-            List<InterfaceExternalIds> updateFromConfigurationExternalIds =
-                    updateFromConfigurationTerminationPointAugmentation
-                            .getInterfaceExternalIds();
-            assertExpectedInterfaceExternalIdsExist(updateFromExpectedExternalIds,
-                    updateFromConfigurationExternalIds);
-            OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmenation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-            List<InterfaceExternalIds> updateFromOperationalExternalIds =
-                    updateFromOperationalTerminationPointAugmenation
-                            .getInterfaceExternalIds();
-            assertExpectedInterfaceExternalIdsExist(updateFromExpectedExternalIds,
-                    updateFromOperationalExternalIds);
-
-            // UPDATE:  update the external_ids
-            testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
-            OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
-                    new OvsdbTerminationPointAugmentationBuilder();
-            tpUpdateAugmentationBuilder.setInterfaceExternalIds(updateToInputExternalIds);
-            InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
-            NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
-            NodeId portUpdateNodeId = createManagedNodeId(portIid);
-            portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
-            TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
-            tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
-            tpUpdateBuilder.addAugmentation(
-                    OvsdbTerminationPointAugmentation.class,
-                    tpUpdateAugmentationBuilder.build());
-            portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
-            boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
-                    portIid, portUpdateNodeBuilder.build());
-            Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-            Assert.assertTrue(result);
+                final int TERMINATION_POINT_TEST_INDEX = 0;
+                // CREATE: Create the test bridge
+                Assert.assertTrue(addBridge(connectionInfo, null,
+                        testBridgeName, null, true,
+                        SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
+                        true, null, null, null, null));
+                NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
+                        connectionInfo, new OvsdbBridgeName(testBridgeName)));
+                OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
+                        createGenericOvsdbTerminationPointAugmentationBuilder();
+                tpCreateAugmentationBuilder.setName(testPortName);
+                helper.writeValues(tpCreateAugmentationBuilder, updateFromInput);
+                Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
+
+                // READ: Read the test port and ensure changes are propagated to the CONFIGURATION data store,
+                // then repeat for OPERATIONAL data store
+                OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
+                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
+                                LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
+                List<T> updateFromConfiguration = null;
+                if (updateFromConfigurationTerminationPointAugmentation != null) {
+                    updateFromConfiguration =
+                        helper.readValues(updateFromConfigurationTerminationPointAugmentation);
+                }
+                if (updateFromConfiguration != null) {
+                    Assert.assertTrue(updateFromConfiguration.containsAll(updateFromExpected));
+                }
+                OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmentation =
+                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
+                                LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
+                List<T> updateFromOperational = null;
+                if (updateFromOperationalTerminationPointAugmentation != null) {
+                    updateFromOperational = helper.readValues(updateFromOperationalTerminationPointAugmentation);
+                }
+                if (updateFromOperational != null) {
+                    Assert.assertTrue(updateFromOperational.containsAll(updateFromExpected));
+                }
 
-            // READ: the test interface and ensure changes are propagated to the CONFIGURATION data store,
-            // then repeat for OPERATIONAL data store
-            OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-            List<InterfaceExternalIds> updateToConfigurationExternalIds =
-                    updateToConfigurationTerminationPointAugmentation
-                    .getInterfaceExternalIds();
-            assertExpectedInterfaceExternalIdsExist(updateToExpectedExternalIds, updateToConfigurationExternalIds);
-            assertExpectedInterfaceExternalIdsExist(updateFromExpectedExternalIds,
-                    updateToConfigurationExternalIds);
-            OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-            List<InterfaceExternalIds> updateToOperationalExternalIds = updateToOperationalTerminationPointAugmentation
-                    .getInterfaceExternalIds();
-            if (updateFromExpectedExternalIds != null) {
-                assertExpectedInterfaceExternalIdsExist(updateToExpectedExternalIds,
-                        updateToOperationalExternalIds);
-                assertExpectedInterfaceExternalIdsExist(updateFromExpectedExternalIds,
-                        updateToOperationalExternalIds);
-            } else {
-                Assert.assertNull(updateToOperationalExternalIds);
+                // UPDATE:  update the external_ids
+                testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
+                OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
+                        new OvsdbTerminationPointAugmentationBuilder();
+                helper.writeValues(tpUpdateAugmentationBuilder, updateToInput);
+                InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
+                NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
+                NodeId portUpdateNodeId = createManagedNodeId(portIid);
+                portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
+                TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
+                tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
+                tpUpdateBuilder.addAugmentation(
+                        OvsdbTerminationPointAugmentation.class,
+                        tpUpdateAugmentationBuilder.build());
+                portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
+                boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
+                        portIid, portUpdateNodeBuilder.build());
+                Thread.sleep(OVSDB_UPDATE_TIMEOUT);
+                Assert.assertTrue(result);
+
+                // READ: the test port and ensure changes are propagated to the CONFIGURATION data store,
+                // then repeat for OPERATIONAL data store
+                OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
+                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
+                                LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
+                List<T> updateToConfiguration = helper.readValues(updateToConfigurationTerminationPointAugmentation);
+                Assert.assertTrue(updateToConfiguration.containsAll(updateToExpected));
+                Assert.assertTrue(updateToConfiguration.containsAll(updateFromExpected));
+                OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
+                        getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
+                                LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
+                List<T> updateToOperational = helper.readValues(updateToOperationalTerminationPointAugmentation);
+                Assert.assertTrue(updateToOperational.containsAll(updateToExpected));
+                Assert.assertTrue(updateToOperational.containsAll(updateFromExpected));
+
+                // DELETE
+                Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
+            } catch (InterruptedException e) {
+                LOG.error("Test interrupted", e);
             }
-
-            // DELETE
-            Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
         }
     }
 
-    /*
-     * Generates the test cases involved in testing TP Options.  See inline comments for descriptions of
-     * the particular cases considered.
-     *
-     * The return value is a Map in the form (K,V)=(testCaseName,testCase).
-     * - testCaseName is a String
-     * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
-     *     either corresponding INPUT TP Options, or EXPECTED TP Options
-     *     INPUT    is the List we use when calling
-     *              <code>TerminationPointAugmentationBuilder.setOptions()</code>
-     *     EXPECTED is the List we expect to receive after calling
-     *              <code>TerminationPointAugmentationBuilder.getOptions()</code>
-     */
-    private Map<String, Map<String, List<Options>>> generateTerminationPointOptionsTestCases() {
-        Map<String, Map<String, List<Options>>> testMap = new HashMap<>();
-
-        final String TP_OPTIONS_KEY = "TPOptionsKey";
-        final String TP_OPTIONS_VALUE = "TPOptionsValue";
-        final String FORMAT_STR = "%s_%s_%d";
-        final String GOOD_KEY = "GoodKey";
-        final String GOOD_VALUE = "GoodValue";
-        final String NO_VALUE_FOR_KEY = "NoValueForKey";
-        final String NO_KEY_FOR_VALUE = "NoKeyForValue";
-
-        // Test Case 1:  TestOneOptions
-        // Test Type:    Positive
-        // Description:  Create a termination point with one Options
-        // Expected:     A termination point is created with the single Options specified below
-        final String testOneOptionsName = "TestOneOptions";
-        int optionsCounter = 0;
-        List<Options> oneOptions = Lists.newArrayList(
-                (new OptionsBuilder()
-                        .setOption(String.format(FORMAT_STR, testOneOptionsName,
-                                TP_OPTIONS_KEY, ++optionsCounter))
-                        .setValue(String.format(FORMAT_STR, testOneOptionsName,
-                                TP_OPTIONS_VALUE, optionsCounter))
-                        .build()));
-        Map<String,List<Options>> testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, oneOptions);
-        testCase.put(INPUT_VALUES_KEY, oneOptions);
-        testMap.put(testOneOptionsName, testCase);
-
-        // Test Case 2:  TestFiveOptions
-        // Test Type:    Positive
-        // Description:  Create a termination point with multiple (five) Options
-        // Expected:     A termination point is created with the five options specified below
-        final String testFiveOptionsName = "TestFiveOptions";
-        optionsCounter = 0;
-        List<Options> fiveOptions = Lists.newArrayList(
-                (new OptionsBuilder()
-                        .setOption(String.format(FORMAT_STR, testFiveOptionsName,
-                                TP_OPTIONS_KEY, ++optionsCounter))
-                        .setValue(String.format(FORMAT_STR, testFiveOptionsName,
-                                TP_OPTIONS_VALUE, optionsCounter))
-                        .build()),
-                (new OptionsBuilder()
-                        .setOption(String.format(FORMAT_STR, testFiveOptionsName,
-                                TP_OPTIONS_KEY, ++optionsCounter))
-                        .setValue(String.format(FORMAT_STR, testFiveOptionsName,
-                                TP_OPTIONS_VALUE, optionsCounter))
-                        .build()),
-                (new OptionsBuilder()
-                        .setOption(String.format(FORMAT_STR, testFiveOptionsName,
-                                TP_OPTIONS_KEY, ++optionsCounter))
-                        .setValue(String.format(FORMAT_STR, testFiveOptionsName,
-                                TP_OPTIONS_VALUE, optionsCounter))
-                        .build()),
-                (new OptionsBuilder()
-                        .setOption(String.format(FORMAT_STR, testFiveOptionsName,
-                                TP_OPTIONS_KEY, ++optionsCounter))
-                        .setValue(String.format(FORMAT_STR, testFiveOptionsName,
-                                TP_OPTIONS_VALUE, optionsCounter))
-                        .build()),
-                (new OptionsBuilder()
-                        .setOption(String.format(FORMAT_STR, testFiveOptionsName,
-                                TP_OPTIONS_KEY, ++optionsCounter))
-                        .setValue(String.format(FORMAT_STR, testFiveOptionsName,
-                                TP_OPTIONS_VALUE, optionsCounter))
-                        .build()));
-        testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, fiveOptions);
-        testCase.put(INPUT_VALUES_KEY, fiveOptions);
-        testMap.put(testFiveOptionsName, testCase);
-
-        // Test Case 3:  TestOneGoodOptionsOneMalformedOptionsValue
-        // Test Type:    Negative
-        // Description:
-        //     One perfectly fine Options
-        //        (TestOneGoodOptionsOneMalformedOptionsValue_OptionsKey_1,
-        //        TestOneGoodOptionsOneMalformedOptions_OptionsValue_1)
-        //     and one malformed Options which only has key specified
-        //        (TestOneGoodOptionsOneMalformedOptionsValue_NoValueForKey_2,
-        //        UNSPECIFIED)
-        // Expected:     A termination point is created without any options
-        final String testOneGoodOptionsOneMalformedOptionsValueName =
-                "TestOneGoodOptionsOneMalformedOptionsValue";
-        optionsCounter = 0;
-        Options oneGood = new OptionsBuilder()
-                .setOption(String.format(FORMAT_STR, testOneGoodOptionsOneMalformedOptionsValueName,
-                        GOOD_KEY, ++optionsCounter))
-                .setValue(String.format(FORMAT_STR,
-                        testOneGoodOptionsOneMalformedOptionsValueName,
-                        GOOD_VALUE, optionsCounter))
-                .build();
-        Options oneBad = new OptionsBuilder()
-                .setOption(String.format(FORMAT_STR,
-                        testOneGoodOptionsOneMalformedOptionsValueName, NO_VALUE_FOR_KEY, ++optionsCounter))
-                .build();
-        List<Options> oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
-        List<Options> oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodOptionsOneMalformedOptionsValueName, testCase);
-
-        // Test Case 4:  TestOneGoodOptionsOneMalformedOptionsKey
-        // Test Type:    Negative
-        // Description:
-        //     One perfectly fine Options
-        //        (TestOneGoodOptionsOneMalformedOptionsValue_OptionsKey_1,
-        //        TestOneGoodOptionsOneMalformedOptions_OptionsValue_1)
-        //     and one malformed Options which only has key specified
-        //        (UNSPECIFIED,
-        //        TestOneGoodOptionsOneMalformedOptionsKey_NoKeyForValue_2)
-        // Expected:     A termination point is created without any options
-        final String testOneGoodOptionsOneMalformedOptionsKeyName =
-                "TestOneGoodOptionsOneMalformedOptionsKey";
-        optionsCounter = 0;
-        oneGood = new OptionsBuilder()
-                .setOption(String.format(FORMAT_STR, testOneGoodOptionsOneMalformedOptionsKeyName,
-                        GOOD_KEY, ++optionsCounter))
-                .setValue(String.format(FORMAT_STR,
-                        testOneGoodOptionsOneMalformedOptionsKeyName,
-                        GOOD_VALUE, optionsCounter))
-                .build();
-        oneBad = new OptionsBuilder()
-                .setOption(String.format(FORMAT_STR,
-                        testOneGoodOptionsOneMalformedOptionsKeyName, NO_KEY_FOR_VALUE, ++optionsCounter))
-                .build();
-        oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
-        oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodOptionsOneMalformedOptionsKeyName, testCase);
-
-        return testMap;
-    }
 
     /*
-     * @see <code>SouthboundIT.testCRUDTerminationPointOptions()</code>
-     * This is helper test method to compare a test "set" of Options against an expected "set"
+     * Generates the test cases involved in testing InterfaceExternalIds.  See inline comments for descriptions of
+     * the particular cases considered.
      */
-    private void assertExpectedOptionsExist( List<Options> expected,
-                                             List<Options> test ) {
-
-        if (expected != null) {
-            for (Options expectedOption : expected) {
-                Assert.assertTrue(test.contains(expectedOption));
-            }
-        }
+    private static List<SouthboundTestCase<InterfaceExternalIds>> generateInterfaceExternalIdsTestCases() {
+        return generateKeyValueTestCases(new SouthboundInterfaceExternalIdsBuilder(), "IntExternalIdKey",
+                "IntExternalIdValue");
     }
 
     /*
-     * Tests the CRUD operations for <code>TerminationPoint</code> <code>options</code>.
+     * Tests the CRUD operations for <code>Interface</code> <code>external_ids</code>.
      *
-     * @see <code>SouthboundIT.generateTerminationPointOptions()</code> for specific test case information
+     * @see <code>SouthboundIT.generateInterfaceExternalIdsTestCases()</code> for specific test case information
      */
     @Test
-    public void testCRUDTerminationPointOptions() throws InterruptedException {
-        final String TEST_PREFIX = "CRUDTPOptions";
+    public void testCRUDTerminationPointInterfaceExternalIds() throws InterruptedException, ExecutionException {
+        final String TEST_PREFIX = "CRUDTPInterfaceExternalIds";
 
         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
         connectOvsdbNode(connectionInfo);
 
         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
         // the update has been performed.
-        Map<String, Map<String, List<Options>>> updateFromTestCases =
-                generateTerminationPointOptionsTestCases();
-        Map<String, Map<String, List<Options>>> updateToTestCases =
-                generateTerminationPointOptionsTestCases();
-        Map<String, List<Options>> updateFromTestCase;
-        List<Options> updateFromInputOptions;
-        List<Options> updateFromExpectedOptions;
-        Map<String, List<Options>> updateToTestCase;
-        List<Options> updateToInputOptions;
-        List<Options> updateToExpectedOptions;
+        List<SouthboundTestCase<InterfaceExternalIds>> updateFromTestCases = generateInterfaceExternalIdsTestCases();
+        List<SouthboundTestCase<InterfaceExternalIds>> updateToTestCases = generateInterfaceExternalIdsTestCases();
         String testBridgeName;
         String testPortName;
 
         int counter = 1;
+        // multithreads the test using NUM_THREADS
         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
-        for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
-            updateFromTestCase = updateFromTestCases.get(updateFromTestCaseKey);
-            updateFromInputOptions = updateFromTestCase.get(INPUT_VALUES_KEY);
-            updateFromExpectedOptions = updateFromTestCase.get(EXPECTED_VALUES_KEY);
-            for (String testCaseKey : updateToTestCases.keySet()) {
-                testPortName = testBridgeName = String.format("%s_%s_%d", TEST_PREFIX, testCaseKey, counter);
+        for (SouthboundTestCase<InterfaceExternalIds> fromTestCase : updateFromTestCases) {
+            for (SouthboundTestCase<InterfaceExternalIds> toTestCase : updateToTestCases) {
+                testPortName = testBridgeName = String.format(FORMAT_STR,
+                        TEST_PREFIX, toTestCase.name, counter);
                 counter += 1;
-                updateToTestCase = updateToTestCases.get(testCaseKey);
-                updateToInputOptions = updateToTestCase.get(INPUT_VALUES_KEY);
-                updateToExpectedOptions = updateToTestCase.get(EXPECTED_VALUES_KEY);
-
-                TestCRUDTerminationPointOptionsRunnable testRunnable =
-                        new TestCRUDTerminationPointOptionsRunnable(
-                                connectionInfo, testBridgeName, testPortName,
-                                updateFromInputOptions,
-                                updateFromExpectedOptions,
-                                updateToInputOptions,
-                                updateToExpectedOptions);
-                executor.submit(testRunnable);
+                executor.submit(new TestCRUDTerminationPointRunnable<>(
+                        new SouthboundTestHelper<InterfaceExternalIds>() {
+                            @Override
+                            public List<InterfaceExternalIds> readValues(
+                                    OvsdbTerminationPointAugmentation augmentation) {
+                                return augmentation.getInterfaceExternalIds();
+                            }
+
+                            @Override
+                            public void writeValues(
+                                    OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
+                                    List<InterfaceExternalIds> values) {
+                                augmentationBuilder.setInterfaceExternalIds(values);
+                            }
+                        },
+                        connectionInfo, testBridgeName, testPortName,
+                        fromTestCase.inputValues,
+                        fromTestCase.expectedValues,
+                        toTestCase.inputValues,
+                        toTestCase.expectedValues));
             }
         }
         executor.shutdown();
@@ -1774,282 +1423,74 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
     }
 
-    class TestCRUDTerminationPointOptionsRunnable implements Runnable {
-
-        ConnectionInfo connectionInfo;
-        String testBridgeName;
-        String testPortName;
-        List<Options> updateFromInputOptions;
-        List<Options> updateFromExpectedOptions;
-        List<Options> updateToInputOptions;
-        List<Options> updateToExpectedOptions;
-
-        TestCRUDTerminationPointOptionsRunnable(
-                ConnectionInfo connectionInfo, String testBridgeName,
-                String testPortName,
-                List<Options> updateFromInputOptions,
-                List<Options> updateFromExpectedOptions,
-                List<Options> updateToInputOptions,
-                List<Options> updateToExpectedOptions) {
-
-            this.connectionInfo = connectionInfo;
-            this.testBridgeName = testBridgeName;
-            this.testPortName = testPortName;
-            this.updateFromInputOptions = updateFromInputOptions;
-            this.updateFromExpectedOptions = updateFromExpectedOptions;
-            this.updateToInputOptions = updateToInputOptions;
-            this.updateToExpectedOptions = updateToExpectedOptions;
-        }
-
-        @Override
-        public void run() {
-            try {
-                test();
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-
-        public void test() throws InterruptedException {
-            final int TERMINATION_POINT_TEST_INDEX = 0;
-            // CREATE: Create the test interface
-            Assert.assertTrue(addBridge(connectionInfo, null,
-                    testBridgeName, null, true, SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
-                    true, null, null, null, null));
-            NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
-                    connectionInfo, new OvsdbBridgeName(testBridgeName)));
-            OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
-                    createGenericOvsdbTerminationPointAugmentationBuilder();
-            tpCreateAugmentationBuilder.setName(testPortName);
-            tpCreateAugmentationBuilder.setOptions(updateFromInputOptions);
-            Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
-
-            // READ: Read the test interface and ensure changes are propagated to the CONFIGURATION data store,
-            // then repeat for OPERATIONAL data store
-            OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-            List<Options> updateFromConfigurationOptions = updateFromConfigurationTerminationPointAugmentation
-                    .getOptions();
-            assertExpectedOptionsExist(updateFromExpectedOptions,
-                    updateFromConfigurationOptions);
-            OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-            List<Options> updateFromOperationalOptions = updateFromOperationalTerminationPointAugmentation
-                    .getOptions();
-            assertExpectedOptionsExist(updateFromExpectedOptions,
-                    updateFromOperationalOptions);
-
-            // UPDATE:  update the external_ids
-            testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
-            OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
-                    new OvsdbTerminationPointAugmentationBuilder();
-            tpUpdateAugmentationBuilder.setOptions(updateToInputOptions);
-            InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
-            NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
-            NodeId portUpdateNodeId = createManagedNodeId(portIid);
-            portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
-            TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
-            tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
-            tpUpdateBuilder.addAugmentation(
-                    OvsdbTerminationPointAugmentation.class,
-                    tpUpdateAugmentationBuilder.build());
-            portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
-            boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
-                    portIid, portUpdateNodeBuilder.build());
-            Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-            Assert.assertTrue(result);
-
-            // READ: the test interface and ensure changes are propagated to the CONFIGURATION data store,
-            // then repeat for OPERATIONAL data store
-            OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-            List<Options> updateToConfigurationOptions = updateToConfigurationTerminationPointAugmentation
-                    .getOptions();
-            assertExpectedOptionsExist(updateToExpectedOptions, updateToConfigurationOptions);
-            assertExpectedOptionsExist(updateFromExpectedOptions, updateToConfigurationOptions);
-            OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-            List<Options> updateToOperationalOptions = updateToOperationalTerminationPointAugmentation
-                    .getOptions();
-            if (updateFromExpectedOptions != null) {
-                assertExpectedOptionsExist(updateToExpectedOptions, updateToOperationalOptions);
-                assertExpectedOptionsExist(updateFromExpectedOptions, updateToOperationalOptions);
-            }
-
-            // DELETE
-            Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
-        }
-    }
-
     /*
-     * Generates the test cases involved in testing Interface other_configs.  See inline comments for descriptions of
-     * the particular cases considered.
-     *
-     * The return value is a Map in the form (K,V)=(testCaseName,testCase).
-     * - testCaseName is a String
-     * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
-     *     either corresponding INPUT interface other_configs, or EXPECTED interface other_configs
-     *     INPUT    is the List we use when calling
-     *              <code>TerminationPointAugmentationBuilder.setInterfaceOtherConfigs()</code>
-     *     EXPECTED is the List we expect to receive after calling
-     *              <code>TerminationPointAugmentationBuilder.getInterfaceOtherConfigs()</code>
-     */
-    private Map<String, Map<String, List<InterfaceOtherConfigs>>> generateInterfaceOtherConfigsTestCases() {
-        Map<String, Map<String, List<InterfaceOtherConfigs>>> testMap = new HashMap<>();
-
-        final String INT_OTHER_CONFIGS_KEY = "IntOtherConfigsKey";
-        final String INT_OTHER_CONFIGS_VALUE = "IntOtherConfigsValue";
-        final String FORMAT_STR = "%s_%s_%d";
-        final String GOOD_KEY = "GoodKey";
-        final String GOOD_VALUE = "GoodValue";
-        final String NO_VALUE_FOR_KEY = "NoValueForKey";
-        final String NO_KEY_FOR_VALUE = "NoKeyForValue";
-
-        // Test Case 1:  TestOneOtherConfigs
-        // Test Type:    Positive
-        // Description:  Create an interface with one other_Configs
-        // Expected:     An interface is created with the single other_configs specified below
-        final String testOneOtherConfigsName = "TestOneInterfaceOtherConfigs";
-        int otherConfigsCounter = 0;
-        List<InterfaceOtherConfigs> oneOtherConfigs = Lists.newArrayList(
-                (new InterfaceOtherConfigsBuilder()
-                        .setOtherConfigKey(String.format(FORMAT_STR, testOneOtherConfigsName,
-                                INT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
-                        .setOtherConfigValue(String.format(FORMAT_STR, testOneOtherConfigsName,
-                                INT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
-                        .build()));
-        Map<String,List<InterfaceOtherConfigs>> testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, oneOtherConfigs);
-        testCase.put(INPUT_VALUES_KEY, oneOtherConfigs);
-        testMap.put(testOneOtherConfigsName, testCase);
-
-        // Test Case 2:  TestFiveInterfaceOtherConfigs
-        // Test Type:    Positive
-        // Description:  Create a termination point with multiple (five) InterfaceOtherConfigs
-        // Expected:     A termination point is created with the five InterfaceOtherConfigs specified below
-        final String testFiveInterfaceOtherConfigsName = "TestFiveInterfaceOtherConfigs";
-        otherConfigsCounter = 0;
-        List<InterfaceOtherConfigs> fiveInterfaceOtherConfigs = Lists.newArrayList(
-                (new InterfaceOtherConfigsBuilder()
-                        .setOtherConfigKey(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
-                                INT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
-                        .setOtherConfigValue(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
-                                INT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
-                        .build()),
-                (new InterfaceOtherConfigsBuilder()
-                        .setOtherConfigKey(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
-                                INT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
-                        .setOtherConfigValue(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
-                                INT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
-                        .build()),
-                (new InterfaceOtherConfigsBuilder()
-                        .setOtherConfigKey(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
-                                INT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
-                        .setOtherConfigValue(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
-                                INT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
-                        .build()),
-                (new InterfaceOtherConfigsBuilder()
-                        .setOtherConfigKey(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
-                                INT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
-                        .setOtherConfigValue(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
-                                INT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
-                        .build()),
-                (new InterfaceOtherConfigsBuilder()
-                        .setOtherConfigKey(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
-                                INT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
-                        .setOtherConfigValue(String.format(FORMAT_STR, testFiveInterfaceOtherConfigsName,
-                                INT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
-                        .build()));
-        testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, fiveInterfaceOtherConfigs);
-        testCase.put(INPUT_VALUES_KEY, fiveInterfaceOtherConfigs);
-        testMap.put(testFiveInterfaceOtherConfigsName, testCase);
-
-        // Test Case 3:  TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValue
-        // Test Type:    Negative
-        // Description:
-        //     One perfectly fine InterfaceOtherConfigs
-        //        (TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValue_InterfaceOtherConfigsKey_1,
-        //        TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigs_InterfaceOtherConfigsValue_1)
-        //     and one malformed InterfaceOtherConfigs which only has key specified
-        //        (TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValue_NoValueForKey_2,
-        //        UNSPECIFIED)
-        // Expected:     A termination point is created without any InterfaceOtherConfigs
-        final String testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValueName =
-                "TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValue";
-        otherConfigsCounter = 0;
-        InterfaceOtherConfigs oneGood = new InterfaceOtherConfigsBuilder()
-                .setOtherConfigKey(String.format(FORMAT_STR,
-                        testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValueName,
-                        GOOD_KEY, ++otherConfigsCounter))
-                .setOtherConfigValue(String.format(FORMAT_STR,
-                        testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValueName,
-                        GOOD_VALUE, otherConfigsCounter))
-                .build();
-        InterfaceOtherConfigs oneBad = new InterfaceOtherConfigsBuilder()
-                .setOtherConfigKey(String.format(FORMAT_STR,
-                        testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValueName, NO_VALUE_FOR_KEY,
-                        ++otherConfigsCounter))
-                .build();
-        List<InterfaceOtherConfigs> oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
-        List<InterfaceOtherConfigs> oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValueName, testCase);
-
-        // Test Case 4:  TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKey
-        // Test Type:    Negative
-        // Description:
-        //     One perfectly fine InterfaceOtherConfigs
-        //        (TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsValue_InterfaceOtherConfigsKey_1,
-        //        TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigs_InterfaceOtherConfigsValue_1)
-        //     and one malformed InterfaceOtherConfigs which only has key specified
-        //        (UNSPECIFIED,
-        //        TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKey_NoKeyForValue_2)
-        // Expected:     A termination point is created without any InterfaceOtherConfigs
-        final String testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKeyName =
-                "TestOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKey";
-        otherConfigsCounter = 0;
-        oneGood = new InterfaceOtherConfigsBuilder()
-                .setOtherConfigKey(String.format(FORMAT_STR,
-                        testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKeyName,
-                        GOOD_KEY, ++otherConfigsCounter))
-                .setOtherConfigValue(String.format(FORMAT_STR,
-                        testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKeyName,
-                        GOOD_VALUE, otherConfigsCounter))
-                .build();
-        oneBad = new InterfaceOtherConfigsBuilder()
-                .setOtherConfigKey(String.format(FORMAT_STR,
-                        testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKeyName, NO_KEY_FOR_VALUE,
-                        ++otherConfigsCounter))
-                .build();
-        oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
-        oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodInterfaceOtherConfigsOneMalformedInterfaceOtherConfigsKeyName, testCase);
-
-        return testMap;
+     * Generates the test cases involved in testing TP Options.  See inline comments for descriptions of
+     * the particular cases considered.
+     */
+    private List<SouthboundTestCase<Options>> generateTerminationPointOptionsTestCases() {
+        return generateKeyValueTestCases(new SouthboundOptionsBuilder(), "TOPOptionsKey", "TPOptionsValue");
     }
 
     /*
-     * @see <code>SouthboundIT.testCRUDInterfaceOtherConfigs()</code>
-     * This is helper test method to compare a test "set" of Options against an expected "set"
+     * Tests the CRUD operations for <code>TerminationPoint</code> <code>options</code>.
+     *
+     * @see <code>SouthboundIT.generateTerminationPointOptions()</code> for specific test case information
      */
-    private void assertExpectedInterfaceOtherConfigsExist( List<InterfaceOtherConfigs> expected,
-                                                           List<InterfaceOtherConfigs> test ) {
+    @Test
+    public void testCRUDTerminationPointOptions() throws InterruptedException {
+        final String TEST_PREFIX = "CRUDTPOptions";
+
+        ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
+        connectOvsdbNode(connectionInfo);
+
+        // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
+        // the update has been performed.
+        List<SouthboundTestCase<Options>> updateFromTestCases = generateTerminationPointOptionsTestCases();
+        List<SouthboundTestCase<Options>> updateToTestCases = generateTerminationPointOptionsTestCases();
+        String testBridgeName;
+        String testPortName;
 
-        if (expected != null && test != null) {
-            for (InterfaceOtherConfigs expectedOtherConfigs : expected) {
-                Assert.assertTrue(test.contains(expectedOtherConfigs));
+        int counter = 1;
+        ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
+        for (SouthboundTestCase<Options> fromTestCase : updateFromTestCases) {
+            for (SouthboundTestCase<Options> toTestCase : updateToTestCases) {
+                testPortName = testBridgeName = String.format(FORMAT_STR,
+                        TEST_PREFIX, toTestCase.name, counter);
+                counter += 1;
+                executor.submit(new TestCRUDTerminationPointRunnable<>(
+                        new SouthboundTestHelper<Options>() {
+                            @Override
+                            public List<Options> readValues(
+                                    OvsdbTerminationPointAugmentation augmentation) {
+                                return augmentation.getOptions();
+                            }
+
+                            @Override
+                            public void writeValues(
+                                    OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
+                                    List<Options> values) {
+                                augmentationBuilder.setOptions(values);
+                            }
+                        },
+                        connectionInfo, testBridgeName, testPortName,
+                        fromTestCase.inputValues,
+                        fromTestCase.expectedValues,
+                        toTestCase.inputValues,
+                        toTestCase.expectedValues));
             }
         }
+        executor.shutdown();
+        executor.awaitTermination(5, TimeUnit.MINUTES);
+        Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
+    }
+
+    /*
+     * Generates the test cases involved in testing Interface other_configs.  See inline comments for descriptions of
+     * the particular cases considered.
+     */
+    private List<SouthboundTestCase<InterfaceOtherConfigs>> generateInterfaceOtherConfigsTestCases() {
+        return generateKeyValueTestCases(new SouthboundInterfaceOtherConfigsBuilder(), "IntOtherConfigsKey",
+                "IntOtherConfigsValue");
     }
 
     /*
@@ -2066,40 +1507,38 @@ public class SouthboundIT extends AbstractMdsalTestBase {
 
         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
         // the update has been performed.
-        Map<String, Map<String, List<InterfaceOtherConfigs>>> updateFromTestCases =
-                generateInterfaceOtherConfigsTestCases();
-        Map<String, Map<String, List<InterfaceOtherConfigs>>> updateToTestCases =
-                generateInterfaceOtherConfigsTestCases();
-        Map<String, List<InterfaceOtherConfigs>> updateFromTestCase;
-        List<InterfaceOtherConfigs> updateFromInputOtherConfigs;
-        List<InterfaceOtherConfigs> updateFromExpectedOtherConfigs;
-        Map<String, List<InterfaceOtherConfigs>> updateToTestCase;
-        List<InterfaceOtherConfigs> updateToInputOtherConfigs;
-        List<InterfaceOtherConfigs> updateToExpectedOtherConfigs;
+        List<SouthboundTestCase<InterfaceOtherConfigs>> updateFromTestCases = generateInterfaceOtherConfigsTestCases();
+        List<SouthboundTestCase<InterfaceOtherConfigs>> updateToTestCases = generateInterfaceOtherConfigsTestCases();
         String testBridgeName;
         String testPortName;
 
         int counter = 1;
         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
-        for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
-            updateFromTestCase = updateFromTestCases.get(updateFromTestCaseKey);
-            updateFromInputOtherConfigs = updateFromTestCase.get(INPUT_VALUES_KEY);
-            updateFromExpectedOtherConfigs = updateFromTestCase.get(EXPECTED_VALUES_KEY);
-            for (String testCaseKey : updateToTestCases.keySet()) {
-                testPortName = testBridgeName = String.format("%s_%s_%d", TEST_PREFIX, testCaseKey, counter);
+        for (SouthboundTestCase<InterfaceOtherConfigs> fromTestCase : updateFromTestCases) {
+            for (SouthboundTestCase<InterfaceOtherConfigs> toTestCase : updateToTestCases) {
+                testPortName = testBridgeName = String.format(FORMAT_STR,
+                        TEST_PREFIX, toTestCase.name, counter);
                 counter += 1;
-                updateToTestCase = updateToTestCases.get(testCaseKey);
-                updateToInputOtherConfigs = updateToTestCase.get(INPUT_VALUES_KEY);
-                updateToExpectedOtherConfigs = updateToTestCase.get(EXPECTED_VALUES_KEY);
-
-                TestCRUDTerminationPointInterfaceOtherConfigsRunnable testRunnable =
-                        new TestCRUDTerminationPointInterfaceOtherConfigsRunnable(
-                                connectionInfo, testBridgeName, testPortName,
-                                updateFromInputOtherConfigs,
-                                updateFromExpectedOtherConfigs,
-                                updateToInputOtherConfigs,
-                                updateToExpectedOtherConfigs);
-                executor.submit(testRunnable);
+                executor.submit(new TestCRUDTerminationPointRunnable<>(
+                        new SouthboundTestHelper<InterfaceOtherConfigs>() {
+                            @Override
+                            public List<InterfaceOtherConfigs> readValues(
+                                    OvsdbTerminationPointAugmentation augmentation) {
+                                return augmentation.getInterfaceOtherConfigs();
+                            }
+
+                            @Override
+                            public void writeValues(
+                                    OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
+                                    List<InterfaceOtherConfigs> values) {
+                                augmentationBuilder.setInterfaceOtherConfigs(values);
+                            }
+                        },
+                        connectionInfo, testBridgeName, testPortName,
+                        fromTestCase.inputValues,
+                        fromTestCase.expectedValues,
+                        toTestCase.inputValues,
+                        toTestCase.expectedValues));
             }
         }
         executor.shutdown();
@@ -2107,300 +1546,13 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
     }
 
-    class TestCRUDTerminationPointInterfaceOtherConfigsRunnable implements Runnable {
-
-        ConnectionInfo connectionInfo;
-        String testBridgeName;
-        String testPortName;
-        List<InterfaceOtherConfigs> updateFromInputOtherConfigs;
-        List<InterfaceOtherConfigs> updateFromExpectedOtherConfigs;
-        List<InterfaceOtherConfigs> updateToInputOtherConfigs;
-        List<InterfaceOtherConfigs> updateToExpectedOtherConfigs;
-
-        TestCRUDTerminationPointInterfaceOtherConfigsRunnable(
-                ConnectionInfo connectionInfo, String testBridgeName,
-                String testPortName,
-                List<InterfaceOtherConfigs> updateFromInputOtherConfigs,
-                List<InterfaceOtherConfigs> updateFromExpectedOtherConfigs,
-                List<InterfaceOtherConfigs> updateToInputOtherConfigs,
-                List<InterfaceOtherConfigs> updateToExpectedOtherConfigs) {
-
-            this.connectionInfo = connectionInfo;
-            this.testBridgeName = testBridgeName;
-            this.testPortName = testPortName;
-            this.updateFromInputOtherConfigs = updateFromInputOtherConfigs;
-            this.updateFromExpectedOtherConfigs = updateFromExpectedOtherConfigs;
-            this.updateToInputOtherConfigs = updateToInputOtherConfigs;
-            this.updateToExpectedOtherConfigs = updateToExpectedOtherConfigs;
-        }
-
-        @Override
-        public void run() {
-            try {
-                test();
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-
-        public void test() throws InterruptedException {
-            final int TERMINATION_POINT_TEST_INDEX = 0;
-
-            // CREATE: Create the test interface
-            Assert.assertTrue(addBridge(connectionInfo, null,
-                    testBridgeName, null, true, SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
-                    true, null, null, null, null));
-            NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
-                    connectionInfo, new OvsdbBridgeName(testBridgeName)));
-            OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
-                    createGenericOvsdbTerminationPointAugmentationBuilder();
-            tpCreateAugmentationBuilder.setName(testPortName);
-            tpCreateAugmentationBuilder.setInterfaceOtherConfigs(updateFromInputOtherConfigs);
-            Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
-
-            // READ: Read the test interface and ensure changes are propagated to the CONFIGURATION data store,
-            // then repeat for OPERATIONAL data store
-            OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                    LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-            List<InterfaceOtherConfigs> updateFromConfigurationOtherConfigs;
-            if (updateFromConfigurationTerminationPointAugmentation != null) {
-                updateFromConfigurationOtherConfigs = updateFromConfigurationTerminationPointAugmentation
-                        .getInterfaceOtherConfigs();
-            } else {
-                updateFromConfigurationOtherConfigs = null;
-            }
-            assertExpectedInterfaceOtherConfigsExist(updateFromExpectedOtherConfigs,
-                    updateFromConfigurationOtherConfigs);
-            OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmenation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-            List<InterfaceOtherConfigs> updateFromOperationalOtherConfigs =
-                    updateFromOperationalTerminationPointAugmenation.getInterfaceOtherConfigs();
-            if (updateFromOperationalOtherConfigs != null) {
-                updateFromOperationalOtherConfigs = updateFromOperationalTerminationPointAugmenation
-                        .getInterfaceOtherConfigs();
-            } else {
-                updateFromOperationalOtherConfigs = null;
-            }
-            assertExpectedInterfaceOtherConfigsExist(updateFromExpectedOtherConfigs,
-                    updateFromOperationalOtherConfigs);
-
-            // UPDATE:  update the other_configs
-            testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
-            OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
-                    new OvsdbTerminationPointAugmentationBuilder();
-            tpUpdateAugmentationBuilder.setInterfaceOtherConfigs(updateToInputOtherConfigs);
-            InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
-            NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
-            NodeId portUpdateNodeId = createManagedNodeId(portIid);
-            portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
-            TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
-            tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
-            tpUpdateBuilder.addAugmentation(
-                    OvsdbTerminationPointAugmentation.class,
-                    tpUpdateAugmentationBuilder.build());
-            portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
-            boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
-                    portIid, portUpdateNodeBuilder.build());
-            Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-            Assert.assertTrue(result);
-
-            // READ: the test interface and ensure changes are propagated to the CONFIGURATION data store,
-            // then repeat for OPERATIONAL data store
-            OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-            List<InterfaceOtherConfigs> updateToConfigurationOtherConfigs =
-                    updateToConfigurationTerminationPointAugmentation
-                            .getInterfaceOtherConfigs();
-            assertExpectedInterfaceOtherConfigsExist(updateToExpectedOtherConfigs,
-                    updateToConfigurationOtherConfigs);
-            assertExpectedInterfaceOtherConfigsExist(updateFromExpectedOtherConfigs,
-                    updateToConfigurationOtherConfigs);
-            OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-            List<InterfaceOtherConfigs> updateToOperationalOtherConfigs =
-                    updateToOperationalTerminationPointAugmentation
-                            .getInterfaceOtherConfigs();
-            if (updateFromExpectedOtherConfigs != null) {
-                assertExpectedInterfaceOtherConfigsExist(updateToExpectedOtherConfigs,
-                        updateToOperationalOtherConfigs);
-                assertExpectedInterfaceOtherConfigsExist(updateFromExpectedOtherConfigs,
-                        updateToOperationalOtherConfigs);
-            }
-
-            // DELETE
-            Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
-        }
-    }
-
     /*
      * Generates the test cases involved in testing Port other_configs.  See inline comments for descriptions of
      * the particular cases considered.
-     *
-     * The return value is a Map in the form (K,V)=(testCaseName,testCase).
-     * - testCaseName is a String
-     * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
-     *     either corresponding INPUT port other_configs, or EXPECTED port other_configs
-     *     INPUT    is the List we use when calling
-     *              <code>TerminationPointAugmentationBuilder.setPortOtherConfigs()</code>
-     *     EXPECTED is the List we expect to receive after calling
-     *              <code>TerminationPointAugmentationBuilder.getPortOtherConfigs()</code>
-     */
-    private Map<String, Map<String, List<PortOtherConfigs>>> generatePortOtherConfigsTestCases() {
-        Map<String, Map<String, List<PortOtherConfigs>>> testMap = new HashMap<>();
-
-        final String PORT_OTHER_CONFIGS_KEY = "PortOtherConfigsKey";
-        final String PORT_OTHER_CONFIGS_VALUE = "PortOtherConfigsValue";
-        final String FORMAT_STR = "%s_%s_%d";
-        final String GOOD_KEY = "GoodKey";
-        final String GOOD_VALUE = "GoodValue";
-        final String NO_VALUE_FOR_KEY = "NoValueForKey";
-        final String NO_KEY_FOR_VALUE = "NoKeyForValue";
-
-        // Test Case 1:  TestOneOtherConfigs
-        // Test Type:    Positive
-        // Description:  Create an port with one other_Configs
-        // Expected:     A port is created with the single other_configs specified below
-        final String testOneOtherConfigsName = "TestOnePortOtherConfigs";
-        int otherConfigsCounter = 0;
-        List<PortOtherConfigs> oneOtherConfigs = Lists.newArrayList(
-                (new PortOtherConfigsBuilder()
-                        .setOtherConfigKey(String.format(FORMAT_STR, testOneOtherConfigsName,
-                                PORT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
-                        .setOtherConfigValue(String.format(FORMAT_STR, testOneOtherConfigsName,
-                                PORT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
-                        .build()));
-        Map<String,List<PortOtherConfigs>> testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, oneOtherConfigs);
-        testCase.put(INPUT_VALUES_KEY, oneOtherConfigs);
-        testMap.put(testOneOtherConfigsName, testCase);
-
-        // Test Case 2:  TestFivePortOtherConfigs
-        // Test Type:    Positive
-        // Description:  Create a termination point with multiple (five) PortOtherConfigs
-        // Expected:     A termination point is created with the five PortOtherConfigs specified below
-        final String testFivePortOtherConfigsName = "TestFivePortOtherConfigs";
-        otherConfigsCounter = 0;
-        List<PortOtherConfigs> fivePortOtherConfigs = Lists.newArrayList(
-                (new PortOtherConfigsBuilder()
-                        .setOtherConfigKey(String.format(FORMAT_STR, testFivePortOtherConfigsName,
-                                PORT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
-                        .setOtherConfigValue(String.format(FORMAT_STR, testFivePortOtherConfigsName,
-                                PORT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
-                        .build()),
-                (new PortOtherConfigsBuilder()
-                        .setOtherConfigKey(String.format(FORMAT_STR, testFivePortOtherConfigsName,
-                                PORT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
-                        .setOtherConfigValue(String.format(FORMAT_STR, testFivePortOtherConfigsName,
-                                PORT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
-                        .build()),
-                (new PortOtherConfigsBuilder()
-                        .setOtherConfigKey(String.format(FORMAT_STR, testFivePortOtherConfigsName,
-                                PORT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
-                        .setOtherConfigValue(String.format(FORMAT_STR, testFivePortOtherConfigsName,
-                                PORT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
-                        .build()),
-                (new PortOtherConfigsBuilder()
-                        .setOtherConfigKey(String.format(FORMAT_STR, testFivePortOtherConfigsName,
-                                PORT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
-                        .setOtherConfigValue(String.format(FORMAT_STR, testFivePortOtherConfigsName,
-                                PORT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
-                        .build()),
-                (new PortOtherConfigsBuilder()
-                        .setOtherConfigKey(String.format(FORMAT_STR, testFivePortOtherConfigsName,
-                                PORT_OTHER_CONFIGS_KEY, ++otherConfigsCounter))
-                        .setOtherConfigValue(String.format(FORMAT_STR, testFivePortOtherConfigsName,
-                                PORT_OTHER_CONFIGS_VALUE, otherConfigsCounter))
-                        .build()));
-        testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, fivePortOtherConfigs);
-        testCase.put(INPUT_VALUES_KEY, fivePortOtherConfigs);
-        testMap.put(testFivePortOtherConfigsName, testCase);
-
-        // Test Case 3:  TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValue
-        // Test Type:    Negative
-        // Description:
-        //     One perfectly fine PortOtherConfigs
-        //        (TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValue_PortOtherConfigsKey_1,
-        //        TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigs_PortOtherConfigsValue_1)
-        //     and one malformed PortOtherConfigs which only has key specified
-        //        (TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValue_NoValueForKey_2,
-        //        UNSPECIFIED)
-        // Expected:     A termination point is created without any PortOtherConfigs
-        final String testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValueName =
-                "TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValue";
-        otherConfigsCounter = 0;
-        PortOtherConfigs oneGood = new PortOtherConfigsBuilder()
-                .setOtherConfigKey(String.format(FORMAT_STR,
-                        testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValueName,
-                        GOOD_KEY, ++otherConfigsCounter))
-                .setOtherConfigValue(String.format(FORMAT_STR,
-                        testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValueName,
-                        GOOD_VALUE, otherConfigsCounter))
-                .build();
-        PortOtherConfigs oneBad = new PortOtherConfigsBuilder()
-                .setOtherConfigKey(String.format(FORMAT_STR,
-                        testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValueName, NO_VALUE_FOR_KEY,
-                        ++otherConfigsCounter))
-                .build();
-        List<PortOtherConfigs> oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
-        List<PortOtherConfigs> oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValueName, testCase);
-
-        // Test Case 4:  TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKey
-        // Test Type:    Negative
-        // Description:
-        //     One perfectly fine PortOtherConfigs
-        //        (TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsValue_PortOtherConfigsKey_1,
-        //        TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigs_PortOtherConfigsValue_1)
-        //     and one malformed PortOtherConfigs which only has key specified
-        //        (UNSPECIFIED,
-        //        TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKey_NoKeyForValue_2)
-        // Expected:     A termination point is created without any PortOtherConfigs
-        final String testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKeyName =
-                "TestOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKey";
-        otherConfigsCounter = 0;
-        oneGood = new PortOtherConfigsBuilder()
-                .setOtherConfigKey(String.format(FORMAT_STR,
-                        testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKeyName,
-                        GOOD_KEY, ++otherConfigsCounter))
-                .setOtherConfigValue(String.format(FORMAT_STR,
-                        testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKeyName,
-                        GOOD_VALUE, otherConfigsCounter))
-                .build();
-        oneBad = new PortOtherConfigsBuilder()
-                .setOtherConfigKey(String.format(FORMAT_STR,
-                        testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKeyName, NO_KEY_FOR_VALUE,
-                        ++otherConfigsCounter))
-                .build();
-        oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
-        oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodPortOtherConfigsOneMalformedPortOtherConfigsKeyName, testCase);
-
-        return testMap;
-    }
-
-    /*
-     * @see <code>SouthboundIT.testCRUDPortOtherConfigs()</code>
-     * This is helper test method to compare a test "set" of Options against an expected "set"
      */
-    private void assertExpectedPortOtherConfigsExist( List<PortOtherConfigs> expected,
-                                                      List<PortOtherConfigs> test ) {
-
-        if (expected != null && test != null) {
-            for (PortOtherConfigs expectedOtherConfigs : expected) {
-                Assert.assertTrue(test.contains(expectedOtherConfigs));
-            }
-        }
+    private List<SouthboundTestCase<PortOtherConfigs>> generatePortOtherConfigsTestCases() {
+        return generateKeyValueTestCases(new SouthboundPortOtherConfigsBuilder(), "PortOtherConfigsKey",
+                "PortOtherConfigsValue");
     }
 
     /*
@@ -2417,40 +1569,38 @@ public class SouthboundIT extends AbstractMdsalTestBase {
 
         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
         // the update has been performed.
-        Map<String, Map<String, List<PortOtherConfigs>>> updateFromTestCases =
-                generatePortOtherConfigsTestCases();
-        Map<String, Map<String, List<PortOtherConfigs>>> updateToTestCases =
-                generatePortOtherConfigsTestCases();
-        Map<String, List<PortOtherConfigs>> updateFromTestCase;
-        List<PortOtherConfigs> updateFromInputOtherConfigs;
-        List<PortOtherConfigs> updateFromExpectedOtherConfigs;
-        Map<String, List<PortOtherConfigs>> updateToTestCase;
-        List<PortOtherConfigs> updateToInputOtherConfigs;
-        List<PortOtherConfigs> updateToExpectedOtherConfigs;
+        List<SouthboundTestCase<PortOtherConfigs>> updateFromTestCases = generatePortOtherConfigsTestCases();
+        List<SouthboundTestCase<PortOtherConfigs>> updateToTestCases = generatePortOtherConfigsTestCases();
         String testBridgeName;
         String testPortName;
 
         int counter = 1;
         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
-        for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
-            updateFromTestCase = updateFromTestCases.get(updateFromTestCaseKey);
-            updateFromInputOtherConfigs = updateFromTestCase.get(INPUT_VALUES_KEY);
-            updateFromExpectedOtherConfigs = updateFromTestCase.get(EXPECTED_VALUES_KEY);
-            for (String testCaseKey : updateToTestCases.keySet()) {
-                testPortName = testBridgeName = String.format("%s_%s_%d", TEST_PREFIX, testCaseKey, counter);
+        for (SouthboundTestCase<PortOtherConfigs> fromTestCase : updateFromTestCases) {
+            for (SouthboundTestCase<PortOtherConfigs> toTestCase : updateToTestCases) {
+                testPortName = testBridgeName = String.format(FORMAT_STR,
+                        TEST_PREFIX, toTestCase.name, counter);
                 counter += 1;
-                updateToTestCase = updateToTestCases.get(testCaseKey);
-                updateToInputOtherConfigs = updateToTestCase.get(INPUT_VALUES_KEY);
-                updateToExpectedOtherConfigs = updateToTestCase.get(EXPECTED_VALUES_KEY);
-
-                TestCRUDTerminationPointPortOtherConfigsRunnable testRunnable =
-                        new TestCRUDTerminationPointPortOtherConfigsRunnable(
-                                connectionInfo, testBridgeName, testPortName,
-                                updateFromInputOtherConfigs,
-                                updateFromExpectedOtherConfigs,
-                                updateToInputOtherConfigs,
-                                updateToExpectedOtherConfigs);
-                executor.submit(testRunnable);
+                executor.submit(new TestCRUDTerminationPointRunnable<>(
+                        new SouthboundTestHelper<PortOtherConfigs>() {
+                            @Override
+                            public List<PortOtherConfigs> readValues(
+                                    OvsdbTerminationPointAugmentation augmentation) {
+                                return augmentation.getPortOtherConfigs();
+                            }
+
+                            @Override
+                            public void writeValues(
+                                    OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
+                                    List<PortOtherConfigs> values) {
+                                augmentationBuilder.setPortOtherConfigs(values);
+                            }
+                        },
+                        connectionInfo, testBridgeName, testPortName,
+                        fromTestCase.inputValues,
+                        fromTestCase.expectedValues,
+                        toTestCase.inputValues,
+                        toTestCase.expectedValues));
             }
         }
         executor.shutdown();
@@ -2458,131 +1608,6 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
     }
 
-    class TestCRUDTerminationPointPortOtherConfigsRunnable implements Runnable {
-        ConnectionInfo connectionInfo;
-        String testBridgeName;
-        String testPortName;
-        List<PortOtherConfigs> updateFromInputOtherConfigs;
-        List<PortOtherConfigs> updateFromExpectedOtherConfigs;
-        List<PortOtherConfigs> updateToInputOtherConfigs;
-        List<PortOtherConfigs> updateToExpectedOtherConfigs;
-
-        TestCRUDTerminationPointPortOtherConfigsRunnable(
-                ConnectionInfo connectionInfo, String testBridgeName,
-                String testPortName,
-                List<PortOtherConfigs> updateFromInputOtherConfigs,
-                List<PortOtherConfigs> updateFromExpectedOtherConfigs,
-                List<PortOtherConfigs> updateToInputOtherConfigs,
-                List<PortOtherConfigs> updateToExpectedOtherConfigs) {
-
-            this.connectionInfo = connectionInfo;
-            this.testBridgeName = testBridgeName;
-            this.testPortName = testPortName;
-            this.updateFromInputOtherConfigs = updateFromInputOtherConfigs;
-            this.updateFromExpectedOtherConfigs = updateFromExpectedOtherConfigs;
-            this.updateToInputOtherConfigs = updateToInputOtherConfigs;
-            this.updateToExpectedOtherConfigs = updateToExpectedOtherConfigs;
-        }
-
-        @Override
-        public void run() {
-            try {
-                test();
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-
-        public void test() throws InterruptedException {
-            final int TERMINATION_POINT_TEST_INDEX = 0;
-            // CREATE: Create the test port
-            Assert.assertTrue(addBridge(connectionInfo, null,
-                    testBridgeName, null, true, SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
-                    true, null, null, null, null));
-            NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
-                    connectionInfo, new OvsdbBridgeName(testBridgeName)));
-            OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
-                    createGenericOvsdbTerminationPointAugmentationBuilder();
-            tpCreateAugmentationBuilder.setName(testPortName);
-            tpCreateAugmentationBuilder.setPortOtherConfigs(updateFromInputOtherConfigs);
-            Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
-
-            // READ: Read the test port and ensure changes are propagated to the CONFIGURATION data store,
-            // then repeat for OPERATIONAL data store
-            OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-            List<PortOtherConfigs> updateFromConfigurationOtherConfigs;
-            if (updateFromConfigurationTerminationPointAugmentation != null) {
-                updateFromConfigurationOtherConfigs = updateFromConfigurationTerminationPointAugmentation
-                        .getPortOtherConfigs();
-            } else {
-                updateFromConfigurationOtherConfigs = null;
-            }
-            assertExpectedPortOtherConfigsExist(updateFromExpectedOtherConfigs,
-                    updateFromConfigurationOtherConfigs);
-            OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmenation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-            List<PortOtherConfigs> updateFromOperationalOtherConfigs =
-                    updateFromOperationalTerminationPointAugmenation.getPortOtherConfigs();
-            if (updateFromOperationalOtherConfigs != null) {
-                updateFromOperationalOtherConfigs = updateFromOperationalTerminationPointAugmenation
-                        .getPortOtherConfigs();
-            } else {
-                updateFromOperationalOtherConfigs = null;
-            }
-            assertExpectedPortOtherConfigsExist(updateFromExpectedOtherConfigs,
-                    updateFromOperationalOtherConfigs);
-
-            // UPDATE:  update the other_configs
-            testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
-            OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
-                    new OvsdbTerminationPointAugmentationBuilder();
-            tpUpdateAugmentationBuilder.setPortOtherConfigs(updateToInputOtherConfigs);
-            InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
-            NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
-            NodeId portUpdateNodeId = createManagedNodeId(portIid);
-            portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
-            TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
-            tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
-            tpUpdateBuilder.addAugmentation(
-                    OvsdbTerminationPointAugmentation.class,
-                    tpUpdateAugmentationBuilder.build());
-            portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
-            boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
-                    portIid, portUpdateNodeBuilder.build());
-            Thread.sleep(OVSDB_UPDATE_TIMEOUT);
-            Assert.assertTrue(result);
-
-            // READ: the test port and ensure changes are propagated to the CONFIGURATION data store,
-            // then repeat for OPERATIONAL data store
-            OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
-            List<PortOtherConfigs> updateToConfigurationOtherConfigs = updateToConfigurationTerminationPointAugmentation
-                    .getPortOtherConfigs();
-            assertExpectedPortOtherConfigsExist(updateToExpectedOtherConfigs,
-                    updateToConfigurationOtherConfigs);
-            assertExpectedPortOtherConfigsExist(updateFromExpectedOtherConfigs,
-                    updateToConfigurationOtherConfigs);
-            OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
-                    getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
-                            LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
-            List<PortOtherConfigs> updateToOperationalOtherConfigs = updateToOperationalTerminationPointAugmentation
-                    .getPortOtherConfigs();
-            if (updateFromExpectedOtherConfigs != null) {
-                assertExpectedPortOtherConfigsExist(updateToExpectedOtherConfigs,
-                        updateToOperationalOtherConfigs);
-                assertExpectedPortOtherConfigsExist(updateFromExpectedOtherConfigs,
-                        updateToOperationalOtherConfigs);
-            }
-
-            // DELETE
-            Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
-        }
-    }
-
     @Test
     public void testCRUDTerminationPointVlan() throws InterruptedException {
         final Integer CREATED_VLAN_ID = 4000;
@@ -2875,148 +1900,10 @@ public class SouthboundIT extends AbstractMdsalTestBase {
     /*
      * Generates the test cases involved in testing BridgeOtherConfigs.  See inline comments for descriptions of
      * the particular cases considered.
-     *
-     * The return value is a Map in the form (K,V)=(testCaseName,testCase).
-     * - testCaseName is a String
-     * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
-     *     either corresponding INPUT bridge other_configs, or EXPECTED bridge other_configs
-     *     INPUT is the List we use when calling BridgeAugmentationBuilder.setBridgeOtherConfigs()
-     *     EXPECTED is the List we expect to receive after calling BridgeAugmentationBuilder.getBridgeOtherConfigs()
      */
-    private Map<String, Map<String, List<BridgeOtherConfigs>>> generateBridgeOtherConfigsTestCases() {
-        Map<String, Map<String, List<BridgeOtherConfigs>>> testMap = new HashMap<>();
-
-        final String BRIDGE_OTHER_CONFIGS_KEY = "BridgeOtherConfigKey";
-        final String BRIDGE_OTHER_CONFIGS_VALUE = "BridgeOtherConfigValue";
-        final String FORMAT_STR = "%s_%s_%d";
-        final String GOOD_KEY = "GoodKey";
-        final String GOOD_VALUE = "GoodValue";
-        final String NO_VALUE_FOR_KEY = "NoValueForKey";
-        final String NO_KEY_FOR_VALUE = "NoKeyForValue";
-
-        // Test Case 1:  TestOneOtherConfig
-        // Test Type:    Positive
-        // Description:  Create a bridge with one other_config
-        // Expected:     A bridge is created with the single other_config specified below
-        final String testOneOtherConfigName = "TestOneOtherConfig";
-        int otherConfigCounter = 0;
-        List<BridgeOtherConfigs> oneOtherConfig = Lists.newArrayList(
-                (new BridgeOtherConfigsBuilder()
-                        .setBridgeOtherConfigKey(String.format(FORMAT_STR, testOneOtherConfigName,
-                                BRIDGE_OTHER_CONFIGS_KEY, ++otherConfigCounter))
-                        .setBridgeOtherConfigValue(String.format(FORMAT_STR, testOneOtherConfigName,
-                                BRIDGE_OTHER_CONFIGS_VALUE, otherConfigCounter))
-                        .build()));
-        Map<String,List<BridgeOtherConfigs>> testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, oneOtherConfig);
-        testCase.put(INPUT_VALUES_KEY, oneOtherConfig);
-        testMap.put(testOneOtherConfigName, testCase);
-
-        // Test Case 2:  TestFiveOtherConfig
-        // Test Type:    Positive
-        // Description:  Create a bridge with multiple (five) other_configs
-        // Expected:     A bridge is created with the five other_configs specified below
-        final String testFiveOtherConfigName = "TestFiveOtherConfig";
-        otherConfigCounter = 0;
-        List<BridgeOtherConfigs> fiveOtherConfig = Lists.newArrayList(
-                (new BridgeOtherConfigsBuilder()
-                        .setBridgeOtherConfigKey(String.format(FORMAT_STR, testFiveOtherConfigName,
-                                BRIDGE_OTHER_CONFIGS_KEY, ++otherConfigCounter))
-                        .setBridgeOtherConfigValue(String.format(FORMAT_STR, testFiveOtherConfigName,
-                                BRIDGE_OTHER_CONFIGS_VALUE, otherConfigCounter))
-                        .build()),
-                (new BridgeOtherConfigsBuilder()
-                        .setBridgeOtherConfigKey(String.format(FORMAT_STR, testFiveOtherConfigName,
-                                BRIDGE_OTHER_CONFIGS_KEY, ++otherConfigCounter))
-                        .setBridgeOtherConfigValue(String.format(FORMAT_STR, testFiveOtherConfigName,
-                                BRIDGE_OTHER_CONFIGS_VALUE, otherConfigCounter))
-                        .build()),
-                (new BridgeOtherConfigsBuilder()
-                        .setBridgeOtherConfigKey(String.format(FORMAT_STR, testFiveOtherConfigName,
-                                BRIDGE_OTHER_CONFIGS_KEY, ++otherConfigCounter))
-                        .setBridgeOtherConfigValue(String.format(FORMAT_STR, testFiveOtherConfigName,
-                                BRIDGE_OTHER_CONFIGS_VALUE, otherConfigCounter))
-                        .build()),
-                (new BridgeOtherConfigsBuilder()
-                        .setBridgeOtherConfigKey(String.format(FORMAT_STR, testFiveOtherConfigName,
-                                BRIDGE_OTHER_CONFIGS_KEY, ++otherConfigCounter))
-                        .setBridgeOtherConfigValue(String.format(FORMAT_STR, testFiveOtherConfigName,
-                                BRIDGE_OTHER_CONFIGS_VALUE, otherConfigCounter))
-                        .build()),
-                (new BridgeOtherConfigsBuilder()
-                        .setBridgeOtherConfigKey(String.format(FORMAT_STR, testFiveOtherConfigName,
-                                BRIDGE_OTHER_CONFIGS_KEY, ++otherConfigCounter))
-                        .setBridgeOtherConfigValue(String.format(FORMAT_STR, testFiveOtherConfigName,
-                                BRIDGE_OTHER_CONFIGS_VALUE, otherConfigCounter))
-                        .build()));
-        testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, fiveOtherConfig);
-        testCase.put(INPUT_VALUES_KEY, fiveOtherConfig);
-        testMap.put(testFiveOtherConfigName, testCase);
-
-        // Test Case 3:  TestOneGoodOtherConfigOneMalformedOtherConfigValue
-        // Test Type:    Negative
-        // Description:
-        //     One perfectly fine BridgeOtherConfig
-        //        (TestOneGoodOtherConfigOneMalformedOtherConfigValue_BridgeOtherConfigKey_1,
-        //        TestOneGoodOtherConfigOneMalformedOtherConfig_BridgeOtherConfigValue_1)
-        //     and one malformed BridgeOtherConfig which only has key specified
-        //        (TestOneGoodOtherConfigOneMalformedOtherConfigValue_NoValueForKey_2,
-        //        UNSPECIFIED)
-        // Expected:     A bridge is created without any other_config
-        final String testOneGoodOtherConfigOneMalformedOtherConfigValueName =
-                "TestOneGoodOtherConfigOneMalformedOtherConfigValue";
-        otherConfigCounter = 0;
-        BridgeOtherConfigs oneGood = new BridgeOtherConfigsBuilder()
-                .setBridgeOtherConfigKey(String.format(FORMAT_STR,
-                        testOneGoodOtherConfigOneMalformedOtherConfigValueName, GOOD_KEY, ++otherConfigCounter))
-                .setBridgeOtherConfigValue(String.format(FORMAT_STR,
-                        testOneGoodOtherConfigOneMalformedOtherConfigValueName,
-                        GOOD_VALUE, otherConfigCounter))
-                .build();
-        BridgeOtherConfigs oneBad = new BridgeOtherConfigsBuilder()
-                .setBridgeOtherConfigKey(String.format(FORMAT_STR,
-                        testOneGoodOtherConfigOneMalformedOtherConfigValueName, NO_VALUE_FOR_KEY, ++otherConfigCounter))
-                .build();
-        List<BridgeOtherConfigs> oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
-        List<BridgeOtherConfigs> oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodOtherConfigOneMalformedOtherConfigValueName, testCase);
-
-        // Test Case 4:  TestOneGoodOtherConfigOneMalformedOtherConfigKey
-        // Test Type:    Negative
-        // Description:
-        //     One perfectly fine BridgeOtherConfig
-        //        (TestOneGoodOtherConfigOneMalformedOtherConfigValue_BridgeOtherConfigKey_1,
-        //        TestOneGoodOtherConfigOneMalformedOtherConfig_BridgeOtherConfigValue_1)
-        //     and one malformed BridgeOtherConfig which only has key specified
-        //        (UNSPECIFIED,
-        //        TestOneGoodOtherConfigOneMalformedOtherConfigKey_NoKeyForValue_2)
-        // Expected:     A bridge is created without any other_config
-        final String testOneGoodOtherConfigOneMalformedOtherConfigKeyName =
-                "TestOneGoodOtherConfigOneMalformedOtherConfigIdKey";
-        otherConfigCounter = 0;
-        oneGood = new BridgeOtherConfigsBuilder()
-                .setBridgeOtherConfigKey(String.format(FORMAT_STR, testOneGoodOtherConfigOneMalformedOtherConfigKeyName,
-                        GOOD_KEY, ++otherConfigCounter))
-                .setBridgeOtherConfigValue(String.format(FORMAT_STR,
-                        testOneGoodOtherConfigOneMalformedOtherConfigKeyName,
-                        GOOD_VALUE, otherConfigCounter))
-                .build();
-        oneBad = new BridgeOtherConfigsBuilder()
-                .setBridgeOtherConfigKey(String.format(FORMAT_STR,
-                        testOneGoodOtherConfigOneMalformedOtherConfigKeyName, NO_KEY_FOR_VALUE, ++otherConfigCounter))
-                .build();
-        oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
-        oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodOtherConfigOneMalformedOtherConfigKeyName, testCase);
-
-        return testMap;
+    private List<SouthboundTestCase<BridgeOtherConfigs>> generateBridgeOtherConfigsTestCases() {
+        return generateKeyValueTestCases(new SouthboundBridgeOtherConfigsBuilder(), "BridgeOtherConfigsKey",
+                "BridgeOtherConfigsValue");
     }
 
     /*
@@ -3043,36 +1930,23 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         connectOvsdbNode(connectionInfo);
         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
         // the update has been performed.
-        Map<String, Map<String, List<BridgeOtherConfigs>>> updateFromTestCases = generateBridgeOtherConfigsTestCases();
-        Map<String, Map<String, List<BridgeOtherConfigs>>> updateToTestCases = generateBridgeOtherConfigsTestCases();
-        Map<String, List<BridgeOtherConfigs>> updateFromTestCase;
-        Map<String, List<BridgeOtherConfigs>> updateToTestCase;
-        List<BridgeOtherConfigs> updateFromInputOtherConfigs;
-        List<BridgeOtherConfigs> updateFromExpectedOtherConfigs;
-        List<BridgeOtherConfigs> updateToInputOtherConfigs;
-        List<BridgeOtherConfigs> updateToExpectedOtherConfigs;
+        List<SouthboundTestCase<BridgeOtherConfigs>> updateFromTestCases = generateBridgeOtherConfigsTestCases();
+        List<SouthboundTestCase<BridgeOtherConfigs>> updateToTestCases = generateBridgeOtherConfigsTestCases();
         String testBridgeName;
 
         int counter = 1;
         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
-        for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
-            updateFromTestCase = updateFromTestCases.get(updateFromTestCaseKey);
-            updateFromInputOtherConfigs = updateFromTestCase.get(INPUT_VALUES_KEY);
-            updateFromExpectedOtherConfigs = updateFromTestCase.get(EXPECTED_VALUES_KEY);
-            for (String testCaseKey : updateToTestCases.keySet()) {
-                testBridgeName = String.format("%s_%s_%d", TEST_BRIDGE_PREFIX, testCaseKey, counter);
+        for (SouthboundTestCase<BridgeOtherConfigs> fromTestCase : updateFromTestCases) {
+            for (SouthboundTestCase<BridgeOtherConfigs> toTestCase : updateToTestCases) {
+                testBridgeName = String.format(FORMAT_STR, TEST_BRIDGE_PREFIX, toTestCase.name, counter);
                 counter += 1;
-                updateToTestCase = updateToTestCases.get(testCaseKey);
-                updateToInputOtherConfigs = updateToTestCase.get(INPUT_VALUES_KEY);
-                updateToExpectedOtherConfigs = updateToTestCase.get(EXPECTED_VALUES_KEY);
-
                 TestCRUDBridgeOtherConfigsRunnable testRunnable =
                         new TestCRUDBridgeOtherConfigsRunnable(
                                 connectionInfo, testBridgeName,
-                                updateFromInputOtherConfigs,
-                                updateFromExpectedOtherConfigs,
-                                updateToInputOtherConfigs,
-                                updateToExpectedOtherConfigs);
+                                fromTestCase.inputValues,
+                                fromTestCase.expectedValues,
+                                toTestCase.inputValues,
+                                toTestCase.expectedValues);
                 executor.submit(testRunnable);
             }
         }
@@ -3173,147 +2047,10 @@ public class SouthboundIT extends AbstractMdsalTestBase {
     /*
      * Generates the test cases involved in testing BridgeExternalIds.  See inline comments for descriptions of
      * the particular cases considered.
-     *
-     * The return value is a Map in the form (K,V)=(testCaseName,testCase).
-     * - testCaseName is a String
-     * - testCase is a Map in the form (K,V) s.t. K=(EXPECTED_VALUES_KEY|INPUT_VALUES_KEY) and V is a List of
-     *     either corresponding INPUT bridge external ids, or EXPECTED bridge external ids
-     *     INPUT is the List we use when calling BridgeAugmentationBuilder.setBridgeExternalIds()
-     *     EXPECTED is the List we expect to receive after calling BridgeAugmentationBuilder.getBridgeExternalIds()
      */
-    private Map<String, Map<String, List<BridgeExternalIds>>> generateBridgeExternalIdsTestCases() {
-        Map<String, Map<String, List<BridgeExternalIds>>> testMap = new HashMap<>();
-
-        final String BRIDGE_EXTERNAL_ID_KEY = "BridgeExternalIdKey";
-        final String BRIDGE_EXTERNAL_ID_VALUE = "BridgeExternalIdValue";
-        final String FORMAT_STR = "%s_%s_%d";
-        final String GOOD_KEY = "GoodKey";
-        final String GOOD_VALUE = "GoodValue";
-        final String NO_VALUE_FOR_KEY = "NoValueForKey";
-        final String NO_KEY_FOR_VALUE = "NoKeyForValue";
-
-        // Test Case 1:  TestOneExternalId
-        // Test Type:    Positive
-        // Description:  Create a bridge with one BridgeExternalIds
-        // Expected:     A bridge is created with the single external_ids specified below
-        final String testOneExternalIdName = "TestOneExternalId";
-        int externalIdCounter = 0;
-        List<BridgeExternalIds> oneExternalId = Lists.newArrayList(
-                (new BridgeExternalIdsBuilder()
-                        .setBridgeExternalIdKey(String.format(FORMAT_STR, testOneExternalIdName,
-                                BRIDGE_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setBridgeExternalIdValue(String.format(FORMAT_STR, testOneExternalIdName,
-                                BRIDGE_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()));
-        Map<String,List<BridgeExternalIds>> testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, oneExternalId);
-        testCase.put(INPUT_VALUES_KEY, oneExternalId);
-        testMap.put(testOneExternalIdName, testCase);
-
-        // Test Case 2:  TestFiveExternalId
-        // Test Type:    Positive
-        // Description:  Create a bridge with multiple (five) BridgeExternalIds
-        // Expected:     A bridge is created with the five external_ids specified below
-        final String testFiveExternalIdName = "TestFiveExternalId";
-        externalIdCounter = 0;
-        List<BridgeExternalIds> fiveExternalId = Lists.newArrayList(
-                (new BridgeExternalIdsBuilder()
-                        .setBridgeExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                BRIDGE_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setBridgeExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                BRIDGE_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()),
-                (new BridgeExternalIdsBuilder()
-                        .setBridgeExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                BRIDGE_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setBridgeExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                BRIDGE_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()),
-                (new BridgeExternalIdsBuilder()
-                        .setBridgeExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                BRIDGE_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setBridgeExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                BRIDGE_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()),
-                (new BridgeExternalIdsBuilder()
-                        .setBridgeExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                BRIDGE_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setBridgeExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                BRIDGE_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()),
-                (new BridgeExternalIdsBuilder()
-                        .setBridgeExternalIdKey(String.format(FORMAT_STR, testFiveExternalIdName,
-                                BRIDGE_EXTERNAL_ID_KEY, ++externalIdCounter))
-                        .setBridgeExternalIdValue(String.format(FORMAT_STR, testFiveExternalIdName,
-                                BRIDGE_EXTERNAL_ID_VALUE, externalIdCounter))
-                        .build()));
-        testCase = Maps.newHashMap();
-        testCase.put(EXPECTED_VALUES_KEY, fiveExternalId);
-        testCase.put(INPUT_VALUES_KEY, fiveExternalId);
-        testMap.put(testFiveExternalIdName, testCase);
-
-        // Test Case 3:  TestOneGoodExternalIdOneMalformedExternalIdValue
-        // Test Type:    Negative
-        // Description:
-        //     One perfectly fine BridgeExternalId
-        //        (TestOneGoodExternalIdOneMalformedExternalIdValue_BridgeExternalIdKey_1,
-        //        TestOneGoodExternalIdOneMalformedExternalId_BridgeExternalIdValue_1)
-        //     and one malformed BridgeExternalId which only has key specified
-        //        (TestOneGoodExternalIdOneMalformedExternalIdValue_NoValueForKey_2,
-        //        UNSPECIFIED)
-        // Expected:     A bridge is created without any external_ids
-        final String testOneGoodExternalIdOneMalformedExternalIdValueName =
-                "TestOneGoodExternalIdOneMalformedExternalIdValue";
-        externalIdCounter = 0;
-        BridgeExternalIds oneGood = new BridgeExternalIdsBuilder()
-                .setBridgeExternalIdKey(String.format(FORMAT_STR, testOneGoodExternalIdOneMalformedExternalIdValueName,
-                        GOOD_KEY, ++externalIdCounter))
-                .setBridgeExternalIdValue(String.format(FORMAT_STR,
-                        testOneGoodExternalIdOneMalformedExternalIdValueName,
-                        GOOD_VALUE, externalIdCounter))
-                .build();
-        BridgeExternalIds oneBad = new BridgeExternalIdsBuilder()
-                .setBridgeExternalIdKey(String.format(FORMAT_STR,
-                        testOneGoodExternalIdOneMalformedExternalIdValueName, NO_VALUE_FOR_KEY, ++externalIdCounter))
-                .build();
-        List<BridgeExternalIds> oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
-        List<BridgeExternalIds> oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodExternalIdOneMalformedExternalIdValueName, testCase);
-
-        // Test Case 4:  TestOneGoodExternalIdOneMalformedExternalIdKey
-        // Test Type:    Negative
-        // Description:
-        //     One perfectly fine BridgeExternalId
-        //        (TestOneGoodExternalIdOneMalformedExternalIdValue_BridgeExternalIdKey_1,
-        //        TestOneGoodExternalIdOneMalformedExternalId_BridgeExternalIdValue_1)
-        //     and one malformed BridgeExternalId which only has key specified
-        //        (UNSPECIFIED,
-        //        TestOneGoodExternalIdOneMalformedExternalIdKey_NoKeyForValue_2)
-        // Expected:     A bridge is created without any external_ids
-        final String testOneGoodExternalIdOneMalformedExternalIdKeyName =
-                "TestOneGoodExternalIdOneMalformedExternalIdKey";
-        externalIdCounter = 0;
-        oneGood = new BridgeExternalIdsBuilder()
-                .setBridgeExternalIdKey(String.format(FORMAT_STR, testOneGoodExternalIdOneMalformedExternalIdKeyName,
-                        GOOD_KEY, ++externalIdCounter))
-                .setBridgeExternalIdValue(String.format(FORMAT_STR,
-                        testOneGoodExternalIdOneMalformedExternalIdKeyName,
-                        GOOD_VALUE, externalIdCounter))
-                .build();
-        oneBad = new BridgeExternalIdsBuilder()
-                .setBridgeExternalIdKey(String.format(FORMAT_STR,
-                        testOneGoodExternalIdOneMalformedExternalIdKeyName, NO_KEY_FOR_VALUE, ++externalIdCounter))
-                .build();
-        oneGoodOneBadInput = Lists.newArrayList(oneGood, oneBad);
-        oneGoodOneBadExpected = null;
-        testCase = Maps.newHashMap();
-        testCase.put(INPUT_VALUES_KEY, oneGoodOneBadInput);
-        testCase.put(EXPECTED_VALUES_KEY, oneGoodOneBadExpected);
-        testMap.put(testOneGoodExternalIdOneMalformedExternalIdKeyName, testCase);
-        return testMap;
+    private List<SouthboundTestCase<BridgeExternalIds>> generateBridgeExternalIdsTestCases() {
+        return generateKeyValueTestCases(new SouthboundBridgeExternalIdsBuilder(), "BridgeExternalIdsKey",
+                "BridgeExternalIdsValue");
     }
 
     /*
@@ -3340,36 +2077,23 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         connectOvsdbNode(connectionInfo);
         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
         // the update has been performed.
-        Map<String, Map<String, List<BridgeExternalIds>>> updateFromTestCases = generateBridgeExternalIdsTestCases();
-        Map<String, Map<String, List<BridgeExternalIds>>> updateToTestCases = generateBridgeExternalIdsTestCases();
-        Map<String, List<BridgeExternalIds>> updateFromTestCase;
-        List<BridgeExternalIds> updateFromInputExternalIds;
-        List<BridgeExternalIds> updateFromExpectedExternalIds;
-        Map<String, List<BridgeExternalIds>> updateToTestCase;
-        List<BridgeExternalIds> updateToInputExternalIds;
-        List<BridgeExternalIds> updateToExpectedExternalIds;
+        List<SouthboundTestCase<BridgeExternalIds>> updateFromTestCases = generateBridgeExternalIdsTestCases();
+        List<SouthboundTestCase<BridgeExternalIds>> updateToTestCases = generateBridgeExternalIdsTestCases();
         String testBridgeName;
 
         int counter = 1;
         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
-        for (String updateFromTestCaseKey : updateFromTestCases.keySet()) {
-            updateFromTestCase = updateFromTestCases.get(updateFromTestCaseKey);
-            updateFromInputExternalIds = updateFromTestCase.get(INPUT_VALUES_KEY);
-            updateFromExpectedExternalIds = updateFromTestCase.get(EXPECTED_VALUES_KEY);
-            for (String testCaseKey : updateToTestCases.keySet()) {
-                testBridgeName = String.format("%s_%s_%d", TEST_BRIDGE_PREFIX, testCaseKey, counter);
+        for (SouthboundTestCase<BridgeExternalIds> fromTestCase : updateFromTestCases) {
+            for (SouthboundTestCase<BridgeExternalIds> toTestCase : updateToTestCases) {
+                testBridgeName = String.format(FORMAT_STR, TEST_BRIDGE_PREFIX, toTestCase.name, counter);
                 counter += 1;
-                updateToTestCase = updateToTestCases.get(testCaseKey);
-                updateToInputExternalIds = updateToTestCase.get(INPUT_VALUES_KEY);
-                updateToExpectedExternalIds = updateToTestCase.get(EXPECTED_VALUES_KEY);
-
                 TestCRUDBridgeExternalIdsRunnable testRunnable =
                         new TestCRUDBridgeExternalIdsRunnable(
                                 connectionInfo, testBridgeName,
-                                updateFromInputExternalIds,
-                                updateFromExpectedExternalIds,
-                                updateToInputExternalIds,
-                                updateToExpectedExternalIds);
+                                fromTestCase.inputValues,
+                                fromTestCase.expectedValues,
+                                toTestCase.inputValues,
+                                toTestCase.expectedValues);
                 executor.submit(testRunnable);
             }
         }
@@ -3466,7 +2190,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
     }
 
     public static NodeId createManagedNodeId(ConnectionInfo key, OvsdbBridgeName bridgeName) {
-        return createManagedNodeId(key.getRemoteIp(),key.getRemotePort(),bridgeName);
+        return createManagedNodeId(key.getRemoteIp(), key.getRemotePort(), bridgeName);
     }
 
     public static NodeId createManagedNodeId(IpAddress ip, PortNumber port, OvsdbBridgeName bridgeName) {
@@ -3502,4 +2226,110 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         NodeKey nodeKey = iid.firstKeyOf(Node.class, NodeKey.class);
         return nodeKey.getNodeId();
     }
+
+    /**
+     * <p>
+     * Representation of a southbound test case. Each test case has a name, a list of input values and a list of
+     * expected values. The input values are provided to the augmentation builder, and the expected values are checked
+     * against the output of the resulting augmentation.
+     * </p>
+     * <p>
+     * Instances of this class are immutable.
+     * </p>
+     *
+     * @param <T> The type of data used for the test case.
+     */
+    private static final class SouthboundTestCase<T> {
+        private final String name;
+        private final List<T> inputValues;
+        private final List<T> expectedValues;
+
+        /**
+         * Creates an instance of a southbound test case.
+         *
+         * @param name The test case's name.
+         * @param inputValues The input values (provided as input to the underlying augmentation builder).
+         * @param expectedValues The expected values (checked against the output of the underlying augmentation).
+         */
+        public SouthboundTestCase(
+                final String name, final List<T> inputValues, final List<T> expectedValues) {
+            this.name = name;
+            this.inputValues = inputValues;
+            this.expectedValues = expectedValues;
+        }
+    }
+
+    /**
+     * Southbound test case builder.
+     *
+     * @param <T> The type of data used for the test case.
+     */
+    private static final class SouthboundTestCaseBuilder<T> {
+        private String name;
+        private List<T> inputValues;
+        private List<T> expectedValues;
+
+        /**
+         * Creates a builder. Builders may be reused, the generated immutable instances are independent of the
+         * builders. There are no default values.
+         */
+        public SouthboundTestCaseBuilder() {
+            // Nothing to do
+        }
+
+        /**
+         * Sets the test case's name.
+         *
+         * @param name The test case's name.
+         * @return The builder.
+         */
+        public SouthboundTestCaseBuilder<T> name(final String name) {
+            this.name = name;
+            return this;
+        }
+
+        /**
+         * Sets the input values.
+         *
+         * @param inputValues The input values.
+         * @return The builder.
+         */
+        @SafeVarargs
+        public final SouthboundTestCaseBuilder<T> input(final T... inputValues) {
+            this.inputValues = Lists.newArrayList(inputValues);
+            return this;
+        }
+
+        /**
+         * Sets the expected output values.
+         *
+         * @param expectedValues The expected output values.
+         * @return The builder.
+         */
+        @SafeVarargs
+        public final SouthboundTestCaseBuilder<T> expect(final T... expectedValues) {
+            this.expectedValues = Lists.newArrayList(expectedValues);
+            return this;
+        }
+
+        /**
+         * Indicates that the provided input values should be expected as output values.
+         *
+         * @return The builder.
+         */
+        public SouthboundTestCaseBuilder<T> expectInputAsOutput() {
+            this.expectedValues = this.inputValues;
+            return this;
+        }
+
+        /**
+         * Builds an immutable instance representing the test case.
+         *
+         * @return The test case.
+         */
+        @SuppressWarnings("unchecked")
+        public SouthboundTestCase<T> build() {
+            return new SouthboundTestCase<>(name, inputValues, expectedValues);
+        }
+    }
 }
index 91d7817323decc7339d7431dfbdca5b6b7377ea7..d0fac74adc426fa3284a3f3aa3a8d7335e9f93bd 100644 (file)
@@ -1,5 +1,5 @@
 /*
-* Copyright (C) 2014 Red Hat, Inc.
+* Copyright (C) 2014 Red Hat, 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,
index 291b2349bb96dc9441a17f2eb3b2febcb8f0d226..c6b0a2bfa1adc7a871e6b24864a8d4389e127647 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2015 Red Hat, Inc.
+ *  Copyright (C) 2015 Red Hat, 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,
index 886ae541eed9f9cf8058f8226f9b0393c555d873..807895c9e7d703de699b1a4b2e04f3d787ae5289 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2014 Red Hat, Inc.
+ *  Copyright (C) 2014 Red Hat, 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,
index 72a837e34bfdea08b6b8d8562beab6535bc258fa..d04b15a970067771ac20cc2d613dc6f6f6786a59 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2015 Red Hat, Inc.
+ *  Copyright (C) 2015 Red Hat, 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,