Merge changes I5809ac06,I4362cd4e
authorGiovanni Meo <gmeo@cisco.com>
Tue, 27 Aug 2013 13:43:00 +0000 (13:43 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 27 Aug 2013 13:43:00 +0000 (13:43 +0000)
* changes:
  Added Intellij files to gitignore
  Fixed typo and remove unecessary java.lang import

237 files changed:
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPCacheEvent.java [new file with mode: 0644]
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java
opendaylight/clustering/services_implementation/src/main/java/org/opendaylight/controller/clustering/services_implementation/internal/ClusterManager.java
opendaylight/clustering/services_implementation/src/main/resources/config/infinispan-config.xml
opendaylight/commons/opendaylight/pom.xml
opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ConfigurationImpl.java
opendaylight/connectionmanager/implementation/src/main/java/org/opendaylight/controller/connectionmanager/internal/Activator.java
opendaylight/connectionmanager/implementation/src/main/java/org/opendaylight/controller/connectionmanager/internal/ConnectionManager.java
opendaylight/connectionmanager/implementation/src/main/java/org/opendaylight/controller/connectionmanager/scheme/AbstractScheme.java
opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/IContainerManager.java
opendaylight/distribution/opendaylight/opendaylight-application.launch
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml
opendaylight/distribution/opendaylight/src/main/resources/run.sh
opendaylight/forwarding/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/internal/Activator.java
opendaylight/forwarding/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/internal/StaticRoutingImplementation.java
opendaylight/forwarding/staticrouting/src/test/java/org/opendaylight/controller/forwarding/staticrouting/StaticRouteTest.java
opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/FlowConfig.java
opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/FlowEntry.java
opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/IForwardingRulesManager.java
opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/Activator.java
opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java
opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/hostAware/HostNodeConnector.java
opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java
opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/RestMessages.java
opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/exception/BadRequestException.java [new file with mode: 0644]
opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/exception/NotImplemented.java [new file with mode: 0644]
opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/exception/NotImplementedException.java [new file with mode: 0644]
opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowConfigs.java
opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowProgrammerNorthbound.java
opendaylight/northbound/integrationtest/src/test/java/org/opendaylight/controller/northbound/integrationtest/NorthboundIT.java
opendaylight/northbound/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/northbound/StaticRoute.java
opendaylight/northbound/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/northbound/StaticRoutes.java
opendaylight/northbound/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/northbound/StaticRoutingNorthbound.java
opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/AllFlowStatistics.java
opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/AllPortStatistics.java
opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/AllTableStatistics.java
opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/FlowStatistics.java
opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/PortStatistics.java
opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/StatisticsNorthbound.java
opendaylight/northbound/statistics/src/main/java/org/opendaylight/controller/statistics/northbound/TableStatistics.java
opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/NodeConnectors.java
opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/Nodes.java
opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/SwitchNorthbound.java
opendaylight/northbound/topology/src/main/java/org/opendaylight/controller/topology/northbound/TopologyNorthboundJAXRS.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IInventoryShimInternalListener.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IOFStatisticsListener.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IReadFilterInternalListener.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IReadServiceFilter.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IRefreshInternalProvider.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/ISwitch.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/Controller.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/MessageReadWriteService.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SwitchEvent.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SwitchHandler.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServiceShim.java
opendaylight/protocol_plugins/stub/src/main/java/org/opendaylight/controller/protocol_plugins/stub/internal/Activator.java
opendaylight/protocol_plugins/stub/src/main/java/org/opendaylight/controller/protocol_plugins/stub/internal/InventoryService.java
opendaylight/routing/dijkstra_implementation/src/main/java/org/opendaylight/controller/routing/dijkstra_implementation/internal/Activator.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/authorization/IResourceAuthorization.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Actions.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Bandwidth.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Buffers.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Capabilities.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Config.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Description.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/ForwardingMode.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/IContainerAware.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/IContainerListener.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Latency.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/MacAddress.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Name.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/NodeTable.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/State.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Tables.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Tier.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/TimeStamp.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginInFlowProgrammerService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/Match.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchField.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IPluginInReadService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IPluginOutReadService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IReadService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/reader/IReadServiceListener.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/routing/IRouting.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/topology/IListenTopoUpdates.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/topology/IPluginOutTopologyService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/ConfigurationObject.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/IListener.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/INodeConnectorFactory.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/INodeFactory.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NetUtils.java
opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java
opendaylight/sal/connection/api/src/main/java/org/opendaylight/controller/sal/connection/IConnectionService.java
opendaylight/sal/connection/api/src/main/java/org/opendaylight/controller/sal/connection/IPluginInConnectionService.java
opendaylight/sal/connection/api/src/main/java/org/opendaylight/controller/sal/connection/IPluginOutConnectionService.java
opendaylight/sal/networkconfiguration/api/src/main/java/org/opendaylight/controller/sal/networkconfig/bridgedomain/IBridgeDomainConfigService.java
opendaylight/sal/networkconfiguration/api/src/main/java/org/opendaylight/controller/sal/networkconfig/bridgedomain/IPluginInBridgeDomainConfigService.java
opendaylight/sal/yang-prototype/pom.xml
opendaylight/sal/yang-prototype/sal/model/model-flow-statistics/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/model/model-flow-statistics/src/main/yang/opendaylight-flow-statistics.yang [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/model/model-flow/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/model/model-flow/src/main/yang/opendaylight-flow.yang [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/model/model-inventory/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/model/model-inventory/src/main/yang/opendaylight-inventory.yang [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/model/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/model/src/main/yang/.gitignore [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/pom.xml
opendaylight/sal/yang-prototype/sal/sal-binding-api/pom.xml
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareConsumer.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareProvider.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareBroker.java
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareConsumer.java
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareProvider.java
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareService.java
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationListener.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationProviderService.java
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationService.java
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java [moved from opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataBrokerService.java with 92% similarity]
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataCommitHandler.java [moved from opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataCommitHandler.java with 93% similarity]
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataProviderService.java [moved from opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataProviderService.java with 79% similarity]
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataRefresher.java [moved from opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataRefresher.java with 68% similarity]
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataValidator.java [moved from opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataValidator.java with 67% similarity]
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/RuntimeDataProvider.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/package-info.java
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/pom.xml
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/.gitignore [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingBrokerImpl.java [deleted file]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BrokerActivator.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/Constants.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataModule.java [deleted file]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationInvoker.java [deleted file]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationModule.java [deleted file]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiProviderContext.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProxyContext.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcServiceRegistrationImpl.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/GeneratorUtils.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/PropertiesUtils.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/package-info.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-spi/pom.xml
opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/DataDomToJavaTransformer.java
opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/JavaToDataDomTransformer.java
opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/Mapper.java
opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/MappingProvider.java
opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcMapper.java
opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/SALBindingModule.java [deleted file]
opendaylight/sal/yang-prototype/sal/sal-broker-impl/pom.xml
opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/BrokerImpl.java
opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/DataBrokerModule.java
opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/NotificationModule.java
opendaylight/sal/yang-prototype/sal/sal-common-util/pom.xml
opendaylight/sal/yang-prototype/sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Futures.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java
opendaylight/sal/yang-prototype/sal/sal-common/pom.xml
opendaylight/sal/yang-prototype/sal/sal-core-api/pom.xml
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/Broker.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/BrokerService.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/Consumer.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/Provider.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementation.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataBrokerService.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataCommitHandler.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataValidator.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/data/package-info.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaService.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationListener.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationProviderService.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationService.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/package-info.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/package-info.java
opendaylight/sal/yang-prototype/sal/sal-core-demo/pom.xml
opendaylight/sal/yang-prototype/sal/sal-core-spi/pom.xml
opendaylight/sal/yang-prototype/sal/sal-data-api/pom.xml
opendaylight/sal/yang-prototype/sal/sal-schema-repository-api/pom.xml
opendaylight/sal/yang-prototype/sal/samples/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/samples/toaster-consumer/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/api/ToastConsumer.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/samples/toaster-it/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/samples/toaster-provider/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterActivator.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/samples/toaster/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/samples/toaster/src/main/yang/toaster.yang [new file with mode: 0644]
opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/SimpleForwardingImpl.java
opendaylight/statisticsmanager/implementation/src/main/java/org/opendaylight/controller/statisticsmanager/internal/StatisticsManager.java
opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/Activator.java
opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java
opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImpl.java
opendaylight/usermanager/implementation/src/main/java/org/opendaylight/controller/usermanager/internal/Activator.java
opendaylight/usermanager/implementation/src/main/java/org/opendaylight/controller/usermanager/internal/UserManagerImpl.java
opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/Devices.java
opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/NodeJsonBean.java [new file with mode: 0644]
opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/SubnetGatewayPortBean.java [new file with mode: 0644]
opendaylight/web/devices/src/main/resources/js/page.js
opendaylight/web/flows/src/main/java/org/opendaylight/controller/flows/web/Flows.java
opendaylight/web/flows/src/main/resources/js/page.js
opendaylight/web/root/src/main/resources/WEB-INF/jsp/main.jsp
opendaylight/web/root/src/main/resources/css/fuelux-responsive.min.css [new file with mode: 0755]
opendaylight/web/root/src/main/resources/css/fuelux.min.css [new file with mode: 0755]
opendaylight/web/root/src/main/resources/css/opendaylight.css [new file with mode: 0644]
opendaylight/web/root/src/main/resources/img/form.png [new file with mode: 0755]
opendaylight/web/root/src/main/resources/img/nextpageleft.png [new file with mode: 0644]
opendaylight/web/root/src/main/resources/img/nextpageright.png [new file with mode: 0644]
opendaylight/web/root/src/main/resources/img/search.png [new file with mode: 0644]
opendaylight/web/root/src/main/resources/img/searchremove.png [new file with mode: 0644]
opendaylight/web/root/src/main/resources/img/sort_down.png [new file with mode: 0644]
opendaylight/web/root/src/main/resources/img/sort_up.png [new file with mode: 0644]
opendaylight/web/root/src/main/resources/js/datasource.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/COPYING [new file with mode: 0644]
opendaylight/web/root/src/main/resources/js/fuelux/all.min.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/checkbox.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/combobox.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/datagrid.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/loader.min.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/pillbox.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/radio.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/search.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/select.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/spinner.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/tree.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/util.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/fuelux/wizard.js [new file with mode: 0755]
opendaylight/web/root/src/main/resources/js/lib.js
opendaylight/web/root/src/main/resources/js/underscore-min.js [new file with mode: 0644]
opendaylight/web/troubleshoot/src/main/java/org/opendaylight/controller/troubleshoot/web/Troubleshoot.java
opendaylight/web/troubleshoot/src/main/resources/js/page.js

diff --git a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPCacheEvent.java b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPCacheEvent.java
new file mode 100644 (file)
index 0000000..e7b342f
--- /dev/null
@@ -0,0 +1,62 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.arphandler;
+
+public class ARPCacheEvent {
+    private ARPEvent event;
+    private boolean newReply;
+
+    public ARPCacheEvent(ARPEvent event, boolean newReply) {
+        super();
+        this.event = event;
+        this.newReply = newReply;
+    }
+
+    public ARPEvent getEvent() {
+        return event;
+    }
+
+    public boolean isNewReply() {
+        return newReply;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((event == null) ? 0 : event.hashCode());
+        result = prime * result + (newReply ? 1231 : 1237);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        ARPCacheEvent other = (ARPCacheEvent) obj;
+        if (event == null) {
+            if (other.event != null)
+                return false;
+        } else if (!event.equals(other.event))
+            return false;
+        if (newReply != other.newReply)
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "ARPCacheEvent [event=" + event + ", newReply=" + newReply + "]";
+    }
+}
index 0ff1cd9bd6a542dc8694b09933bfe2c1835d3bbd..f3b22c75d8102a76beeb78229e7faabb89e60bd5 100644 (file)
@@ -21,10 +21,13 @@ import java.util.HashSet;
 import java.util.Set;
 import java.util.Timer;
 import java.util.TimerTask;
+import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.LinkedBlockingQueue;
 
+import org.opendaylight.controller.arphandler.ARPCacheEvent;
 import org.opendaylight.controller.arphandler.ARPEvent;
 import org.opendaylight.controller.arphandler.ARPReply;
 import org.opendaylight.controller.arphandler.ARPRequest;
@@ -49,6 +52,7 @@ import org.opendaylight.controller.sal.packet.IPv4;
 import org.opendaylight.controller.sal.packet.Packet;
 import org.opendaylight.controller.sal.packet.PacketResult;
 import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
 import org.opendaylight.controller.sal.utils.EtherTypes;
 import org.opendaylight.controller.sal.utils.HexEncode;
 import org.opendaylight.controller.sal.utils.NetUtils;
@@ -71,6 +75,8 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA
     private ConcurrentMap<InetAddress, Set<HostNodeConnector>> arpRequestors;
     private ConcurrentMap<InetAddress, Short> countDownTimers;
     private Timer periodicTimer;
+    private BlockingQueue<ARPCacheEvent> ARPCacheEvents = new LinkedBlockingQueue<ARPCacheEvent>();
+    Thread cacheEventHandler;
     /*
      * A cluster allocated cache. Used for synchronizing ARP request/reply
      * events across all cluster controllers. To raise an event, we put() a specific
@@ -504,6 +510,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA
     void init() {
         arpRequestors = new ConcurrentHashMap<InetAddress, Set<HostNodeConnector>>();
         countDownTimers = new ConcurrentHashMap<InetAddress, Short>();
+        cacheEventHandler = new Thread(new ARPCacheEventHandler(), "ARPCacheEventHandler Thread");
 
         allocateCaches();
         retrieveCaches();
@@ -536,7 +543,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA
 
         try{
             clusterContainerService.createCache(ARP_EVENT_CACHE_NAME,
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
         } catch (CacheConfigException e){
             log.error("ARPHandler cache configuration invalid!");
         } catch (CacheExistException e){
@@ -565,6 +572,8 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA
      */
     void start() {
         startPeriodicTimer();
+        cacheEventHandler.start();
+
     }
 
     /**
@@ -687,31 +696,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA
 
     @Override
     public void entryUpdated(ARPEvent key, Boolean new_value, String cacheName, boolean originLocal) {
-        if (key instanceof ARPRequest) {
-            ARPRequest req = (ARPRequest) key;
-            // If broadcast request
-            if (req.getHost() == null) {
-                sendBcastARPRequest(req.getTargetIP(), req.getSubnet());
-
-            //If unicast and local, send reply
-            } else if (connectionManager.isLocal(req.getHost().getnodeconnectorNode())) {
-                sendUcastARPRequest(req.getHost(), req.getSubnet());
-            }
-        } else if (key instanceof ARPReply) {
-            ARPReply rep = (ARPReply) key;
-            // New reply received by controller, notify all awaiting requestors across the cluster
-            if (new_value) {
-                generateAndSendReply(rep.getTargetIP(), rep.getTargetMac());
-
-            // Otherwise, a specific reply. If local, send out.
-            } else if (connectionManager.isLocal(rep.getPort().getNode())) {
-                sendARPReply(rep.getPort(),
-                        rep.getSourceMac(),
-                        rep.getSourceIP(),
-                        rep.getTargetMac(),
-                        rep.getTargetIP());
-            }
-        }
+        enqueueARPCacheEvent(key, new_value);
     }
 
     @Override
@@ -722,4 +707,58 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA
     public void entryDeleted(ARPEvent key, String cacheName, boolean originLocal) {
         // nothing to do
     }
+
+    private void enqueueARPCacheEvent (ARPEvent event, boolean new_value) {
+        try {
+            ARPCacheEvent cacheEvent = new ARPCacheEvent(event, new_value);
+            if (!ARPCacheEvents.contains(cacheEvent)) {
+                this.ARPCacheEvents.add(cacheEvent);
+            }
+        } catch (Exception e) {
+            log.debug("enqueueARPCacheEvent caught Interrupt Exception for event {}", event);
+        }
+    }
+
+    /*
+     * this thread monitors the connectionEvent queue for new incoming events from
+     */
+    private class ARPCacheEventHandler implements Runnable {
+        @Override
+        public void run() {
+            while (true) {
+                try {
+                    ARPCacheEvent ev = ARPCacheEvents.take();
+                    ARPEvent event = ev.getEvent();
+                    if (event instanceof ARPRequest) {
+                        ARPRequest req = (ARPRequest) event;
+                        // If broadcast request
+                        if (req.getHost() == null) {
+                            sendBcastARPRequest(req.getTargetIP(), req.getSubnet());
+
+                        //If unicast and local, send reply
+                        } else if (connectionManager.isLocal(req.getHost().getnodeconnectorNode())) {
+                            sendUcastARPRequest(req.getHost(), req.getSubnet());
+                        }
+                    } else if (event instanceof ARPReply) {
+                        ARPReply rep = (ARPReply) event;
+                        // New reply received by controller, notify all awaiting requestors across the cluster
+                        if (ev.isNewReply()) {
+                            generateAndSendReply(rep.getTargetIP(), rep.getTargetMac());
+
+                        // Otherwise, a specific reply. If local, send out.
+                        } else if (connectionManager.isLocal(rep.getPort().getNode())) {
+                            sendARPReply(rep.getPort(),
+                                    rep.getSourceMac(),
+                                    rep.getSourceIP(),
+                                    rep.getTargetMac(),
+                                    rep.getTargetIP());
+                        }
+                    }
+                } catch (InterruptedException e) {
+                    ARPCacheEvents.clear();
+                    return;
+                }
+            }
+        }
+    }
 }
index c3fd30ae9b65629c8e83bb7f789229b0b6bc5870..f5c655a4eae8fb52afcefad92507177ff1cc479a 100644 (file)
@@ -227,7 +227,8 @@ public class ClusterManager implements IClusterServices, IContainerAware {
         if (amIGossipRouter) {
             logger.info("I'm a GossipRouter will listen on port {}",
                     gossipRouterPort);
-            res = new GossipRouter(gossipRouterPort);
+            // Start a GossipRouter with JMX support
+            res = new GossipRouter(gossipRouterPort, null, true);
         }
         return res;
     }
index e917eea825bf7049e620ce8013bf0ce497bc095c..ff6f99cb4bdd45adb87582f40d47356d4f8ee711 100644 (file)
@@ -28,7 +28,7 @@
         syncRollbackPhase="true"
         syncCommitPhase="true"
         cacheStopTimeout="30000"
-        use1PcForAutoCommitTransactions="false"
+        use1PcForAutoCommitTransactions="true"
         autoCommit="true"
         lockingMode="OPTIMISTIC"
         useSynchronization="true"
index ff6b5a1cefe9cb5aafd082e51ee4531b7339ff49..7edee854597328aa46bf263c7a36862bc93ada67 100644 (file)
     <geminiweb.version>2.2.0.RELEASE</geminiweb.version>
     <checkstyle.version>2.10</checkstyle.version>
     <testvm.argLine>-Xmx1024m -XX:MaxPermSize=256m</testvm.argLine>
+    <yang.version>0.5.7-SNAPSHOT</yang.version>
+    <guava.version>14.0.1</guava.version>
+    <ietf-inet-types.version>2010.09.24-SNAPSHOT</ietf-inet-types.version>
+    <ietf-yang-types.version>2010.09.24-SNAPSHOT</ietf-yang-types.version>
+    <yang-ext.version>2013.09.07-SNAPSHOT</yang-ext.version>
+    <javassist.version>3.17.1-GA</javassist.version>
+    <sample-toaster.version>1.0-SNAPSHOT</sample-toaster.version>
   </properties>
 
   <pluginRepositories>
       <artifactId>jersey-json</artifactId>
       <version>${jersey.version}</version>
     </dependency>
+
+    <!-- yangtools -->
+
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-binding</artifactId>
+      <version>${yang.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-common</artifactId>
+      <version>${yang.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-api</artifactId>
+      <version>${yang.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-model-api</artifactId>
+      <version>${yang.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-util</artifactId>
+      <version>${yang.version}</version>
+    </dependency>
+
+    <!-- Models -->
+
+    <dependency>
+      <groupId>org.opendaylight.yangtools.model</groupId>
+      <artifactId>ietf-inet-types</artifactId>
+      <version>${ietf-inet-types.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools.model</groupId>
+      <artifactId>ietf-yang-types</artifactId>
+      <version>${ietf-yang-types.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-ext</artifactId>
+      <version>${yang-ext.version}</version>
+    </dependency>
+
+    <!-- Other MDSAL dependencies -->
+
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+      <version>${guava.version}</version>
+      <type>jar</type>
+    </dependency>
+    <dependency>
+      <groupId>org.javassist</groupId>
+      <artifactId>javassist</artifactId>
+      <version>${javassist.version}</version>
+    </dependency>
   </dependencies>
 </project>
index 8e2741e7d1b1231b5d16ab63af07712ea4a8cad9..fa81ee026a39ac2766456958636515fffee4e6f5 100644 (file)
@@ -145,7 +145,7 @@ public class ConfigurationImpl implements IConfigurationService, ICacheUpdateAwa
         }
         try {
             this.clusterServices.createCache("config.event.save",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
         } catch (CacheConfigException cce) {
             logger.error("Error creating Configuration cache ", cce);
         } catch (CacheExistException cce) {
index 4bee2537656e3ac1ddfda162cd20735939a50a58..c0d1b50a4657a314fbcdd7010fdb89d28e72ffa8 100644 (file)
@@ -25,6 +25,7 @@ import org.apache.felix.dm.Component;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.inventory.IInventoryService;
 import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
 
 public class Activator extends ComponentActivatorAbstractBase {
@@ -37,6 +38,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      * ComponentActivatorAbstractBase.
      *
      */
+    @Override
     public void init() {
     }
 
@@ -45,6 +47,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      * cleanup done by ComponentActivatorAbstractBase
      *
      */
+    @Override
     public void destroy() {
     }
 
@@ -61,6 +64,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      * @return The list of implementations the bundle will support,
      * in Global version
      */
+    @Override
     protected Object[] getGlobalImplementations() {
         Object[] res = { ConnectionManager.class };
         return res;
@@ -74,6 +78,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      * @param imp implementation to be configured
      * @param containerName container on which the configuration happens
      */
+    @Override
     protected void configureGlobalInstance(Component c, Object imp) {
         if (imp.equals(ConnectionManager.class)) {
             Dictionary<String, Object> props = new Hashtable<String, Object>();
@@ -100,6 +105,9 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.add(createServiceDependency().setService(IConnectionService.class)
                     .setCallbacks("setConnectionService", "unsetConnectionService")
                     .setRequired(true));
+            c.add(createServiceDependency().setService(IInventoryService.class, "(scope=Global)")
+                    .setCallbacks("setInventoryService", "unsetInventoryService")
+                    .setRequired(true));
         }
     }
 }
index fdba533b5bfa827bf2ccd79bf2f061785d06d597..e2d8f6b03b270f7f602de6b4470bc0a971487f61 100644 (file)
@@ -32,7 +32,6 @@ import java.util.concurrent.LinkedBlockingQueue;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
 import org.eclipse.osgi.framework.console.CommandInterpreter;
 import org.eclipse.osgi.framework.console.CommandProvider;
 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
@@ -49,6 +48,7 @@ import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.inventory.IInventoryService;
 import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
@@ -66,6 +66,7 @@ public class ConnectionManager implements IConnectionManager, IConnectionListene
     private IConnectionService connectionService;
     private Thread connectionEventThread;
     private BlockingQueue<ConnectionMgmtEvent> connectionEvents;
+    private IInventoryService inventoryService;
 
     public void setClusterServices(IClusterGlobalServices i) {
         this.clusterServices = i;
@@ -87,12 +88,48 @@ public class ConnectionManager implements IConnectionManager, IConnectionListene
         }
     }
 
+    public void setInventoryService(IInventoryService service) {
+        logger.trace("Got inventory service set request {}", service);
+        this.inventoryService = service;
+    }
+
+    public void unsetInventoryService(IInventoryService service) {
+        logger.trace("Got a service UNset request");
+        this.inventoryService = null;
+    }
+
+    private void getInventories() {
+        Map<Node, Map<String, Property>> nodeProp = this.inventoryService.getNodeProps();
+        for (Map.Entry<Node, Map<String, Property>> entry : nodeProp.entrySet()) {
+            Node node = entry.getKey();
+            logger.debug("getInventories for node:{}", new Object[] { node });
+            Map<String, Property> propMap = entry.getValue();
+            Set<Property> props = new HashSet<Property>();
+            for (Property property : propMap.values()) {
+                props.add(property);
+            }
+            updateNode(node, UpdateType.ADDED, props);
+        }
+
+        Map<NodeConnector, Map<String, Property>> nodeConnectorProp = this.inventoryService.getNodeConnectorProps();
+        for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProp.entrySet()) {
+            Map<String, Property> propMap = entry.getValue();
+            Set<Property> props = new HashSet<Property>();
+            for (Property property : propMap.values()) {
+                props.add(property);
+            }
+            updateNodeConnector(entry.getKey(), UpdateType.ADDED, props);
+        }
+    }
+
     public void started() {
         connectionEventThread = new Thread(new EventHandler(), "ConnectionEvent Thread");
         connectionEventThread.start();
 
         registerWithOSGIConsole();
         notifyClusterViewChanged();
+        // Should pull the Inventory updates in case we missed it
+        getInventories();
     }
 
     public void init() {
index 6b20909a877ce81de268c585c5e309be9fe7e2cf..d7c4e5f933bdba54e0a0cd5411627546c0133b72 100644 (file)
@@ -75,6 +75,7 @@ public abstract class AbstractScheme {
 
     @SuppressWarnings("deprecation")
     public void handleClusterViewChanged() {
+        log.debug("Handling Cluster View changed notification");
         List<InetAddress> controllers = clusterServices.getClusteredControllers();
         ConcurrentMap <InetAddress, Set<Node>> controllerNodesMap = getControllerToNodesMap();
         List<InetAddress> toRemove = new ArrayList<InetAddress>();
@@ -103,8 +104,8 @@ public abstract class AbstractScheme {
                             clusterServices.tcommit();
                         }
                     } catch (Exception e) {
-                        log.error("Exception in replacing nodeConnections ", e);
-                        retry = false;
+                        log.debug("Exception in replacing nodeConnections ", e);
+                        retry = true;
                         try {
                             clusterServices.trollback();
                         } catch (Exception e1) {}
@@ -115,10 +116,8 @@ public abstract class AbstractScheme {
         }
         if (retry) {
             try {
-                Thread.sleep(100);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {}
             handleClusterViewChanged();
         }
     }
@@ -238,13 +237,12 @@ public abstract class AbstractScheme {
                  * with this controller to take hold of a Node.
                  */
                 if (isConnectionAllowed(node)) {
-                    if (!nodeConnections.replace(node, oldControllers, newControllers)) {
+                    if (oldControllers == null || !nodeConnections.replace(node, oldControllers, newControllers)) {
                         clusterServices.trollback();
                         try {
                             Thread.sleep(100);
                         } catch ( InterruptedException e) {}
-                        log.debug("Replace failed... old={} with new={} for {} to {}", oldControllers.toString(), newControllers.toString(),
-                                controller.getHostAddress(), node.toString());
+                        log.debug("Retrying ... {} with {}", controller.getHostAddress(), node.toString());
                         return putNodeToController(node, controller);
                     } else {
                         log.debug("Replace successful old={} with new={} for {} to {}", oldControllers.toString(), newControllers.toString(),
index 89c0c0b217f6de65dfc6a2bfd855e6d259b65782..9300921be9c424dbc2b10146926a9d42dcb81f9c 100644 (file)
@@ -14,8 +14,7 @@ import java.util.List;
 import org.opendaylight.controller.sal.utils.Status;
 
 /**
- * Container Manager interface
- *
+ * Container Manager Interface - provides methods to get information on existing OSGI containers
  *
  */
 public interface IContainerManager {
@@ -23,14 +22,14 @@ public interface IContainerManager {
     /**
      * Returns true if there are any non-default Containers present.
      *
-     * @return  true, if any non-default container is present, else false
+     * @return  true if any non-default container is present false otherwise.
      */
     public boolean hasNonDefaultContainer();
 
     /**
-     * Returns a list of Containers that currently exist.
+     * Returns a list of the existing containers.
      *
-     * @return  array of String Container names
+     * @return  List of Container name strings.
      */
     public List<String> getContainerNames();
 
@@ -41,5 +40,6 @@ public interface IContainerManager {
      *
      * @return  status code
      */
+    @Deprecated
     public Status saveContainerConfig();
 }
index 5de9baee2f4d72ca0875785f37ebd7055da7756f..78737f58dfe38f295d9aac80e9c97efada0246a8 100644 (file)
@@ -7,7 +7,7 @@
 <listEntry value="4"/>
 </listAttribute>
 <stringAttribute key="org.eclipse.debug.core.source_locator_id" value="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"/>
-<stringAttribute key="org.eclipse.debug.core.source_locator_memento" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;sourceLookupDirector&gt;&#10;&lt;sourceContainers duplicates=&quot;false&quot;&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;switchmanager.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;commons.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;configuration&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;configuration.implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;containermanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;flowprogrammer.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;forwarding.staticrouting.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;hosttracker&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;hosttracker.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;protocol_plugins.openflow&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;statistics.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;subnets.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;topology.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;containermanager.implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;devices.web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;flows.web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;samples.simpleforwarding&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;topology.web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;troubleshoot.web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;clustering.services&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;mactracker&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;sal&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;slicemanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;switchmanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;topologymanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;arphandler&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;clustering.services-implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;clustering.test&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;configuration.web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;forwarding.ipswitch&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;forwarding.staticrouting&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;forwardingrulesmanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;home.web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;monitor&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;northboundtest&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;onep.topology.southbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;openflowj&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;protocol_plugin.openflow&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;routing.dijkstra_implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;sal.implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;slicemanager.implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;statisticsmanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;tifmgr&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;usermanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;/sourceContainers&gt;&#10;&lt;/sourceLookupDirector&gt;&#10;"/>
+<stringAttribute key="org.eclipse.debug.core.source_locator_memento" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;sourceLookupDirector&gt;&#10;&lt;sourceContainers duplicates=&quot;false&quot;&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;switchmanager.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;commons.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;configuration&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;configuration.implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;containermanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;flowprogrammer.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;forwarding.staticrouting.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;hosttracker&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;hosttracker.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;protocol_plugins.openflow&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;statistics.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;subnets.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;topology.northbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;containermanager.implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;devices.web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;flows.web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;samples.simpleforwarding&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;topology.web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;troubleshoot.web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;clustering.services&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;mactracker&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;sal&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;slicemanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;switchmanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;topologymanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;arphandler&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;clustering.services-implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;clustering.test&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;configuration.web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;forwarding.ipswitch&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;forwarding.staticrouting&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;forwardingrulesmanager.implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;forwardingrulesmanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;home.web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;monitor&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;northboundtest&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;onep.topology.southbound&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;openflowj&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;protocol_plugin.openflow&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;routing.dijkstra_implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;sal.implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;slicemanager.implementation&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;statisticsmanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;tifmgr&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;usermanager&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;javaProject name=&amp;quot;web&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.javaProject&quot;/&gt;&#10;&lt;/sourceContainers&gt;&#10;&lt;/sourceLookupDirector&gt;&#10;"/>
 <listAttribute key="org.eclipse.debug.ui.favoriteGroups">
 <listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
 <listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
index 1833b4ae592fa5867ccb58730dd8a7bb4feccf21..abf508efc2bb308f2727f69d9e4d8cc9b80da35e 100644 (file)
@@ -5,10 +5,10 @@
   <prerequisites>
     <maven>3.0</maven>
   </prerequisites>
-
   <scm>
-    <connection>scm:git:https://git.opendaylight.org/gerrit/p/controller.git</connection>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
     <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
   </scm>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
@@ -67,6 +67,7 @@
     <module>../../../third-party/openflowj</module>
     <module>../../../third-party/net.sf.jung2</module>
     <module>../../../third-party/jersey-servlet</module>
+    <module>../../../third-party/commons/thirdparty</module>
 
     <!-- SAL bundles -->
     <module>../../sal/api</module>
@@ -78,6 +79,9 @@
     <module>../../sal/networkconfiguration/api</module>
     <module>../../sal/networkconfiguration/implementation</module>
 
+    <!-- MD-SAL bundles -->
+    <module>../../sal/yang-prototype</module>
+
     <!--  Web bundles -->
     <module>../../web/root</module>
     <module>../../web/flows</module>
     <module>../../samples/simpleforwarding</module>
     <module>../../samples/loadbalancer</module>
     <module>../../samples/northbound/loadbalancer</module>
+
+    <!-- Parents -->
     <module>../../commons/concepts</module>
     <module>../../commons/integrationtest</module>
     <module>../../commons/checkstyle</module>
     <module>../../commons/opendaylight</module>
+    <module>../../commons/parent</module>
   </modules>
 
   <build>
index b99b4bfdcaf40aefc2aae1daa0c340f97e96d218..f9899d7d8b3c5ca5821a2971c336d8d07f43bdac 100644 (file)
@@ -77,9 +77,9 @@ org.eclipse.gemini.web.tomcat.config.path=configuration/tomcat-server.xml
 # entries, including switches' Certification Authority (CA) certificates. For example,
 # secureChannelEnabled=true
 # controllerKeyStore=./configuration/ctlKeyStore
-# controllerKeyStorePassword=xxxxx (this password should match the password used for KeyStore generation)
+# controllerKeyStorePassword=xxxxxxxx (this password should match the password used for KeyStore generation and at least 6 characters)
 # controllerTrustStore=./configuration/ctlTrustStore
-# controllerTrustStorePassword=xxxxx (this password should match the password used for TrustStore generation)
+# controllerTrustStorePassword=xxxxxxxx (this password should match the password used for TrustStore generation and at least 6 characters)
 
 secureChannelEnabled=false
 controllerKeyStore=
index de0a3bcd19e990c0287338d0b5e3b1fbe8696c1b..50a87fb568c54ec8e6f6d4e7895c793386d46cf9 100644 (file)
@@ -34,6 +34,9 @@
   </root>
 
   <!--  Base log level  -->
+  <logger name="org.opendaylight" level="INFO"/>
+
+  <!-- Controller log level -->
   <logger name="org.opendaylight.controller" level="INFO"/>
 
   <!-- OSGi logging bridge -->
@@ -69,4 +72,4 @@
   <logger name="audit" level="INFO" additivity="false">
        <appender-ref ref="audit-file"/>
   </logger>
-</configuration>
\ No newline at end of file
+</configuration>
index 313b3b2c79cdd18dbf585f6a76adbeecf8e688f9..2daa1f42e3da236d9b320bdad504cdf48eb67903 100755 (executable)
@@ -1,9 +1,5 @@
 #!/bin/bash
 
-[[ -z ${JAVA_HOME} ]] && echo "Need to set JAVA_HOME environment variable" && exit -1;
-[[ ! -x ${JAVA_HOME}/bin/java ]] && echo "Cannot find an executable \
-JVM at path ${JAVA_HOME}/bin/java check your JAVA_HOME" && exit -1;
-
 platform='unknown'
 unamestr=`uname`
 if [[ "$unamestr" == 'Linux' ]]; then
@@ -32,12 +28,19 @@ elif [[ $platform == 'osx' ]]; then
    PHYS_DIR=`pwd -P`
    RESULT=$PHYS_DIR/$TARGET_FILE
    fullpath=$RESULT
+
+   [[ -z ${JAVA_HOME} ]] && [[ -x "/usr/libexec/java_home" ]] && export JAVA_HOME=`/usr/libexec/java_home -v 1.7`;
+
 fi
 
+[[ -z ${JAVA_HOME} ]] && echo "Need to set JAVA_HOME environment variable" && exit -1;
+[[ ! -x ${JAVA_HOME}/bin/java ]] && echo "Cannot find an executable \
+JVM at path ${JAVA_HOME}/bin/java check your JAVA_HOME" && exit -1;
+
 basedir=`dirname ${fullpath}`
 
 function usage {
-    echo "Usage: $0 [-debug] [-debugsuspend] [-debugport <num>] [-start [<console port>]] [-stop] [-status] [-console] [-help] [<other args will automatically be used for the JVM>]"
+    echo "Usage: $0 [-jmx] [-jmxport <num>] [-debug] [-debugsuspend] [-debugport <num>] [-start [<console port>]] [-stop] [-status] [-console] [-help] [<other args will automatically be used for the JVM>]"
     exit 1
 }
 
@@ -53,6 +56,9 @@ debugportread=""
 startdaemon=0
 daemonport=2400
 daemonportread=""
+jmxport=1088
+jmxportread=""
+startjmx=0
 stopdaemon=0
 statusdaemon=0
 consolestart=1
@@ -62,8 +68,10 @@ unknown_option=0
 while true ; do
     case "$1" in
         -debug) debug=1; shift ;;
+        -jmx) startjmx=1; shift ;;
         -debugsuspend) debugsuspend=1; shift ;;
         -debugport) shift; debugportread="$1"; if [[ "${debugportread}" =~ ^[0-9]+$ ]] ; then debugport=${debugportread}; shift; else echo "-debugport expects a number but was not found"; exit -1; fi;;
+        -jmxport) shift; jmxportread="$1"; if [[ "${jmxportread}" =~ ^[0-9]+$ ]] ; then jmxport=${jmxportread}; shift; else echo "-jmxport expects a number but was not found"; exit -1; fi;;
         -start) startdaemon=1; shift; daemonportread="$1"; if [[ "${daemonportread}" =~ ^[0-9]+$ ]] ; then daemonport=${daemonportread}; shift; fi;;
         -stop) stopdaemon=1; shift ;;
         -status) statusdaemon=1; shift ;;
@@ -97,6 +105,12 @@ if [[ "${daemonport}" -lt 1024 ]] || [[ "${daemonport}" -gt 65535 ]]; then
     exit -1
 fi
 
+# Validate jmx port
+if [[ "${jmxport}" -lt 1024 ]] || [[ "${jmxport}" -gt 65535 ]]; then
+    echo "JMX Port not in the range [1024,65535] value is ${jmxport}"
+    exit -1
+fi
+
 # Debug options
 if [ "${debugsuspend}" -eq 1 ]; then
     extraJVMOpts="${extraJVMOpts} -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=${debugport}"
@@ -104,6 +118,11 @@ elif [ "${debug}" -eq 1 ]; then
     extraJVMOpts="${extraJVMOpts} -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=${debugport}"
 fi
 
+# Add JMX support
+if [ "${startjmx}" -eq 1 ]; then
+    extraJVMOpts="${extraJVMOpts} -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=${jmxport} -Dcom.sun.management.jmxremote"
+fi
+
 ########################################
 # Now add to classpath the OSGi JAR
 ########################################
index 37f38734808cdbb583c5c7a20c17d80624df9352..a4397537486e738b482184ab6dc768270594e413 100644 (file)
@@ -21,7 +21,6 @@ import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
 import org.opendaylight.controller.hosttracker.IfIptoHost;
@@ -79,16 +78,10 @@ public class Activator extends ComponentActivatorAbstractBase {
      */
     public void configureInstance(Component c, Object imp, String containerName) {
         if (imp.equals(StaticRoutingImplementation.class)) {
-            Dictionary<String, Set<String>> props = new Hashtable<String, Set<String>>();
-            Set<String> propSet = new HashSet<String>();
-            propSet.add("forwarding.staticrouting.configSaveEvent");
-            props.put("cachenames", propSet);
-            // export the service
-
-            c.setInterface(new String[] { ICacheUpdateAware.class.getName(),
+            c.setInterface(new String[] {
                     IForwardingStaticRouting.class.getName(),
                     IfNewHostNotify.class.getName(),
-                    IConfigurationContainerAware.class.getName() }, props);
+                    IConfigurationContainerAware.class.getName() }, null);
 
             c.add(createContainerServiceDependency(containerName).setService(
                     IClusterContainerServices.class).setCallbacks(
index bccdea416208ef27d30294b9f7ddcebf83a77ba2..eac854c10674f796fae64ec174aaef07aad4aed5 100644 (file)
@@ -36,7 +36,6 @@ import java.util.regex.Pattern;
 import org.apache.felix.dm.Component;
 import org.opendaylight.controller.clustering.services.CacheConfigException;
 import org.opendaylight.controller.clustering.services.CacheExistException;
-import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
 import org.opendaylight.controller.clustering.services.IClusterServices;
 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
@@ -60,8 +59,7 @@ import org.slf4j.LoggerFactory;
  * Static Routing feature provides the bridge between SDN and Non-SDN networks.
  */
 public class StaticRoutingImplementation implements IfNewHostNotify,
-        IForwardingStaticRouting, IObjectReader, IConfigurationContainerAware,
-        ICacheUpdateAware<Long, String> {
+        IForwardingStaticRouting, IObjectReader, IConfigurationContainerAware {
     private static Logger log = LoggerFactory
             .getLogger(StaticRoutingImplementation.class);
     private static String ROOT = GlobalConstants.STARTUPHOME.toString();
@@ -71,7 +69,6 @@ public class StaticRoutingImplementation implements IfNewHostNotify,
     private IfIptoHost hostTracker;
     private Timer gatewayProbeTimer;
     private String staticRoutesFileName = null;
-    private Map<Long, String> configSaveEvent;
     private IClusterContainerServices clusterContainerService = null;
     private Set<IStaticRoutingAware> staticRoutingAware = Collections
             .synchronizedSet(new HashSet<IStaticRoutingAware>());
@@ -100,6 +97,7 @@ public class StaticRoutingImplementation implements IfNewHostNotify,
         }
     }
 
+    @Override
     public ConcurrentMap<String, StaticRouteConfig> getStaticRouteConfigs() {
         return staticRouteConfigs;
     }
@@ -134,8 +132,6 @@ public class StaticRoutingImplementation implements IfNewHostNotify,
 
 
     private Status saveConfig() {
-        // Publish the save config event to the cluster nodes
-        configSaveEvent.put(new Date().getTime(), SAVE);
         return saveConfigInternal();
     }
 
@@ -165,14 +161,10 @@ public class StaticRoutingImplementation implements IfNewHostNotify,
         try {
             clusterContainerService.createCache(
                     "forwarding.staticrouting.routes", EnumSet
-                            .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                            .of(IClusterServices.cacheMode.TRANSACTIONAL));
             clusterContainerService.createCache(
                     "forwarding.staticrouting.configs", EnumSet
-                            .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
-            clusterContainerService.createCache(
-                    "forwarding.staticrouting.configSaveEvent", EnumSet
-                            .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
-
+                            .of(IClusterServices.cacheMode.TRANSACTIONAL));
         } catch (CacheExistException cee) {
             log
                     .error("\nCache already exists - destroy and recreate if needed");
@@ -200,25 +192,6 @@ public class StaticRoutingImplementation implements IfNewHostNotify,
         if (staticRouteConfigs == null) {
             log.error("\nFailed to get rulesDB handle");
         }
-        configSaveEvent = (ConcurrentMap<Long, String>) clusterContainerService
-                .getCache("forwarding.staticrouting.configSaveEvent");
-        if (configSaveEvent == null) {
-            log.error("\nFailed to get cache for configSaveEvent");
-        }
-    }
-
-    @Override
-    public void entryCreated(Long key, String cacheName, boolean local) {
-    }
-
-    @Override
-    public void entryUpdated(Long key, String new_value, String cacheName,
-            boolean originLocal) {
-        saveConfigInternal();
-    }
-
-    @Override
-    public void entryDeleted(Long key, String cacheName, boolean originLocal) {
     }
 
     private void notifyStaticRouteUpdate(StaticRoute s, boolean update) {
@@ -286,11 +259,13 @@ public class StaticRoutingImplementation implements IfNewHostNotify,
     }
 
     private void notifyHostUpdate(HostNodeConnector host, boolean added) {
-        if (host == null)
+        if (host == null) {
             return;
+        }
         for (StaticRoute s : staticRoutes.values()) {
-            if (s.getType() == StaticRoute.NextHopType.SWITCHPORT)
+            if (s.getType() == StaticRoute.NextHopType.SWITCHPORT) {
                 continue;
+            }
             if (s.getNextHopAddress().equals(host.getNetworkAddress())) {
                 if (added) {
                     s.setHost(host);
@@ -313,8 +288,9 @@ public class StaticRoutingImplementation implements IfNewHostNotify,
     }
 
     public boolean isIPv4AddressValid(String cidr) {
-        if (cidr == null)
+        if (cidr == null) {
             return false;
+        }
 
         String values[] = cidr.split("/");
         Pattern ipv4Pattern = Pattern
@@ -350,6 +326,7 @@ public class StaticRoutingImplementation implements IfNewHostNotify,
         return 0;
     }
 
+    @Override
     public StaticRoute getBestMatchStaticRoute(InetAddress ipAddress) {
         ByteBuffer bblongestPrefix = null;
         try {
@@ -377,10 +354,9 @@ public class StaticRoutingImplementation implements IfNewHostNotify,
         return longestPrefixRoute;
     }
 
+    @Override
     public Status addStaticRoute(StaticRouteConfig config) {
-        Status status;
-
-        status = config.isValid();
+        Status status = config.isValid();
         if (!status.isSuccess()) {
             return status;
         }
@@ -389,22 +365,29 @@ public class StaticRoutingImplementation implements IfNewHostNotify,
                                 "A valid Static Route configuration with this name " +
                                                 "already exists. Please use a different name");
         }
-        for (StaticRouteConfig s : staticRouteConfigs.values()) {
-            if (s.equals(config)) {
+
+        // Update database
+        StaticRoute sRoute = new StaticRoute(config);
+
+        for (Map.Entry<String, StaticRoute> entry : staticRoutes.entrySet()) {
+            if (entry.getValue().compareTo(sRoute) == 0) {
                 return new Status(StatusCode.CONFLICT,
-                                "This conflicts with an existing Static Route " +
-                                        "Configuration. Please check the configuration " +
-                                                "and try again");
+                        "This conflicts with an existing Static Route " +
+                                "Configuration. Please check the configuration " +
+                                        "and try again");
             }
         }
+        staticRoutes.put(config.getName(), sRoute);
 
+        // Update config databse
         staticRouteConfigs.put(config.getName(), config);
-        StaticRoute sRoute = new StaticRoute(config);
-        staticRoutes.put(config.getName(), sRoute);
+
+        // Notify
         checkAndUpdateListeners(sRoute, true);
         return status;
     }
 
+    @Override
     public Status removeStaticRoute(String name) {
         staticRouteConfigs.remove(name);
         StaticRoute sRoute = staticRoutes.remove(name);
@@ -452,8 +435,9 @@ public class StaticRoutingImplementation implements IfNewHostNotify,
         allocateCaches();
         retrieveCaches();
         this.executor = Executors.newFixedThreadPool(1);
-        if (staticRouteConfigs.isEmpty())
+        if (staticRouteConfigs.isEmpty()) {
             loadConfiguration();
+        }
 
         /*
          *  Slow probe to identify any gateway that might have silently appeared
index 4a497a058c0df7a1bdc5b16c5a0cac656010c8f3..25b2dacde10656cba2475775136265d85817fc18 100644 (file)
@@ -83,9 +83,9 @@ public class StaticRouteTest {
         Assert.assertFalse(staticRoute1.equals(staticRoute3));
         Assert.assertFalse(staticRoute1.equals(staticRoute4));
 
-        Assert.assertTrue(staticRoute1.compareTo(staticRoute2) == 0 ? true : false);
-        Assert.assertFalse(staticRoute1.compareTo(staticRoute3) == 0 ? true : false);
-        Assert.assertTrue(staticRoute1.compareTo(staticRoute4) == 0 ? true : false);
+        Assert.assertTrue(staticRoute1.compareTo(staticRoute2) == 0);
+        Assert.assertFalse(staticRoute1.compareTo(staticRoute3) == 0);
+        Assert.assertTrue(staticRoute1.compareTo(staticRoute4) == 0);
 
         }
 
index 5db7d32745f12b3bd8e264222291ae8d4cf766c6..0304af493d9fe64abab2df516bc5b3c2e63c098c 100644 (file)
@@ -72,7 +72,7 @@ public class FlowConfig implements Serializable {
     private static final long serialVersionUID = 1L;
     private static final Logger log = LoggerFactory.getLogger(FlowConfig.class);
     private static final String NAMEREGEX = "^[a-zA-Z0-9]+$";
-    private static final String STATICFLOWGROUP = "__StaticFlows__";
+    public static final String STATICFLOWGROUP = "__StaticFlows__";
     public static final String INTERNALSTATICFLOWGROUP = "__InternalStaticFlows__";
     public static final String INTERNALSTATICFLOWBEGIN = "__";
     public static final String INTERNALSTATICFLOWEND = "__";
index e8c5f648fa69c4c7d3c9f5f4846daf73a8e78341..83106a391cb7bdc00ff0911fa703e7dee1c1c2f4 100644 (file)
@@ -168,14 +168,13 @@ public class FlowEntry implements Cloneable, Serializable {
     public FlowEntry mergeWith(ContainerFlow containerFlow) {
         Match myMatch = flow.getMatch();
 
-        // Based on this flow direction, rearrange the match
-        Match match = containerFlow.getMatch();
+        Match filter = containerFlow.getMatch();
 
         // Merge
-        myMatch.mergeWithFilter(match);
+        Match merge = myMatch.mergeWithFilter(filter);
 
         // Replace this Flow's match with merged version
-        flow.setMatch(myMatch);
+        flow.setMatch(merge);
 
         return this;
     }
index 4b8257488ef08c072785a5cef76f56c550ba882a..9f0005e7fb5b2aa3a7dea5cbfa62fdf11be94dab 100644 (file)
@@ -199,14 +199,29 @@ public interface IForwardingRulesManager {
 
     /**
      * Returns the list of Flow entries across network nodes which are part of
-     * the same flow group, policy
+     * the same flow group, policy. This list contains the flows as they were
+     * requested to be installed by the applications, before any merging with
+     * container flow is done.
      *
      * @param group
      *            the group name
-     * @return the list of flow entries belonging to the specified group
+     * @return the original list of flow entries belonging to the specified group
      */
     public List<FlowEntry> getFlowEntriesForGroup(String group);
 
+    /**
+     * Returns the list of Flow entries installed in network nodes which are part of
+     * the same flow group, policy. This list contains the effective flows installed
+     * on the nodes after the merging with any possible container flow was performed.
+     * If no container flow are specified, this method returns the same list returned
+     * by getFlowEntriesForGroup(String group).
+     *
+     * @param group
+     *            the group name
+     * @return the list of container flow merged flow entries belonging to the specified group
+     */
+    public List<FlowEntry> getInstalledFlowEntriesForGroup(String policyName);
+
     /**
      * Add a list of output port to the flow with the specified name on the
      * specified network node
index b3dae0f97fb72da0175f508309c6a2b01d77347a..bbb9ad7b7385fe8f7fe09d17e1f9433d9382a417 100644 (file)
@@ -28,7 +28,6 @@ import org.opendaylight.controller.switchmanager.ISwitchManagerAware;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
 
 public class Activator extends ComponentActivatorAbstractBase {
@@ -88,18 +87,14 @@ public class Activator extends ComponentActivatorAbstractBase {
     public void configureInstance(Component c, Object imp, String containerName) {
         if (imp.equals(ForwardingRulesManager.class)) {
             String interfaces[] = null;
-            Dictionary<String, Set<String>> props = new Hashtable<String, Set<String>>();
-            Set<String> propSet = new HashSet<String>();
-            propSet.add("frm.flowsSaveEvent");
-            props.put("cachenames", propSet);
 
             // export the service
             interfaces = new String[] { IContainerListener.class.getName(), ISwitchManagerAware.class.getName(),
                     IForwardingRulesManager.class.getName(), IInventoryListener.class.getName(),
-                    ICacheUpdateAware.class.getName(), IConfigurationContainerAware.class.getName(),
+                    IConfigurationContainerAware.class.getName(),
                     IFlowProgrammerListener.class.getName() };
 
-            c.setInterface(interfaces, props);
+            c.setInterface(interfaces, null);
 
             c.add(createContainerServiceDependency(containerName).setService(IFlowProgrammerService.class)
                     .setCallbacks("setFlowProgrammerService", "unsetFlowProgrammerService").setRequired(true));
index 836c12749f0b94c6cce567910f60b5f0af797d81..19b045b217a3a5877a4d3e00cb58840e23f13f7e 100644 (file)
@@ -15,9 +15,7 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Date;
 import java.util.EnumSet;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -32,7 +30,6 @@ import org.eclipse.osgi.framework.console.CommandInterpreter;
 import org.eclipse.osgi.framework.console.CommandProvider;
 import org.opendaylight.controller.clustering.services.CacheConfigException;
 import org.opendaylight.controller.clustering.services.CacheExistException;
-import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
 import org.opendaylight.controller.clustering.services.IClusterServices;
 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
@@ -90,12 +87,11 @@ import org.slf4j.LoggerFactory;
  */
 public class ForwardingRulesManager implements IForwardingRulesManager, PortGroupChangeListener,
         IContainerListener, ISwitchManagerAware, IConfigurationContainerAware, IInventoryListener, IObjectReader,
-        ICacheUpdateAware<Long, String>, CommandProvider, IFlowProgrammerListener {
-    private static final String SAVE = "Save";
+        CommandProvider, IFlowProgrammerListener {
     private static final String NODEDOWN = "Node is Down";
     private static final String SUCCESS = StatusCode.SUCCESS.toString();
     private static final Logger log = LoggerFactory.getLogger(ForwardingRulesManager.class);
-    private Map<Long, String> flowsSaveEvent;
+    private static final String PORTREMOVED = "Port removed";
     private String frmFileName;
     private String portGroupFileName;
     private ConcurrentMap<Integer, FlowConfig> staticFlows;
@@ -980,7 +976,6 @@ public class ForwardingRulesManager implements IForwardingRulesManager, PortGrou
         portGroupConfigs = new ConcurrentHashMap<String, PortGroupConfig>();
         portGroupData = new ConcurrentHashMap<PortGroupConfig, Map<Node, PortGroup>>();
         staticFlows = new ConcurrentHashMap<Integer, FlowConfig>();
-        flowsSaveEvent = new HashMap<Long, String>();
         inactiveFlows = new ConcurrentHashMap<FlowEntry, FlowEntry>();
     }
 
@@ -1040,6 +1035,19 @@ public class ForwardingRulesManager implements IForwardingRulesManager, PortGrou
         return list;
     }
 
+    @Override
+    public List<FlowEntry> getInstalledFlowEntriesForGroup(String policyName) {
+        List<FlowEntry> list = new ArrayList<FlowEntry>();
+        if (policyName != null && !policyName.trim().isEmpty()) {
+            for (Map.Entry<FlowEntryInstall, FlowEntryInstall> entry : this.installedSwView.entrySet()) {
+                if (policyName.equals(entry.getKey().getGroupName())) {
+                    list.add(entry.getKey().getInstall().clone());
+                }
+            }
+        }
+        return list;
+    }
+
     @Override
     public void addOutputPort(Node node, String flowName, List<NodeConnector> portList) {
 
@@ -1163,37 +1171,37 @@ public class ForwardingRulesManager implements IForwardingRulesManager, PortGrou
 
         try {
             clusterContainerService.createCache("frm.originalSwView",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterContainerService.createCache("frm.installedSwView",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterContainerService.createCache("frm.inactiveFlows",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterContainerService.createCache("frm.nodeFlows",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterContainerService.createCache("frm.groupFlows",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterContainerService.createCache("frm.staticFlows",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterContainerService.createCache("frm.flowsSaveEvent",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterContainerService.createCache("frm.staticFlowsOrdinal",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterContainerService.createCache("frm.portGroupConfigs",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterContainerService.createCache("frm.portGroupData",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterContainerService.createCache("frm.TSPolicies",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
         } catch (CacheConfigException cce) {
             log.error("CacheConfigException");
@@ -1256,13 +1264,6 @@ public class ForwardingRulesManager implements IForwardingRulesManager, PortGrou
             log.error("Retrieval of frm.staticFlows cache failed for Container {}", container.getName());
         }
 
-        map = clusterContainerService.getCache("frm.flowsSaveEvent");
-        if (map != null) {
-            flowsSaveEvent = (ConcurrentMap<Long, String>) map;
-        } else {
-            log.error("Retrieval of frm.flowsSaveEvent cache failed for Container {}", container.getName());
-        }
-
         map = clusterContainerService.getCache("frm.staticFlowsOrdinal");
         if (map != null) {
             staticFlowsOrdinal = (ConcurrentMap<Integer, Integer>) map;
@@ -1820,8 +1821,6 @@ public class ForwardingRulesManager implements IForwardingRulesManager, PortGrou
 
     @Override
     public Status saveConfig() {
-        // Publish the save config event to the cluster nodes
-        flowsSaveEvent.put(new Date().getTime(), SAVE);
         return saveConfigInternal();
     }
 
@@ -1841,19 +1840,6 @@ public class ForwardingRulesManager implements IForwardingRulesManager, PortGrou
         return new Status(StatusCode.SUCCESS, null);
     }
 
-    @Override
-    public void entryCreated(Long key, String cacheName, boolean local) {
-    }
-
-    @Override
-    public void entryUpdated(Long key, String new_value, String cacheName, boolean originLocal) {
-        saveConfigInternal();
-    }
-
-    @Override
-    public void entryDeleted(Long key, String cacheName, boolean originLocal) {
-    }
-
     @Override
     public void subnetNotify(Subnet sub, boolean add) {
     }
@@ -1941,6 +1927,32 @@ public class ForwardingRulesManager implements IForwardingRulesManager, PortGrou
         }
     }
 
+    private boolean doesFlowContainNodeConnector(Flow flow, NodeConnector nc) {
+        if (nc == null) {
+            return false;
+        }
+
+        Match match = flow.getMatch();
+        if (match.isPresent(MatchType.IN_PORT)) {
+            NodeConnector matchPort = (NodeConnector) match.getField(MatchType.IN_PORT).getValue();
+            if (matchPort.equals(nc)) {
+                return true;
+            }
+        }
+        List<Action> actionsList = flow.getActions();
+        if (actionsList != null) {
+            for (Action action : actionsList) {
+                if (action instanceof Output) {
+                    NodeConnector actionPort = ((Output) action).getPort();
+                    if (actionPort.equals(nc)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
     @Override
     public void notifyNode(Node node, UpdateType type, Map<String, Property> propMap) {
         this.pendingEvents.offer(new NodeUpdateEvent(type, node));
@@ -2284,10 +2296,66 @@ public class ForwardingRulesManager implements IForwardingRulesManager, PortGrou
     }
 
     @Override
-    public void nodeConnectorUpdated(String containerName, NodeConnector p, UpdateType t) {
+    public void nodeConnectorUpdated(String containerName, NodeConnector nc, UpdateType t) {
         if (!container.getName().equals(containerName)) {
             return;
         }
+
+        boolean updateStaticFlowCluster = false;
+
+        switch (t) {
+        case REMOVED:
+
+            List<FlowEntryInstall> nodeFlowEntries = nodeFlows.get(nc.getNode());
+            if (nodeFlowEntries == null) {
+                return;
+            }
+            for (FlowEntryInstall fei : new ArrayList<FlowEntryInstall>(nodeFlowEntries)) {
+                if (doesFlowContainNodeConnector(fei.getInstall().getFlow(), nc)) {
+                    Status status = this.removeEntryInternal(fei, true);
+                    if (!status.isSuccess()) {
+                        continue;
+                    }
+                    /*
+                     * If the flow entry is a static flow, then update its
+                     * configuration
+                     */
+                    if (fei.getGroupName().equals(FlowConfig.STATICFLOWGROUP)) {
+                        FlowConfig flowConfig = getStaticFlow(fei.getFlowName(), fei.getNode());
+                        if (flowConfig != null) {
+                            flowConfig.setStatus(PORTREMOVED);
+                            updateStaticFlowCluster = true;
+                        }
+                    }
+                }
+            }
+            if (updateStaticFlowCluster) {
+                refreshClusterStaticFlowsStatus(nc.getNode());
+            }
+            break;
+        case ADDED:
+            List<FlowConfig> flowConfigForNode = getStaticFlows(nc.getNode());
+            for (FlowConfig flowConfig : flowConfigForNode) {
+                if (doesFlowContainNodeConnector(flowConfig.getFlow(), nc)) {
+                    if (flowConfig.installInHw()) {
+                        Status status = this.installFlowEntry(flowConfig.getFlowEntry());
+                        if (!status.isSuccess()) {
+                            flowConfig.setStatus(status.getDescription());
+                        } else {
+                            flowConfig.setStatus(SUCCESS);
+                        }
+                        updateStaticFlowCluster = true;
+                    }
+                }
+            }
+            if (updateStaticFlowCluster) {
+                refreshClusterStaticFlowsStatus(nc.getNode());
+            }
+            break;
+        case CHANGED:
+            break;
+        default:
+        }
     }
 
     @Override
index 893648cde8b7180cb054fc5ddb45ecaf3611894d..206124b93bf67a2fc995e960e36bc0bdae21942a 100644 (file)
@@ -35,7 +35,7 @@ public class HostNodeConnector extends Host implements Serializable {
     private short vlan;
     @XmlElement
     private boolean staticHost;
-    private transient short arpSendCountDown;
+    private short arpSendCountDown;
 
     /**
      * Private constructor used for JAXB mapping
index 4fa4da318a2f67f645bad1d92255899fd8875937..367df5ebb05e87e7b93737f9a9db03bd43075e9f 100644 (file)
@@ -29,6 +29,8 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 
 import org.apache.felix.dm.Component;
+import org.eclipse.osgi.framework.console.CommandInterpreter;
+import org.eclipse.osgi.framework.console.CommandProvider;
 import org.opendaylight.controller.clustering.services.CacheConfigException;
 import org.opendaylight.controller.clustering.services.CacheExistException;
 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
@@ -63,6 +65,8 @@ import org.opendaylight.controller.switchmanager.ISwitchManagerAware;
 import org.opendaylight.controller.switchmanager.Subnet;
 import org.opendaylight.controller.topologymanager.ITopologyManager;
 import org.opendaylight.controller.topologymanager.ITopologyManagerAware;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -80,9 +84,9 @@ import org.slf4j.LoggerFactory;
  */
 
 public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAware, IInventoryListener,
-        ITopologyManagerAware, ICacheUpdateAware<InetAddress, HostNodeConnector> {
-    static final String ACTIVE_HOST_CACHE = "hostTrackerAH";
-    static final String INACTIVE_HOST_CACHE = "hostTrackerIH";
+        ITopologyManagerAware, ICacheUpdateAware<InetAddress, HostNodeConnector>, CommandProvider {
+    static final String ACTIVE_HOST_CACHE = "hosttracker.ActiveHosts";
+    static final String INACTIVE_HOST_CACHE = "hosttracker.InactiveHosts";
     private static final Logger logger = LoggerFactory.getLogger(HostTracker.class);
     private IHostFinder hostFinder;
     private ConcurrentMap<InetAddress, HostNodeConnector> hostsDB;
@@ -130,10 +134,9 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
             hostTrackerCallable = callable;
         }
     }
-
     // This list contains the hosts for which ARP requests are being sent
     // periodically
-    private final List<ARPPending> ARPPendingList = new ArrayList<HostTracker.ARPPending>();
+    ConcurrentMap<InetAddress, ARPPending> ARPPendingList;
     /*
      * This list below contains the hosts which were initially in ARPPendingList
      * above, but ARP response didn't come from there hosts after multiple
@@ -150,12 +153,13 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
      *
      * We can't recover from condition 3 above
      */
-    private final List<ARPPending> failedARPReqList = new ArrayList<HostTracker.ARPPending>();
+    ConcurrentMap<InetAddress, ARPPending> failedARPReqList;
 
     public HostTracker() {
     }
 
     private void startUp() {
+        nonClusterObjectCreate();
         allocateCache();
         retrieveCache();
 
@@ -177,9 +181,9 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
         logger.debug("Creating Cache for HostTracker");
         try {
             this.clusterContainerService.createCache(ACTIVE_HOST_CACHE,
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
             this.clusterContainerService.createCache(INACTIVE_HOST_CACHE,
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
         } catch (CacheConfigException cce) {
             logger.error("Cache couldn't be created for HostTracker -  check cache mode");
         } catch (CacheExistException cce) {
@@ -213,6 +217,8 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
     public void nonClusterObjectCreate() {
         hostsDB = new ConcurrentHashMap<InetAddress, HostNodeConnector>();
         inactiveStaticHosts = new ConcurrentHashMap<NodeConnector, HostNodeConnector>();
+        ARPPendingList = new ConcurrentHashMap<InetAddress, ARPPending>();
+        failedARPReqList = new ConcurrentHashMap<InetAddress, ARPPending>();
     }
 
 
@@ -378,26 +384,14 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
 
         arphost.setHostIP(networkAddr);
         arphost.setSent_count((short) 1);
-        ARPPendingList.add(arphost);
+        ARPPendingList.put(networkAddr, arphost);
         logger.debug("Host Added to ARPPending List, IP: {}", networkAddr);
     }
 
-    private void removePendingARPFromList(int index) {
-        if (index >= ARPPendingList.size()) {
-            logger.warn("removePendingARPFromList(): index greater than the List. Size:{}, Index:{}",
-                    ARPPendingList.size(), index);
-            return;
-        }
-        ARPPending arphost = ARPPendingList.remove(index);
-        HostTrackerCallable htCallable = arphost.getHostTrackerCallable();
-        if (htCallable != null)
-            htCallable.wakeup();
-    }
-
     public void setCallableOnPendingARP(InetAddress networkAddr, HostTrackerCallable callable) {
         ARPPending arphost;
-        for (int i = 0; i < ARPPendingList.size(); i++) {
-            arphost = ARPPendingList.get(i);
+        for (Entry <InetAddress, ARPPending> entry : ARPPendingList.entrySet()) {
+            arphost = entry.getValue();
             if (arphost.getHostIP().equals(networkAddr)) {
                 arphost.setHostTrackerCallable(callable);
             }
@@ -407,34 +401,22 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
     private void processPendingARPReqs(InetAddress networkAddr) {
         ARPPending arphost;
 
-        for (int i = 0; i < ARPPendingList.size(); i++) {
-            arphost = ARPPendingList.get(i);
-            if (arphost.getHostIP().equals(networkAddr)) {
-                /*
-                 * An ARP was sent for this host. The address is learned, remove
-                 * the request
-                 */
-                removePendingARPFromList(i);
-                logger.debug("Host Removed from ARPPending List, IP: {}", networkAddr);
-                return;
-            }
+        if ((arphost = ARPPendingList.remove(networkAddr)) != null) {
+            // Remove the arphost from ARPPendingList as it has been learned now
+            logger.debug("Host Removed from ARPPending List, IP: {}", networkAddr);
+            HostTrackerCallable htCallable = arphost.getHostTrackerCallable();
+            if (htCallable != null)
+                htCallable.wakeup();
+            return;
         }
 
         /*
          * It could have been a host from the FailedARPReqList
          */
 
-        for (int i = 0; i < failedARPReqList.size(); i++) {
-            arphost = failedARPReqList.get(i);
-            if (arphost.getHostIP().equals(networkAddr)) {
-                /*
-                 * An ARP was sent for this host. The address is learned, remove
-                 * the request
-                 */
-                failedARPReqList.remove(i);
-                logger.debug("Host Removed from FailedARPReqList List, IP: {}", networkAddr);
-                return;
-            }
+        if  (failedARPReqList.containsKey(networkAddr)) {
+            failedARPReqList.remove(networkAddr);
+            logger.debug("Host Removed from FailedARPReqList List, IP: {}", networkAddr);
         }
     }
 
@@ -452,7 +434,15 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
     }
 
     private void replaceHost(InetAddress networkAddr, HostNodeConnector removedHost, HostNodeConnector newHost) {
+        // Ignore ARP messages from internal nodes
+        NodeConnector newHostNc = newHost.getnodeConnector();
+        boolean newHostIsInternal = topologyManager.isInternal(newHostNc);
+        if (newHostIsInternal) {
+            return;
+        }
+
         newHost.initArpSendCountDown();
+
         if (hostsDB.replace(networkAddr, removedHost, newHost)) {
             logger.debug("Host move occurred: Old Host IP:{}, New Host IP: {}", removedHost.getNetworkAddress()
                     .getHostAddress(), newHost.getNetworkAddress().getHostAddress());
@@ -910,9 +900,9 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
     public void subnetNotify(Subnet sub, boolean add) {
         logger.debug("Received subnet notification: {}  add={}", sub, add);
         if (add) {
-            for (int i = 0; i < failedARPReqList.size(); i++) {
+            for (Entry <InetAddress, ARPPending> entry : failedARPReqList.entrySet()) {
                 ARPPending arphost;
-                arphost = failedARPReqList.get(i);
+                arphost = entry.getValue();
                 if (hostFinder == null) {
                     logger.warn("ARPHandler Services are not available on subnet addition");
                     continue;
@@ -927,9 +917,20 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
         @Override
         public void run() {
             ARPPending arphost;
+
             /* This routine runs every 4 seconds */
-            for (int i = 0; i < ARPPendingList.size(); i++) {
-                arphost = ARPPendingList.get(i);
+            logger.trace("Number of Entries in ARP Pending/Failed Lists: ARPPendingList = {}, failedARPReqList = {}",
+                    ARPPendingList.size(), failedARPReqList.size());
+            for (Entry <InetAddress, ARPPending> entry : ARPPendingList.entrySet()) {
+                arphost = entry.getValue();
+
+                if (hostsDB.containsKey(arphost.getHostIP())) {
+                    // this host is already learned, shouldn't be in ARPPendingList
+                    // Remove it and continue
+                    logger.warn("Learned Host {} found in ARPPendingList", arphost.getHostIP());
+                    ARPPendingList.remove(entry.getKey());
+                    continue;
+                }
                 if (arphost.getSent_count() < switchManager.getHostRetryCount()) {
                     /*
                      * No reply has been received of first ARP Req, send the
@@ -948,7 +949,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
                      * ARP requests have been sent without receiving a
                      * reply, remove this from the pending list
                      */
-                    removePendingARPFromList(i);
+                    ARPPendingList.remove(entry.getKey());
                     logger.debug("ARP reply not received after multiple attempts, removing from Pending List IP: {}",
                             arphost.getHostIP().getHostAddress());
                     /*
@@ -956,10 +957,10 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
                      * on link up events
                      */
                     logger.debug("Adding the host to FailedARPReqList IP: {}", arphost.getHostIP().getHostAddress());
-                    failedARPReqList.add(arphost);
+                    failedARPReqList.put(entry.getKey(), arphost);
 
                 } else {
-                    logger.error("Inavlid arp_sent count for entry at index: {}", i);
+                    logger.error("Inavlid arp_sent count for entry: {}", entry);
                 }
             }
         }
@@ -1086,6 +1087,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
              */
             if (switchManager.isNodeConnectorEnabled(nc)) {
                 learnNewHost(host);
+                processPendingARPReqs(networkAddr);
                 notifyHostLearnedOrRemoved(host, true);
             } else {
                 inactiveStaticHosts.put(nc, host);
@@ -1297,11 +1299,12 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
 
     private void handleNodeConnectorStatusUp(NodeConnector nodeConnector) {
         ARPPending arphost;
+        HostNodeConnector host = null;
 
         logger.debug("handleNodeConnectorStatusUp {}", nodeConnector);
 
-        for (int i = 0; i < failedARPReqList.size(); i++) {
-            arphost = failedARPReqList.get(i);
+        for (Entry <InetAddress, ARPPending> entry : failedARPReqList.entrySet()) {
+            arphost = entry.getValue();
             logger.debug("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostIP().getHostAddress());
             if (hostFinder == null) {
                 logger.warn("ARPHandler is not available at interface  up");
@@ -1309,12 +1312,26 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
                         nodeConnector);
                 continue;
             }
-            hostFinder.find(arphost.getHostIP());
+
+            // Send a broadcast ARP only on the interface which just came up.
+            // Use hostFinder's "probe" method
+            try {
+                byte[] dataLayerAddress = NetUtils.getBroadcastMACAddr();
+                host = new HostNodeConnector(dataLayerAddress, arphost.getHostIP(), nodeConnector, (short) 0);
+                hostFinder.probe(host);
+            } catch (ConstructionException e) {
+                logger.debug("HostNodeConnector couldn't be created for Host: {}, NodeConnector: {}",
+                        arphost.getHostIP(), nodeConnector);
+                logger.error("", e);
+            }
+            logger.debug("Done. handleNodeConnectorStatusUp {}", nodeConnector);
         }
-        HostNodeConnector host = inactiveStaticHosts.get(nodeConnector);
+
+        host = inactiveStaticHosts.get(nodeConnector);
         if (host != null) {
             inactiveStaticHosts.remove(nodeConnector);
             learnNewHost(host);
+            processPendingARPReqs(host.getNetworkAddress());
             notifyHostLearnedOrRemoved(host, true);
         }
     }
@@ -1394,6 +1411,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
      *
      */
     void start() {
+        registerWithOSGIConsole();
     }
 
     /**
@@ -1440,4 +1458,30 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
             boolean originLocal) {
     }
 
+    private void registerWithOSGIConsole() {
+        BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+        bundleContext.registerService(CommandProvider.class.getName(), this, null);
+    }
+
+    @Override
+    public String getHelp() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public void _dumpPendingARPReqList(CommandInterpreter ci) {
+        ARPPending arphost;
+        for (Entry <InetAddress, ARPPending> entry : ARPPendingList.entrySet()) {
+            arphost = entry.getValue();
+            ci.println(arphost.getHostIP().toString());
+        }
+    }
+
+    public void _dumpFailedARPReqList(CommandInterpreter ci) {
+        ARPPending arphost;
+        for (Entry <InetAddress, ARPPending> entry : failedARPReqList.entrySet()) {
+            arphost = entry.getValue();
+            ci.println(arphost.getHostIP().toString());
+        }
+    }
 }
index ebe36a9d78aecfd45525560530508e2bd5110aa6..668efbc7ee3868b2ea3b8e1c22a3ce9c9b305e78 100644 (file)
@@ -9,17 +9,13 @@
 package org.opendaylight.controller.northbound.commons;
 
 public enum RestMessages {
-    SUCCESS("Success"), NOCONTAINER("Container does not exist"), NOFLOWSPEC(
-            "Flow Spec does not exist"), NOSUBNET("Subnet does not exist"), NOSTATICROUTE(
-            "Static Route does not exist"), NOHOST("Host does not exist"), NOFLOW(
-            "Flow does not exist"), NONODE("Node does not exist"), NOPOLICY(
-            "Policy does not exist"), NORESOURCE("Resource does not exist"), RESOURCECONFLICT(
-            "Operation failed due to Resource Conflict"), NODEFAULT(
-            "Container default is not a custom container"), DEFAULTDISABLED(
+    SUCCESS("Success"), NOCONTAINER("Container does not exist"), NOSUBNET("Subnet does not exist"), NOSTATICROUTE(
+            "Static Route does not exist"), NOHOST("Host does not exist"), NOFLOW("Flow does not exist"), NONODE(
+            "Node does not exist"), NOPOLICY("Policy does not exist"), NORESOURCE("Resource does not exist"), RESOURCECONFLICT(
+            "Operation failed due to Resource Conflict"), NODEFAULT("Container default is not a custom container"), DEFAULTDISABLED(
             "Container(s) are configured. Container default is not operational"), NOTALLOWEDONDEFAULT(
-            "Container default is a static resource, no modification allowed on it"), UNKNOWNACTION(
-            "Unknown action"), INVALIDJSON("JSON message is invalid"), INVALIDADDRESS(
-            "invalid InetAddress"), AVAILABLESOON(
+            "Container default is a static resource, no modification allowed on it"), UNKNOWNACTION("Unknown action"), INVALIDJSON(
+            "JSON message is invalid"), INVALIDADDRESS("invalid InetAddress"), AVAILABLESOON(
             "Resource is not implemented yet"), INTERNALERROR("Internal Error"), SERVICEUNAVAILABLE(
             "Service is not available. Could be down for maintanence"), INVALIDDATA(
             "Data is invalid or conflicts with URI");
@@ -30,6 +26,7 @@ public enum RestMessages {
         message = msg;
     }
 
+    @Override
     public String toString() {
         return message;
     }
diff --git a/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/exception/BadRequestException.java b/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/exception/BadRequestException.java
new file mode 100644 (file)
index 0000000..c1b832d
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.northbound.commons.exception;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Status Code 400 (Bad Request)
+ *
+ * The request could not be understood by the server due to malformed syntax.
+ * The client SHOULD NOT repeat the request without modifications.
+ */
+public class BadRequestException extends WebApplicationException {
+    private static final long serialVersionUID = 1L;
+
+    public BadRequestException(String string) {
+        super(Response.status(Response.Status.BAD_REQUEST).entity(string).type(MediaType.TEXT_PLAIN).build());
+    }
+}
diff --git a/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/exception/NotImplemented.java b/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/exception/NotImplemented.java
new file mode 100644 (file)
index 0000000..16d0cd6
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.northbound.commons.exception;
+
+import javax.ws.rs.core.Response;
+
+/**
+ * Implementation of StatusType for error 501 as in:
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.6
+ */
+public class NotImplemented implements Response.StatusType {
+    @Override
+    public int getStatusCode() {
+        return 501;
+    }
+
+    @Override
+    public String getReasonPhrase() {
+        return "Not Implemented";
+    }
+
+    @Override
+    public Response.Status.Family getFamily() {
+        return Response.Status.Family.SERVER_ERROR;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/exception/NotImplementedException.java b/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/exception/NotImplementedException.java
new file mode 100644 (file)
index 0000000..5c931d2
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.northbound.commons.exception;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Status Code 501 (Not Implemented)
+ *
+ * The server does not support the functionality required to fulfill the
+ * request. This is the appropriate response when the server does not recognize
+ * the request method and is not capable of supporting it for any resource.
+ */
+public class NotImplementedException extends WebApplicationException {
+    private static final long serialVersionUID = 1L;
+
+    public NotImplementedException(String string) {
+        super(Response.status(new NotImplemented()).entity(string).type(MediaType.TEXT_PLAIN).build());
+    }
+}
index 4b3761219ff6673f789dd870fa6852550a22c214..e05aa10365810e542a887df09160021da2f7e3d0 100644 (file)
@@ -17,7 +17,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 
 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
 
-@XmlRootElement
+@XmlRootElement (name = "list")
 @XmlAccessorType(XmlAccessType.NONE)
 
 public class FlowConfigs {
index 6bccc2d2e9ff25bde94925be51f4555f409c5e98..32b9dd32bb41304f5451a26eeeb2260f258bbe43 100644 (file)
@@ -33,6 +33,7 @@ import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
 import org.opendaylight.controller.northbound.commons.RestMessages;
 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
+import org.opendaylight.controller.northbound.commons.exception.MethodNotAllowedException;
 import org.opendaylight.controller.northbound.commons.exception.NotAcceptableException;
 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
@@ -149,9 +150,36 @@ public class FlowProgrammerNorthbound {
      * Returns a list of Flows configured on the given container
      *
      * @param containerName
-     *            Name of the Container. The Container name for the base
-     *            controller is "default".
-     * @return List of configured flows configured on a given container
+     *            Name of the Container (Eg. 'default')
+     * @return List of flows configured on a given container
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/flow/default
+     *
+     * Response in XML:
+     * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
+     * &lt;list&gt;
+     *     &#x20;&#x20;&#x20;&lt;flowConfig&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;installInHw&gt;true&lt;/installInHw&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;flow1&lt;/name&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;node id="00:00:00:00:00:00:00:01" type="OF"/&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;ingressPort&gt;1&lt;/ingressPort&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;priority&gt;500&lt;/priority&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;etherType&gt;0x800&lt;/etherType&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nwSrc&gt;9.9.1.1&lt;/nwSrc&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;actions&gt;OUTPUT=2&lt;/actions&gt;
+     *     &#x20;&#x20;&#x20;&lt;/flowConfig&gt;
+     * &lt;/list&gt;
+     *
+     * Response in JSON:
+     * {"flowConfig":{"installInHw":"true","name":"flow1","node":{"@id":"00:00:00:00:00:00:00:01","@type":"OF"},
+     * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}}
+     *
+     * </pre>
      */
     @Path("/{containerName}")
     @GET
@@ -159,6 +187,7 @@ public class FlowProgrammerNorthbound {
     @TypeHint(FlowConfigs.class)
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public FlowConfigs getStaticFlows(
@@ -179,20 +208,48 @@ public class FlowProgrammerNorthbound {
      * Returns a list of Flows configured on a Node in a given container
      *
      * @param containerName
-     *            Name of the Container. The Container name for the base
-     *            controller is "default".
+     *            Name of the Container (Eg. 'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
-     *            Node Identifier
-     * @return List of configured flows configured on a Node in a container
+     *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
+     * @return List of flows configured on a Node in a container
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01
+     *
+     * Response in XML:
+     * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
+     * &lt;list&gt;
+     *     &#x20;&#x20;&#x20;&lt;flowConfig&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;installInHw&gt;true&lt;/installInHw&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;flow1&lt;/name&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;node id="00:00:00:00:00:00:00:01" type="OF"/&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;ingressPort&gt;1&lt;/ingressPort&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;priority&gt;500&lt;/priority&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;etherType&gt;0x800&lt;/etherType&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nwSrc&gt;9.9.1.1&lt;/nwSrc&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;actions&gt;OUTPUT=2&lt;/actions&gt;
+     *     &#x20;&#x20;&#x20;&lt;/flowConfig&gt;
+     * &lt;/list&gt;
+     *
+     * Response in JSON:
+     * {"flowConfig":{"installInHw":"true","name":"flow1","node":{"@id":"00:00:00:00:00:00:00:01","@type":"OF"},
+     * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}}
+     *
+     * </pre>
      */
-    @Path("/{containerName}/{nodeType}/{nodeId}")
+    @Path("/{containerName}/node/{nodeType}/{nodeId}")
     @GET
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(FlowConfigs.class)
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The containerName or nodeId is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public FlowConfigs getStaticFlows(
@@ -219,22 +276,48 @@ public class FlowProgrammerNorthbound {
      * on a given Container.
      *
      * @param containerName
-     *            Name of the Container. The Container name for the base
-     *            controller is "default".
+     *            Name of the Container (Eg. 'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
-     *            Node Identifier
+     *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
      * @param name
-     *            Human-readable name for the configured flow.
+     *            Human-readable name for the configured flow (Eg. 'Flow1')
      * @return Flow configuration matching the name and nodeId on a Container
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
+     *
+     * Response in XML:
+     * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
+     * &lt;flowConfig&gt;
+     *     &#x20;&#x20;&#x20;&lt;installInHw&gt;true&lt;/installInHw&gt;
+     *     &#x20;&#x20;&#x20;&lt;name&gt;flow1&lt;/name&gt;
+     *     &#x20;&#x20;&#x20;&lt;node id="00:00:00:00:00:00:00:01" type="OF"/&gt;
+     *     &#x20;&#x20;&#x20;&lt;ingressPort&gt;1&lt;/ingressPort&gt;
+     *     &#x20;&#x20;&#x20;&lt;priority&gt;500&lt;/priority&gt;
+     *     &#x20;&#x20;&#x20;&lt;etherType&gt;0x800&lt;/etherType&gt;
+     *     &#x20;&#x20;&#x20;&lt;nwSrc&gt;9.9.1.1&lt;/nwSrc&gt;
+     *     &#x20;&#x20;&#x20;&lt;actions&gt;OUTPUT=2&lt;/actions&gt;
+     * &lt;/flowConfig&gt;
+     *
+     * Response in JSON:
+     * {"installInHw":"true","name":"flow1","node":{"@id":"00:00:00:00:00:00:00:01","@type":"OF"},
+     * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}
+     *
+     * </pre>
      */
-    @Path("/{containerName}/{nodeType}/{nodeId}/{name}")
+    @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}")
     @GET
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(FlowConfig.class)
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The containerName or NodeId or Configuration name is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public FlowConfig getStaticFlow(
@@ -268,27 +351,53 @@ public class FlowProgrammerNorthbound {
      * Add a flow configuration
      *
      * @param containerName
-     *            Name of the Container. The Container name for the base
-     *            controller is "default".
+     *            Name of the Container (Eg. 'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
-     *            Node Identifier
+     *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
      * @param name
-     *            Name of the Static Flow configuration
+     *            Name of the Static Flow configuration (Eg. 'Flow2')
      * @param FlowConfig
      *            Flow Configuration in JSON or XML format
      * @return Response as dictated by the HTTP Response Status code
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
+     *
+     * Request in XML:
+     * &lt;flowConfig&gt;
+     *         &#x20;&#x20;&#x20;&lt;installInHw&gt;true&lt;/installInHw&gt;
+     *         &#x20;&#x20;&#x20;&lt;name&gt;flow1&lt;/name&gt;
+     *         &#x20;&#x20;&#x20;&lt;node id="00:00:00:00:00:00:00:01" type="OF"/&gt;
+     *         &#x20;&#x20;&#x20;&lt;ingressPort&gt;1&lt;/ingressPort&gt;
+     *         &#x20;&#x20;&#x20;&lt;priority&gt;500&lt;/priority&gt;
+     *         &#x20;&#x20;&#x20;&lt;etherType&gt;0x800&lt;/etherType&gt;
+     *         &#x20;&#x20;&#x20;&lt;nwSrc&gt;9.9.1.1&lt;/nwSrc&gt;
+     *         &#x20;&#x20;&#x20;&lt;actions&gt;OUTPUT=2&lt;/actions&gt;
+     * &lt;/flowConfig&gt;
+     *
+     * Request in JSON:
+     * {"installInHw":"true","name":"flow1","node":{"@id":"00:00:00:00:00:00:00:01","@type":"OF"},
+     * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}
+     *
+     * </pre>
      */
 
-    @Path("/{containerName}/{nodeType}/{nodeId}/{name}")
-    @POST
+    @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}")
+    @PUT
     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes({
             @ResponseCode(code = 201, condition = "Flow Config processed successfully"),
-            @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
+            @ResponseCode(code = 400, condition = "Failed to create Static Flow entry due to invalid flow configuration"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
+            @ResponseCode(code = 404, condition = "The Container Name or nodeId is not found"),
             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
-            @ResponseCode(code = 409, condition = "Failed to create Static Flow entry due to Conflicting Name"),
+            @ResponseCode(code = 409, condition = "Failed to create Static Flow entry due to Conflicting Name or configuration"),
             @ResponseCode(code = 500, condition = "Failed to create Static Flow entry. Failure Reason included in HTTP Error response"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
     public Response addFlow(
@@ -304,6 +413,8 @@ public class FlowProgrammerNorthbound {
                     "User is not authorized to perform this operation on container "
                             + containerName);
         }
+        handleResourceCongruence(name, flowConfig.getValue().getName());
+        handleResourceCongruence(nodeId, flowConfig.getValue().getNode().getNodeIDString());
         handleDefaultDisabled(containerName);
 
         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
@@ -325,35 +436,42 @@ public class FlowProgrammerNorthbound {
 
         if (status.isSuccess()) {
             NorthboundUtils.auditlog("Flow", username, "added", name, containerName);
-            return Response.status(Response.Status.CREATED).build();
+            return Response.status(Response.Status.CREATED).entity("Success").build();
         }
-        throw new InternalServerErrorException(status.getDescription());
+        return NorthboundUtils.getResponse(status);
     }
 
     /**
      * Delete a Flow configuration
      *
-     * DELETE /flows/{containerName}/{nodeType}/{nodeId}/{name}
-     *
      * @param containerName
-     *            Name of the Container. The Container name for the base
-     *            controller is "default".
+     *            Name of the Container (Eg. 'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
-     *            Node Identifier
+     *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
      * @param name
-     *            Name of the Static Flow configuration
+     *            Name of the Static Flow configuration (Eg. 'Flow1')
      * @return Response as dictated by the HTTP Response code
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
+     *
+     * </pre>
      */
 
-    @Path("/{containerName}/{nodeType}/{nodeId}/{name}")
+    @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}")
     @DELETE
     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Flow Config deleted successfully"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
-            @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
+            @ResponseCode(code = 406, condition = "Failed to delete Flow config due to invalid operation. Failure details included in HTTP Error response"),
             @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"),
             @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
     public Response deleteFlow(
@@ -388,33 +506,40 @@ public class FlowProgrammerNorthbound {
         Status status = frm.removeStaticFlow(name, node);
         if (status.isSuccess()) {
             NorthboundUtils.auditlog("Flow", username, "removed", name, containerName);
-            return Response.ok().build();
         }
-        throw new InternalServerErrorException(status.getDescription());
+        return NorthboundUtils.getResponse(status);
     }
 
     /**
      * Toggle a Flow configuration
      *
      * @param containerName
-     *            Name of the Container. The Container name for the base
-     *            controller is "default".
+     *            Name of the Container (Eg. 'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
-     *            Node Identifier
+     *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
      * @param name
-     *            Name of the Static Flow configuration
+     *            Name of the Static Flow configuration (Eg. 'Flow1')
      * @return Response as dictated by the HTTP Response code
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
+     *
+     * </pre>
      */
-
-    @Path("/{containerName}/{nodeType}/{nodeId}/{name}")
-    @PUT
+    @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}")
+    @POST
     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes({
-            @ResponseCode(code = 200, condition = "Flow Config deleted successfully"),
+            @ResponseCode(code = 200, condition = "Flow Config processed successfully"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
-            @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
+            @ResponseCode(code = 406, condition = "Failed to delete Flow config due to invalid operation. Failure details included in HTTP Error response"),
             @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"),
             @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
     public Response toggleFlow(
@@ -450,9 +575,8 @@ public class FlowProgrammerNorthbound {
         Status status = frm.toggleStaticFlowStatus(staticFlow);
         if (status.isSuccess()) {
             NorthboundUtils.auditlog("Flow", username, "toggled", name, containerName);
-            return Response.ok().build();
         }
-        throw new InternalServerErrorException(status.getDescription());
+        return NorthboundUtils.getResponse(status);
     }
 
     private Node handleNodeAvailability(String containerName, String nodeType,
@@ -493,4 +617,10 @@ public class FlowProgrammerNorthbound {
         }
     }
 
+    private void handleResourceCongruence(String resource, String configured) {
+        if (!resource.equals(configured)) {
+            throw new MethodNotAllowedException("Path's resource name conflicts with payload's resource name");
+        }
+    }
+
 }
index ad694b0b65a4cccb6b7304a12299d5feea464fdd..6958ecb96ad77e7da668d62d0f0871b6158c5e60 100644 (file)
@@ -208,29 +208,29 @@ public class NorthboundIT {
         if (timestamp == null || timestampName == null) {
             Assert.assertFalse(properties.has("timeStamp"));
         } else {
-            Assert.assertEquals(timestamp, (Integer) properties.getJSONObject("timeStamp").getInt("timestamp"));
-            Assert.assertEquals(timestampName, properties.getJSONObject("timeStamp").getString("timestampName"));
+            Assert.assertEquals(timestamp, (Integer) properties.getJSONObject("timeStamp").getInt("value"));
+            Assert.assertEquals(timestampName, properties.getJSONObject("timeStamp").getString("name"));
         }
         if (actionsValue == null) {
             Assert.assertFalse(properties.has("actions"));
         } else {
-            Assert.assertEquals(actionsValue, (Integer) properties.getJSONObject("actions").getInt("actionsValue"));
+            Assert.assertEquals(actionsValue, (Integer) properties.getJSONObject("actions").getInt("value"));
         }
         if (capabilitiesValue == null) {
             Assert.assertFalse(properties.has("capabilities"));
         } else {
             Assert.assertEquals(capabilitiesValue,
-                    (Integer) properties.getJSONObject("capabilities").getInt("capabilitiesValue"));
+                    (Integer) properties.getJSONObject("capabilities").getInt("value"));
         }
         if (tablesValue == null) {
             Assert.assertFalse(properties.has("tables"));
         } else {
-            Assert.assertEquals(tablesValue, (Integer) properties.getJSONObject("tables").getInt("tablesValue"));
+            Assert.assertEquals(tablesValue, (Integer) properties.getJSONObject("tables").getInt("value"));
         }
         if (buffersValue == null) {
             Assert.assertFalse(properties.has("buffers"));
         } else {
-            Assert.assertEquals(buffersValue, (Integer) properties.getJSONObject("buffers").getInt("buffersValue"));
+            Assert.assertEquals(buffersValue, (Integer) properties.getJSONObject("buffers").getInt("value"));
         }
     }
 
@@ -249,18 +249,18 @@ public class NorthboundIT {
         if (state == null) {
             Assert.assertFalse(properties.has("state"));
         } else {
-            Assert.assertEquals(state, (Integer) properties.getJSONObject("state").getInt("stateValue"));
+            Assert.assertEquals(state, (Integer) properties.getJSONObject("state").getInt("value"));
         }
         if (capabilities == null) {
             Assert.assertFalse(properties.has("capabilities"));
         } else {
             Assert.assertEquals(capabilities,
-                    (Integer) properties.getJSONObject("capabilities").getInt("capabilitiesValue"));
+                    (Integer) properties.getJSONObject("capabilities").getInt("value"));
         }
         if (bandwidth == null) {
             Assert.assertFalse(properties.has("bandwidth"));
         } else {
-            Assert.assertEquals(bandwidth, (Integer) properties.getJSONObject("bandwidth").getInt("bandwidthValue"));
+            Assert.assertEquals(bandwidth, (Integer) properties.getJSONObject("bandwidth").getInt("value"));
         }
 
     }
@@ -353,11 +353,11 @@ public class NorthboundIT {
         // Test insert static route
         String requestBody = "{\"name\":\"" + name1 + "\", \"prefix\":\"" + prefix1 + "\", \"nextHop\":\"" + nextHop1
                 + "\"}";
-        result = getJsonResult(baseURL + "default/" + name1, "POST", requestBody);
+        result = getJsonResult(baseURL + "default/route/" + name1, "POST", requestBody);
         Assert.assertEquals(201, httpResponseCode.intValue());
 
         requestBody = "{\"name\":\"" + name2 + "\", \"prefix\":\"" + prefix2 + "\", \"nextHop\":\"" + nextHop2 + "\"}";
-        result = getJsonResult(baseURL + "default/" + name2, "POST", requestBody);
+        result = getJsonResult(baseURL + "default/route/" + name2, "POST", requestBody);
         Assert.assertEquals(201, httpResponseCode.intValue());
 
         // Test Get all static routes
@@ -382,7 +382,7 @@ public class NorthboundIT {
         }
 
         // Test get specific static route
-        result = getJsonResult(baseURL + "default/" + name1);
+        result = getJsonResult(baseURL + "default/route/" + name1);
         jt = new JSONTokener(result);
         json = new JSONObject(jt);
 
@@ -390,7 +390,7 @@ public class NorthboundIT {
         Assert.assertEquals(prefix1, json.getString("prefix"));
         Assert.assertEquals(nextHop1, json.getString("nextHop"));
 
-        result = getJsonResult(baseURL + "default/" + name2);
+        result = getJsonResult(baseURL + "default/route/" + name2);
         jt = new JSONTokener(result);
         json = new JSONObject(jt);
 
@@ -399,7 +399,7 @@ public class NorthboundIT {
         Assert.assertEquals(nextHop2, json.getString("nextHop"));
 
         // Test delete static route
-        result = getJsonResult(baseURL + "default/" + name1, "DELETE");
+        result = getJsonResult(baseURL + "default/route/" + name1, "DELETE");
         Assert.assertEquals(200, httpResponseCode.intValue());
 
         result = getJsonResult(baseURL + "default");
@@ -489,9 +489,9 @@ public class NorthboundIT {
         // Test add property to node
         // Add Tier and Description property to node1
         result = getJsonResult(baseURL + "node/STUB/" + nodeId_1 + "/property/tier/1001", "PUT");
-        Assert.assertEquals(200, httpResponseCode.intValue());
+        Assert.assertEquals(201, httpResponseCode.intValue());
         result = getJsonResult(baseURL + "node/STUB/" + nodeId_1 + "/property/description/node1", "PUT");
-        Assert.assertEquals(200, httpResponseCode.intValue());
+        Assert.assertEquals(201, httpResponseCode.intValue());
 
         // Test for first node
         result = getJsonResult(baseURL + "nodes");
@@ -499,8 +499,8 @@ public class NorthboundIT {
         json = new JSONObject(jt);
         node = getJsonInstance(json, "nodeProperties", nodeId_1);
         Assert.assertNotNull(node);
-        Assert.assertEquals(1001, node.getJSONObject("properties").getJSONObject("tier").getInt("tierValue"));
-        Assert.assertEquals("node1", node.getJSONObject("properties").getJSONObject("description").getString("descriptionValue"));
+        Assert.assertEquals(1001, node.getJSONObject("properties").getJSONObject("tier").getInt("value"));
+        Assert.assertEquals("node1", node.getJSONObject("properties").getJSONObject("description").getString("value"));
 
         // Test delete nodeConnector property
         // Delete state property of nodeconnector1
@@ -558,7 +558,7 @@ public class NorthboundIT {
 
         String baseURL = "http://127.0.0.1:8080/controller/nb/v2/statistics/default/";
 
-        String result = getJsonResult(baseURL + "flowstats");
+        String result = getJsonResult(baseURL + "flow");
         JSONTokener jt = new JSONTokener(result);
         JSONObject json = new JSONObject(jt);
         JSONObject flowStatistics = getJsonInstance(json, "flowStatistics", 0xCAFE);
@@ -568,7 +568,7 @@ public class NorthboundIT {
         Assert.assertEquals(node.getString("@type"), "STUB");
 
         // test that flow statistics results are correct
-        JSONArray flowStats = flowStatistics.getJSONArray("flowStat");
+        JSONArray flowStats = flowStatistics.getJSONArray("flowStatistic");
         for (int i = 0; i < flowStats.length(); i++) {
 
             JSONObject flowStat = flowStats.getJSONObject(i);
@@ -576,8 +576,8 @@ public class NorthboundIT {
 
         }
 
-        // for /controller/nb/v2/statistics/default/portstats
-        result = getJsonResult(baseURL + "portstats");
+        // for /controller/nb/v2/statistics/default/port
+        result = getJsonResult(baseURL + "port");
         jt = new JSONTokener(result);
         json = new JSONObject(jt);
         JSONObject portStatistics = getJsonInstance(json, "portStatistics", 0xCAFE);
@@ -587,7 +587,7 @@ public class NorthboundIT {
         Assert.assertEquals(node2.getString("@type"), "STUB");
 
         // test that port statistic results are correct
-        JSONObject portStat = portStatistics.getJSONObject("portStat");
+        JSONObject portStat = portStatistics.getJSONObject("portStatistic");
         Assert.assertTrue(portStat.getInt("receivePackets") == 250);
         Assert.assertTrue(portStat.getInt("transmitPackets") == 500);
         Assert.assertTrue(portStat.getInt("receiveBytes") == 1000);
@@ -602,7 +602,7 @@ public class NorthboundIT {
         Assert.assertTrue(portStat.getInt("collisionCount") == 4);
 
         // test for getting one specific node's stats
-        result = getJsonResult(baseURL + "flowstats/STUB/51966");
+        result = getJsonResult(baseURL + "flow/node/STUB/51966");
         jt = new JSONTokener(result);
         json = new JSONObject(jt);
         node = json.getJSONObject("node");
@@ -611,13 +611,13 @@ public class NorthboundIT {
         Assert.assertEquals(node.getString("@type"), "STUB");
 
         // test that flow statistics results are correct
-        flowStats = json.getJSONArray("flowStat");
+        flowStats = json.getJSONArray("flowStatistic");
         for (int i = 0; i < flowStats.length(); i++) {
             JSONObject flowStat = flowStats.getJSONObject(i);
             testFlowStat(flowStat, actionTypes[i], i);
         }
 
-        result = getJsonResult(baseURL + "portstats/STUB/51966");
+        result = getJsonResult(baseURL + "port/node/STUB/51966");
         jt = new JSONTokener(result);
         json = new JSONObject(jt);
         node2 = json.getJSONObject("node");
@@ -626,7 +626,7 @@ public class NorthboundIT {
         Assert.assertEquals(node2.getString("@type"), "STUB");
 
         // test that port statistic results are correct
-        portStat = json.getJSONObject("portStat");
+        portStat = json.getJSONObject("portStatistic");
         Assert.assertTrue(portStat.getInt("receivePackets") == 250);
         Assert.assertTrue(portStat.getInt("transmitPackets") == 500);
         Assert.assertTrue(portStat.getInt("receiveBytes") == 1000);
@@ -734,16 +734,16 @@ public class NorthboundIT {
         String baseURL = "http://127.0.0.1:8080/controller/nb/v2/flow/default/";
         // Attempt to get a flow that doesn't exit. Should return 404
         // status.
-        String result = getJsonResult(baseURL + "STUB/51966/test1", "GET");
+        String result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test1", "GET");
         Assert.assertTrue(result.equals("404"));
 
         // test add flow1
         String fc = "{\"dynamic\":\"false\", \"name\":\"test1\", \"node\":{\"@id\":\"51966\",\"@type\":\"STUB\"}, \"actions\":[\"DROP\"]}";
-        result = getJsonResult(baseURL + "STUB/51966/test1", "POST", fc);
+        result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test1", "PUT", fc);
         Assert.assertTrue(httpResponseCode == 201);
 
         // test get returns flow that was added.
-        result = getJsonResult(baseURL + "STUB/51966/test1", "GET");
+        result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test1", "GET");
         // check that result came out fine.
         Assert.assertTrue(httpResponseCode == 200);
         JSONTokener jt = new JSONTokener(result);
@@ -756,21 +756,21 @@ public class NorthboundIT {
         Assert.assertEquals(node.getString("@id"), "51966");
         // test adding same flow again fails due to repeat name..return 409
         // code
-        result = getJsonResult(baseURL + "STUB/51966/test1", "POST", fc);
+        result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test1", "PUT", fc);
         Assert.assertTrue(result.equals("409"));
 
         fc = "{\"dynamic\":\"false\", \"name\":\"test2\", \"node\":{\"@id\":\"51966\",\"@type\":\"STUB\"}, \"actions\":[\"DROP\"]}";
-        result = getJsonResult(baseURL + "STUB/51966/test2", "POST", fc);
-        // test should return 500 for error due to same flow being added.
-        Assert.assertTrue(result.equals("500"));
+        result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test2", "PUT", fc);
+        // test should return 409 for error due to same flow being added.
+        Assert.assertTrue(result.equals("409"));
 
         // add second flow that's different
         fc = "{\"dynamic\":\"false\", \"name\":\"test2\", \"nwSrc\":\"1.1.1.1\", \"node\":{\"@id\":\"51966\",\"@type\":\"STUB\"}, \"actions\":[\"DROP\"]}";
-        result = getJsonResult(baseURL + "STUB/51966/test2", "POST", fc);
+        result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test2", "PUT", fc);
         Assert.assertTrue(httpResponseCode == 201);
 
         // check that request returns both flows given node.
-        result = getJsonResult(baseURL + "STUB/51966/", "GET");
+        result = getJsonResult(baseURL + "node/STUB/51966/", "GET");
         jt = new JSONTokener(result);
         json = new JSONObject(jt);
         Assert.assertTrue(json.get("flowConfig") instanceof JSONArray);
@@ -788,10 +788,10 @@ public class NorthboundIT {
         Assert.assertTrue(count == 2);
 
         // delete a flow, check that it's no longer in list.
-        result = getJsonResult(baseURL + "STUB/51966/test2", "DELETE");
+        result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test2", "DELETE");
         Assert.assertTrue(httpResponseCode == 200);
 
-        result = getJsonResult(baseURL + "STUB/51966/test2", "GET");
+        result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test2", "GET");
         Assert.assertTrue(result.equals("404"));
     }
 
@@ -1091,9 +1091,9 @@ public class NorthboundIT {
                 Assert.assertEquals(tailNode.getString("@type"),nodeType);
                 Assert.assertEquals(tailNode.getString("@type"), nodeConnType);
                 Assert.assertEquals(tailNC.getLong("@id"), tailNC1_nodeConnId);
-                Assert.assertEquals(bandw.getLong("bandwidthValue"), bw_1);
-                Assert.assertTrue((short) stt.getInt("stateValue") == state_1);
-                Assert.assertEquals(ltc.getLong("latencyValue"), lat_1);
+                Assert.assertEquals(bandw.getLong("value"), bw_1);
+                Assert.assertTrue((short) stt.getInt("value") == state_1);
+                Assert.assertEquals(ltc.getLong("value"), lat_1);
             } else if (headNC.getInt("@id") == headNC2_nodeConnId) {
                 Assert.assertEquals(headNode.getString("@type"),nodeType);
                 Assert.assertEquals(headNode.getLong("@id"), headNC2_nodeId);
@@ -1102,9 +1102,9 @@ public class NorthboundIT {
                 Assert.assertTrue(tailNode.getInt("@id") == tailNC2_nodeId);
                 Assert.assertEquals(tailNC.getString("@type"), nodeConnType);
                 Assert.assertEquals(tailNC.getLong("@id"), tailNC2_nodeConnId);
-                Assert.assertEquals(bandw.getLong("bandwidthValue"), bw_2);
-                Assert.assertTrue((short) stt.getInt("stateValue") == state_2);
-                Assert.assertEquals(ltc.getLong("latencyValue"), lat_2);
+                Assert.assertEquals(bandw.getLong("value"), bw_2);
+                Assert.assertTrue((short) stt.getInt("value") == state_2);
+                Assert.assertEquals(ltc.getLong("value"), lat_2);
             }
         }
 
@@ -1127,11 +1127,11 @@ public class NorthboundIT {
                 .append("dstNodeConnector",
                         nodeConnectorType_2 + "|" + nodeConnectorId_2 + "@" + nodeType_2 + "|" + nodeId_2);
         // execute HTTP request and verify response code
-        result = getJsonResult(baseURL + "/userLink", "POST", jo.toString());
+        result = getJsonResult(baseURL + "/user-link", "POST", jo.toString());
         Assert.assertTrue(httpResponseCode == 201);
 
         // === test GET method for getUserLinks()
-        result = getJsonResult(baseURL + "/userLink", "GET");
+        result = getJsonResult(baseURL + "/user-link", "GET");
         Assert.assertTrue(httpResponseCode == 200);
         if (debugMsg) {
             System.out.println("result:" + result);
@@ -1176,12 +1176,12 @@ public class NorthboundIT {
 
         // === test DELETE method for deleteUserLink()
         String userName = "userLink_1";
-        result = getJsonResult(baseURL + "/userLink/" + userName, "DELETE");
+        result = getJsonResult(baseURL + "/user-link/" + userName, "DELETE");
         Assert.assertTrue(httpResponseCode == 200);
 
         // execute another getUserLinks() request to verify that userLink_1 is
         // removed
-        result = getJsonResult(baseURL + "/userLink", "GET");
+        result = getJsonResult(baseURL + "/user-link", "GET");
         Assert.assertTrue(httpResponseCode == 200);
         if (debugMsg) {
             System.out.println("result:" + result);
index ffa80f6496135ded21866f18c5b7f10e17bafdd1..573a08189f109fc36286bad60a13c1537606a9e3 100644 (file)
@@ -14,21 +14,32 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
-@XmlRootElement
-@XmlAccessorType(XmlAccessType.NONE)
 /**
- * This class contains static route data  that is returned as a response to the NorthBound GET request.
- *
- *
+ * StaticRoute represents the static route data that is returned as a response to
+ * the NorthBound GET request.
  *
  */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
 public class StaticRoute {
+    /**
+     * The name of the static route.
+     */
     @XmlElement
     private String name;
+
+    /**
+     * The prefix for the route.
+     * Format: A.B.C.D/MM  Where A.B.C.D is the Default Gateway IP (L3) or ARP Querier IP (L2)
+     */
     @XmlElement
-    private String prefix; // A.B.C.D/MM  Where A.B.C.D is the Default Gateway IP (L3) or ARP Querier IP (L2)
+    private String prefix;
+
+    /**
+     * NextHop IP-Address (or) datapath ID/port list: xx:xx:xx:xx:xx:xx:xx:xx/a,b,c-m,r-t,y
+     */
     @XmlElement
-    private String nextHop; // NextHop IP-Address (or) datapath ID/port list: xx:xx:xx:xx:xx:xx:xx:xx/a,b,c-m,r-t,y
+    private String nextHop;
 
     public StaticRoute() {
     }
index 683a9a2d906a285b37dab19bdb4b36b528aa8b57..27aa0ed3f91b2f5ad6d9c54921fd83d5f9a748b8 100644 (file)
@@ -17,9 +17,11 @@ import javax.xml.bind.annotation.XmlRootElement;
 
 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
 
-@XmlRootElement
+/**
+ * This class represents a list of static routes.
+ */
+@XmlRootElement(name = "list")
 @XmlAccessorType(XmlAccessType.NONE)
-
 public class StaticRoutes {
         @XmlElement
         List<StaticRoute> staticRoute;
index 3deb8dfa7b59766fab862b6151e3b2f00e4fc6d3..dceafac4abeb48facf3270a58322b1a5a1acc433 100644 (file)
@@ -23,6 +23,7 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.core.UriInfo;
 import javax.xml.bind.JAXBElement;
 
 import org.codehaus.enunciate.jaxrs.ResponseCode;
@@ -44,16 +45,26 @@ import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.controller.sal.utils.Status;
 
 /**
- * Static Routing Northbound APIs
+ * <p>Static Routing Northbound API allows for the management of the static
+ * routes.</p>
+ * </br>
+ * An example request/response for retrieving the static routes may look like this: </br>
+ * <pre>
+ * GET http://localhost:8080/controller/nb/v2/staticroute/default HTTP/1.1
+ * Accept: application/json
+ *
+ * HTTP/1.1 200 OK
+ * Content-Type: application/json
+ *
+ * {"staticRoute":{"name":"route-1","prefix":"10.10.1.0/24","nextHop":"1.1.1.1"}}
+ *
+ * </pre>
  *
  * <br><br>
  * Authentication scheme : <b>HTTP Basic</b><br>
  * Authentication realm : <b>opendaylight</b><br>
  * Transport : <b>HTTP and HTTPS</b><br>
  * <br>
- * HTTPS Authentication is disabled by default. Administrator can enable it in tomcat-server.xml after adding
- * a proper keystore / SSL certificate from a trusted authority.<br>
- * More info : http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
  */
 @Path("/")
 public class StaticRoutingNorthbound {
@@ -93,10 +104,30 @@ public class StaticRoutingNorthbound {
     }
 
     /**
-     * Returns a list of static routes present on the given container
+     * Get a list of static routes present on the given container.
      *
      * @param containerName Name of the Container. The Container name for the base controller is "default".
      * @return List of configured static routes on the given container
+     *
+     * <pre>
+     * Example:
+     *
+     * Request URL:
+     * GET http://localhost:8080/controller/nb/v2/staticroute/default
+     *
+     * Response in XML:
+     *  &lt;list&gt;
+     *   &lt;staticRoute&gt;
+     *     &lt;name&gt;route-1&lt;/name&gt;
+     *     &lt;prefix&gt;10.10.1.0/24&lt;/prefix&gt;
+     *     &lt;nextHop&gt;1.1.1.1&lt;/nextHop&gt;
+     *   &lt;/staticRoute&gt;
+     *  &lt;/list&gt;
+     *
+     * Response in JSON:
+     * {"staticRoute":{"name":"route-1","prefix":"10.10.1.0/24","nextHop":"1.1.1.1"}}
+     *
+     * </pre>
      */
     @Path("/{containerName}")
     @GET
@@ -121,10 +152,29 @@ public class StaticRoutingNorthbound {
      * Returns the static route for the provided configuration name on a given container
      *
      * @param containerName Name of the Container. The Container name for the base controller is "default".
-     * @param name Name of the Static Route configuration
+     * @param route Name of the Static Route configuration
      * @return Static route configured with the supplied Name.
+     *
+     * <pre>
+     * Example:
+     *
+     * Request URL:
+     * GET http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
+     *
+     * Response in XML:
+     *
+     *   &lt;staticRoute&gt;
+     *     &lt;name&gt;route-1&lt;/name&gt;
+     *     &lt;prefix&gt;10.10.1.0/24&lt;/prefix&gt;
+     *     &lt;nextHop&gt;1.1.1.1&lt;/nextHop&gt;
+     *   &lt;/staticRoute&gt;
+     *
+     * Response in JSON:
+     * {"name":"route-1","prefix":"10.10.1.0/24","nextHop":"1.1.1.1"}
+     *
+     * </pre>
      */
-    @Path("/{containerName}/{name}")
+    @Path("/{containerName}/route/{route}")
     @GET
     @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(StaticRoute.class)
@@ -133,7 +183,7 @@ public class StaticRoutingNorthbound {
             @ResponseCode(code = 404, condition = "The Container Name or Static Route Configuration name passed was not found") })
     public StaticRoute getStaticRoute(
             @PathParam("containerName") String containerName,
-            @PathParam("name") String name) {
+            @PathParam("route") String route) {
 
         if(!NorthboundUtils.isAuthorized(getUserName(), containerName,
                 Privilege.WRITE, this)){
@@ -142,9 +192,9 @@ public class StaticRoutingNorthbound {
                             + containerName);
         }
         List<StaticRoute> routes = this.getStaticRoutesInternal(containerName);
-        for (StaticRoute route : routes) {
-            if (route.getName().equalsIgnoreCase(name)) {
-                return route;
+        for (StaticRoute r : routes) {
+            if (r.getName().equalsIgnoreCase(route)) {
+                return r;
             }
         }
 
@@ -157,10 +207,21 @@ public class StaticRoutingNorthbound {
      * Add a new Static Route
      *
      * @param containerName Name of the Container. The Container name for the base controller is "default".
-     * @param name Name of the Static Route configuration
+     * @param route Name of the Static Route configuration
      * @return Response as dictated by the HTTP Response code
+     *
+     * <pre>
+     * Example:
+     *
+     * Request URL:
+     * POST http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
+     *
+     * Request payload in JSON:
+     * {"name":"route-1","prefix":"10.10.1.0/24","nextHop":"1.1.1.1"}
+     *
+     * </pre>
      */
-    @Path("/{containerName}/{name}")
+    @Path("/{containerName}/route/{route}")
     @POST
     @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes( {
@@ -169,8 +230,9 @@ public class StaticRoutingNorthbound {
             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
             @ResponseCode(code = 409, condition = "Failed to create Static Route entry due to Conflicting Name or Prefix."), })
     public Response addStaticRoute(
+            @Context UriInfo uriInfo,
             @PathParam(value = "containerName") String containerName,
-            @PathParam(value = "name") String name,
+            @PathParam(value = "route") String route,
             @TypeHint(StaticRoute.class) JAXBElement<StaticRoute> staticRouteData) {
 
 
@@ -196,8 +258,8 @@ public class StaticRoutingNorthbound {
                 sRoute.getPrefix(), sRoute.getNextHop());
         Status response = staticRouting.addStaticRoute(cfgObject);
         if (response.isSuccess()) {
-            NorthboundUtils.auditlog("Static Route", username, "added", name, containerName);
-            return Response.status(Response.Status.CREATED).build();
+            NorthboundUtils.auditlog("Static Route", username, "added", route, containerName);
+            return Response.created(uriInfo.getRequestUri()).build();
         }
         throw new ResourceConflictException(response.getDescription());
     }
@@ -207,12 +269,19 @@ public class StaticRoutingNorthbound {
      * Delete a Static Route
      *
      * @param containerName Name of the Container. The Container name for the base controller is "default".
-     * @param name Name of the Static Route configuration to be removed
+     * @param route Name of the Static Route configuration to be removed
      *
      * @return Response as dictated by the HTTP Response code
+     *
+     * <pre>
+     * Example:
+     *
+     * Request URL:
+     * DELETE http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
+     *
+     * </pre>
      */
-
-    @Path("/{containerName}/{name}")
+    @Path("/{containerName}/route/{route}")
     @DELETE
     @StatusCodes( {
             @ResponseCode(code = 200, condition = "Operation successful"),
@@ -220,7 +289,7 @@ public class StaticRoutingNorthbound {
             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active") })
     public Response removeStaticRoute(
             @PathParam(value = "containerName") String containerName,
-            @PathParam(value = "name") String name) {
+            @PathParam(value = "route") String route) {
 
         if(!NorthboundUtils.isAuthorized(getUserName(), containerName,
                 Privilege.WRITE, this)){
@@ -239,9 +308,9 @@ public class StaticRoutingNorthbound {
                     .toString());
         }
 
-        Status status = staticRouting.removeStaticRoute(name);
+        Status status = staticRouting.removeStaticRoute(route);
         if (status.isSuccess()) {
-            NorthboundUtils.auditlog("Static Route", username, "removed", name, containerName);
+            NorthboundUtils.auditlog("Static Route", username, "removed", route, containerName);
             return Response.ok().build();
         }
         throw new ResourceNotFoundException(status.getDescription());
index 7f37afec21eb4c2e1201af6696c4076e2beda05b..18627285eaa7f7d834ccd96966d4691fa67101bf 100644 (file)
@@ -15,15 +15,14 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
-@XmlRootElement
+@XmlRootElement(name = "list")
 @XmlAccessorType(XmlAccessType.NONE)
-
 public class AllFlowStatistics {
         @XmlElement
         List<FlowStatistics> flowStatistics;
         //To satisfy JAXB
-        private AllFlowStatistics() {
-        }
+        @SuppressWarnings("unused")
+        private AllFlowStatistics() {}
 
         public AllFlowStatistics(List<FlowStatistics> flowStatistics) {
                 this.flowStatistics = flowStatistics;
index e377de2b8836a10c1089eddb098533e2bf95820b..2117690d974326eb0be37b93c02f56914b3f05ac 100644 (file)
@@ -15,15 +15,14 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
-@XmlRootElement
+@XmlRootElement(name = "list")
 @XmlAccessorType(XmlAccessType.NONE)
-
 public class AllPortStatistics {
         @XmlElement
         List<PortStatistics> portStatistics;
         //To satisfy JAXB
-        private AllPortStatistics() {
-        }
+        @SuppressWarnings("unused")
+        private AllPortStatistics() {}
 
         public AllPortStatistics(List<PortStatistics> portStatistics) {
                 this.portStatistics = portStatistics;
index 5b998ee21a131d4482ba70396c05937bcc091165..4a10eb4fa2af2d5151ba6d24da582855834e9e2b 100644 (file)
@@ -14,14 +14,14 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
-@XmlRootElement
+@XmlRootElement(name = "list")
 @XmlAccessorType(XmlAccessType.NONE)
 public class AllTableStatistics {
     @XmlElement
     List<TableStatistics> tableStatistics;
     //To satisfy JAXB
-    private AllTableStatistics() {
-    }
+    @SuppressWarnings("unused")
+    private AllTableStatistics() {}
 
     public AllTableStatistics(List<TableStatistics> tableStatistics) {
         this.tableStatistics = tableStatistics;
index 25b671c1a881d44cd7e61137fdaca09621aa1885..9b31b913fefa9f71cf0645da0cef0f89aa043bfc 100644 (file)
@@ -14,26 +14,27 @@ import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 
-@XmlRootElement
+@XmlRootElement(name = "nodeFlowStatistics")
 @XmlAccessorType(XmlAccessType.NONE)
 public class FlowStatistics {
     @XmlElement
     private Node node;
-    @XmlElement(name="flowStat")
-    private List<FlowOnNode> flowStat;
+    @XmlElement
+    private List<FlowOnNode> flowStatistic;
 
     // To satisfy JAXB
     @SuppressWarnings("unused")
-        private FlowStatistics() {
+    private FlowStatistics() {
     }
 
     public FlowStatistics(Node node, List<FlowOnNode> flowStat) {
         super();
         this.node = node;
-        this.flowStat = flowStat;
+        this.flowStatistic = flowStat;
     }
 
     public Node getNode() {
@@ -45,10 +46,10 @@ public class FlowStatistics {
     }
 
     public List<FlowOnNode> getFlowStats() {
-        return flowStat;
+        return flowStatistic;
     }
 
     public void setFlowStats(List<FlowOnNode> flowStats) {
-        this.flowStat = flowStats;
+        this.flowStatistic = flowStats;
     }
 }
index 876bb7f7b08f11b85c068a12edb37a38747750ab..e519472d40c2afeb1ed2beaf3d6b7b31800e5c6d 100644 (file)
@@ -18,13 +18,13 @@ import javax.xml.bind.annotation.XmlRootElement;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 
-@XmlRootElement
+@XmlRootElement(name = "nodePortStatistics")
 @XmlAccessorType(XmlAccessType.NONE)
 public class PortStatistics {
     @XmlElement
     private Node node;
-    @XmlElement(name="portStat")
-    private List<NodeConnectorStatistics> portStats;
+    @XmlElement
+    private List<NodeConnectorStatistics> portStatistic;
 
     // To satisfy JAXB
     @SuppressWarnings("unused")
@@ -34,7 +34,7 @@ public class PortStatistics {
     public PortStatistics(Node node, List<NodeConnectorStatistics> portStats) {
         super();
         this.node = node;
-        this.portStats = portStats;
+        this.portStatistic = portStats;
     }
 
     public Node getNode() {
@@ -46,11 +46,11 @@ public class PortStatistics {
     }
 
     public List<NodeConnectorStatistics> getPortStats() {
-        return portStats;
+        return portStatistic;
     }
 
     public void setFlowStats(List<NodeConnectorStatistics> portStats) {
-        this.portStats = portStats;
+        this.portStatistic = portStats;
     }
 
 }
index 197ebabf9133d43f7b81f5360f46b7d3138b1f9e..1c3fd1cf2ea10d32b148aec6d8dbb2fb2fab357a 100644 (file)
@@ -23,9 +23,12 @@ import org.codehaus.enunciate.jaxrs.ResponseCode;
 import org.codehaus.enunciate.jaxrs.StatusCodes;
 import org.codehaus.enunciate.jaxrs.TypeHint;
 import org.opendaylight.controller.containermanager.IContainerManager;
-
 import org.opendaylight.controller.northbound.commons.RestMessages;
-import org.opendaylight.controller.northbound.commons.exception.*;
+import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
 import org.opendaylight.controller.sal.authorization.Privilege;
 import org.opendaylight.controller.sal.core.Node;
@@ -39,7 +42,7 @@ import org.opendaylight.controller.switchmanager.ISwitchManager;
 
 /**
  * Northbound APIs that returns various Statistics exposed by the Southbound
- * plugins such as Openflow.
+ * protocol plugins such as Openflow.
  *
  * <br>
  * <br>
@@ -107,9 +110,114 @@ public class StatisticsNorthbound {
      *            Name of the Container. The Container name for the base
      *            controller is "default".
      * @return List of FlowStatistics from all the Nodes
+     *
+     *         <pre>
+     * Example:
+     * Request URL: localhost:8080/controller/nb/v2/statistics/default/flow
+     *
+     * Response in JSON:
+     * {
+     *     "flowStatistics": [
+     *         {
+     *             "node": {
+     *                 "@type": "OF",
+     *                 "@id": "00:00:00:00:00:00:00:02"
+     *             },
+     *             "flowStatistic": [
+     *                 {
+     *                     "flow": {
+     *                         "match": {
+     *                             "matchField": [
+     *                                 {
+     *                                     "type": "DL_TYPE",
+     *                                     "value": "2048"
+     *                                 },
+     *                                 {
+     *                                     "mask": "255.255.255.255",
+     *                                     "type": "NW_DST",
+     *                                     "value": "1.1.1.1"
+     *                                 }
+     *                             ]
+     *                         },
+     *                         "actions": {
+     *                             "@type": "output",
+     *                             "port": {
+     *                                 "@type": "OF",
+     *                                 "@id": "3",
+     *                                 "node": {
+     *                                     "@type": "OF",
+     *                                     "@id": "00:00:00:00:00:00:00:02"
+     *                                 }
+     *                             }
+     *                         },
+     *                         "priority": "1",
+     *                         "idleTimeout": "0",
+     *                         "hardTimeout": "0",
+     *                         "id": "0"
+     *                     },
+     *                     "tableId": "0",
+     *                     "durationSeconds": "1828",
+     *                     "durationNanoseconds": "397000000",
+     *                     "packetCount": "0",
+     *                     "byteCount": "0"
+     *                 }
+     *             ]
+     *         },
+     *         {   flow statistics of another node
+     *             ............
+     *             ................
+     *             ......................
+     *         }
+     *
+     *     ]
+     * }
+     * Response in XML:
+     * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
+     * &lt;list&gt;
+     *     &lt;flowStatistics&gt;
+     *         &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:02&quot;/&gt;
+     *         &lt;flowStatistic&gt;
+     *             &lt;flow&gt;
+     *                 &lt;match&gt;
+     *                     &lt;matchField&gt;
+     *                         &lt;type&gt;DL_TYPE&lt;/type&gt;
+     *                         &lt;value&gt;2048&lt;/value&gt;
+     *                     &lt;/matchField&gt;
+     *                     &lt;matchField&gt;
+     *                         &lt;mask&gt;255.255.255.255&lt;/mask&gt;
+     *                         &lt;type&gt;NW_DST&lt;/type&gt;
+     *                         &lt;value&gt;1.1.1.2&lt;/value&gt;
+     *                     &lt;/matchField&gt;
+     *                 &lt;/match&gt;
+     *                 &lt;actions
+     *                     xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:type=&quot;output&quot;&gt;
+     *                     &lt;port type=&quot;OF&quot; id=&quot;3&quot;&gt;
+     *                         &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:02&quot;/&gt;
+     *                     &lt;/port&gt;
+     *                 &lt;/actions&gt;
+     *                 &lt;priority&gt;1&lt;/priority&gt;
+     *                 &lt;idleTimeout&gt;0&lt;/idleTimeout&gt;
+     *                 &lt;hardTimeout&gt;0&lt;/hardTimeout&gt;
+     *                 &lt;id&gt;0&lt;/id&gt;
+     *             &lt;/flow&gt;
+     *             &lt;tableId&gt;0&lt;/tableId&gt;
+     *             &lt;durationSeconds&gt;337&lt;/durationSeconds&gt;
+     *             &lt;durationNanoseconds&gt;149000000&lt;/durationNanoseconds&gt;
+     *             &lt;packetCount&gt;0&lt;/packetCount&gt;
+     *             &lt;byteCount&gt;0&lt;/byteCount&gt;
+     *         &lt;/flowStatistic&gt;
+     *     &lt;/flowStatistics&gt;
+     *     &lt;flowStatistics&gt;
+     *          flow statistics for another node
+     *          ..........
+     *          ................
+     *          .....................
+     *     &lt;/flowStatistics&gt;
+     * &lt;/list&gt;
+     * </pre>
      */
 
-    @Path("/{containerName}/flowstats")
+    @Path("/{containerName}/flow")
     @GET
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(AllFlowStatistics.class)
@@ -159,12 +267,138 @@ public class StatisticsNorthbound {
      *            Name of the Container. The Container name for the base
      *            controller is "default".
      * @param nodeType
-     *            Node Type as specifid by Node class
+     *            Node Type as specifid in {@link org.opendaylight.controller.sal.core.Node} class
      * @param nodeId
      *            Node Identifier
-     * @return List of Flow Statistics for a given Node.
+     * @return List of Flow Statistics for a given Node. *
+     *
+     *         <pre>
+     * Example:
+     * Request URL:
+     * http://host:8080/controller/nb/v2/statistics/default/flow/node/OF/00:00:00:00:00:00:00:01
+     *
+     * Response in JSON:
+     * {
+     *     "node": {
+     *         "@type": "OF",
+     *         "@id": "00:00:00:00:00:00:00:01"
+     *     },
+     *     "flowStatistic": [
+     *         {
+     *             "flow": {
+     *                 "match": {
+     *                     "matchField": [
+     *                         {
+     *                             "type": "DL_TYPE",
+     *                             "value": "2048"
+     *                         },
+     *                         {
+     *                             "mask": "255.255.255.255",
+     *                             "type": "NW_DST",
+     *                             "value": "1.1.1.2"
+     *                         }
+     *                     ]
+     *                 },
+     *                 "actions": [
+     *                     {
+     *                         "@type": "setDlDst",
+     *                         "address": "52d28b0f76ec"
+     *                     },
+     *                     {
+     *                         "@type": "output",
+     *                         "port": {
+     *                             "@type": "OF",
+     *                             "@id": "5",
+     *                             "node": {
+     *                                 "@type": "OF",
+     *                                 "@id": "00:00:00:00:00:00:00:01"
+     *                             }
+     *                         }
+     *                     }
+     *                 ],
+     *                 "priority": "1",
+     *                 "idleTimeout": "0",
+     *                 "hardTimeout": "0",
+     *                 "id": "0"
+     *             },
+     *             "tableId": "0",
+     *             "durationSeconds": "2089",
+     *             "durationNanoseconds": "538000000",
+     *             "packetCount": "0",
+     *             "byteCount": "0"
+     *         }
+     *     ]
+     * }
+     *
+     *
+     * Response in XML:
+     * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
+     *     &lt;nodeFlowStatistics&gt;
+     *         &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:02&quot;/&gt;
+     *         &lt;flowStatistic&gt;
+     *             &lt;flow&gt;
+     *                 &lt;match&gt;
+     *                     &lt;matchField&gt;
+     *                         &lt;type&gt;DL_TYPE&lt;/type&gt;
+     *                         &lt;value&gt;2048&lt;/value&gt;
+     *                     &lt;/matchField&gt;
+     *                     &lt;matchField&gt;
+     *                         &lt;mask&gt;255.255.255.255&lt;/mask&gt;
+     *                         &lt;type&gt;NW_DST&lt;/type&gt;
+     *                         &lt;value&gt;1.1.1.2&lt;/value&gt;
+     *                     &lt;/matchField&gt;
+     *                 &lt;/match&gt;
+     *                 &lt;actions
+     *                     xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:type=&quot;output&quot;&gt;
+     *                     &lt;port type=&quot;OF&quot; id=&quot;3&quot;&gt;
+     *                         &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:02&quot;/&gt;
+     *                     &lt;/port&gt;
+     *                 &lt;/actions&gt;
+     *                 &lt;priority&gt;1&lt;/priority&gt;
+     *                 &lt;idleTimeout&gt;0&lt;/idleTimeout&gt;
+     *                 &lt;hardTimeout&gt;0&lt;/hardTimeout&gt;
+     *                 &lt;id&gt;0&lt;/id&gt;
+     *             &lt;/flow&gt;
+     *             &lt;tableId&gt;0&lt;/tableId&gt;
+     *             &lt;durationSeconds&gt;337&lt;/durationSeconds&gt;
+     *             &lt;durationNanoseconds&gt;149000000&lt;/durationNanoseconds&gt;
+     *             &lt;packetCount&gt;0&lt;/packetCount&gt;
+     *             &lt;byteCount&gt;0&lt;/byteCount&gt;
+     *         &lt;/flowStatistic&gt;
+     *         &lt;flowStatistic&gt;
+     *             &lt;flow&gt;
+     *                 &lt;match&gt;
+     *                     &lt;matchField&gt;
+     *                         &lt;type&gt;DL_TYPE&lt;/type&gt;
+     *                         &lt;value&gt;2048&lt;/value&gt;
+     *                     &lt;/matchField&gt;
+     *                     &lt;matchField&gt;
+     *                         &lt;mask&gt;255.255.255.255&lt;/mask&gt;
+     *                         &lt;type&gt;NW_DST&lt;/type&gt;
+     *                         &lt;value&gt;1.1.1.1&lt;/value&gt;
+     *                     &lt;/matchField&gt;
+     *                 &lt;/match&gt;
+     *                 &lt;actions
+     *                     xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:type=&quot;output&quot;&gt;
+     *                     &lt;port type=&quot;OF&quot; id=&quot;3&quot;&gt;
+     *                         &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:02&quot;/&gt;
+     *                     &lt;/port&gt;
+     *                 &lt;/actions&gt;
+     *                 &lt;priority&gt;1&lt;/priority&gt;
+     *                 &lt;idleTimeout&gt;0&lt;/idleTimeout&gt;
+     *                 &lt;hardTimeout&gt;0&lt;/hardTimeout&gt;
+     *                 &lt;id&gt;0&lt;/id&gt;
+     *             &lt;/flow&gt;
+     *             &lt;tableId&gt;0&lt;/tableId&gt;
+     *             &lt;durationSeconds&gt;337&lt;/durationSeconds&gt;
+     *             &lt;durationNanoseconds&gt;208000000&lt;/durationNanoseconds&gt;
+     *             &lt;packetCount&gt;0&lt;/packetCount&gt;
+     *             &lt;byteCount&gt;0&lt;/byteCount&gt;
+     *         &lt;/flowStatistic&gt;
+     *     &lt;/nodeFlowStatistics&gt;
+     * </pre>
      */
-    @Path("/{containerName}/flowstats/{nodeType}/{nodeId}")
+    @Path("/{containerName}/flow/node/{nodeType}/{nodeId}")
     @GET
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(FlowStatistics.class)
@@ -210,9 +444,128 @@ public class StatisticsNorthbound {
      *            controller is "default".
      * @return List of all the Port Statistics across all the NodeConnectors on
      *         all the Nodes.
+     *
+     *         <pre>
+     * Example:
+     *
+     * Requset URL: http://host:8080/controller/nb/v2/statistics/default/port
+     *
+     * Response in JSON:
+     * {
+     *     "portStatistics": [
+     *         {
+     *             "node": {
+     *                 "@type": "OF",
+     *                 "@id": "00:00:00:00:00:00:00:02"
+     *             },
+     *             "portStatistic": [
+     *                 {
+     *                     "nodeConnector": {
+     *                         "@type": "OF",
+     *                         "@id": "3",
+     *                         "node": {
+     *                             "@type": "OF",
+     *                             "@id": "00:00:00:00:00:00:00:02"
+     *                         }
+     *                     },
+     *                     "receivePackets": "182",
+     *                     "transmitPackets": "173",
+     *                     "receiveBytes": "12740",
+     *                     "transmitBytes": "12110",
+     *                     "receiveDrops": "0",
+     *                     "transmitDrops": "0",
+     *                     "receiveErrors": "0",
+     *                     "transmitErrors": "0",
+     *                     "receiveFrameError": "0",
+     *                     "receiveOverRunError": "0",
+     *                     "receiveCrcError": "0",
+     *                     "collisionCount": "0"
+     *                 },
+     *                 {
+     *                     "nodeConnector": {
+     *                         "@type": "OF",
+     *                         "@id": "2",
+     *                         "node": {
+     *                             "@type": "OF",
+     *                             "@id": "00:00:00:00:00:00:00:02"
+     *                         }
+     *                     },
+     *                     "receivePackets": "174",
+     *                     "transmitPackets": "181",
+     *                     "receiveBytes": "12180",
+     *                     "transmitBytes": "12670",
+     *                     "receiveDrops": "0",
+     *                     "transmitDrops": "0",
+     *                     "receiveErrors": "0",
+     *                     "transmitErrors": "0",
+     *                     "receiveFrameError": "0",
+     *                     "receiveOverRunError": "0",
+     *                     "receiveCrcError": "0",
+     *                     "collisionCount": "0"
+     *                 },
+     *
+     *             ]
+     *         },
+     *         {
+     *             "node": {
+     *                 "@type": "OF",
+     *                 "@id": "00:00:00:00:00:00:00:03"
+     *             },
+     *             "portStatistic": [
+     *                  ..................
+     *                  .......................
+     *                  ..........................
+     *             ]
+     *         }
+     *     ]
+     * }
+     *
+     * Response in XML:
+     * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
+     * &lt;list&gt;
+     *     &lt;portStatistics&gt;
+     *         &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:02&quot;/&gt;
+     *         &lt;portStatistic&gt;
+     *             &lt;nodeConnector type=&quot;OF&quot; id=&quot;3&quot;&gt;
+     *                 &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:02&quot;/&gt;
+     *             &lt;/nodeConnector&gt;
+     *             &lt;receivePackets&gt;181&lt;/receivePackets&gt;
+     *             &lt;transmitPackets&gt;172&lt;/transmitPackets&gt;
+     *             &lt;receiveBytes&gt;12670&lt;/receiveBytes&gt;
+     *             &lt;transmitBytes&gt;12040&lt;/transmitBytes&gt;
+     *             &lt;receiveDrops&gt;0&lt;/receiveDrops&gt;
+     *             &lt;transmitDrops&gt;0&lt;/transmitDrops&gt;
+     *             &lt;receiveErrors&gt;0&lt;/receiveErrors&gt;
+     *             &lt;transmitErrors&gt;0&lt;/transmitErrors&gt;
+     *             &lt;receiveFrameError&gt;0&lt;/receiveFrameError&gt;
+     *             &lt;receiveOverRunError&gt;0&lt;/receiveOverRunError&gt;
+     *             &lt;receiveCrcError&gt;0&lt;/receiveCrcError&gt;
+     *             &lt;collisionCount&gt;0&lt;/collisionCount&gt;
+     *         &lt;/portStatistic&gt;
+     *         &lt;portStatistic&gt;
+     *             &lt;nodeConnector type=&quot;OF&quot; id=&quot;2&quot;&gt;
+     *                 &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:02&quot;/&gt;
+     *             &lt;/nodeConnector&gt;
+     *             &lt;receivePackets&gt;173&lt;/receivePackets&gt;
+     *             &lt;transmitPackets&gt;180&lt;/transmitPackets&gt;
+     *             &lt;receiveBytes&gt;12110&lt;/receiveBytes&gt;
+     *             &lt;transmitBytes&gt;12600&lt;/transmitBytes&gt;
+     *             &lt;receiveDrops&gt;0&lt;/receiveDrops&gt;
+     *             &lt;transmitDrops&gt;0&lt;/transmitDrops&gt;
+     *             &lt;receiveErrors&gt;0&lt;/receiveErrors&gt;
+     *             &lt;transmitErrors&gt;0&lt;/transmitErrors&gt;
+     *             &lt;receiveFrameError&gt;0&lt;/receiveFrameError&gt;
+     *             &lt;receiveOverRunError&gt;0&lt;/receiveOverRunError&gt;
+     *             &lt;receiveCrcError&gt;0&lt;/receiveCrcError&gt;
+     *             &lt;collisionCount&gt;0&lt;/collisionCount&gt;
+     *         &lt;/portStatistic&gt;
+     *
+     *     &lt;/portStatistics&gt;
+     * &lt;/list&gt;
+     * </pre>
      */
 
-    @Path("/{containerName}/portstats")
+    @Path("/{containerName}/port")
     @GET
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(AllPortStatistics.class)
@@ -260,13 +613,114 @@ public class StatisticsNorthbound {
      *            Name of the Container. The Container name for the base
      *            controller is "default".
      * @param nodeType
-     *            Node Type as specifid by Node class
+     *            Node Type as specifid in {@link org.opendaylight.controller.sal.core.Node} class
      * @param Node
-     *            Identifier
+     *            Identifier (e.g. MAC address)
      * @return Returns a list of all the Port Statistics across all the
      *         NodeConnectors in a given Node.
+     *
+     *         <pre>
+     * Example:
+     *
+     * Request URL:
+     * http://host:8080/controller/nb/v2/statistics/default/port/node/OF/00:00:00:00:00:00:00:01
+     *
+     * Response in JSON:
+     * {
+     *     "node": {
+     *         "@type": "OF",
+     *         "@id": "00:00:00:00:00:00:00:01"
+     *     },
+     *     "portStatistic": [
+     *         {
+     *             "nodeConnector": {
+     *                 "@type": "OF",
+     *                 "@id": "3",
+     *                 "node": {
+     *                     "@type": "OF",
+     *                     "@id": "00:00:00:00:00:00:00:01"
+     *                 }
+     *             },
+     *             "receivePackets": "171",
+     *             "transmitPackets": "2451",
+     *             "receiveBytes": "11970",
+     *             "transmitBytes": "235186",
+     *             "receiveDrops": "0",
+     *             "transmitDrops": "0",
+     *             "receiveErrors": "0",
+     *             "transmitErrors": "0",
+     *             "receiveFrameError": "0",
+     *             "receiveOverRunError": "0",
+     *             "receiveCrcError": "0",
+     *             "collisionCount": "0"
+     *         },
+     *         {
+     *             "nodeConnector": {
+     *                 "@type": "OF",
+     *                 "@id": "2",
+     *                 "node": {
+     *                     "@type": "OF",
+     *                     "@id": "00:00:00:00:00:00:00:01"
+     *                 }
+     *             },
+     *             "receivePackets": "179",
+     *             "transmitPackets": "2443",
+     *             "receiveBytes": "12530",
+     *             "transmitBytes": "234626",
+     *             "receiveDrops": "0",
+     *             "transmitDrops": "0",
+     *             "receiveErrors": "0",
+     *             "transmitErrors": "0",
+     *             "receiveFrameError": "0",
+     *             "receiveOverRunError": "0",
+     *             "receiveCrcError": "0",
+     *             "collisionCount": "0"
+     *         }
+     *     ]
+     * }
+     *
+     * Response in XML:
+     * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
+     * &lt;nodePortStatistics&gt;
+     *     &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:01&quot;/&gt;
+     *     &lt;portStatistic&gt;
+     *         &lt;nodeConnector type=&quot;OF&quot; id=&quot;2&quot;&gt;
+     *             &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:01&quot;/&gt;
+     *         &lt;/nodeConnector&gt;
+     *         &lt;receivePackets&gt;180&lt;/receivePackets&gt;
+     *         &lt;transmitPackets&gt;2594&lt;/transmitPackets&gt;
+     *         &lt;receiveBytes&gt;12600&lt;/receiveBytes&gt;
+     *         &lt;transmitBytes&gt;249396&lt;/transmitBytes&gt;
+     *         &lt;receiveDrops&gt;0&lt;/receiveDrops&gt;
+     *         &lt;transmitDrops&gt;0&lt;/transmitDrops&gt;
+     *         &lt;receiveErrors&gt;0&lt;/receiveErrors&gt;
+     *         &lt;transmitErrors&gt;0&lt;/transmitErrors&gt;
+     *         &lt;receiveFrameError&gt;0&lt;/receiveFrameError&gt;
+     *         &lt;receiveOverRunError&gt;0&lt;/receiveOverRunError&gt;
+     *         &lt;receiveCrcError&gt;0&lt;/receiveCrcError&gt;
+     *         &lt;collisionCount&gt;0&lt;/collisionCount&gt;
+     *     &lt;/portStatistic&gt;
+     *     &lt;portStatistic&gt;
+     *         &lt;nodeConnector type=&quot;OF&quot; id=&quot;5&quot;&gt;
+     *             &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:01&quot;/&gt;
+     *         &lt;/nodeConnector&gt;
+     *         &lt;receivePackets&gt;2542&lt;/receivePackets&gt;
+     *         &lt;transmitPackets&gt;2719&lt;/transmitPackets&gt;
+     *         &lt;receiveBytes&gt;243012&lt;/receiveBytes&gt;
+     *         &lt;transmitBytes&gt;255374&lt;/transmitBytes&gt;
+     *         &lt;receiveDrops&gt;0&lt;/receiveDrops&gt;
+     *         &lt;transmitDrops&gt;0&lt;/transmitDrops&gt;
+     *         &lt;receiveErrors&gt;0&lt;/receiveErrors&gt;
+     *         &lt;transmitErrors&gt;0&lt;/transmitErrors&gt;
+     *         &lt;receiveFrameError&gt;0&lt;/receiveFrameError&gt;
+     *         &lt;receiveOverRunError&gt;0&lt;/receiveOverRunError&gt;
+     *         &lt;receiveCrcError&gt;0&lt;/receiveCrcError&gt;
+     *         &lt;collisionCount&gt;0&lt;/collisionCount&gt;
+     *     &lt;/portStatistic&gt;
+     * &lt;/nodePortStatistics&gt;
+     * </pre>
      */
-    @Path("/{containerName}/portstats/{nodeType}/{nodeId}")
+    @Path("/{containerName}/port/node/{nodeType}/{nodeId}")
     @GET
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(PortStatistics.class)
@@ -313,11 +767,91 @@ public class StatisticsNorthbound {
      *            controller is "default".
      *
      * @return Returns a list of all the Table Statistics in a given Node.
+     *
+     *         <pre>
+     *
+     *  Example:
+     *
+     *  Request URL:
+     *  http://host:8080/controller/nb/v2/statistics/default/table
+     *
+     *  Response in JSON:
+     *
+     * {
+     *     "tableStatistics": [
+     *         {
+     *             "node": {
+     *                 "@type": "OF",
+     *                 "@id": "00:00:00:00:00:00:00:02"
+     *             },
+     *             "tableStatistic": [
+     *                 {
+     *                     "nodeTable": {
+     *                         "@id": "0",
+     *                         "node": {
+     *                             "@type": "OF",
+     *                             "@id": "00:00:00:00:00:00:00:02"
+     *                         }
+     *                     },
+     *                     "activeCount": "11",
+     *                     "lookupCount": "816",
+     *                     "matchedCount": "220"
+     *                 },
+     *                 {
+     *                     ...another table
+     *                     .....
+     *                     ........
+     *                 }
+     *
+     *             ]
+     *         }
+     *     ]
+     * }
+     *
+     *
+     *  Response in XML:
+     *  &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
+     *  &lt;list&gt;
+     *  &lt;tableStatistics&gt;
+     *      &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:01&quot;/&gt;
+     *      &lt;tableStatistic&gt;
+     *          &lt;nodeTable id=&quot;0&quot;&gt;
+     *              &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:01&quot;/&gt;
+     *          &lt;/nodeTable&gt;
+     *          &lt;activeCount&gt;12&lt;/activeCount&gt;
+     *          &lt;lookupCount&gt;10935&lt;/lookupCount&gt;
+     *          &lt;matchedCount&gt;10084&lt;/matchedCount&gt;
+     *      &lt;/tableStatistic&gt;
+     *      &lt;tableStatistic&gt;
+     *          &lt;nodeTable id=&quot;1&quot;&gt;
+     *              &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:01&quot;/&gt;
+     *          &lt;/nodeTable&gt;
+     *          &lt;activeCount&gt;0&lt;/activeCount&gt;
+     *          &lt;lookupCount&gt;0&lt;/lookupCount&gt;
+     *          &lt;matchedCount&gt;0&lt;/matchedCount&gt;
+     *      &lt;/tableStatistic&gt;
+     *      &lt;tableStatistic&gt;
+     *          &lt;nodeTable id=&quot;2&quot;&gt;
+     *              &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:01&quot;/&gt;
+     *          &lt;/nodeTable&gt;
+     *          &lt;activeCount&gt;0&lt;/activeCount&gt;
+     *          &lt;lookupCount&gt;0&lt;/lookupCount&gt;
+     *          &lt;matchedCount&gt;0&lt;/matchedCount&gt;
+     *      &lt;/tableStatistic&gt;
+     *  &lt;/tableStatistics&gt;
+     *  &lt;tableStatistics&gt;
+     *  ...
+     *  ......
+     *  ........
+     *  &lt;/tableStatistics&gt;
+     *  &lt;/list&gt;
+     *
+     * </pre>
      */
-    @Path("/{containerName}/tablestats")
+    @Path("/{containerName}/table")
     @GET
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-    @TypeHint(TableStatistics.class)
+    @TypeHint(AllTableStatistics.class)
     @StatusCodes({
         @ResponseCode(code = 200, condition = "Operation successful"),
         @ResponseCode(code = 404, condition = "The containerName is not found"),
@@ -325,17 +859,15 @@ public class StatisticsNorthbound {
     public AllTableStatistics getTableStatistics(
             @PathParam("containerName") String containerName) {
 
-        if (!NorthboundUtils.isAuthorized(
-                getUserName(), containerName, Privilege.READ, this)) {
-            throw new UnauthorizedException(
-                    "User is not authorized to perform this operation on container "
-                            + containerName);
+        if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException("User is not authorized to perform this operation on container "
+                    + containerName);
         }
         handleDefaultDisabled(containerName);
 
         IStatisticsManager statisticsManager = getStatisticsService(containerName);
         if (statisticsManager == null) {
-            throw new ServiceUnavailableException("Statistics "
+            throw new ServiceUnavailableException("Statistics manager"
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
 
@@ -357,18 +889,92 @@ public class StatisticsNorthbound {
     }
 
     /**
-     * Returns a list of all the Table Statistics on all Nodes.
+     * Returns a list of all the Table Statistics on a specific node.
      *
      * @param containerName
      *            Name of the Container. The Container name for the base
      *            controller is "default".
      * @param nodeType
-     *            Node Type as specifid by Node class
+     *            Node Type as specified in {@link org.opendaylight.controller.sal.core.Node} class (e.g. OF for Openflow)
      * @param Node
-     *            Identifier
+     *            Identifier (e.g. MAC address)
      * @return Returns a list of all the Table Statistics in a given Node.
+     *
+     *         <pre>
+     *
+     * Example:
+     *
+     * Request URL:
+     * http://host:8080/controller/nb/v2/statistics/default/table/node/OF/00:00:00:00:00:00:00:01
+     *
+     * Response in JSON:
+     * {
+     *     "node": {
+     *         "@type": "OF",
+     *         "@id": "00:00:00:00:00:00:00:01"
+     *     },
+     *     "tableStatistic": [
+     *         {
+     *             "nodeTable": {
+     *                 "@id": "0",
+     *                 "node": {
+     *                     "@type": "OF",
+     *                     "@id": "00:00:00:00:00:00:00:01"
+     *                 }
+     *             },
+     *             "activeCount": "12",
+     *             "lookupCount": "11382",
+     *             "matchedCount": "10524"
+     *         },
+     *         {
+     *             "nodeTable": {
+     *                 "@id": "1",
+     *                 "node": {
+     *                     "@type": "OF",
+     *                     "@id": "00:00:00:00:00:00:00:01"
+     *                 }
+     *             },
+     *             "activeCount": "0",
+     *             "lookupCount": "0",
+     *             "matchedCount": "0"
+     *         }
+     *    ]
+     * }
+     *
+     * Response in XML:
+     * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
+     * &lt;nodeTableStatistics&gt;
+     *     &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:01&quot;/&gt;
+     *     &lt;tableStatistic&gt;
+     *         &lt;nodeTable id=&quot;0&quot;&gt;
+     *             &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:01&quot;/&gt;
+     *         &lt;/nodeTable&gt;
+     *         &lt;activeCount&gt;12&lt;/activeCount&gt;
+     *         &lt;lookupCount&gt;10935&lt;/lookupCount&gt;
+     *         &lt;matchedCount&gt;10084&lt;/matchedCount&gt;
+     *     &lt;/tableStatistic&gt;
+     *     &lt;tableStatistic&gt;
+     *         &lt;nodeTable id=&quot;1&quot;&gt;
+     *             &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:01&quot;/&gt;
+     *         &lt;/nodeTable&gt;
+     *         &lt;activeCount&gt;0&lt;/activeCount&gt;
+     *         &lt;lookupCount&gt;0&lt;/lookupCount&gt;
+     *         &lt;matchedCount&gt;0&lt;/matchedCount&gt;
+     *     &lt;/tableStatistic&gt;
+     *     &lt;tableStatistic&gt;
+     *         &lt;nodeTable id=&quot;2&quot;&gt;
+     *             &lt;node type=&quot;OF&quot; id=&quot;00:00:00:00:00:00:00:01&quot;/&gt;
+     *         &lt;/nodeTable&gt;
+     *         &lt;activeCount&gt;0&lt;/activeCount&gt;
+     *         &lt;lookupCount&gt;0&lt;/lookupCount&gt;
+     *         &lt;matchedCount&gt;0&lt;/matchedCount&gt;
+     *     &lt;/tableStatistic&gt;
+     * &lt;/nodeTableStatistics&gt;
+     *
+     *
+     * </pre>
      */
-    @Path("/{containerName}/tablestats/{nodeType}/{nodeId}")
+    @Path("/{containerName}/table/node/{nodeType}/{nodeId}")
     @GET
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(TableStatistics.class)
index a1c20190e61499e26669a42a7597ea426f0cd34e..552e707daef5780b2c3f3c40c2f963a797fc41b7 100644 (file)
@@ -5,7 +5,9 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
+
 package org.opendaylight.controller.statistics.northbound;
+
 import java.util.List;
 
 import javax.xml.bind.annotation.XmlAccessType;
@@ -16,13 +18,13 @@ import javax.xml.bind.annotation.XmlRootElement;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 
-@XmlRootElement
+@XmlRootElement(name = "nodeTableStatistics")
 @XmlAccessorType(XmlAccessType.NONE)
 public class TableStatistics {
     @XmlElement
     private Node node;
-    @XmlElement(name="tableStat")
-    private List<NodeTableStatistics> tableStats;
+    @XmlElement
+    private List<NodeTableStatistics> tableStatistic;
 
     // To satisfy JAXB
     @SuppressWarnings("unused")
@@ -32,7 +34,7 @@ public class TableStatistics {
     public TableStatistics(Node node, List<NodeTableStatistics> tableStats) {
         super();
         this.node = node;
-        this.tableStats = tableStats;
+        this.tableStatistic = tableStats;
     }
 
     public Node getNode() {
@@ -44,11 +46,11 @@ public class TableStatistics {
     }
 
     public List<NodeTableStatistics> getTableStats() {
-        return tableStats;
+        return tableStatistic;
     }
 
     public void setTableStats(List<NodeTableStatistics> tableStats) {
-        this.tableStats = tableStats;
+        this.tableStatistic = tableStats;
     }
 
 }
index 4a31317d95b3b61926ec96ca751bc5205c5f59c5..32e1002c94afa6e3c6a1b81dce396b6c7fbae1ce 100644 (file)
@@ -15,7 +15,7 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
-@XmlRootElement
+@XmlRootElement(name="list")
 @XmlAccessorType(XmlAccessType.NONE)
 
 public class NodeConnectors {
index b7f1c53ae850dec4c7d8bf258853bbec849e5801..061e51732ed3c41316d03d08eec5f63288a3826c 100644 (file)
@@ -15,7 +15,7 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
-@XmlRootElement
+@XmlRootElement(name="list")
 @XmlAccessorType(XmlAccessType.NONE)
 
 public class Nodes {
index e67d1b75686934b48fb15cb409bf0cdf5cd3d123..98aa5ad94e06c713dcd02fe7a71141ec02b46782 100644 (file)
@@ -107,11 +107,56 @@ public class SwitchNorthbound {
      * Retrieve a list of all the nodes and their properties in the network
      *
      * @param containerName
-     *            The container for which we want to retrieve the list
+     *            Name of the Container (Eg. 'default')
      * @return A list of Pair each pair represents a
      *         {@link org.opendaylight.controller.sal.core.Node} and Set of
      *         {@link org.opendaylight.controller.sal.core.Property} attached to
      *         it.
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://.../default/nodes
+     *
+     * Response in XML:
+     * &lt;list&gt;
+     *     &#x20;&#x20;&#x20;&lt;nodeProperties&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;node type="OF" id="00:00:00:00:00:00:00:02"/&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;properties&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;tables&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;-1&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/tables&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;description&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;Switch2&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/description&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;actions&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;4095&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/actions&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;macAddress&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;00:00:00:00:00:02&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/macAddress&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;capabilities&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;199&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/capabilities&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;timeStamp&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;1377291227877&lt;/value&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;connectedSince&lt;/name&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/timeStamp&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;buffers&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;256&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/buffers&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/properties&gt;
+     *     &#x20;&#x20;&#x20;&lt;/nodeProperties&gt;
+     * &lt;/list&gt;
+     *
+     * Response in JSON:
+     * {"nodeProperties":[{"node":{"@type":"OF","@id":"00:00:00:00:00:00:00:02"},"properties":{"tables":{"value":"-1"},
+     * "description":{"value":"None"},"actions":{"value":"4095"},"macAddress":{"value":"00:00:00:00:00:02"},"capabilities"
+     * :{"value":"199"},"timeStamp":{"value":"1377291227877","name":"connectedSince"},"buffers":{"value":"256"}}}]}
+     *
+     * </pre>
      */
     @Path("/{containerName}/nodes")
     @GET
@@ -119,6 +164,7 @@ public class SwitchNorthbound {
     @TypeHint(Nodes.class)
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public Nodes getNodes(@PathParam("containerName") String containerName) {
@@ -161,49 +207,54 @@ public class SwitchNorthbound {
     }
 
     /**
-     * Add a Name, Tier and Forwarding mode property to a node.
-     *
-     * <pre>
-     * Example Request:
-     *  http://localhost:8080/controller/nb/v2/switch/red/node/OF/00:00:00:00:00:03/property/description/Switch3
-     *  (Valid properties that can be configured are: description, forwarding(only for default container) and tier)
-     * </pre>
+     * Add a Description, Tier and Forwarding mode property to a node.
      *
      * @param containerName
-     *            Name of the Container
+     *            Name of the Container (Eg. 'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
      *            Node Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.Node}
-     * @param propName
-     *            Name of the Property specified by
-     *            {@link org.opendaylight.controller.sal.core.Property} and its
-     *            extended classes
-     * @param propValue
-     *            Value of the Property specified by
-     *            {@link org.opendaylight.controller.sal.core.Property} and its
-     *            extended classes
+     *            (Eg. '00:00:00:00:00:00:00:03')
+     * @param propertyName
+     *            Name of the Property. Properties that can be
+     *            configured are: description, forwarding(only for default
+     *            container) and tier
+     * @param propertyValue
+     *            Value of the Property. Description can be any string (Eg. 'Node1'),
+     *            valid values for tier are 0, 1 and 2, and valid values for forwarding are 0 for
+     *            reactive and 1 for proactive forwarding.
      * @return Response as dictated by the HTTP Response Status code
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://.../default/node/OF/00:00:00:00:00:00:00:03/property/description/Switch3
+     *
+     * </pre>
      */
 
-    @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propName}/{propValue}")
+    @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propertyName}/{propertyValue}")
     @PUT
     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(Response.class)
     @StatusCodes({
-            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 201, condition = "Operation successful"),
             @ResponseCode(code = 400, condition = "The nodeId or configuration is invalid"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The Container Name or node or configuration name is not found"),
             @ResponseCode(code = 406, condition = "The property cannot be configured in non-default container"),
-            @ResponseCode(code = 409, condition = "Unable to update configuration due to cluster conflict"),
+            @ResponseCode(code = 409, condition = "Unable to update configuration due to cluster conflict or conflicting description property"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
     public Response addNodeProperty(
             @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
             @PathParam("nodeId") String nodeId,
-            @PathParam("propName") String propName,
-            @PathParam("propValue") String propValue) {
+            @PathParam("propertyName") String propertyName,
+            @PathParam("propertyValue") String propertyValue) {
 
         if (!isValidContainer(containerName)) {
             throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
@@ -222,9 +273,9 @@ public class SwitchNorthbound {
 
         handleNodeAvailability(containerName, nodeType, nodeId);
         Node node = Node.fromString(nodeType, nodeId);
-        Property prop = switchManager.createProperty(propName, propValue);
+        Property prop = switchManager.createProperty(propertyName, propertyValue);
         if (prop == null) {
-            throw new ResourceNotFoundException("Property with name " + propName + " does not exist.");
+            throw new ResourceNotFoundException("Property with name " + propertyName + " does not exist.");
         }
         SwitchConfig switchConfig = switchManager.getSwitchConfig(node.toString());
         Map<String, Property> nodeProperties = (switchConfig == null) ? new HashMap<String, Property>()
@@ -232,29 +283,36 @@ public class SwitchNorthbound {
         nodeProperties.put(prop.getName(), prop);
         SwitchConfig newSwitchConfig = new SwitchConfig(node.toString(), nodeProperties);
         Status status = switchManager.updateNodeConfig(newSwitchConfig);
+        if (status.isSuccess()) {
+            return Response.status(Response.Status.CREATED).build();
+        }
         return NorthboundUtils.getResponse(status);
     }
 
     /**
      * Delete a property of a node
      *
-     * <pre>
-     * Example Request:
-     *  http://localhost:8080/controller/nb/v2/switch/default/node/OF/00:00:00:00:00:03/property/forwarding
-     * </pre>
-     *
      * @param containerName
-     *            Name of the Container
+     *            Name of the Container (Eg. 'SliceRed')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
      *            Node Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.Node}
+     *            (Eg. '00:00:00:00:00:03:01:02')
      * @param propertyName
-     *            Name of the Property specified by
-     *            {@link org.opendaylight.controller.sal.core.Property} and its
-     *            extended classes
+     *            Name of the Property. Properties that can be deleted are
+     *            description, forwarding(only in default container) and tier.
      * @return Response as dictated by the HTTP Response Status code
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://.../default/node/OF/00:00:00:00:00:00:00:03/property/forwarding
+     *
+     * </pre>
      */
 
     @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propertyName}")
@@ -263,6 +321,7 @@ public class SwitchNorthbound {
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 400, condition = "The nodeId or configuration is invalid"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
             @ResponseCode(code = 409, condition = "Unable to delete property due to cluster conflict"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
@@ -313,21 +372,56 @@ public class SwitchNorthbound {
 
     /**
      *
-     * Retrieve a list of all the node connectors and their properties in a
+     * Retrieve a list of all the nodeconnectors and their properties in a
      * given node
      *
      * @param containerName
-     *            The container for which we want to retrieve the list
+     *            The container for which we want to retrieve the list (Eg.
+     *            'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
      *            Node Identifier as specified by
-     *            {@link org.opendaylight.controller.sal.core.Node}
+     *            {@link org.opendaylight.controller.sal.core.Node} (Eg.
+     *            '00:00:00:00:00:00:00:03')
      * @return A List of Pair each pair represents a
      *         {@link org.opendaylight.controller.sal.core.NodeConnector} and
      *         its corresponding
      *         {@link org.opendaylight.controller.sal.core.Property} attached to
      *         it.
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://.../default/node/OF/00:00:00:00:00:00:00:01
+     *
+     * Response in XML:
+     * &lt;list&gt;
+     *     &#x20;&#x20;&#x20;&lt;nodeConnectorProperties&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nodeconnector type="OF" id="2"&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;node type="OF" id="00:00:00:00:00:00:00:01"/&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/nodeconnector&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;properties&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;state&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;1&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/state&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;config&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;1&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/config&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;L1_2-C2_1&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/name&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/properties&gt;
+     *     &#x20;&#x20;&#x20;&lt;/nodeConnectorProperties&gt;
+     * &lt;/list&gt;
+     *
+     * Response in JSON:
+     * {"nodeConnectorProperties":[{"nodeconnector":{"@type":"OF","@id":"2","node":{"@type":"OF","@id":"00:00:00:00:00:00:00:01"}},
+     * "properties":{"state":{"value":"1"},"config":{"value":"1"},"name":{"value":"L1_2-C2_1"}}}]}
+     *
+     * </pre>
      */
     @Path("/{containerName}/node/{nodeType}/{nodeId}")
     @GET
@@ -335,6 +429,7 @@ public class SwitchNorthbound {
     @TypeHint(NodeConnectors.class)
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public NodeConnectors getNodeConnectors(
@@ -382,37 +477,51 @@ public class SwitchNorthbound {
     }
 
     /**
-     * Add a Name/Bandwidth property to a node connector
+     * Add Bandwidth property to a node connector
      *
      * @param containerName
-     *            Name of the Container
+     *            Name of the Container (Eg. 'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
      *            Node Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.Node}
+     *            (Eg. '00:00:00:00:00:00:00:03')
      * @param nodeConnectorType
-     *            Type of the node connector being programmed
+     *            Type of the node connector being programmed (Eg. 'OF')
      * @param nodeConnectorId
      *            NodeConnector Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
-     * @param propName
+     *            (Eg. '2')
+     * @param propertyName
      *            Name of the Property specified by
      *            {@link org.opendaylight.controller.sal.core.Property} and its
      *            extended classes
-     * @param propValue
+     *            Property that can be configured is bandwidth
+     * @param propertyValue
      *            Value of the Property specified by
      *            {@link org.opendaylight.controller.sal.core.Property} and its
      *            extended classes
      * @return Response as dictated by the HTTP Response Status code
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://.../default/nodeconnector/OF/00:00:00:00:00:00:00:01/OF/2/property/bandwidth/1
+     *
+     * </pre>
      */
 
-    @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propName}/{propValue}")
+    @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propertyName}/{propertyValue}")
     @PUT
     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes({
-            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 201, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
+            @ResponseCode(code = 409, condition = "Unable to add property due to cluster conflict"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
     public Response addNodeConnectorProperty(
             @PathParam("containerName") String containerName,
@@ -420,8 +529,8 @@ public class SwitchNorthbound {
             @PathParam("nodeId") String nodeId,
             @PathParam("nodeConnectorType") String nodeConnectorType,
             @PathParam("nodeConnectorId") String nodeConnectorId,
-            @PathParam("propName") String propName,
-            @PathParam("propValue") String propValue) {
+            @PathParam("propertyName") String propertyName,
+            @PathParam("propertyValue") String propertyValue) {
 
         if (!isValidContainer(containerName)) {
             throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
@@ -447,7 +556,7 @@ public class SwitchNorthbound {
         NodeConnector nc = NodeConnector
                 .fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
 
-        Property prop = switchManager.createProperty(propName, propValue);
+        Property prop = switchManager.createProperty(propertyName, propertyValue);
         if (prop == null) {
             throw new ResourceNotFoundException(
                     RestMessages.INVALIDDATA.toString());
@@ -464,22 +573,33 @@ public class SwitchNorthbound {
      * Delete a property of a node connector
      *
      * @param containerName
-     *            Name of the Container
+     *            Name of the Container (Eg. 'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
      *            Node Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.Node}
+     *            (Eg. '00:00:00:00:00:00:00:01')
      * @param nodeConnectorType
-     *            Type of the node connector being programmed
+     *            Type of the node connector being programmed (Eg. 'OF')
      * @param nodeConnectorId
      *            NodeConnector Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
+     *            (Eg. '1')
      * @param propertyName
      *            Name of the Property specified by
      *            {@link org.opendaylight.controller.sal.core.Property} and its
-     *            extended classes
+     *            extended classes. Property that can be deleted is bandwidth
      * @return Response as dictated by the HTTP Response Status code
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://.../default/nodeconnector/OF/00:00:00:00:00:00:00:01/OF/2/property/bandwidth
+     *
+     * </pre>
      */
 
     @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propertyName}")
@@ -487,6 +607,7 @@ public class SwitchNorthbound {
     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
     public Response deleteNodeConnectorProperty(
@@ -528,125 +649,30 @@ public class SwitchNorthbound {
         throw new ResourceNotFoundException(ret.getDescription());
     }
 
-    /*    *//**
-     * Retrieve a list of Span ports that were configured previously.
-     *
-     * @param containerName
-     *            Name of the Container
-     * @return list of
-     *         {@link org.opendaylight.controller.switchmanager.SpanConfig}
-     *         resources
-     */
-    /*
-     * @Path("/span-config/{containerName}")
-     *
-     * @GET
-     *
-     * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-     *
-     * @StatusCodes( {
-     *
-     * @ResponseCode(code = 200, condition = "Operation successful"),
-     *
-     * @ResponseCode(code = 404, condition = "The containerName is not found"),
-     *
-     * @ResponseCode(code = 503, condition =
-     * "One or more of Controller Services are unavailable") }) public
-     * List<SpanConfig> getSpanConfigList(@PathParam("containerName") String
-     * containerName) { ISwitchManager switchManager = (ISwitchManager)
-     * getIfSwitchManagerService(containerName); if (switchManager == null) {
-     * throw new ServiceUnavailableException("Switch Manager " +
-     * RestMessages.SERVICEUNAVAILABLE.toString()); }
-     *
-     * return switchManager.getSpanConfigList(); }
-     *//**
-     * Add a span configuration
-     *
-     * @param containerName
-     *            Name of the Container
-     * @param config
-     *            {@link org.opendaylight.controller.switchmanager.SpanConfig}
-     *            in JSON or XML format
-     * @return Response as dictated by the HTTP Response Status code
-     */
-    /*
-     * @Path("/span-config/{containerName}")
-     *
-     * @PUT
-     *
-     * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-     *
-     * @StatusCodes( {
-     *
-     * @ResponseCode(code = 200, condition = "Operation successful"),
-     *
-     * @ResponseCode(code = 404, condition = "The containerName is not found"),
-     *
-     * @ResponseCode(code = 503, condition =
-     * "One or more of Controller Services are unavailable") }) public Response
-     * addSpanConfig(@PathParam("containerName") String containerName,
-     *
-     * @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
-     * ISwitchManager switchManager = (ISwitchManager)
-     * getIfSwitchManagerService(containerName); if (switchManager == null) {
-     * throw new ServiceUnavailableException("Switch Manager " +
-     * RestMessages.SERVICEUNAVAILABLE.toString()); }
-     *
-     * String ret = switchManager.addSpanConfig(config.getValue()); if
-     * (ret.equals(ReturnString.SUCCESS.toString())) { return
-     * Response.status(Response.Status.CREATED).build(); } throw new
-     * InternalServerErrorException(ret); }
-     *//**
-     * Delete a span configuration
+    /**
+     * Save the current switch configurations
      *
      * @param containerName
-     *            Name of the Container
-     * @param config
-     *            {@link org.opendaylight.controller.switchmanager.SpanConfig}
-     *            in JSON or XML format
+     *            Name of the Container (Eg. 'default')
      * @return Response as dictated by the HTTP Response Status code
-     */
-    /*
-     * @Path("/span-config/{containerName}")
-     *
-     * @DELETE
-     *
-     * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
      *
-     * @StatusCodes( {
-     *
-     * @ResponseCode(code = 200, condition = "Operation successful"),
-     *
-     * @ResponseCode(code = 404, condition = "The containerName is not found"),
+     * <pre>
      *
-     * @ResponseCode(code = 503, condition =
-     * "One or more of Controller Services are unavailable") }) public Response
-     * deleteSpanConfig(@PathParam("containerName") String containerName,
+     * Example:
      *
-     * @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
-     * ISwitchManager switchManager = (ISwitchManager)
-     * getIfSwitchManagerService(containerName); if (switchManager == null) {
-     * throw new ServiceUnavailableException("Switch Manager " +
-     * RestMessages.SERVICEUNAVAILABLE.toString()); }
+     * RequestURL:
+     * http://.../default/switch-config
      *
-     * String ret = switchManager.removeSpanConfig(config.getValue()); if
-     * (ret.equals(ReturnString.SUCCESS.toString())) { return
-     * Response.ok().build(); } throw new ResourceNotFoundException(ret); }
-     */
-
-    /**
-     * Save the current switch configurations
-     *
-     * @param containerName
-     *            Name of the Container
-     * @return Response as dictated by the HTTP Response Status code
+     * </pre>
      */
     @Path("/{containerName}/switch-config")
     @POST
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
+            @ResponseCode(code = 500, condition = "Failed to save switch configuration. Failure Reason included in HTTP Error response"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public Response saveSwitchConfig(
             @PathParam("containerName") String containerName) {
index fb4e8229ff48fd87dd8e6195ee272d497bfbd095..3ba1eb18435612565e8c6f68c125d75bb951420c 100644 (file)
@@ -78,16 +78,31 @@ public class TopologyNorthboundJAXRS {
      * Retrieve the Topology
      *
      * @param containerName
-     *            The container for which we want to retrieve the topology
+     *            The container for which we want to retrieve the topology (Eg. 'default')
      *
      * @return A List of EdgeProps each EdgeProp represent an Edge of the grap
      *         with the corresponding properties attached to it.
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/topology/default
+     *
+     * Response in XML:
+     * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;topology&gt;&lt;edgeProperties&gt;&lt;edge&gt;&lt;tailNodeConnector id="2" type="OF"&gt;&lt;node id="00:00:00:00:00:00:00:02" type="OF"/&gt;&lt;/tailNodeConnector&gt;&lt;headNodeConnector id="2" type="OF"&gt;&lt;node id="00:00:00:00:00:00:00:51" type="OF"/&gt;&lt;/headNodeConnector&gt;&lt;/edge&gt;&lt;properties&gt;&lt;state&gt;&lt;value&gt;1&lt;/value&gt;&lt;/state&gt;&lt;config&gt;&lt;value&gt;1&lt;/value&gt;&lt;/config&gt;&lt;name&gt;&lt;value&gt;C1_2-L2_2&lt;/value&gt;&lt;/name&gt;&lt;timeStamp&gt;&lt;value&gt;1377279422032&lt;/value&gt;&lt;name&gt;creation&lt;/name&gt;&lt;/timeStamp&gt;&lt;/properties&gt;&lt;/edgeProperties&gt;&lt;edgeProperties&gt;&lt;edge&gt;&lt;tailNodeConnector id="2" type="OF"&gt;&lt;node id="00:00:00:00:00:00:00:51" type="OF"/&gt;&lt;/tailNodeConnector&gt;&lt;headNodeConnector id="2" type="OF"&gt;&lt;node id="00:00:00:00:00:00:00:02" type="OF"/&gt;&lt;/headNodeConnector&gt;&lt;/edge&gt;&lt;properties&gt;&lt;state&gt;&lt;value&gt;1&lt;/value&gt;&lt;/state&gt;&lt;name&gt;&lt;value&gt;L2_2-C1_2&lt;/value&gt;&lt;/name&gt;&lt;config&gt;&lt;value&gt;1&lt;/value&gt;&lt;/config&gt;&lt;timeStamp&gt;&lt;value&gt;1377279423564&lt;/value&gt;&lt;name&gt;creation&lt;/name&gt;&lt;/timeStamp&gt;&lt;/properties&gt;&lt;/edgeProperties&gt;&lt;/topology&gt;
+     *
+     * Response in JSON:
+     * {"edgeProperties":[{"edge":{"tailNodeConnector":{"@id":"2","@type":"OF","node":{"@id":"00:00:00:00:00:00:00:02","@type":"OF"}},"headNodeConnector":{"@id":"2","@type":"OF","node":{"@id":"00:00:00:00:00:00:00:51","@type":"OF"}}},"properties":{"timeStamp":{"value":"1377278961017","name":"creation"}}},{"edge":{"tailNodeConnector":{"@id":"2","@type":"OF","node":{"@id":"00:00:00:00:00:00:00:51","@type":"OF"}},"headNodeConnector":{"@id":"2","@type":"OF","node":{"@id":"00:00:00:00:00:00:00:02","@type":"OF"}}},"properties":{"timeStamp":{"value":"1377278961018","name":"creation"}}}]}
+     *
+     * </pre>
      */
     @Path("/{containerName}")
     @GET
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(Topology.class)
-    @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name passed was not found") })
+    @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
     public Topology getTopology(@PathParam("containerName") String containerName) {
 
         if (!NorthboundUtils.isAuthorized(
@@ -121,15 +136,30 @@ public class TopologyNorthboundJAXRS {
      * Retrieve the user configured links
      *
      * @param containerName
-     *            The container for which we want to retrieve the user links
+     *            The container for which we want to retrieve the user links (Eg. 'default')
      *
      * @return A List of user configured links
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/topology/default/user-link
+     *
+     * Response in XML:
+     * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;topologyUserLinks&gt;&lt;userLinks&gt;&lt;status&gt;Success&lt;/status&gt;&lt;name&gt;link1&lt;/name&gt;&lt;srcNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:02&lt;/srcNodeConnector&gt;&lt;dstNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:51&lt;/dstNodeConnector&gt;&lt;/userLinks&gt;&lt;/topologyUserLinks&gt;
+     *
+     * Response in JSON:
+     * {"userLinks":{"status":"Success","name":"link1","srcNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:02","dstNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:51"}}
+     *
+     * </pre>
      */
-    @Path("/{containerName}/userLink")
+    @Path("/{containerName}/user-link")
     @GET
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(TopologyUserLinks.class)
-    @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name passed was not found") })
+    @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
     public TopologyUserLinks getUserLinks(
             @PathParam("containerName") String containerName) {
 
@@ -161,18 +191,33 @@ public class TopologyNorthboundJAXRS {
      * Add an User Link
      *
      * @param containerName
-     *            Name of the Container. The base Container is "default".
+     *            Name of the Container (Eg. 'default')
      * @param TopologyUserLinkConfig
      *            in JSON or XML format
      * @return Response as dictated by the HTTP Response Status code
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/topology/default/user-link/config1-content
+     *
+     * Request in XML:
+     * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;topologyUserLinks&gt;&lt;status&gt;Success&lt;/status&gt;&lt;name&gt;link1&lt;/name&gt;&lt;srcNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:02&lt;/srcNodeConnector&gt;&lt;dstNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:51&lt;/dstNodeConnector&gt;&lt;/topologyUserLinks&gt;
+     *
+     * Request in JSON:
+     * {"status":"Success","name":"link1","srcNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:02","dstNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:51"}
+     *
+     * </pre>
      */
-
-    @Path("/{containerName}/userLink")
+    @Path("/{containerName}/user-link")
     @POST
     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes({
             @ResponseCode(code = 201, condition = "User Link added successfully"),
-            @ResponseCode(code = 404, condition = "The Container Name passed was not found"),
+            @ResponseCode(code = 404, condition = "The Container Name was not found"),
             @ResponseCode(code = 409, condition = "Failed to add User Link due to Conflicting Name"),
             @ResponseCode(code = 500, condition = "Failed to add User Link. Failure Reason included in HTTP Error response"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
@@ -205,15 +250,24 @@ public class TopologyNorthboundJAXRS {
      * Delete an User Link
      *
      * @param containerName
-     *            Name of the Container. The base Container is "default".
+     *            Name of the Container (Eg. 'default')
      * @param name
-     *            Name of the Link Configuration
+     *            Name of the Link Configuration (Eg. 'config1')
      * @return Response as dictated by the HTTP Response Status code
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/topology/default/user-link/config1
+     *
+     * </pre>
      */
-
-    @Path("/{containerName}/userLink/{name}")
+    @Path("/{containerName}/user-link/{name}")
     @DELETE
     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
             @ResponseCode(code = 404, condition = "The Container Name or Link Configuration Name was not found"),
@@ -242,5 +296,4 @@ public class TopologyNorthboundJAXRS {
         }
         throw new ResourceNotFoundException(ret.getDescription());
     }
-
 }
index 9bcd7c0dc45229a4efa1cc845f20a51dc1bbb726..3c698b6ce3f928cec80554ff57229131ca8f1b19 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -24,22 +23,32 @@ public interface IInventoryShimInternalListener {
     /**
      * Updates node and its properties
      *
-     * @param node                      {@link org.opendaylight.controller.sal.core.Node} being updated
-     * @param type              {@link org.opendaylight.controller.sal.core.UpdateType}
-     * @param props             set of {@link org.opendaylight.controller.sal.core.Property} such as
-     *                                          {@link org.opendaylight.controller.sal.core.Description} and/or
-     *                                          {@link org.opendaylight.controller.sal.core.Tier} etc.
+     * @param node
+     *            {@link org.opendaylight.controller.sal.core.Node} being
+     *            updated
+     * @param type
+     *            update type {@link org.opendaylight.controller.sal.core.UpdateType}
+     * @param props
+     *            set of {@link org.opendaylight.controller.sal.core.Property}
+     *            such as
+     *            {@link org.opendaylight.controller.sal.core.Description}
+     *            and/or {@link org.opendaylight.controller.sal.core.Tier} etc.
      */
     public void updateNode(Node node, UpdateType type, Set<Property> props);
 
     /**
      * Updates node connector and its properties
      *
-     * @param nodeConnector {@link org.opendaylight.controller.sal.core.NodeConnector} being updated
-     * @param type              {@link org.opendaylight.controller.sal.core.UpdateType}
-     * @param props             set of {@link org.opendaylight.controller.sal.core.Property} such as
-     *                                          {@link org.opendaylight.controller.sal.core.Description} and/or
-     *                                          {@link org.opendaylight.controller.sal.core.State} etc.
+     * @param nodeConnector
+     *            {@link org.opendaylight.controller.sal.core.NodeConnector}
+     *            being updated
+     * @param type
+     *            update type {@link org.opendaylight.controller.sal.core.UpdateType}
+     * @param props
+     *            set of {@link org.opendaylight.controller.sal.core.Property}
+     *            such as
+     *            {@link org.opendaylight.controller.sal.core.Description}
+     *            and/or {@link org.opendaylight.controller.sal.core.State} etc.
      */
     public void updateNodeConnector(NodeConnector nodeConnector,
             UpdateType type, Set<Property> props);
index 1c22966299356d1998d2a0cad2aa225ba06504f0..6980479fa82a834340ec82763f7fe10b6b8a26d9 100644 (file)
@@ -5,16 +5,52 @@ import java.util.List;
 import org.openflow.protocol.statistics.OFStatistics;
 
 /**
- * Interface defines the api which gets called when the information
- * contained in the OF statistics reply message from a network is updated with
- * new one.
+ * Interface which defines the notification functions which will get called when
+ * the information contained in the OF statistics reply message received from a
+ * network node is different from the cached one.
  */
 public interface IOFStatisticsListener {
+    /**
+     * Notifies that a new list of description statistics objects for the given
+     * switch is available
+     *
+     * @param switchId
+     *            The datapath id of the openflow switch
+     * @param description
+     *            The new list of description statistics objects
+     */
     public void descriptionStatisticsRefreshed(Long switchId, List<OFStatistics> description);
 
+    /**
+     * Notifies that a new list of flows statistics objects for the given switch
+     * is available
+     *
+     * @param switchId
+     *            The datapath id of the openflow switch
+     * @param flows
+     *            The new list of flow statistics objects
+     */
     public void flowStatisticsRefreshed(Long switchId, List<OFStatistics> flows);
 
+    /**
+     * Notifies that a new list of port statistics objects for the given switch
+     * is available
+     *
+     * @param switchId
+     *            The datapath id of the openflow switch
+     * @param flows
+     *            The new list of port statistics objects
+     */
     public void portStatisticsRefreshed(Long switchId, List<OFStatistics> ports);
 
+    /**
+     * Notifies that a new list of table statistics objects for the given switch
+     * is available
+     *
+     * @param switchId
+     *            The datapath id of the openflow switch
+     * @param flows
+     *            The new list of table statistics objects
+     */
     public void tableStatisticsRefreshed(Long switchId, List<OFStatistics> tables);
 }
index d5f4d31f2bfd0e8ec88867efbae8b0e01c9e9e82..9622af97ef3fa66e5b376b4640894978b926aae4 100644 (file)
@@ -9,38 +9,45 @@ import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 
 /**
- * The Interface provides statistics updates to ReaderFilter listeners within
- * the protocol plugin
+ * The Interface provides notification of statistics (hardware view) updates to
+ * ReaderFilter listeners within the protocol plugin
  */
 public interface IReadFilterInternalListener {
 
     /**
-     * Notifies the hardware view of all the flow installed on the specified network node
+     * Notifies the hardware view of all the flow installed on the specified
+     * network node was updated
+     *
      * @param node
-     * @return
+     *            the network node
+     * @param flowStatsList
      */
     public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList);
 
     /**
-     * Notifies the hardware view of the specified network node connector
+     * Notifies the hardware view of the specified network node connectors was
+     * updated
+     *
      * @param node
-     * @return
+     *            the network node
      */
     public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList);
 
     /**
-     * Notifies all the table statistics for a node
+     * Notifies the hardware view of the specified network node tables was
+     * updated
+     *
      * @param node
-     * @return
+     *            the network node
      */
     public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList);
 
     /**
-     * Notifies the hardware view of all the flow installed on the specified network node
+     * Notifies the hardware view of all the flow installed on the specified
+     * network node was updated
+     *
      * @param node
-     * @return
+     *            the network node
      */
     public void nodeDescriptionStatisticsUpdated(Node node, NodeDescription nodeDescription);
-
-
 }
index a10e22b394c6c3e3d741367c588959a26ca332ba..9ba67e382f9b41f7a7428fab37116e678c286d39 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -21,90 +20,139 @@ import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
 
 /**
- * Interface to serve the hardware information requests coming from SAL
- * It is implemented by the respective OF1.0 plugin component
+ * Interface to serve the hardware information requests coming from SAL It is
+ * implemented by the respective OF1.0 plugin component
  *
  */
 public interface IReadServiceFilter {
     /**
-     * Returns the hardware image for the specified flow
-     * on the specified network node for the passed container
+     * Returns the hardware image for the specified flow on the specified
+     * network node for the passed container
      *
      * @param container
+     *            the container for which the request is originated
      * @param node
+     *            the network node
      * @param flow
+     *            the target flow
      * @param cached
-     * @return
+     *            specify if entry has to be queried from the cached hardware
+     *            information maintained in the protocol plugin or directly from
+     *            the network node.
+     * @return The FlowOnNode object containing the information present in
+     *         hardware for the passed flow on the specified network node
      */
-    public FlowOnNode readFlow(String container, Node node, Flow flow,
-            boolean cached);
+    public FlowOnNode readFlow(String container, Node node, Flow flow, boolean cached);
 
     /**
-     * Returns the hardware view of all the flow installed
-     * on the specified network node for the passed container
+     * Returns the hardware view of all the flow installed on the specified
+     * network node for the passed container
      *
      * @param container
+     *            the container for which the request is originated
      * @param node
+     *            the network node
      * @param cached
-     * @return
+     *            specify if entries have to be queried from the cached hardware
+     *            information maintained in the protocol plugin or directly from
+     *            the network node.
+     * @return The list of FlowOnNode objects containing the information present
+     *         in hardware on the specified network node for all its flows
      */
-    public List<FlowOnNode> readAllFlow(String container, Node node,
-            boolean cached);
+    public List<FlowOnNode> readAllFlow(String container, Node node, boolean cached);
 
     /**
-     * Returns the description of the network node as provided by the node itself
+     * Returns the description of the network node as provided by the node
+     * itself
      *
      * @param node
+     *            the network node
      * @param cached
-     * @return
+     *            specify if entry has to be queried from the cached hardware
+     *            information maintained in the protocol plugin or directly from
+     *            the network node.
+     * @return The NodeDescription object containing the description information
+     *         for the specified network node
      */
     public NodeDescription readDescription(Node node, boolean cached);
 
     /**
-     * Returns the hardware view of the specified network node connector
-     * for the given container
-     * @param node
-     * @return
+     * Returns the hardware view of the specified network node connector for the
+     * given container
+     *
+     * @param container
+     *            the container for which the request is originated
+     * @param nodeConnector
+     *            the target nodeConnector
+     * @param cached
+     *            specify if entry has to be queried from the cached hardware
+     *            information maintained in the protocol plugin or directly from
+     *            the corresponding network node.
+     * @return The NodeConnectorStatistics object containing the statistics
+     *         present in hardware for the corresponding network node port
      */
-    public NodeConnectorStatistics readNodeConnector(String container,
-            NodeConnector nodeConnector, boolean cached);
+    public NodeConnectorStatistics readNodeConnector(String container, NodeConnector nodeConnector, boolean cached);
 
     /**
-     * Returns the hardware info for all the node connectors on the
-     * specified network node for the given container
+     * Returns the hardware info for all the node connectors on the specified
+     * network node for the given container
      *
+     * @param container
+     *            the container for which the request is originated
      * @param node
-     * @return
+     *            the target node
+     * @param cached
+     *            specify if entries have to be queried from the cached hardware
+     *            information maintained in the protocol plugin or directly from
+     *            the corresponding network node.
+     * @return The list of NodeConnectorStatistics objects containing the
+     *         statistics present in hardware for all the network node ports
      */
-    public List<NodeConnectorStatistics> readAllNodeConnector(String container,
-            Node node, boolean cached);
+    public List<NodeConnectorStatistics> readAllNodeConnector(String container, Node node, boolean cached);
 
     /**
-     * Returns the table statistics of the node as specified by the given container
-     * @param node
+     * Returns the table statistics of the node as specified by the given
+     * container
+     *
+     * @param container
+     *            the container for which the request is originated
+     * @param nodeTable
+     *            the target network node table
      * @param cached
-     * @return
+     *            specify if entry has to be queried from the cached hardware
+     *            information maintained in the protocol plugin or directly from
+     *            the corresponding network node.
+     * @return The NodeTableStatistics object containing the statistics present
+     *         in hardware for the corresponding network node table
      */
-    public NodeTableStatistics readNodeTable(String container,
-            NodeTable nodeTable, boolean cached);
+    public NodeTableStatistics readNodeTable(String container, NodeTable nodeTable, boolean cached);
 
     /**
      * Returns the table statistics of all the tables for the specified node
      *
+     * @param container
+     *            the container for which the request is originated
      * @param node
-     * @return
+     *            the target node
+     * @param cached
+     *            specify if entries have to be queried from the cached hardware
+     *            information maintained in the protocol plugin or directly from
+     *            the corresponding network node.
+     * @return The list of NodeTableStatistics objects containing the statistics
+     *         present in hardware for all the network node tables
      */
-    public List<NodeTableStatistics> readAllNodeTable(String containerName,
-            Node node, boolean cached);
+    public List<NodeTableStatistics> readAllNodeTable(String containerName, Node node, boolean cached);
 
     /**
-     * Returns the average transmit rate for the specified node conenctor on
-     * the given container. If the node connector does not belong to the passed
+     * Returns the average transmit rate for the specified node connector on the
+     * given container. If the node connector does not belong to the passed
      * container a zero value is returned
      *
      * @param container
+     *            the container for which the request is originated
      * @param nodeConnector
-     * @return tx rate [bps]
+     *            the target node connector
+     * @return The average tx rate in bps
      */
     public long getTransmitRate(String container, NodeConnector nodeConnector);
 }
index 9fca60f1a039d1b9514469ad0410024b0b2147ce..506d1702af309132e4ee26ee86cc769b39b41990 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -16,7 +15,7 @@ package org.opendaylight.controller.protocol_plugin.openflow;
  *                      to be fetched from the plugin
  *
  * For example, an application that has been started late, will want to
- * be up to date with the latest topology.  Hence, it requests for a
+ * be up to date with the latest topology. Hence, it requests for a
  * topology refresh from the plugin.
  */
 
@@ -29,6 +28,7 @@ public interface IRefreshInternalProvider {
 
     /**
      * @param containerName
+     *            Name of the container for the topology
      */
     public void requestRefresh(String containerName);
 }
index 41da311fd916dc8c1913b98f19976d9b319bf7d8..af3641823c874e485c01e19f627b2963ff9bf953 100644 (file)
@@ -119,6 +119,8 @@ public interface ISwitch {
      *
      * @param msg
      *            The OF message to be sent
+     * @param xid
+     *            The XID to be used in the message
      * @return The XID used
      */
     public Integer asyncFastSend(OFMessage msg, int xid);
@@ -175,6 +177,7 @@ public interface ISwitch {
      * Returns True if the port is enabled,
      *
      * @param portNumber
+     *            the port ID
      * @return True if the port is enabled
      */
     public boolean isPortEnabled(short portNumber);
@@ -183,6 +186,7 @@ public interface ISwitch {
      * Returns True if the port is enabled.
      *
      * @param port
+     *            the OpenFlow port
      * @return True if the port is enabled
      */
     public boolean isPortEnabled(OFPhysicalPort port);
@@ -220,12 +224,12 @@ public interface ISwitch {
      * Send Barrier message synchronously. The caller will be blocked until the
      * Barrier reply arrives.
      */
-    Object syncSendBarrierMessage();
+    public Object syncSendBarrierMessage();
 
     /**
      * Send Barrier message asynchronously. The caller is not blocked. The
      * Barrier message will be sent in a transmit thread which will be blocked
      * until the Barrier reply arrives.
      */
-    Object asyncSendBarrierMessage();
+    public Object asyncSendBarrierMessage();
 }
index c7c6c8924d29807da61aa5896c4b2b1e1b79cc59..172ec98780ce7bd90a5b4fe19ded1ca462161ec4 100644 (file)
@@ -13,15 +13,15 @@ import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.PriorityBlockingQueue;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.eclipse.osgi.framework.console.CommandInterpreter;
@@ -32,7 +32,6 @@ import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitchStateListener;
 import org.opendaylight.controller.sal.connection.ConnectionConstants;
 import org.opendaylight.controller.sal.connection.IPluginInConnectionService;
-import org.opendaylight.controller.sal.connection.IPluginOutConnectionService;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
@@ -50,7 +49,7 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
     private ControllerIO controllerIO;
     private Thread switchEventThread;
     private ConcurrentHashMap<Long, ISwitch> switches;
-    private BlockingQueue<SwitchEvent> switchEvents;
+    private PriorityBlockingQueue<SwitchEvent> switchEvents;
     // only 1 message listener per OFType
     private ConcurrentMap<OFType, IMessageListener> messageListeners;
     // only 1 switch state listener
@@ -58,6 +57,8 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
     private AtomicInteger switchInstanceNumber;
     private int MAXQUEUESIZE = 50000;
 
+    private static enum SwitchEventPriority { LOW, NORMAL, HIGH }
+
     /*
      * this thread monitors the switchEvents queue for new incoming events from
      * switch
@@ -119,7 +120,12 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
     public void init() {
         logger.debug("Initializing!");
         this.switches = new ConcurrentHashMap<Long, ISwitch>();
-        this.switchEvents = new LinkedBlockingQueue<SwitchEvent>(MAXQUEUESIZE);
+        this.switchEvents = new PriorityBlockingQueue<SwitchEvent>(MAXQUEUESIZE, new Comparator<SwitchEvent>() {
+            @Override
+            public int compare(SwitchEvent p1, SwitchEvent p2) {
+                return p2.getPriority() - p1.getPriority();
+            }
+        });
         this.messageListeners = new ConcurrentHashMap<OFType, IMessageListener>();
         this.switchStateListener = null;
         this.switchInstanceNumber = new AtomicInteger(0);
@@ -244,7 +250,7 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
         if (((SwitchHandler) sw).isOperational()) {
             Long sid = sw.getId();
             if (this.switches.remove(sid, sw)) {
-                logger.warn("{} is Disconnected", sw);
+                logger.info("{} is removed", sw);
                 notifySwitchDeleted(sw);
             }
         }
@@ -265,35 +271,31 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
     }
 
     private synchronized void addSwitchEvent(SwitchEvent event) {
-        try {
-            this.switchEvents.put(event);
-        } catch (InterruptedException e) {
-            logger.debug("SwitchEvent caught Interrupt Exception");
-        }
+        this.switchEvents.put(event);
     }
 
     public void takeSwitchEventAdd(ISwitch sw) {
-        SwitchEvent ev = new SwitchEvent(
-                SwitchEvent.SwitchEventType.SWITCH_ADD, sw, null);
+        SwitchEvent ev = new SwitchEvent(SwitchEvent.SwitchEventType.SWITCH_ADD, sw, null,
+                SwitchEventPriority.HIGH.ordinal());
         addSwitchEvent(ev);
     }
 
     public void takeSwitchEventDelete(ISwitch sw) {
-        SwitchEvent ev = new SwitchEvent(
-                SwitchEvent.SwitchEventType.SWITCH_DELETE, sw, null);
+        SwitchEvent ev = new SwitchEvent(SwitchEvent.SwitchEventType.SWITCH_DELETE, sw, null,
+                SwitchEventPriority.HIGH.ordinal());
         addSwitchEvent(ev);
     }
 
     public void takeSwitchEventError(ISwitch sw) {
-        SwitchEvent ev = new SwitchEvent(
-                SwitchEvent.SwitchEventType.SWITCH_ERROR, sw, null);
+        SwitchEvent ev = new SwitchEvent(SwitchEvent.SwitchEventType.SWITCH_ERROR, sw, null,
+                SwitchEventPriority.NORMAL.ordinal());
         addSwitchEvent(ev);
     }
 
     public void takeSwitchEventMsg(ISwitch sw, OFMessage msg) {
         if (messageListeners.get(msg.getType()) != null) {
-            SwitchEvent ev = new SwitchEvent(
-                    SwitchEvent.SwitchEventType.SWITCH_MESSAGE, sw, msg);
+            SwitchEvent ev = new SwitchEvent(SwitchEvent.SwitchEventType.SWITCH_MESSAGE, sw, msg,
+                    SwitchEventPriority.LOW.ordinal());
             addSwitchEvent(ev);
         }
     }
@@ -308,6 +310,10 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
         return this.switches.get(switchId);
     }
 
+    public void _controllerShowQueueSize(CommandInterpreter ci) {
+        ci.print("switchEvents queue size: " + switchEvents.size() + "\n");
+    }
+
     public void _controllerShowSwitches(CommandInterpreter ci) {
         Set<Long> sids = switches.keySet();
         StringBuffer s = new StringBuffer();
@@ -378,6 +384,7 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
         help.append("\t controllerShowSwitches\n");
         help.append("\t controllerReset\n");
         help.append("\t controllerShowConnConfig\n");
+        help.append("\t controllerShowQueueSize\n");
         return help.toString();
     }
 
index fc2e0ee324b2cc4934a1f4181988cf674d6bebc1..dfbecfeb0682ad41e7e7140767427d13b9170498 100644 (file)
@@ -58,7 +58,7 @@ public class MessageReadWriteService implements IMessageReadWrite {
      * @throws Exception
      */
     @Override
-    public void asyncSend(OFMessage msg) throws IOException {
+    public void asyncSend(OFMessage msg) throws Exception {
         synchronized (outBuffer) {
             int msgLen = msg.getLengthU();
             if (outBuffer.remaining() < msgLen) {
@@ -94,7 +94,7 @@ public class MessageReadWriteService implements IMessageReadWrite {
      * @throws Exception
      */
     @Override
-    public void resumeSend() throws IOException {
+    public void resumeSend() throws Exception {
         synchronized (outBuffer) {
             if (!socket.isOpen()) {
                 return;
@@ -121,7 +121,7 @@ public class MessageReadWriteService implements IMessageReadWrite {
      * @throws Exception
      */
     @Override
-    public List<OFMessage> readMessages() throws IOException {
+    public List<OFMessage> readMessages() throws Exception {
         if (!socket.isOpen()) {
             return null;
         }
index 64031fd01212cceeaaed4ae95b65a0db3904f3da..bb4defcecab81bd3f3bdb737b231adfa786981ef 100644 (file)
@@ -41,7 +41,6 @@ public class SecureMessageReadWriteService implements IMessageReadWrite {
             .getLogger(SecureMessageReadWriteService.class);
 
     private Selector selector;
-    private SelectionKey clientSelectionKey;
     private SocketChannel socket;
     private BasicFactory factory;
 
@@ -132,12 +131,28 @@ public class SecureMessageReadWriteService implements IMessageReadWrite {
         sslEngine = sslContext.createSSLEngine();
         sslEngine.setUseClientMode(false);
         sslEngine.setNeedClientAuth(true);
+        sslEngine.setEnabledCipherSuites(new String[] {
+                "SSL_RSA_WITH_RC4_128_MD5",
+                "SSL_RSA_WITH_RC4_128_SHA",
+                "TLS_RSA_WITH_AES_128_CBC_SHA",
+                "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+                "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+                "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
+                "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+                "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
+                "SSL_RSA_WITH_DES_CBC_SHA",
+                "SSL_DHE_RSA_WITH_DES_CBC_SHA",
+                "SSL_DHE_DSS_WITH_DES_CBC_SHA",
+                "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
+                "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
+                "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+                "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+                "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"});
 
         // Do initial handshake
         doHandshake(socket, sslEngine);
 
-        this.clientSelectionKey = this.socket.register(this.selector,
-                SelectionKey.OP_READ);
+        this.socket.register(this.selector, SelectionKey.OP_READ);
     }
 
     /**
@@ -182,12 +197,10 @@ public class SecureMessageReadWriteService implements IMessageReadWrite {
 
             if (myAppData.hasRemaining()) {
                 myAppData.compact();
-                this.clientSelectionKey = this.socket.register(this.selector,
-                        SelectionKey.OP_WRITE, this);
+                this.socket.register(this.selector, SelectionKey.OP_WRITE, this);
             } else {
                 myAppData.clear();
-                this.clientSelectionKey = this.socket.register(this.selector,
-                        SelectionKey.OP_READ, this);
+                this.socket.register(this.selector, SelectionKey.OP_READ, this);
             }
 
             logger.trace("Message sent: {}", msg);
@@ -221,12 +234,10 @@ public class SecureMessageReadWriteService implements IMessageReadWrite {
 
             if (myAppData.hasRemaining()) {
                 myAppData.compact();
-                this.clientSelectionKey = this.socket.register(this.selector,
-                        SelectionKey.OP_WRITE, this);
+                this.socket.register(this.selector, SelectionKey.OP_WRITE, this);
             } else {
                 myAppData.clear();
-                this.clientSelectionKey = this.socket.register(this.selector,
-                        SelectionKey.OP_READ, this);
+                this.socket.register(this.selector, SelectionKey.OP_READ, this);
             }
         }
     }
@@ -280,8 +291,7 @@ public class SecureMessageReadWriteService implements IMessageReadWrite {
             peerAppData.clear();
         }
 
-        this.clientSelectionKey = this.socket.register(this.selector,
-                SelectionKey.OP_READ, this);
+        this.socket.register(this.selector, SelectionKey.OP_READ, this);
 
         return msgs;
     }
index 87e30d70c61ebcc2e1fffe0c376a1b146d8ab561..785be9be092258ef8e36e10795597f8006d64080 100644 (file)
@@ -21,11 +21,13 @@ public class SwitchEvent {
     private SwitchEventType eventType;
     private ISwitch sw;
     private OFMessage msg;
+    private int priority;
 
-    public SwitchEvent(SwitchEventType type, ISwitch sw, OFMessage msg) {
+    public SwitchEvent(SwitchEventType type, ISwitch sw, OFMessage msg, int priority) {
         this.eventType = type;
         this.sw = sw;
         this.msg = msg;
+        this.priority = priority;
     }
 
     public SwitchEventType getEventType() {
@@ -40,6 +42,14 @@ public class SwitchEvent {
         return this.msg;
     }
 
+    public int getPriority() {
+        return priority;
+    }
+
+    public void setPriority(int priority) {
+        this.priority = priority;
+    }
+
     @Override
     public String toString() {
         String s;
index 52ea7fd575a76ae4f2053c5b1c96c7a10e622c0e..91909d20f53a5bde5adea2b7020c38a78406f080 100644 (file)
@@ -8,10 +8,6 @@
 
 package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
 
-import java.io.IOException;
-import java.net.SocketException;
-import java.nio.channels.AsynchronousCloseException;
-import java.nio.channels.ClosedSelectorException;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.channels.SocketChannel;
@@ -32,6 +28,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -64,8 +61,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class SwitchHandler implements ISwitch {
-    private static final Logger logger = LoggerFactory
-            .getLogger(SwitchHandler.class);
+    private static final Logger logger = LoggerFactory.getLogger(SwitchHandler.class);
     private static final int SWITCH_LIVENESS_TIMER = 5000;
     private static final int switchLivenessTimeout = getSwitchLivenessTimeout();
     private final int MESSAGE_RESPONSE_TIMER = 2000;
@@ -99,8 +95,7 @@ public class SwitchHandler implements ISwitch {
     private Thread transmitThread;
 
     private enum SwitchState {
-        NON_OPERATIONAL(0), WAIT_FEATURES_REPLY(1), WAIT_CONFIG_REPLY(2), OPERATIONAL(
-                3);
+        NON_OPERATIONAL(0), WAIT_FEATURES_REPLY(1), WAIT_CONFIG_REPLY(2), OPERATIONAL(3);
 
         private int value;
 
@@ -141,9 +136,7 @@ public class SwitchHandler implements ISwitch {
             try {
                 responseTimerValue = Integer.decode(rTimer);
             } catch (NumberFormatException e) {
-                logger.warn(
-                        "Invalid of.messageResponseTimer: {} use default({})",
-                        rTimer, MESSAGE_RESPONSE_TIMER);
+                logger.warn("Invalid of.messageResponseTimer: {} use default({})", rTimer, MESSAGE_RESPONSE_TIMER);
             }
         }
     }
@@ -168,8 +161,7 @@ public class SwitchHandler implements ISwitch {
                     try {
                         // wait for an incoming connection
                         selector.select(0);
-                        Iterator<SelectionKey> selectedKeys = selector
-                                .selectedKeys().iterator();
+                        Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
                         while (selectedKeys.hasNext()) {
                             SelectionKey skey = selectedKeys.next();
                             selectedKeys.remove();
@@ -189,7 +181,9 @@ public class SwitchHandler implements ISwitch {
         switchHandlerThread.start();
     }
 
-    public void stop() {
+    private void stopInternal() {
+        logger.debug("{} receives stop signal",
+                (isOperational() ? HexString.toHexString(sid) : "unknown"));
         running = false;
         cancelSwitchTimer();
         try {
@@ -205,9 +199,14 @@ public class SwitchHandler implements ISwitch {
             msgReadWriteService.stop();
         } catch (Exception e) {
         }
-        executor.shutdown();
+        logger.debug("executor shutdown now");
+        executor.shutdownNow();
 
         msgReadWriteService = null;
+    }
+
+    public void stop() {
+        stopInternal();
 
         if (switchHandlerThread != null) {
             switchHandlerThread.interrupt();
@@ -337,9 +336,7 @@ public class SwitchHandler implements ISwitch {
      */
     private void asyncSendNow(OFMessage msg) {
         if (msgReadWriteService == null) {
-            logger.warn(
-                    "asyncSendNow: {} is not sent because Message ReadWrite Service is not available.",
-                    msg);
+            logger.warn("asyncSendNow: {} is not sent because Message ReadWrite Service is not available.", msg);
             return;
         }
 
@@ -362,8 +359,7 @@ public class SwitchHandler implements ISwitch {
         }
 
         if (msgs == null) {
-            logger.debug("{} is down", this);
-            // the connection is down, inform core
+            logger.info("{} is down", this);
             reportSwitchStateChange(false);
             return;
         }
@@ -374,23 +370,19 @@ public class SwitchHandler implements ISwitch {
             switch (type) {
             case HELLO:
                 // send feature request
-                OFMessage featureRequest = factory
-                        .getMessage(OFType.FEATURES_REQUEST);
+                OFMessage featureRequest = factory.getMessage(OFType.FEATURES_REQUEST);
                 asyncFastSend(featureRequest);
                 // delete all pre-existing flows
                 OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
-                OFFlowMod flowMod = (OFFlowMod) factory
-                        .getMessage(OFType.FLOW_MOD);
-                flowMod.setMatch(match).setCommand(OFFlowMod.OFPFC_DELETE)
-                        .setOutPort(OFPort.OFPP_NONE)
+                OFFlowMod flowMod = (OFFlowMod) factory.getMessage(OFType.FLOW_MOD);
+                flowMod.setMatch(match).setCommand(OFFlowMod.OFPFC_DELETE).setOutPort(OFPort.OFPP_NONE)
                         .setLength((short) OFFlowMod.MINIMUM_LENGTH);
                 asyncFastSend(flowMod);
                 this.state = SwitchState.WAIT_FEATURES_REPLY;
                 startSwitchTimer();
                 break;
             case ECHO_REQUEST:
-                OFEchoReply echoReply = (OFEchoReply) factory
-                        .getMessage(OFType.ECHO_REPLY);
+                OFEchoReply echoReply = (OFEchoReply) factory.getMessage(OFType.ECHO_REPLY);
                 // respond immediately
                 asyncSendNow(echoReply, msg.getXid());
                 break;
@@ -436,8 +428,7 @@ public class SwitchHandler implements ISwitch {
             updatePhysicalPort(port);
         } else if (msg.getReason() == (byte) OFPortReason.OFPPR_ADD.ordinal()) {
             updatePhysicalPort(port);
-        } else if (msg.getReason() == (byte) OFPortReason.OFPPR_DELETE
-                .ordinal()) {
+        } else if (msg.getReason() == (byte) OFPortReason.OFPPR_DELETE.ordinal()) {
             deletePhysicalPort(port);
         }
 
@@ -454,35 +445,29 @@ public class SwitchHandler implements ISwitch {
                         if (probeSent) {
                             // switch failed to respond to our probe, consider
                             // it down
-                            logger.warn("{} is idle for too long, disconnect",
-                                    toString());
+                            logger.warn("{} sid {} is idle for too long, disconnect", socket.socket()
+                                    .getRemoteSocketAddress().toString().split("/")[1], (sid == 0) ? "unknown"
+                                    : HexString.toHexString(sid));
                             reportSwitchStateChange(false);
                         } else {
                             // send a probe to see if the switch is still alive
-                            logger.debug(
-                                    "Send idle probe (Echo Request) to {}",
-                                    this);
+                            logger.debug("Send idle probe (Echo Request) to {}", this);
                             probeSent = true;
-                            OFMessage echo = factory
-                                    .getMessage(OFType.ECHO_REQUEST);
+                            OFMessage echo = factory.getMessage(OFType.ECHO_REQUEST);
                             asyncFastSend(echo);
                         }
                     } else {
                         if (state == SwitchState.WAIT_FEATURES_REPLY) {
                             // send another features request
-                            OFMessage request = factory
-                                    .getMessage(OFType.FEATURES_REQUEST);
+                            OFMessage request = factory.getMessage(OFType.FEATURES_REQUEST);
                             asyncFastSend(request);
                         } else {
                             if (state == SwitchState.WAIT_CONFIG_REPLY) {
                                 // send another config request
-                                OFSetConfig config = (OFSetConfig) factory
-                                        .getMessage(OFType.SET_CONFIG);
-                                config.setMissSendLength((short) 0xffff)
-                                        .setLengthU(OFSetConfig.MINIMUM_LENGTH);
+                                OFSetConfig config = (OFSetConfig) factory.getMessage(OFType.SET_CONFIG);
+                                config.setMissSendLength((short) 0xffff).setLengthU(OFSetConfig.MINIMUM_LENGTH);
                                 asyncFastSend(config);
-                                OFMessage getConfig = factory
-                                        .getMessage(OFType.GET_CONFIG_REQUEST);
+                                OFMessage getConfig = factory.getMessage(OFType.GET_CONFIG_REQUEST);
                                 asyncFastSend(getConfig);
                             }
                         }
@@ -501,18 +486,18 @@ public class SwitchHandler implements ISwitch {
     }
 
     private void reportError(Exception e) {
-        if (e instanceof AsynchronousCloseException
-                || e instanceof InterruptedException
-                || e instanceof SocketException || e instanceof IOException
-                || e instanceof ClosedSelectorException) {
-            if (logger.isDebugEnabled()) {
-              logger.debug("Caught exception {}", e.getMessage());
-            }
-        } else {
-            logger.warn("Caught exception ", e);
+        if (!running) {
+            logger.debug("Caught exception {} while switch {} is shutting down. Skip", e.getMessage(),
+                    (isOperational() ? HexString.toHexString(sid) : "unknown"));
+            return;
         }
+        logger.debug("Caught exception: ", e);
+
         // notify core of this error event and disconnect the switch
         ((Controller) core).takeSwitchEventError(this);
+
+        // clean up some internal states immediately
+        stopInternal();
     }
 
     private void reportSwitchStateChange(boolean added) {
@@ -540,10 +525,8 @@ public class SwitchHandler implements ISwitch {
                 updatePhysicalPort(port);
             }
             // config the switch to send full data packet
-            OFSetConfig config = (OFSetConfig) factory
-                    .getMessage(OFType.SET_CONFIG);
-            config.setMissSendLength((short) 0xffff).setLengthU(
-                    OFSetConfig.MINIMUM_LENGTH);
+            OFSetConfig config = (OFSetConfig) factory.getMessage(OFType.SET_CONFIG);
+            config.setMissSendLength((short) 0xffff).setLengthU(OFSetConfig.MINIMUM_LENGTH);
             asyncFastSend(config);
             // send config request to make sure the switch can handle the set
             // config
@@ -561,17 +544,11 @@ public class SwitchHandler implements ISwitch {
         portBandwidth
                 .put(portNumber,
                         port.getCurrentFeatures()
-                                & (OFPortFeatures.OFPPF_10MB_FD.getValue()
-                                        | OFPortFeatures.OFPPF_10MB_HD
-                                                .getValue()
-                                        | OFPortFeatures.OFPPF_100MB_FD
-                                                .getValue()
-                                        | OFPortFeatures.OFPPF_100MB_HD
-                                                .getValue()
-                                        | OFPortFeatures.OFPPF_1GB_FD
-                                                .getValue()
-                                        | OFPortFeatures.OFPPF_1GB_HD
-                                                .getValue() | OFPortFeatures.OFPPF_10GB_FD
+                                & (OFPortFeatures.OFPPF_10MB_FD.getValue() | OFPortFeatures.OFPPF_10MB_HD.getValue()
+                                        | OFPortFeatures.OFPPF_100MB_FD.getValue()
+                                        | OFPortFeatures.OFPPF_100MB_HD.getValue()
+                                        | OFPortFeatures.OFPPF_1GB_FD.getValue()
+                                        | OFPortFeatures.OFPPF_1GB_HD.getValue() | OFPortFeatures.OFPPF_10GB_FD
                                             .getValue()));
     }
 
@@ -589,13 +566,10 @@ public class SwitchHandler implements ISwitch {
     @Override
     public String toString() {
         try {
-            return ("Switch:"
-                    + socket.socket().getRemoteSocketAddress().toString().split("/")[1]
-                    + " SWID:" + (isOperational() ? HexString
+            return ("Switch:" + socket.socket().getRemoteSocketAddress().toString().split("/")[1] + " SWID:" + (isOperational() ? HexString
                     .toHexString(this.sid) : "unknown"));
         } catch (Exception e) {
-            return (isOperational() ? HexString.toHexString(this.sid)
-                    : "unknown");
+            return (isOperational() ? HexString.toHexString(this.sid) : "unknown");
         }
 
     }
@@ -614,13 +588,20 @@ public class SwitchHandler implements ISwitch {
         int xid = getNextXid();
         StatisticsCollector worker = new StatisticsCollector(this, xid, req);
         messageWaitingDone.put(xid, worker);
-        Future<Object> submit = executor.submit(worker);
+        Future<Object> submit;
         Object result = null;
+        try {
+            submit = executor.submit(worker);
+        } catch (RejectedExecutionException re) {
+            messageWaitingDone.remove(xid);
+            return result;
+        }
         try {
             result = submit.get(responseTimerValue, TimeUnit.MILLISECONDS);
             return result;
         } catch (Exception e) {
-            logger.warn("Timeout while waiting for {} replies", req.getType());
+            logger.warn("Timeout while waiting for {} replies from {}",
+                    req.getType(), (isOperational() ? HexString.toHexString(sid) : "unknown"));
             result = null; // to indicate timeout has occurred
             worker.wakeup();
             return result;
@@ -629,6 +610,10 @@ public class SwitchHandler implements ISwitch {
 
     @Override
     public Object syncSend(OFMessage msg) {
+        if (!running) {
+            logger.debug("Switch is going down, ignore syncSend");
+            return null;
+        }
         int xid = getNextXid();
         return syncSend(msg, xid);
     }
@@ -639,8 +624,7 @@ public class SwitchHandler implements ISwitch {
      */
     private void processBarrierReply(OFBarrierReply msg) {
         Integer xid = msg.getXid();
-        SynchronousMessage worker = (SynchronousMessage) messageWaitingDone
-                .remove(xid);
+        SynchronousMessage worker = (SynchronousMessage) messageWaitingDone.remove(xid);
         if (worker == null) {
             return;
         }
@@ -672,8 +656,7 @@ public class SwitchHandler implements ISwitch {
 
     private void processStatsReply(OFStatisticsReply reply) {
         Integer xid = reply.getXid();
-        StatisticsCollector worker = (StatisticsCollector) messageWaitingDone
-                .get(xid);
+        StatisticsCollector worker = (StatisticsCollector) messageWaitingDone.get(xid);
         if (worker == null) {
             return;
         }
@@ -743,8 +726,7 @@ public class SwitchHandler implements ISwitch {
         if ((portState & OFPortState.OFPPS_LINK_DOWN.getValue()) > 0) {
             return false;
         }
-        if ((portState & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK
-                .getValue()) {
+        if ((portState & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue()) {
             return false;
         }
         return true;
@@ -782,8 +764,7 @@ public class SwitchHandler implements ISwitch {
                         syncMessageInternal(pmsg.msg, pmsg.msg.getXid(), false);
                     }
                 } catch (InterruptedException ie) {
-                    reportError(new InterruptedException(
-                            "PriorityMessageTransmit thread interrupted"));
+                    reportError(new InterruptedException("PriorityMessageTransmit thread interrupted"));
                 } catch (Exception e) {
                     reportError(e);
                 }
@@ -796,17 +777,16 @@ public class SwitchHandler implements ISwitch {
      * Setup and start the transmit thread
      */
     private void startTransmitThread() {
-        this.transmitQ = new PriorityBlockingQueue<PriorityMessage>(11,
-                new Comparator<PriorityMessage>() {
-                    @Override
-                    public int compare(PriorityMessage p1, PriorityMessage p2) {
-                        if (p2.priority != p1.priority) {
-                            return p2.priority - p1.priority;
-                        } else {
-                            return (p2.seqNum < p1.seqNum) ? 1 : -1;
-                        }
-                    }
-                });
+        this.transmitQ = new PriorityBlockingQueue<PriorityMessage>(11, new Comparator<PriorityMessage>() {
+            @Override
+            public int compare(PriorityMessage p1, PriorityMessage p2) {
+                if (p2.priority != p1.priority) {
+                    return p2.priority - p1.priority;
+                } else {
+                    return (p2.seqNum < p1.seqNum) ? 1 : -1;
+                }
+            }
+        });
         this.transmitThread = new Thread(new PriorityMessageTransmit());
         this.transmitThread.start();
     }
@@ -832,9 +812,8 @@ public class SwitchHandler implements ISwitch {
 
     private IMessageReadWrite getMessageReadWriteService() throws Exception {
         String str = System.getProperty("secureChannelEnabled");
-        return ((str != null) && (str.trim().equalsIgnoreCase("true"))) ? new SecureMessageReadWriteService(
-                socket, selector) : new MessageReadWriteService(socket,
-                selector);
+        return ((str != null) && (str.trim().equalsIgnoreCase("true"))) ? new SecureMessageReadWriteService(socket,
+                selector) : new MessageReadWriteService(socket, selector);
     }
 
     /**
@@ -910,7 +889,13 @@ public class SwitchHandler implements ISwitch {
         messageWaitingDone.put(xid, worker);
         Object result = null;
         Boolean status = false;
-        Future<Object> submit = executor.submit(worker);
+        Future<Object> submit;
+        try {
+           submit = executor.submit(worker);
+        } catch (RejectedExecutionException re) {
+            messageWaitingDone.remove(xid);
+            return result;
+        }
         try {
             result = submit.get(responseTimerValue, TimeUnit.MILLISECONDS);
             messageWaitingDone.remove(xid);
@@ -927,14 +912,12 @@ public class SwitchHandler implements ISwitch {
                 // this message
                 // the result if OFError already
                 if (logger.isDebugEnabled()) {
-                  logger.debug("Send {} failed --> {}", msg.getType(),
-                               (result));
+                    logger.debug("Send {} failed --> {}", msg.getType(), (result));
                 }
             }
             return result;
         } catch (Exception e) {
-            logger.warn("Timeout while waiting for {} reply", msg.getType()
-                    .toString());
+            logger.warn("Timeout while waiting for {} reply", msg.getType().toString());
             // convert the result into a Boolean with value false
             status = false;
             result = status;
index bb303e3651de7e3a95659641cf001da4b0153bb4..1938cb1ae68e66efe8bb68b12f42e3fcf1373703 100644 (file)
@@ -61,8 +61,6 @@ import org.opendaylight.controller.sal.utils.HexEncode;
 import org.opendaylight.controller.sal.utils.NetUtils;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
 import org.opendaylight.controller.sal.utils.NodeCreator;
-import org.opendaylight.controller.sal.utils.Status;
-import org.opendaylight.controller.sal.utils.StatusCode;
 
 /**
  * The class describes neighbor discovery service for an OpenFlow network.
@@ -579,6 +577,14 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
         readyListHi.add(nodeConnector);
     }
 
+    private void removeNodeConnector(NodeConnector nodeConnector) {
+        readyListLo.remove(nodeConnector);
+        readyListHi.remove(nodeConnector);
+        stagingList.remove(nodeConnector);
+        holdTime.remove(nodeConnector);
+        elapsedTime.remove(nodeConnector);
+    }
+
     private Set<NodeConnector> getRemoveSet(Collection<NodeConnector> c, Node node) {
         Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
         if (c == null) {
@@ -586,16 +592,7 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
         }
         for (NodeConnector nodeConnector : c) {
             if (node.equals(nodeConnector.getNode())) {
-                Edge edge1 = edgeMap.get(nodeConnector);
-                if (edge1 != null) {
-                    removeSet.add(nodeConnector);
-
-                    // check reverse direction
-                    Edge edge2 = edgeMap.get(edge1.getTailNodeConnector());
-                    if ((edge2 != null) && node.equals(edge2.getTailNodeConnector().getNode())) {
-                        removeSet.add(edge2.getHeadNodeConnector());
-                    }
-                }
+                removeSet.add(nodeConnector);
             }
         }
         return removeSet;
@@ -604,6 +601,29 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
     private void removeDiscovery(Node node) {
         Set<NodeConnector> removeSet;
 
+        removeSet = getRemoveSet(edgeMap.keySet(), node);
+        NodeConnector peerConnector;
+        Edge edge1, edge2;
+        for (NodeConnector nodeConnector : removeSet) {
+            // get the peer for fast removal of the edge in reverse direction
+            peerConnector = null;
+            edge1 = edgeMap.get(nodeConnector);
+            if (edge1 != null) {
+                edge2 = edgeMap.get(edge1.getTailNodeConnector());
+                if ((edge2 != null) && node.equals(edge2.getTailNodeConnector().getNode())) {
+                    peerConnector = edge2.getHeadNodeConnector();
+                }
+            }
+
+            removeEdge(nodeConnector, false);
+            removeEdge(peerConnector, isEnabled(peerConnector));
+        }
+
+        removeSet = getRemoveSet(prodMap.keySet(), node);
+        for (NodeConnector nodeConnector : removeSet) {
+            removeProdEdge(nodeConnector);
+        }
+
         removeSet = getRemoveSet(readyListHi, node);
         readyListHi.removeAll(removeSet);
 
@@ -618,22 +638,14 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
             holdTime.remove(nodeConnector);
         }
 
-        removeSet = getRemoveSet(edgeMap.keySet(), node);
+        removeSet = getRemoveSet(elapsedTime.keySet(), node);
         for (NodeConnector nodeConnector : removeSet) {
-            removeEdge(nodeConnector, false);
-        }
-
-        removeSet = getRemoveSet(prodMap.keySet(), node);
-        for (NodeConnector nodeConnector : removeSet) {
-            removeProdEdge(nodeConnector);
+            elapsedTime.remove(nodeConnector);
         }
     }
 
     private void removeDiscovery(NodeConnector nodeConnector) {
-        readyListHi.remove(nodeConnector);
-        readyListLo.remove(nodeConnector);
-        stagingList.remove(nodeConnector);
-        holdTime.remove(nodeConnector);
+        removeNodeConnector(nodeConnector);
         removeEdge(nodeConnector, false);
         removeProdEdge(nodeConnector);
     }
@@ -672,7 +684,6 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
 
             for (NodeConnector nodeConnector : retrySet) {
                 // Allow one more retry
-                readyListLo.add(nodeConnector);
                 elapsedTime.remove(nodeConnector);
                 if (connectionOutService.isLocal(nodeConnector.getNode())) {
                     transmitQ.add(nodeConnector);
@@ -805,6 +816,11 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
         }
         elapsedTime.remove(src);
 
+        // fast discovery of the edge in reverse direction
+        if (!edgeMap.containsKey(dst) && !readyListHi.contains(dst) && !elapsedTime.keySet().contains(dst)) {
+            moveToReadyListHi(dst);
+        }
+
         // notify
         updateEdge(edge, UpdateType.ADDED, props);
         logger.trace("Add edge {}", edge);
@@ -871,18 +887,15 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
      * Remove OpenFlow edge
      */
     private void removeEdge(NodeConnector nodeConnector, boolean stillEnabled) {
-        holdTime.remove(nodeConnector);
-        readyListLo.remove(nodeConnector);
-        readyListHi.remove(nodeConnector);
+        if (nodeConnector == null) {
+            return;
+        }
+
+        removeNodeConnector(nodeConnector);
 
         if (stillEnabled) {
             // keep discovering
-            if (!stagingList.contains(nodeConnector)) {
-                stagingList.add(nodeConnector);
-            }
-        } else {
-            // stop it
-            stagingList.remove(nodeConnector);
+            stagingList.add(nodeConnector);
         }
 
         Edge edge = null;
@@ -1240,7 +1253,15 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
 
         if (val != null) {
             try {
-                int ticks = Integer.parseInt(val);
+                int ticks;
+                Set<NodeConnector> monitorSet = holdTime.keySet();
+                if (monitorSet != null) {
+                    for (NodeConnector nodeConnector : monitorSet) {
+                        holdTime.put(nodeConnector, 0);
+                    }
+                }
+
+                ticks = Integer.parseInt(val);
                 DiscoveryPeriod.INTERVAL.setTick(ticks);
                 discoveryBatchRestartTicks = getDiscoveryInterval();
                 discoveryBatchPauseTicks = getDiscoveryPauseInterval();
index 028779d10651936d4d77f3400a0f996026dcb3bf..99501c280a97a04af2f181c003fdab6a5bb2e5df 100644 (file)
@@ -729,18 +729,37 @@ public class TopologyServiceShim implements IDiscoveryListener,
         bulkNotifyQ.add(containerName);
     }
 
+    /**
+     * Retrieve/construct edge map for a given container
+     *
+     * @param containerName
+     *            the container name
+     * @return the edges and their properties
+     */
+    private Map<NodeConnector, Pair<Edge, Set<Property>>> getEdgeMap(String containerName) {
+        Map<NodeConnector, Pair<Edge, Set<Property>>> edgePropMap = null;
+
+        /*
+         * When container is freshly created, need to construct map based on global map.
+         */
+        edgePropMap = edgeMap.get(containerName);
+
+        return edgePropMap;
+    }
+
     /**
      * Reading the current topology database, the method will replay all the
      * edge updates for the ITopologyServiceShimListener instance in the given
      * container, which will in turn publish them toward SAL.
      *
      * @param containerName
+     *            the container name
      */
     private void TopologyBulkUpdate(String containerName) {
         Map<NodeConnector, Pair<Edge, Set<Property>>> edgePropMap = null;
 
         logger.debug("Try bulk update for container:{}", containerName);
-        edgePropMap = edgeMap.get(containerName);
+        edgePropMap = getEdgeMap(containerName);
         if (edgePropMap == null) {
             logger.debug("No edges known for container:{}", containerName);
             return;
index 76c38664d4d44adde2e799d1f5ff595702aa0c67..79edd93c67466a6da6820fe654dd0aeea95ac656 100644 (file)
@@ -40,6 +40,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      * are done by the ComponentActivatorAbstractBase.
      *
      */
+    @Override
     public void init() {
         Node.NodeIDType.registerIDType("STUB", Integer.class);
         NodeConnector.NodeConnectorIDType.registerIDType("STUB", Integer.class, "STUB");
@@ -50,6 +51,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      * ComponentActivatorAbstractBase
      *
      */
+    @Override
     public void destroy() {
         Node.NodeIDType.unRegisterIDType("STUB");
         NodeConnector.NodeConnectorIDType.unRegisterIDType("STUB");
@@ -64,6 +66,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      *         instantiated in order to get an fully working implementation
      *         Object
      */
+    @Override
     public Object[] getImplementations() {
         Object[] res = { ReadService.class, InventoryService.class };
         return res;
@@ -84,6 +87,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      *            per-container different behavior if needed, usually should not
      *            be the case though.
      */
+    @Override
     public void configureInstance(Component c, Object imp, String containerName) {
         if (imp.equals(ReadService.class)) {
             // export the service to be used by SAL
@@ -104,11 +108,18 @@ public class Activator extends ComponentActivatorAbstractBase {
         }
     }
 
+    @Override
     public Object[] getGlobalImplementations() {
-        Object[] res = { FlowProgrammerService.class, StubNodeFactory.class, StubNodeConnectorFactory.class };
+        Object[] res =
+                {
+                        FlowProgrammerService.class,
+                        StubNodeFactory.class,
+                        StubNodeConnectorFactory.class,
+                        InventoryService.class };
         return res;
     }
 
+    @Override
     public void configureGlobalInstance(Component c, Object imp){
         if (imp.equals(FlowProgrammerService.class)) {
             // export the service to be used by SAL
@@ -136,6 +147,17 @@ public class Activator extends ComponentActivatorAbstractBase {
             props.put("protocolName", "STUB");
             c.setInterface(INodeConnectorFactory.class.getName(), props);
         }
-
+        if (imp.equals(InventoryService.class)) {
+            // export the service to be used by SAL
+            Dictionary<String, Object> props = new Hashtable<String, Object>();
+            // Set the protocolPluginType property which will be used
+            // by SAL
+            props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString(), "STUB");
+            props.put("scope", "Global");
+            c.setInterface(IPluginInInventoryService.class.getName(), props);
+            c.add(createServiceDependency().setService(IPluginOutInventoryService.class, "(scope=Global)")
+                    .setCallbacks("setPluginOutInventoryServices", "unsetPluginOutInventoryServices")
+                    .setRequired(true));
+        }
     }
 }
index 22a4343f332ed2e79e7f7ecc979d8535acc4ea26..b94ffec1ddba5d1f6cc699813d22fea6b02c7c0e 100644 (file)
@@ -12,11 +12,11 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArraySet;
 
 import org.apache.felix.dm.Component;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
 import org.opendaylight.controller.sal.core.Actions;
 import org.opendaylight.controller.sal.core.Bandwidth;
 import org.opendaylight.controller.sal.core.Buffers;
@@ -29,7 +29,9 @@ import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.core.State;
 import org.opendaylight.controller.sal.core.Tables;
 import org.opendaylight.controller.sal.core.TimeStamp;
+import org.opendaylight.controller.sal.core.UpdateType;
 import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
 import org.opendaylight.controller.sal.utils.NodeCreator;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
 
@@ -55,6 +57,22 @@ public class InventoryService implements IPluginInInventoryService {
                                                                                     // global
                                                                                     // container
                                                                                     // only
+    private final Set<IPluginOutInventoryService> pluginOutInventoryServices =
+            new CopyOnWriteArraySet<IPluginOutInventoryService>();
+
+    public void setPluginOutInventoryServices(IPluginOutInventoryService service) {
+        logger.trace("Got a service set request {}", service);
+        if (this.pluginOutInventoryServices != null) {
+            this.pluginOutInventoryServices.add(service);
+        }
+    }
+
+    public void unsetPluginOutInventoryServices(IPluginOutInventoryService service) {
+        logger.trace("Got a service UNset request");
+        if (this.pluginOutInventoryServices != null) {
+            this.pluginOutInventoryServices.remove(service);
+        }
+    }
 
     /**
      * Function called by the dependency manager when all the required
@@ -173,6 +191,29 @@ public class InventoryService implements IPluginInInventoryService {
     void start() {
     }
 
+    /**
+     * Method called when the plugin has exposed it's services, this will be
+     * used to publish the updates so connection manager can think the
+     * connection is local
+     */
+    void started() {
+        // update sal and discovery
+        for (IPluginOutInventoryService service : pluginOutInventoryServices) {
+            for (Node node : nodeProps.keySet()) {
+                Set<Property> props = new HashSet<Property>(nodeProps.get(node)
+                        .values());
+                service.updateNode(node, UpdateType.ADDED, props);
+                logger.trace("Adding Node {} with props {}", node, props);
+            }
+            for (NodeConnector nc : nodeConnectorProps.keySet()) {
+                Set<Property> props = new HashSet<Property>(nodeConnectorProps.get(nc)
+                        .values());
+                service.updateNodeConnector(nc, UpdateType.ADDED, props);
+                logger.trace("Adding NodeConnectors {} with props {}", nc, props);
+            }
+        }
+    }
+
     /**
      * Function called by the dependency manager before the services exported by
      * the component are unregistered, this will be followed by a "destroy ()"
@@ -180,6 +221,7 @@ public class InventoryService implements IPluginInInventoryService {
      *
      */
     void stop() {
+        pluginOutInventoryServices.clear();
     }
 
     /**
index e25c34c75f8c863262053c10167bc70da0279102..82f37d0235842fdf05fa735ae33cb7324da5c3c8 100644 (file)
@@ -23,7 +23,6 @@ import org.opendaylight.controller.sal.routing.IRouting;
 import org.opendaylight.controller.switchmanager.ISwitchManager;
 import org.opendaylight.controller.topologymanager.ITopologyManager;
 import org.opendaylight.controller.topologymanager.ITopologyManagerClusterWideAware;
-import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
 
 public class Activator extends ComponentActivatorAbstractBase {
index 453976bf680d1ee3af50fa7719aececff1cedc74..c88c53decf36d7e6cdcf3e55ecd46ce1ff830032 100644 (file)
@@ -47,13 +47,15 @@ public interface IResourceAuthorization {
     public List<String> getRoles();
 
     /**
-     * Returns the application role level for the specified role
-     * If the role is not known to this application <code>NOUSER<code>
-     * will be returned as specified in {@link AppRoleLevel}
+     * Returns the application role level for the specified role. If the role is
+     * not known to this application NOUSER will be returned as specified in
+     * {@link AppRoleLevel}
      *
-     * @param roleName the role name to query
-     * @return the application level of the given role in the application context as specified by {@link AppRoleLevel}
-     *                  if the role is not part of this application's roles, <code>NOUSER<code> is returned
+     * @param roleName
+     *            the role name to query
+     * @return the application level of the given role in the application
+     *         context as specified by {@link AppRoleLevel}. If the role is not
+     *         part of this application's roles, NOUSER is returned.
      */
     public AppRoleLevel getApplicationRoleLevel(String roleName);
 
@@ -114,18 +116,18 @@ public interface IResourceAuthorization {
     /**
      * Unassign the passed resource group from the specified role
      *
-     * @param group
-     * @param role
+     * @param groupName the name of the resource group
+     * @param role the role name
      * @return the status of the request
      */
-    public Status unassignResourceGroupFromRole(String group, String role);
+    public Status unassignResourceGroupFromRole(String groupName, String role);
 
     /**
      * Returns the list of resource groups the given Role is authorized to use
      * The returning object expresses the resource group name and the access
      * its privilege for the given user role
      *
-     * @param role
+     * @param role  the role name
      * @return list of resources
      */
     public List<ResourceGroup> getAuthorizedGroups(String role);
@@ -141,7 +143,7 @@ public interface IResourceAuthorization {
     /**
      * Returns the list of authorized resources for the given role
      * For each resource only the highest privilege occurrence is returned
-     * @param role
+     * @param role  the role name
      * @return the list of Resource
      */
     public List<Resource> getAuthorizedResources(String role);
@@ -179,8 +181,8 @@ public interface IResourceAuthorization {
      * Returns the highest privilege that the user has on the specified
      * resource in this application context
      *
-     * @param userName
-     * @param resource
+     * @param userName the user name
+     * @param resource the given resource
      * @return the privilege the user has on the passed resource
      */
     public Privilege getResourcePrivilege(String userName, Object resource);
index 135a67dcd1cbfdd83a00f5695ab2d18e4833fc9d..c26800890bb933d4dd5702dda513bcdec4b37e5f 100644 (file)
@@ -23,7 +23,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 @XmlRootElement
 public class Actions extends Property {
         private static final long serialVersionUID = 1L;
-    @XmlElement
+    @XmlElement(name="value")
     private int actionsValue;
 
     public enum ActionType {
@@ -69,6 +69,7 @@ public class Actions extends Property {
         this.actionsValue = 0;
     }
 
+    @Override
     public Actions clone() {
         return new Actions(this.actionsValue);
     }
index 8048cf882c6c9eec22883b9f3c823b23d8c72149..1282d5ef9c2c18259077390a32a4d6840c8ac068 100644 (file)
@@ -25,7 +25,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 public class Bandwidth extends Property {
     private static final long serialVersionUID = 1L;
 
-    @XmlElement
+    @XmlElement(name="value")
     protected long bandwidthValue;
 
     public static final long BWUNK = 0;
@@ -71,6 +71,7 @@ public class Bandwidth extends Property {
         super(name);
     }
 
+    @Override
     public Bandwidth clone() {
         return new Bandwidth(this.bandwidthValue);
     }
index 99089d9096c9db1e0c37391e790322b093db5f47..6d7369d72bb6f25480cc2d40f359b240eeaed8f8 100644 (file)
@@ -22,7 +22,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 @XmlRootElement
 public class Buffers extends Property {
         private static final long serialVersionUID = 1L;
-    @XmlElement
+    @XmlElement(name="value")
     private int buffersValue;
 
     public static final String BuffersPropName = "buffers";
@@ -46,6 +46,7 @@ public class Buffers extends Property {
         this.buffersValue = 0;
     }
 
+    @Override
     public Buffers clone() {
         return new Buffers(this.buffersValue);
     }
index fb121d7b9a48aa4c4c21b626de4f6baf5d661444..7867b93a683d48f565b65cf03ba3a710b7fe3e5c 100644 (file)
@@ -22,7 +22,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 @XmlRootElement
 public class Capabilities extends Property {
         private static final long serialVersionUID = 1L;
-    @XmlElement
+    @XmlElement(name="value")
     private int capabilitiesValue;
 
     public enum CapabilitiesType {
@@ -63,6 +63,7 @@ public class Capabilities extends Property {
         this.capabilitiesValue = 0;
     }
 
+    @Override
     public Capabilities clone() {
         return new Capabilities(this.capabilitiesValue);
     }
index bae984eaec00f4f9524e4e0db719c8e2ec74e4e3..ef6efc58211577fb9799509c1d998949a44364dc 100644 (file)
@@ -19,7 +19,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 @XmlRootElement
 @SuppressWarnings("serial")
 public class Config extends Property {
-    @XmlElement
+    @XmlElement(name="value")
     private short configValue;
 
     public static final short ADMIN_DOWN = 0;
@@ -40,6 +40,7 @@ public class Config extends Property {
         this.configValue = config;
     }
 
+    @Override
     public Config clone() {
         return new Config(this.configValue);
     }
index 92cd5b12e49bfe770dd8a2ed93a5baa518f3194d..6915404e24ab43af15299c1469695101b53a6984 100644 (file)
@@ -9,7 +9,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 @XmlRootElement
 @SuppressWarnings("serial")
 public class Description extends Property {
-    @XmlElement
+    @XmlElement(name="value")
     private String descriptionValue;
     public static final String propertyName = "description";
 
@@ -26,6 +26,7 @@ public class Description extends Property {
         this.descriptionValue = description;
     }
 
+    @Override
     public Description clone() {
         return new Description(this.descriptionValue);
     }
index c28eb13d55666c29085e3812e87384004a492667..a1d4ff9db735476fa593f0fe2f2c577b13b9d473 100644 (file)
@@ -9,7 +9,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 @XmlRootElement
 @SuppressWarnings("serial")
 public class ForwardingMode extends Property {
-    @XmlElement
+    @XmlElement(name="value")
     private final int modeValue;
     public static final int REACTIVE_FORWARDING = 0;
     public static final int PROACTIVE_FORWARDING = 1;
index 008ec59bfa2d08e4c1859afcec840e040b8860f2..ce6c00e7c036bbc8b929bbbcdc77df342ab84c13 100644 (file)
 package org.opendaylight.controller.sal.core;
 
 /**
- * @file   IContainerAware.java
- *
- * @brief  Define the interface to be called when the Container is being
+ * The interface describes methods to be called when the Container is being
  * created/destroyed
- *
- *
  */
 
 public interface IContainerAware {
index 8ba62e234de1f95596b4c20d7b1ba8afbec68040..1629c1dd17808e32ec868028d8fbcda77cad4585 100644 (file)
@@ -21,8 +21,8 @@
 package org.opendaylight.controller.sal.core;
 
 /**
- *
- * Interface used to retrieve the status of a given Container
+ * The interface describes methods used to retrieve the status of a given
+ * Container
  */
 public interface IContainerListener {
     /**
@@ -42,38 +42,54 @@ public interface IContainerListener {
     /**
      * Notification raised when the container flow layout changes
      *
-     * @param containerName container for which the update has been raised
-     * @param previousFlow previous value of the container flow under
-     * update, differs from the currentFlow only and only if it's an
-     * update operation
-     * @param currentFlow current version of the container flow differs from
-     * the previousFlow only in case of update
-     * @param t type of update
+     * @param containerName
+     *            container for which the update has been raised
+     * @param previousFlow
+     *            previous value of the container flow
+     *            {@link org.opendaylight.controller.sal.core.ContainerFlow}
+     *            under update, differs from the currentFlow only and only if
+     *            it's an update operation
+     * @param currentFlow
+     *            current version of the container flow
+     *            {@link org.opendaylight.controller.sal.core.ContainerFlow}
+     *            differs from the previousFlow only in case of update
+     * @param t
+     *            type of update
+     *            {@link org.opendaylight.controller.sal.core.UpdateType}
      */
     public void containerFlowUpdated(String containerName,
             ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t);
 
     /**
-     * Notification raised when a NodeConnector is added or removed in
-     * the container.
+     * Notification raised when a NodeConnector is added or removed in the
+     * container.
      *
-     * @param containerName container for which the update has been raised
-     * @param p NodeConnector being updated
-     * @param t type of modification, but among the types the modify
-     * operation is not expected to be raised because the
-     * nodeConnectors are anyway immutable so this is only used to
-     * add/delete
+     * @param containerName
+     *            container for which the update has been raised
+     * @param p
+     *            NodeConnector
+     *            {@link org.opendaylight.controller.sal.core.NodeConnector}
+     *            being updated
+     * @param t
+     *            type of modification
+     *            {@link org.opendaylight.controller.sal.core.UpdateType}, but
+     *            among the types the modify operation is not expected to be
+     *            raised because the nodeConnectors are anyway immutable so this
+     *            is only used to add/delete
      */
     public void nodeConnectorUpdated(String containerName, NodeConnector p,
             UpdateType t);
 
     /**
-     * Notification raised when the container mode has changed
-     * This notification is needed for some bundle in the default container
-     * to cleanup some HW state when switching from non-slicing to
-     * slicing case and vice-versa
+     * Notification raised when the container mode has changed This notification
+     * is needed for some bundle in the default container to cleanup some HW
+     * state when switching from non-slicing to slicing case and vice-versa
      *
-     * @param t  ADDED when first container is created, REMOVED when last container is removed
+     * @param t
+     *            type of modification
+     *            {@link org.opendaylight.controller.sal.core.UpdateType}. ADDED
+     *            when first container is created, REMOVED when last container
+     *            is removed
      */
     public void containerModeUpdated(UpdateType t);
 }
index 818002a21e042f87da32f5e14573e1b502ffc328..a0ba47b29d2458aadcffa90e115f0c1a218602e6 100644 (file)
@@ -23,7 +23,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 public class Latency extends Property {
     private static final long serialVersionUID = 1L;
 
-    @XmlElement
+    @XmlElement(name="value")
     private long latencyValue;
 
     public static final long LATENCYUNK = 0;
@@ -61,6 +61,7 @@ public class Latency extends Property {
         this.latencyValue = (long) latency;
     }
 
+    @Override
     public Latency clone() {
         return new Latency(this.latencyValue);
     }
index 4470e17e82bc2b77109a4ca39b9acc741c7a1515..27e74e08008094759bda6bc5c6c846f40eef262c 100644 (file)
@@ -22,7 +22,7 @@ import org.opendaylight.controller.sal.utils.HexEncode;
 @XmlAccessorType(XmlAccessType.NONE)
 public class MacAddress extends Property implements Cloneable {
     private static final long serialVersionUID = 1L;
-    @XmlElement(name="macAddress")
+    @XmlElement(name="value")
     private final String address;
     public static final String name = "macAddress";
 
index ddb663f5901fe8aa45ab2318a8e86615ae3de05d..d35610add0f6b2df7101dd6e3422f6252d272e4e 100644 (file)
@@ -18,7 +18,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 @XmlRootElement
 @SuppressWarnings("serial")
 public class Name extends Property {
-    @XmlElement
+    @XmlElement(name="value")
     private String nameValue;
     public static final String NamePropName = "name";
 
@@ -35,6 +35,7 @@ public class Name extends Property {
         this.nameValue = name;
     }
 
+    @Override
     public Name clone() {
         return new Name(this.nameValue);
     }
index 22c379614dbd0657d0d97e556a06f48a25b91309..68ff9b4f3804d773790b5a573c77563b6b46ccea 100644 (file)
@@ -118,6 +118,7 @@ public class NodeTable implements Serializable {
     /**
      * Private constructor used for JAXB mapping
      */
+    @SuppressWarnings("unused")
     private NodeTable() {
         this.nodeTableIDString = null;
         this.nodeTableID = null;
@@ -207,7 +208,7 @@ public class NodeTable implements Serializable {
      */
     @XmlAttribute(name = "id")
     public String getNodeTableIDString() {
-        return this.nodeTableIDString.toString();
+        return this.nodeTableIDString != null? this.nodeTableIDString : nodeTableID.toString();
     }
 
     /**
index ba67e0d8213454e76d3fc8fc9760177745e0bec9..058adb63e2156172879dbf7b6d512f7258d2a725 100644 (file)
@@ -20,7 +20,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 @XmlRootElement
 @SuppressWarnings("serial")
 public class State extends Property {
-    @XmlElement
+    @XmlElement(name="value")
     private short stateValue;
 
     public static final short EDGE_DOWN = 0;
@@ -41,6 +41,7 @@ public class State extends Property {
         this.stateValue = state;
     }
 
+    @Override
     public State clone() {
         return new State(this.stateValue);
     }
index 156a0b8ee0225a3b719b7019976c6bc4556a55ba..bd50cf9be067aea6b842e7c9d1e3d8da1b9c746b 100644 (file)
@@ -22,7 +22,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 @XmlRootElement
 public class Tables extends Property {
         private static final long serialVersionUID = 1L;
-    @XmlElement
+    @XmlElement(name="value")
     private byte tablesValue;
 
     public static final String TablesPropName = "tables";
@@ -45,6 +45,7 @@ public class Tables extends Property {
         this.tablesValue = 0;
     }
 
+    @Override
     public Tables clone() {
         return new Tables(this.tablesValue);
     }
index ed4d02b2457da40b210ce05d77cebd76e55d6fac..6756a8213547b1851c1457432827f8934e8b1979 100644 (file)
@@ -20,7 +20,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 @XmlRootElement
 @SuppressWarnings("serial")
 public class Tier extends Property {
-    @XmlElement
+    @XmlElement(name="value")
     private int tierValue;
     public static final String TierPropName = "tier";
 
@@ -37,6 +37,7 @@ public class Tier extends Property {
         this.tierValue = 0;
     }
 
+    @Override
     public Tier clone() {
         return new Tier(this.tierValue);
     }
index a15b3fa9cd10166b3179e163c80b5de7f50170ba..b38ec8582b17db2d765a35c9df4d3b888ed96228 100644 (file)
@@ -25,9 +25,9 @@ import javax.xml.bind.annotation.XmlRootElement;
 @XmlRootElement
 public class TimeStamp extends Property {
     private static final long serialVersionUID = 1L;
-    @XmlElement
+    @XmlElement(name = "value")
     private long timestamp;
-    @XmlElement
+    @XmlElement(name = "name")
     private String timestampName;
 
     public static final String TimeStampPropName = "timeStamp";
@@ -57,6 +57,7 @@ public class TimeStamp extends Property {
         this.timestampName = null;
     }
 
+    @Override
     public TimeStamp clone() {
         return new TimeStamp(this.timestamp, this.timestampName);
     }
index 5157788ce7b58982414fdc91436d8cf24f5eb167..dacec15d79534e418533197076b7c8594a2b4f4b 100644 (file)
@@ -12,16 +12,23 @@ import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.utils.Status;
 
 /**
- * @file IPluginOutFlowProgrammer.java
- *
- * @brief Flow programmer interface to be implemented by protocol plugins
+ * This interface defines the flow programmer methods to be implemented by
+ * protocol plugins
  */
 public interface IPluginInFlowProgrammerService {
     /**
      * Synchronously add a flow to the network node
      *
      * @param node
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node} on which the
+     *            flow got added
      * @param flow
+     *            the flow
+     *            {@link org.opendaylight.controller.sal.flowprogrammer.Flow}
+     *            that got added
+     * @return Status the operation status
+     *         {@link org.opendaylight.controller.sal.utils.Status}
      */
     Status addFlow(Node node, Flow flow);
 
@@ -29,7 +36,15 @@ public interface IPluginInFlowProgrammerService {
      * Synchronously modify existing flow on the switch
      *
      * @param node
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node} on which the
+     *            flow got modified
      * @param flow
+     *            the flow
+     *            {@link org.opendaylight.controller.sal.flowprogrammer.Flow}
+     *            that got modified
+     * @return Status the operation status
+     *         {@link org.opendaylight.controller.sal.utils.Status}
      */
     Status modifyFlow(Node node, Flow oldFlow, Flow newFlow);
 
@@ -37,7 +52,15 @@ public interface IPluginInFlowProgrammerService {
      * Synchronously remove the flow from the network node
      *
      * @param node
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node} on which the
+     *            flow got removed
      * @param flow
+     *            the flow
+     *            {@link org.opendaylight.controller.sal.flowprogrammer.Flow}
+     *            that got removed
+     * @return Status the operation status
+     *         {@link org.opendaylight.controller.sal.utils.Status}
      */
     Status removeFlow(Node node, Flow flow);
 
@@ -45,8 +68,17 @@ public interface IPluginInFlowProgrammerService {
      * Asynchronously add a flow to the network node
      *
      * @param node
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node} on which the
+     *            flow got added
      * @param flow
+     *            the flow
+     *            {@link org.opendaylight.controller.sal.flowprogrammer.Flow}
+     *            that got added
      * @param rid
+     *            the request id
+     * @return Status the operation status
+     *         {@link org.opendaylight.controller.sal.utils.Status}
      */
     Status addFlowAsync(Node node, Flow flow, long rid);
 
@@ -54,8 +86,19 @@ public interface IPluginInFlowProgrammerService {
      * Asynchronously modify existing flow on the switch
      *
      * @param node
-     * @param flow
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node} on which the
+     *            flow got modified
+     * @param oldFlow
+     *            the original flow
+     *            {@link org.opendaylight.controller.sal.flowprogrammer.Flow}
+     * @param newFlow
+     *            the new flow
+     *            {@link org.opendaylight.controller.sal.flowprogrammer.Flow}
      * @param rid
+     *            the request id
+     * @return Status the operation status
+     *         {@link org.opendaylight.controller.sal.utils.Status}
      */
     Status modifyFlowAsync(Node node, Flow oldFlow, Flow newFlow, long rid);
 
@@ -63,8 +106,17 @@ public interface IPluginInFlowProgrammerService {
      * Asynchronously remove the flow from the network node
      *
      * @param node
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node} on which the
+     *            flow got removed
      * @param flow
+     *            the flow
+     *            {@link org.opendaylight.controller.sal.flowprogrammer.Flow}
+     *            that got removed
      * @param rid
+     *            the request id
+     * @return Status the operation status
+     *         {@link org.opendaylight.controller.sal.utils.Status}
      */
     Status removeFlowAsync(Node node, Flow flow, long rid);
 
@@ -72,6 +124,11 @@ public interface IPluginInFlowProgrammerService {
      * Remove all flows present on the network node
      *
      * @param node
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node} on which the
+     *            flow got removed
+     * @return Status the operation status
+     *         {@link org.opendaylight.controller.sal.utils.Status}
      */
     Status removeAllFlows(Node node);
 
@@ -80,6 +137,10 @@ public interface IPluginInFlowProgrammerService {
      * Barrier reply arrives.
      *
      * @param node
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @return Status the operation status
+     *         {@link org.opendaylight.controller.sal.utils.Status}
      */
     Status syncSendBarrierMessage(Node node);
 
@@ -87,6 +148,10 @@ public interface IPluginInFlowProgrammerService {
      * Send Barrier message asynchronously. The caller is not blocked.
      *
      * @param node
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @return Status the operation status
+     *         {@link org.opendaylight.controller.sal.utils.Status}
      */
     Status asyncSendBarrierMessage(Node node);
 }
index 9bab8391986df5a82dfc6b3aeeab51155eb84f88..30c25af57f688539c7bf569aa4ecccf0f804af26 100644 (file)
@@ -246,93 +246,195 @@ public class Match implements Cloneable, Serializable {
     /**
      * Check whether the current match conflicts with the passed filter match
      * This match conflicts with the filter if for at least a MatchType defined
-     * in the filter match, the respective MatchFields differ or are not compatible
+     * in the filter match, the respective MatchFields differ or are not
+     * compatible
+     *
+     * In other words the function returns true if the set of packets described
+     * by one match and the set of packets described by the other match are
+     * disjoint. Equivalently, if the intersection of the two sets of packets
+     * described by the two matches is an empty.
      *
      * For example, Let's suppose the filter has the following MatchFields:
      * DL_TYPE = 0x800
-     * NW_DST =  172.20.30.110/24
+     * NW_DST = 172.20.30.110/24
      *
      * while this match has the following MatchFields:
+     * DL_TYPE = 0x800
      * NW_DST = 172.20.30.45/24
      * TP_DST = 80
      *
-     * Then the function would return false as the two Match are not conflicting
+     * Then the function would return false as the two Match are not
+     * conflicting.
      *
-     * Note: the mask value is taken into account only for MatchType.NW_SRC and MatchType.NW_DST
+     * Note: the mask value is taken into account only for MatchType.NW_SRC and
+     * MatchType.NW_DST
      *
-     * @param match the MAtch describing the filter
-     * @return true if the match is conflicting with the filter, false otherwise
+     * @param match
+     *            the Match describing the filter
+     * @return true if the set of packets described by one match and the set of
+     *         packets described by the other match are disjoint, false
+     *         otherwise
      */
     public boolean conflictWithFilter(Match filter) {
-        // Iterate through the MatchType defined in the filter
-        for (MatchType type : filter.getMatchesList()) {
+        return !this.intersetcs(filter);
+    }
+
+    /**
+     * Merge the current Match fields with the fields of the filter Match. A
+     * check is first run to see if this Match is compatible with the filter
+     * Match. If it is not, the merge is not attempted.
+     *
+     * The result is the match object representing the intersection of the set
+     * of packets described by this match with the set of packets described by
+     * the filter match. If the intersection of the two sets is empty, the
+     * return match will be null.
+     *
+     * @param filter
+     *            the match with which attempting the merge
+     * @return a new Match object describing the set of packets represented by
+     *         the intersection of this and the filter matches. null if the
+     *         intersection is empty.
+     */
+    public Match mergeWithFilter(Match filter) {
+        return this.getIntersection(filter);
+    }
+
+    /**
+     * Return the match representing the intersection of the set of packets
+     * described by this match with the set of packets described by the other
+     * match. Such as m.getIntersection(m) == m, m.getIntersection(u) == m and
+     * m.getIntersection(o) == o where u is an empty match (universal set, all
+     * packets) and o is the null match (empty set).
+     *
+     * @param other
+     *            the match with which computing the intersection
+     * @return a new Match object representing the intersection of the set of
+     *         packets described by this match with the set of packets described
+     *         by the other match. null when the intersection is the empty set.
+     */
+    public Match getIntersection(Match other) {
+        // If no intersection, return the empty set
+        if (!this.intersetcs(other)) {
+            return null;
+        }
+        // Check if any of the two is the universal match
+        if (this.getMatches() == 0) {
+            return other.clone();
+        }
+        if (other.getMatches() == 0) {
+            return this.clone();
+        }
+        // Derive the intersection
+        Match intersection = new Match();
+        for (MatchType type : MatchType.values()) {
+            if (this.isAny(type) && other.isAny(type)) {
+                continue;
+            }
             if (this.isAny(type)) {
+                intersection.setField(other.getField(type).clone());
+                continue;
+            } else if (other.isAny(type)) {
+                intersection.setField(this.getField(type).clone());
+                continue;
+            }
+            // Either they are equal or it is about IP address
+            switch (type) {
+            // When it is about IP address, take the wider prefix address
+            // between the twos
+            case NW_SRC:
+            case NW_DST:
+                MatchField thisField = this.getField(type);
+                MatchField otherField = other.getField(type);
+                InetAddress thisAddress = (InetAddress) thisField.getValue();
+                InetAddress otherAddress = (InetAddress) otherField.getValue();
+                InetAddress thisMask = (InetAddress) thisField.getMask();
+                InetAddress otherMask = (InetAddress) otherField.getMask();
+
+                int thisMaskLen = (thisMask == null) ? ((thisAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
+                        .getSubnetMaskLength(thisMask);
+                int otherMaskLen = (otherMask == null) ? ((otherAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
+                        .getSubnetMaskLength(otherMask);
+                if (otherMaskLen < thisMaskLen) {
+                    intersection.setField(new MatchField(type, NetUtils.getSubnetPrefix(otherAddress, otherMaskLen),
+                            otherMask));
+                } else {
+                    intersection.setField(new MatchField(type, NetUtils.getSubnetPrefix(thisAddress, thisMaskLen),
+                            thisMask));
+                }
+                break;
+            default:
+                // this and other match field are equal for this type, pick this
+                // match field
+                intersection.setField(this.getField(type).clone());
+            }
+        }
+        return intersection;
+    }
+
+    /**
+     * Checks whether the intersection of the set of packets described by this
+     * match with the set of packets described by the other match is non empty
+     *
+     * For example, if this match is: DL_SRC = 00:cc:bb:aa:11:22
+     *
+     * and the other match is: DL_TYPE = 0x800 NW_SRC = 1.2.3.4
+     *
+     * then their respective matching packets set intersection is non empty:
+     * DL_SRC = 00:cc:bb:aa:11:22 DL_TYPE = 0x800 NW_SRC = 1.2.3.4
+     *
+     * @param other
+     *            the other match with which testing the intersection
+     * @return true if the intersection of the respective matching packets sets
+     *         is non empty
+     */
+    public boolean intersetcs(Match other) {
+        // No intersection with the empty set
+        if (other == null) {
+            return false;
+        }
+        // Always intersection with the universal set
+        if (this.getMatches() == 0 || other.getMatches() == 0) {
+            return true;
+        }
+        // Iterate through the MatchType defined in the filter
+        for (MatchType type : MatchType.values()) {
+            if (this.isAny(type) || other.isAny(type)) {
                 continue;
             }
 
             MatchField thisField = this.getField(type);
-            MatchField filterField = filter.getField(type);
+            MatchField otherField = other.getField(type);
 
             switch (type) {
             case DL_SRC:
             case DL_DST:
-                if (Arrays.equals((byte[]) thisField.getValue(),
-                        (byte[]) filterField.getValue())) {
+                if (!Arrays.equals((byte[]) thisField.getValue(), (byte[]) otherField.getValue())) {
                     return false;
                 }
                 break;
             case NW_SRC:
             case NW_DST:
                 InetAddress thisAddress = (InetAddress) thisField.getValue();
-                InetAddress filterAddress = (InetAddress) filterField
-                        .getValue();
+                InetAddress otherAddress = (InetAddress) otherField.getValue();
                 // Validity check
-                if (thisAddress instanceof Inet4Address
-                        && filterAddress instanceof Inet6Address
-                        || thisAddress instanceof Inet6Address
-                        && filterAddress instanceof Inet4Address) {
-                    return true;
+                if (thisAddress instanceof Inet4Address && otherAddress instanceof Inet6Address
+                        || thisAddress instanceof Inet6Address && otherAddress instanceof Inet4Address) {
+                    return false;
                 }
                 InetAddress thisMask = (InetAddress) thisField.getMask();
-                InetAddress filterMask = (InetAddress) filterField.getMask();
-                // thisAddress has to be in same subnet of filterAddress
-                if (NetUtils.inetAddressConflict(thisAddress, filterAddress,
-                        thisMask, filterMask)) {
-                    return true;
+                InetAddress otherMask = (InetAddress) otherField.getMask();
+                if (NetUtils.inetAddressConflict(thisAddress, otherAddress, thisMask, otherMask)
+                        && NetUtils.inetAddressConflict(otherAddress, thisAddress, otherMask, thisMask)) {
+                    return false;
                 }
                 break;
             default:
-                if (!thisField.getValue().equals(filterField.getValue())) {
-                    return true;
-                }
-            }
-            //TODO: check v4 v6 incompatibility
-        }
-        return false;
-    }
-
-    /**
-     * Merge the current Match fields with the fields of the filter Match
-     * A check is first run to see if this Match is compatible with the
-     * filter Match. If it is not, the merge is not attempted.
-     *
-     *
-     * @param filter
-     * @return
-     */
-    public Match mergeWithFilter(Match filter) {
-        if (!this.conflictWithFilter(filter)) {
-            /*
-             * No conflict with the filter
-             * We can copy over the fields which this match does not have
-             */
-            for (MatchType type : filter.getMatchesList()) {
-                if (this.isAny(type)) {
-                    this.setField(filter.getField(type).clone());
+                if (!thisField.getValue().equals(otherField.getValue())) {
+                    return false;
                 }
             }
         }
-        return this;
+        return true;
     }
 
     @Override
index 3b8a2952164eafb0cf463208d06cc29a182e2d6f..54be4c67189412a208dc5cfebb6fef2ff49f0301 100644 (file)
@@ -184,7 +184,8 @@ public class MatchField implements Cloneable, Serializable {
 
     @Override
     public String toString() {
-        return type + "(" + getValueString() + "," + getMaskString() + ")";
+        return (mask == null) ? String.format("%s(%s)", getTypeString(), getValueString()) :
+            String.format("%s(%s,%s)", getTypeString(), getValueString(), getMaskString());
     }
 
     @Override
index 1b950d7cf592df1a78fc775d3a4c390a274d4efa..e9efd382da09c35274c25cc613b6dd1c92fc8c5b 100644 (file)
@@ -17,70 +17,119 @@ import org.opendaylight.controller.sal.core.NodeTable;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 
 /**
- * @file   IPluginInReadService.java
- *
- * @brief  Hardware view interface to be implemented by protocol plugins
- *
- *
- *
+ * The interface defines hardware view read methods to be implemented by protocol plugins
  */
 public interface IPluginInReadService {
 
     /**
-     * Returns the hardware image for the specified flow on the specified network node
+     * Returns the hardware image for the specified flow on the specified
+     * network node
+     *
      * @param node
+     *            the network node
      * @param flow
-     * @return
+     *            the target flow
+     * @param cached
+     *            specify if entry has to be queried from the cached hardware
+     *            information maintained locally or directly from the network
+     *            node.
+     * @return The FlowOnNode object containing the information present in
+     *         hardware for the passed flow on the specified network node
      */
     public FlowOnNode readFlow(Node node, Flow flow, boolean cached);
 
     /**
-     * Returns the hardware view of all the flow installed on the specified network node
+     * Returns the hardware view of all the flow installed on the specified
+     * network node
+     *
      * @param node
-     * @return
+     *            the network node
+     * @param cached
+     *            specify if entries have to be queried from the cached hardware
+     *            information maintained locally or directly from the network
+     *            node.
+     * @return The list of FlowOnNode objects containing the information present
+     *         in hardware on the specified network node for all its flows
      */
     public List<FlowOnNode> readAllFlow(Node node, boolean cached);
 
     /**
-     * Returns the description of the network node as provided by the node itself
+     * Returns the description of the network node as provided by the node
+     * itself
+     *
      * @param node
-     * @return
+     *            the network node
+     * @param cached
+     *            specify if entry has to be queried from the cached hardware
+     *            information maintained locally or directly from the network
+     *            node.
+     * @return The NodeDescription object containing the description information
+     *         for the specified network node
      */
     public NodeDescription readDescription(Node node, boolean cached);
 
     /**
      * Returns the hardware view of the specified network node connector
-     * @param node
-     * @return
+     *
+     * @param connector
+     *            the target nodeConnector
+     * @param cached
+     *            specify if entry has to be queried from the cached hardware
+     *            information maintained locally or directly from the
+     *            corresponding network node.
+     * @return The NodeConnectorStatistics object containing the statistics
+     *         present in hardware for the corresponding network node port
      */
     public NodeConnectorStatistics readNodeConnector(NodeConnector connector,
             boolean cached);
 
     /**
-     * Returns the hardware info for all the node connectors on the specified network node
+     * Returns the hardware info for all the node connectors on the specified
+     * network node
+     *
      * @param node
-     * @return
+     *            the target node
+     * @param cached
+     *            specify if entries have to be queried from the cached hardware
+     *            information maintained locally or directly from the
+     *            corresponding network node.
+     * @return The list of NodeConnectorStatistics objects containing the
+     *         statistics present in hardware for all the network node ports
      */
     public List<NodeConnectorStatistics> readAllNodeConnector(Node node,
             boolean cached);
 
     /**
      * Returns the table statistics for the node
-     * @param node
-     * @return
+     * @param table
+     *            the target network node table
+     * @param cached
+     *            specify if entry has to be queried from the cached hardware
+     *            information maintained locally or directly from
+     *            the corresponding network node.
+     * @return The NodeTableStatistics object containing the statistics present
+     *         in hardware for the corresponding network node table
      */
     public NodeTableStatistics readNodeTable(NodeTable table, boolean cached);
 
     /**
      * Returns all the table statistics for the node
+     *
      * @param node
-     * @return
+     *            the target node
+     * @param cached
+     *            specify if entries have to be queried from the cached hardware
+     *            information maintained locally or directly from the
+     *            corresponding network node.
+     * @return The list of NodeTableStatistics objects containing the statistics
+     *         present in hardware for all the network node tables
      */
     public List<NodeTableStatistics> readAllNodeTable(Node node, boolean cached);
 
     /**
      * Returns the averaged transmit rate for the specified node connector
      * @param connector
+     *            the target nodeConnector
      * @return tx rate [bps]
      */
     public long getTransmitRate(NodeConnector connector);
index 3c1b6f241a2df9e1fc090c65e772fdb2fb5ac434..f6e92ad1a902877358166682df5893438f74e9aa 100644 (file)
@@ -14,36 +14,60 @@ import java.util.List;
 import org.opendaylight.controller.sal.core.Node;
 
 /**
- * @file   IPluginOutReadService.java
- *
- * @brief  Hardware statistics updates service to be offered by protocol plugins
+ * The interface defines hardware statistics updates service to be offered by
+ * protocol plugins
  */
 public interface IPluginOutReadService {
 
     /**
-     * Notifies the hardware view of all the flow installed on the specified network node
+     * Notifies the hardware view of all the flow installed on the specified
+     * network node
+     *
      * @param node
-     * @return
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @param flowStatsList
+     *            the hardware view of all the flow
+     *            {@link org.opendaylight.controller.sal.reader.FlowOnNode}
+     *            installed on the specified network node
      */
     public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList);
 
     /**
-     * Notifies the hardware view of the specified network node connector
+     * Notifies the hardware view of the specified network node
+     *
      * @param node
-     * @return
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @param ncStatsList
+     *            the statistics
+     *            {@link org.opendaylight.controller.sal.reader.NodeConnectorStatistics}
+     *            for all node connectors in a given node
      */
     public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList);
 
     /**
      * Notifies all the table statistics for a node
+     *
      * @param node
-     * @return
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @param tableStatsList
+     *            the statistics
+     *            {@link org.opendaylight.controller.sal.reader.NodeTableStatistics}
+     *            for all the tables in a given node
      */
     public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList);
+
     /**
      * Notifies the hardware view of node description changes
+     *
      * @param node
-     * @return
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @param nodeDescription
+     *            the node description
+     *            {@link org.opendaylight.controller.sal.reader.NodeDescription}
      */
     public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription );
 
index ae975f1a58d21c7d30b52f7e878b48db4db905f0..c3af91dd345035549e5138dbf4c1fd788ca18f35 100644 (file)
@@ -17,17 +17,23 @@ import org.opendaylight.controller.sal.core.NodeTable;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 
 /**
- * Interface for retrieving the network node's flow/port/queue hardware view
- *
- *
- *
+ * This interface defines methods for retrieving the network node's
+ * flow/port/queue hardware view
  */
 public interface IReadService {
     /**
-     * Get the hardware view for the specified flow on the specified network node
+     * Get the hardware view for the specified flow on the specified network
+     * node
      *
      * @param node
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
      * @param flow
+     *            the given flow
+     *            {@link org.opendaylight.controller.sal.flowprogrammer.Flow}
+     * @return the flow
+     *         {@link org.opendaylight.controller.sal.reader.FlowOnNode}
+     *         installed on the node
      */
     FlowOnNode readFlow(Node node, Flow flow);
 
@@ -37,7 +43,14 @@ public interface IReadService {
      * Caller will be blocked until node replies or request times out
      *
      * @param node
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
      * @param flow
+     *            the given flow
+     *            {@link org.opendaylight.controller.sal.flowprogrammer.Flow}
+     * @return the flow
+     *         {@link org.opendaylight.controller.sal.reader.FlowOnNode}
+     *         installed on the node
      */
     FlowOnNode nonCachedReadFlow(Node node, Flow flow);
 
@@ -45,7 +58,11 @@ public interface IReadService {
      * Get the hardware view for all the flows installed on the network node
      *
      * @param node
-     * @return
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @return all the flows
+     *         {@link org.opendaylight.controller.sal.reader.FlowOnNode}
+     *         installed on the node
      */
     List<FlowOnNode> readAllFlows(Node node);
 
@@ -55,14 +72,22 @@ public interface IReadService {
      * Caller will be blocked until node replies or request times out
      *
      * @param node
-     * @param flow
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @return the hardware view of all the flows
+     *         {@link org.opendaylight.controller.sal.reader.FlowOnNode}
+     *         installed on the node
      */
     List<FlowOnNode> nonCachedReadAllFlows(Node node);
 
     /**
      * Get the description information for the network node
+     *
      * @param node
-     * @return
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @return the node description
+     *         {@link org.opendaylight.controller.sal.reader.NodeDescription}
      */
     NodeDescription readDescription(Node node);
 
@@ -72,33 +97,57 @@ public interface IReadService {
      * Caller will be blocked until node replies or request times out
      *
      * @param node
-     * @return
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @return the node description
+     *         {@link org.opendaylight.controller.sal.reader.NodeDescription}
      */
     NodeDescription nonCachedReadDescription(Node node);
 
     /**
      * Get the hardware view for the specified node connector
+     *
      * @param connector
+     *            the given node connector
+     *            {@link org.opendaylight.controller.sal.core.NodeConnector}
+     * @return the node connector statistics
+     *         {@link org.opendaylight.controller.sal.reader.NodeConnectorStatistics}
      */
     NodeConnectorStatistics readNodeConnector(NodeConnector connector);
 
     /**
      * Get the hardware view for all the node connectors
      * present on the specified network node
-     * @param connector
+     *
+     * @param node
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @return the statistics for all the node connectors
+     *         {@link org.opendaylight.controller.sal.reader.NodeConnectorStatistics}
      */
     List<NodeConnectorStatistics> readNodeConnectors(Node node);
 
     /**
      * Read the Table statistics for the given node table
+     *
      * @param table
+     *            the table
+     *            {@link org.opendaylight.controller.sal.core.NodeTable}
+     * @return the table statistics
+     *         {@link org.opendaylight.controller.sal.reader.NodeTableStatistics}
      */
     NodeTableStatistics readNodeTable(NodeTable table);
 
     /**
-     * Read the Table statistics for the given node
-     * This is not used. Querying all tables on a node is not currently a feature.
-     * @param table
+     * Read the Table statistics for the given node This is not used. Querying
+     * all tables on a node is not currently a feature.
+     *
+     * @param node
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @return the table statistics
+     *         {@link org.opendaylight.controller.sal.reader.NodeTableStatistics}
+     *         for all tables in a given node
      */
     List<NodeTableStatistics> readNodeTable(Node node);
 
@@ -108,6 +157,10 @@ public interface IReadService {
      * Caller will be blocked until the node replies or request times out
      *
      * @param table
+     *            the table
+     *            {@link org.opendaylight.controller.sal.core.NodeTable}
+     * @return the table statistics
+     *         {@link org.opendaylight.controller.sal.reader.NodeTableStatistics}
      */
     NodeTableStatistics nonCachedReadNodeTable(NodeTable table);
 
@@ -117,15 +170,22 @@ public interface IReadService {
      * Caller will be blocked until node replies or request times out
      *
      * @param node
-     * @return
+     *            the network node
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @return the statistics
+     *         {@link org.opendaylight.controller.sal.reader.NodeConnectorStatistics}
+     *         for all node connectors in a given node
      */
     List<NodeConnectorStatistics> nonCachedReadNodeConnectors(Node node);
 
     /**
      * Get the node connectors statistics information for the network node
      *
-     * @param node
-     * @return
+     * @param connector
+     *            the given node connector
+     *            {@link org.opendaylight.controller.sal.core.NodeConnector}
+     * @return the node connector statistics
+     *         {@link org.opendaylight.controller.sal.reader.NodeConnectorStatistics}
      */
     NodeConnectorStatistics nonCachedReadNodeConnector(NodeConnector connector);
 
@@ -133,6 +193,8 @@ public interface IReadService {
      * Get the transmit rate for the specified node connector
      *
      * @param connector
+     *            the given node connector
+     *            {@link org.opendaylight.controller.sal.core.NodeConnector}
      * @return tx rate [bps]
      */
     long getTransmitRate(NodeConnector connector);
index 2cf237bc89e5a004eb25d833827c53ee7ccfe2ce..28d0905bae142294f4b064486dc42efd5e11aa5e 100644 (file)
@@ -1,10 +1,8 @@
 package org.opendaylight.controller.sal.reader;
 
-
 /**
- * @file   IReadServiceListener.java
- *
- * @brief  SAL service to be consumed by functional modules that are interested in reader updates
+ * The interface describes SAL service to be consumed by functional modules that
+ * are interested in reader updates
  */
 public interface IReadServiceListener extends IPluginOutReadService {
 
index 80950e66a5289fffca8ebbc12fd0fec31ae01525..d06dce6576014be4e3e1334067d91c3db56283af 100644 (file)
@@ -17,32 +17,48 @@ import org.opendaylight.controller.sal.core.Path;
 
 /**
  * This interface provides APIs to manage and query the routing information
 *
+ *
  */
 public interface IRouting {
 
     /**
      * Returns a Path leading from the source to the destination
-     * @param src: source Node
-     * @param dst: destination Node
-     * @return: Path
+     *
+     * @param src
+     *            source {@link org.opendaylight.controller.sal.core.Node}
+     *
+     * @param dst
+     *            destination
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @return: the {@link org.opendaylight.controller.sal.core.Path}
      */
     public Path getRoute(Node src, Node dst);
 
     /**
      * Returns a Max ThroughPut Path leading from the source to the destination
-     * @param src: source Node
-     * @param dst: destination Node
-     * @return: MTPath
+     *
+     * @param src
+     *            source {@link org.opendaylight.controller.sal.core.Node}
+     *
+     * @param dst
+     *            destination
+     *            {@link org.opendaylight.controller.sal.core.Node}
+     * @return: the max throughput {@link org.opendaylight.controller.sal.core.Path}
      */
     public Path getMaxThroughputRoute(Node src, Node dst);
 
     /**
-     * Returns a Path leading from the source to the destination that meets the specified bandwidth
-     * @param src: source Node
-     * @param dst: destination Node
-     * @param Bw: bandwidth
-     * @return: Path
+     * Returns a Path leading from the source to the destination that meets the
+     * specified bandwidth
+     *
+     * @param src
+     *            source {@link org.opendaylight.controller.sal.core.Node}
+     *
+     * @param dst
+     *            destination {@link org.opendaylight.controller.sal.core.Node}
+     * @param Bw
+     *            the bandwidth
+     * @return: the {@link org.opendaylight.controller.sal.core.Path}
      */
     public Path getRoute(Node src, Node dst, Short Bw);
 
@@ -58,9 +74,12 @@ public interface IRouting {
 
     /**
      * Initialization For Max Throughput
-     * @param EdgeWeightMap: Map containing Edge and Corresponding
-     * Weight. Optional Param - if null, implementation specific weight
-     * calculation will be used.
+     *
+     * @param EdgeWeightMap
+     *            Map containing
+     *            {@link org.opendaylight.controller.sal.core.Edge} and
+     *            Corresponding Weight. Optional Param - if null, implementation
+     *            specific weight calculation will be used.
      */
     public void initMaxThroughput(Map<Edge, Number> EdgeWeightMap);
 
index 11cdc990131a1ab6bbadc9cb142fcc7fb4476205..6850cc6373d0263fdb108bf35b652667c56fa1e0 100644 (file)
@@ -13,19 +13,11 @@ import java.util.List;
 import org.opendaylight.controller.sal.core.Edge;
 
 /**
- * @file   IListenTopoUpdates.java
- *
- * @brief  Topology notifications provided by SAL toward the application
- *
- * For example an application that wants to keep up to date with the
- * updates coming from SAL it will register in the OSGi service
- * registry this interface (on a per-container base) and SAL will call it
- * providing the update
- */
-
-/**
- * Topology notifications provided by SAL toward the application
- *
+ * This interface defines the methods for topology notifications provided by SAL
+ * toward the application. For example an application that wants to keep up to
+ * date with the updates coming from SAL it will register in the OSGi service
+ * registry. This interface (on a per-container base) and SAL will call it
+ * providing the update.
  */
 public interface IListenTopoUpdates {
     /**
@@ -51,6 +43,7 @@ public interface IListenTopoUpdates {
      * threshold level configured on the controller
      *
      * @param edge
+     *            The edge which bandwidth usage is back to normal
      */
     public void edgeUtilBackToNormal(Edge edge);
 }
index 6667628b0dcfc201a2d6e80aad1c49ad03cd97ce..32851e86f6236cf6932ce982a504d7626caf5d2b 100644 (file)
@@ -9,25 +9,13 @@
 package org.opendaylight.controller.sal.topology;
 
 import java.util.List;
-import java.util.Set;
-
 import org.opendaylight.controller.sal.core.Edge;
-import org.opendaylight.controller.sal.core.Property;
-import org.opendaylight.controller.sal.core.UpdateType;
-
-/**
- * @file   IPluginOutTopologyService.java
- *
- * @brief  Methods that are invoked from Protocol Plugin toward SAL
- *
- * Every time a protocol plugin update the topology, it will call this
- * service provided by SAL so the update can migrate upward toward the
- * applications
- */
 
 /**
- * Methods that are invoked from Protocol Plugin toward SAL
- *
+ * This interface defines the methods that are invoked from Protocol Plugin
+ * toward SAL. Every time a protocol plugin update the topology, it will call
+ * this service provided by SAL so the update can migrate upward toward the
+ * applications.
  */
 public interface IPluginOutTopologyService {
 
@@ -45,7 +33,8 @@ public interface IPluginOutTopologyService {
      * on the controller
      *
      * @param edge
-     */
+      *            The edge which bandwidth usage is above the safety level
+    */
     public void edgeOverUtilized(Edge edge);
 
     /**
@@ -53,6 +42,7 @@ public interface IPluginOutTopologyService {
      * threshold level configured on the controller
      *
      * @param edge
+     *            The edge which bandwidth usage is back to normal
      */
     public void edgeUtilBackToNormal(Edge edge);
 }
index 2e0009cd4794540156f27dda98837a364b920d05..2488c754b89e3d427c695f9caf9f147a9f0fb9b5 100644 (file)
@@ -9,6 +9,10 @@
 
 package org.opendaylight.controller.sal.utils;
 
+/**
+ * This interface defines the methods for configuration object
+ *
+ */
 public interface ConfigurationObject {
 
 }
index 4196025088cfccfccc500ef4e96a7a5fada9056c..406614d164b60a96a1a4dc8a0264858ffc4fde13 100644 (file)
 
 package org.opendaylight.controller.sal.utils;
 
+/**
+ * This interface defines the methods for callback ordering
+ *
+ */
+
 public interface IListener<T> {
     public enum Command {
         CONTINUE, STOP
@@ -41,7 +46,7 @@ public interface IListener<T> {
     /**
      * The name assigned to this listener
      *
-     * @return
+     * @return the name string
      */
     public String getName();
 
index 317976dc3e68fca821a44540c0ead4f01709a060..fd51a787aa2828e2fb766b902eb68b8a12cdb8de 100644 (file)
@@ -13,9 +13,7 @@ import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 
 /**
- * @file   INodeFactory.java
- *
- * @brief  Define the interface to be called when looking up custom node types
+ * This interface defines the methods to be called when looking up custom node types
  *
  */
 
@@ -23,6 +21,15 @@ public interface INodeConnectorFactory {
     /**
      * Method to get custom NodeConnector types from protocol plugins
      *
+     * @param typeStr
+     *            {@Link
+     *            org.opendaylight.controller.sal.core.NodeConnector} type
+     *            string
+     * @param IDStr
+     *            {@Link
+     *            org.opendaylight.controller.sal.core.NodeConnector} ID string
+     * @return the custom {@Link
+     *         org.opendaylight.controller.sal.core.NodeConnector}
      */
     public NodeConnector fromStringNoNode(String typeStr, String IDStr,
             Node n);
index dce6eb03f6885329cfd910ade984366ff7a8e5c8..1ccd04bedac69bd72201c4d6443170a9863a5df0 100644 (file)
@@ -12,9 +12,7 @@ package org.opendaylight.controller.sal.utils;
 import org.opendaylight.controller.sal.core.Node;
 
 /**
- * @file   INodeFactory.java
- *
- * @brief  Define the interface to be called when looking up custom node types
+ * This interface defines the methods to be called when looking up custom node types
  *
  */
 
@@ -22,6 +20,14 @@ public interface INodeFactory {
     /**
      * Method to get custom node types from protocol plugins
      *
+     * @param nodeType
+     *            {@Link org.opendaylight.controller.sal.core.Node} type
+     *            string
+     * @param nodeId
+     *            {@Link org.opendaylight.controller.sal.core.Node} ID
+     *            string
+     * @return the custom {@Link
+     *         org.opendaylight.controller.sal.core.Node}
      */
     public Node fromString(String nodeType, String nodeId);
 }
index f81e7e3d03b0c4af14f5e539b45567725d80c43b..e94021119d14f11e7581d5e68b6e096921a07725 100644 (file)
@@ -12,6 +12,7 @@ import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.Arrays;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -246,11 +247,18 @@ public abstract class NetUtils {
      * Checks if the test address and mask conflicts with the filter address and
      * mask
      *
-     * For example: testAddress: 172.28.2.23 testMask: 255.255.255.0
-     * filtAddress: 172.28.1.10 testMask: 255.255.255.0 conflict
+     * For example:
+     * testAddress: 172.28.2.23
+     * testMask: 255.255.255.0
+     * filterAddress: 172.28.1.10
+     * testMask: 255.255.255.0
+     * do conflict
      *
-     * testAddress: 172.28.2.23 testMask: 255.255.255.0 filtAddress: 172.28.1.10
-     * testMask: 255.255.0.0 do not conflict
+     * testAddress: 172.28.2.23
+     * testMask: 255.255.255.0
+     * filterAddress: 172.28.1.10
+     * testMask: 255.255.0.0
+     * do not conflict
      *
      * Null parameters are permitted
      *
@@ -274,7 +282,8 @@ public abstract class NetUtils {
 
         int testMaskLen = (testMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
                 .getSubnetMaskLength(testMask);
-        int filterMaskLen = NetUtils.getSubnetMaskLength(filterMask);
+        int filterMaskLen = (filterMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
+                .getSubnetMaskLength(filterMask);
 
         // Mask length check. Test mask has to be more specific than filter one
         if (testMaskLen < filterMaskLen) {
@@ -463,7 +472,7 @@ public abstract class NetUtils {
 
     /*
      * Following utilities are useful when you need to compare or bit shift java
-     * primitive type variable which are inerently signed
+     * primitive type variable which are inherently signed
      */
     /**
      * Returns the unsigned value of the passed byte variable
@@ -502,4 +511,14 @@ public abstract class NetUtils {
             return null;
         }
     }
+
+    /**
+     * Returns Broadcast MAC Address
+     *
+     * @return the byte array containing  broadcaset mac address
+     */
+    public static byte[] getBroadcastMACAddr() {
+        return Arrays.copyOf(BroadcastMACAddr, BroadcastMACAddr.length);
+    }
+
 }
index ae78e1acc8af45f8ef879b0ad16477bf9040330a..f3c7a95b0ebcdfb44a5de81e8a5509572827d2f6 100644 (file)
@@ -523,4 +523,98 @@ public class MatchTest {
         Assert.assertTrue(field.getValue().equals(new Short(vlan)));
         Assert.assertTrue(field.isValid());
     }
+
+    @Test
+    public void testIntersection() throws UnknownHostException {
+        Short ethType = Short.valueOf((short)0x800);
+        InetAddress ip1 = InetAddress.getByName("1.1.1.1");
+        InetAddress ip2 = InetAddress.getByName("1.1.1.0");
+        InetAddress ipm2 = InetAddress.getByName("255.255.255.0");
+        InetAddress ip3 = InetAddress.getByName("1.3.0.0");
+        InetAddress ipm3 = InetAddress.getByName("255.255.0.0");
+
+        Match m1 = new Match();
+        m1.setField(MatchType.DL_TYPE, ethType);
+        m1.setField(MatchType.NW_SRC, ip1);
+
+        Match m2 = new Match();
+        m2.setField(MatchType.DL_TYPE, ethType);
+        m2.setField(MatchType.NW_SRC, ip2, ipm2);
+
+        Match m3 = new Match();
+        m3.setField(MatchType.DL_TYPE, ethType);
+        m3.setField(MatchType.NW_SRC, ip3, ipm3);
+        m3.setField(MatchType.NW_PROTO, IPProtocols.TCP.byteValue());
+
+        Match m3r = m3.reverse();
+        Assert.assertTrue(m3.intersetcs(m3r));
+
+        Assert.assertTrue(m1.intersetcs(m2));
+        Assert.assertTrue(m2.intersetcs(m1));
+        Assert.assertFalse(m1.intersetcs(m3));
+        Assert.assertTrue(m1.intersetcs(m3r));
+        Assert.assertFalse(m3.intersetcs(m1));
+        Assert.assertTrue(m3.intersetcs(m1.reverse()));
+        Assert.assertFalse(m2.intersetcs(m3));
+        Assert.assertFalse(m3.intersetcs(m2));
+        Assert.assertTrue(m2.intersetcs(m3r));
+
+
+        Match i = m1.getIntersection(m2);
+        Assert.assertTrue(((Short)i.getField(MatchType.DL_TYPE).getValue()).equals(ethType));
+        Assert.assertTrue(((InetAddress)i.getField(MatchType.NW_SRC).getValue()).equals(ip2));
+        Assert.assertTrue(((InetAddress)i.getField(MatchType.NW_SRC).getMask()).equals(ipm2));
+
+        // Empty set
+        i = m2.getIntersection(m3);
+        Assert.assertNull(i);
+
+        Match m4 = new Match();
+        m4.setField(MatchType.DL_TYPE, ethType);
+        m4.setField(MatchType.NW_PROTO, IPProtocols.TCP.byteValue());
+        Assert.assertTrue(m4.intersetcs(m3));
+
+        Match m5 = new Match();
+        m5.setField(MatchType.DL_TYPE, ethType);
+        m3.setField(MatchType.NW_SRC, ip3, ipm3);
+        m5.setField(MatchType.NW_PROTO, IPProtocols.UDP.byteValue());
+        Assert.assertFalse(m5.intersetcs(m3));
+        Assert.assertFalse(m5.intersetcs(m4));
+        Assert.assertTrue(m5.intersetcs(m5));
+        Assert.assertFalse(m3.intersetcs(m5));
+        Assert.assertFalse(m4.intersetcs(m5));
+
+
+        Match i2 = m4.getIntersection(m3);
+        Assert.assertFalse(i2.getMatches() == 0);
+        Assert.assertFalse(i2.getMatchesList().isEmpty());
+        Assert.assertTrue(((InetAddress)i2.getField(MatchType.NW_SRC).getValue()).equals(ip3));
+        Assert.assertTrue(((InetAddress)i2.getField(MatchType.NW_SRC).getMask()).equals(ipm3));
+        Assert.assertTrue(((Byte)i2.getField(MatchType.NW_PROTO).getValue()).equals(IPProtocols.TCP.byteValue()));
+
+        byte src[] = {(byte)0, (byte)0xab,(byte)0xbc,(byte)0xcd,(byte)0xde,(byte)0xef};
+        byte dst[] = {(byte)0x10, (byte)0x11,(byte)0x12,(byte)0x13,(byte)0x14,(byte)0x15};
+        Short srcPort = (short)1024;
+        Short dstPort = (short)80;
+
+        // Check identity
+        Match m6 = new Match();
+        m6.setField(MatchType.DL_SRC, src);
+        m6.setField(MatchType.DL_DST, dst);
+        m6.setField(MatchType.NW_SRC, ip2, ipm2);
+        m6.setField(MatchType.NW_DST, ip3, ipm3);
+        m6.setField(MatchType.NW_PROTO, IPProtocols.UDP.byteValue());
+        m6.setField(MatchType.TP_SRC, srcPort);
+        m6.setField(MatchType.TP_DST, dstPort);
+        Assert.assertTrue(m6.intersetcs(m6));
+        Assert.assertTrue(m6.getIntersection(m6).equals(m6));
+
+        // Empty match, represents the universal set (all packets)
+        Match u = new Match();
+        Assert.assertTrue(m6.getIntersection(u).equals(m6));
+        Assert.assertTrue(u.getIntersection(m6).equals(m6));
+
+        // No intersection with null match, empty set
+        Assert.assertNull(m6.getIntersection(null));
+    }
 }
index 685738c7e7420bc0f25aad9771268512a2aa1a36..ff63cf7578293a0828ac5e2e062566352d1c85ca 100644 (file)
@@ -27,11 +27,10 @@ public interface IConnectionService {
      * plugins and is an opaque value for SAL. Typical values keyed inside this params are
      * Management IP-Address, Username, Password, Security Keys, etc...
      *
-     *  @return Node
+     * @return Node {@link org.opendaylight.controller.sal.core.Node}
      */
     public Node connect (String type, String connectionIdentifier, Map<ConnectionConstants, String> params);
 
-
     /**
      * Discover the node type and Connect to the first plugin that is able to connect with the specified parameters.
      *
@@ -41,7 +40,7 @@ public interface IConnectionService {
      * plugins and is an opaque value for SAL. Typical values keyed inside this params are
      * Management IP-Address, Username, Password, Security Keys, etc...
      *
-     *  @return Node
+     * @return Node {@link org.opendaylight.controller.sal.core.Node}
      */
     public Node connect (String connectionIdentifier, Map<ConnectionConstants, String> params);
 
@@ -49,12 +48,16 @@ public interface IConnectionService {
      * Disconnect a Node that is connected to this Controller.
      *
      * @param node
-     * @param flow
+     *            the node {@link org.opendaylight.controller.sal.core.Node}
+     * @return Status {@link org.opendaylight.controller.sal.utils.Status}
      */
     public Status disconnect(Node node);
 
     /**
      * View Change notification
+     *
+     * @param node
+     *            the node {@link org.opendaylight.controller.sal.core.Node}
      */
     public void notifyNodeDisconnectFromMaster(Node node);
 
index 9bae1238b528094a58fbb2e29d6b8af90dc3cf07..f4e16fac54af4e72bd8f8ebc0392f3944f15e674 100644 (file)
@@ -14,16 +14,14 @@ import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.utils.Status;
 
 /**
- * @file IPluginInConnectionService.java
- *
- * @brief Connection interface to be implemented by protocol plugins
+ * The interface describes methods to be implemented by protocol plugins
  */
 public interface IPluginInConnectionService {
     /**
      * Disconnect a Node that is connected to this Controller.
      *
      * @param node
-     * @param flow
+     *            the given node {@link org.opendaylight.controller.sal.core.Node}
      */
     public Status disconnect(Node node);
 
@@ -46,6 +44,9 @@ public interface IPluginInConnectionService {
 
     /**
      * Node Disconnected from the node's master controller.
+     *
+     * @param node
+     *            the given node {@link org.opendaylight.controller.sal.core.Node}
      */
     public void notifyNodeDisconnectFromMaster(Node node);
 
index b602d61952e7778a7f6fb5d66a14e9338102a030..456acf016684cdfa4ece97918c03c89240c26bf2 100644 (file)
@@ -10,10 +10,15 @@ package org.opendaylight.controller.sal.connection;
 
 import org.opendaylight.controller.sal.core.Node;
 
+/**
+ * The interface describes methods to be implemented by SAL connection service
+ */
 public interface IPluginOutConnectionService {
     /**
      * Method to test if a node is local to a controller.
      *
+     * @param node
+     *            the given node {@link org.opendaylight.controller.sal.core.Node}
      * @return true if node is local to this controller. false otherwise.
      */
     public boolean isLocal(Node node);
index 04dd59ef3a706b71e2d9b3b35735819eb5ecb1f0..432d82354f589ca5d401fba7344444f0ac3f951b 100644 (file)
@@ -1,4 +1,7 @@
 package org.opendaylight.controller.sal.networkconfig.bridgedomain;
 
+/**
+ * This interface is just a wrapper of IPluginInBridgeDomainConfigService
+ */
 public interface IBridgeDomainConfigService extends IPluginInBridgeDomainConfigService {
 }
\ No newline at end of file
index 20562b80e7f4fdaba44bd6c9fcec6981001ff3b0..cdb14b734774759d6d79261d372a2acb3f940a63 100644 (file)
@@ -8,8 +8,8 @@ import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.utils.Status;
 
 /**
- * @file IPluginInConfigurationService.java
- *
+ * This interface defines bridge domain configuration service methods to be
+ * implemented by protocol plugins
  */
 public interface IPluginInBridgeDomainConfigService {
     /**
index 6cd785cc2584638d4d08a380d55a3177f848f36c..525d8d179556b6dc031a4f61d1dcba687f6fc791 100644 (file)
@@ -12,6 +12,7 @@
     </description>
 
     <modules>
+        <module>sal</module>
         <module>concepts-lang</module>
     </modules>
 
     </properties>
 
     <pluginRepositories>
+        <pluginRepository>
+            <id>central</id>
+            <name>central</name>
+            <url>${nexusproxy}/repositories/central/</url>
+        </pluginRepository>
         <pluginRepository>
             <id>central2</id>
             <name>central2</name>
diff --git a/opendaylight/sal/yang-prototype/sal/model/model-flow-statistics/pom.xml b/opendaylight/sal/yang-prototype/sal/model/model-flow-statistics/pom.xml
new file mode 100644 (file)
index 0000000..98617a8
--- /dev/null
@@ -0,0 +1,26 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <artifactId>model-parent</artifactId>
+        <groupId>org.opendaylight.controller.model</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>model-flow-statistics</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>model-inventory</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>model-flow</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+    <packaging>bundle</packaging>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/model/model-flow-statistics/src/main/yang/opendaylight-flow-statistics.yang b/opendaylight/sal/yang-prototype/sal/model/model-flow-statistics/src/main/yang/opendaylight-flow-statistics.yang
new file mode 100644 (file)
index 0000000..36d8bf2
--- /dev/null
@@ -0,0 +1,82 @@
+module opendaylight-flow-statistics {
+    namespace "urn:opendaylight:flow:statistics";
+    prefix flowstat;
+
+    import yang-ext {prefix ext;}
+    import ietf-inet-types {prefix inet;}
+    import ietf-yang-types {prefix yang;}
+    import opendaylight-flow {prefix flow;}
+    import opendaylight-inventory {prefix inv;}
+
+    revision "2013-08-19" {
+        description "Initial revision of flow service";
+    }
+
+    augment "/flow:flows/flow:flow" {
+        ext:augment-identifier "flow-statistics";
+
+        leaf packet-count {
+            type uint64;
+        } 
+
+        leaf byte-count {
+            type uint64;
+        }
+
+        container duration {
+            leaf second {
+                type uint64;
+            }
+            leaf nanosecond {
+                type uint64;
+            }
+        }
+    }
+
+    augment "/inv:nodes/inv:node/inv:node-connector" {
+        ext:augment-identifier "node-connector-statistics";
+
+        container packets {
+            leaf received {
+                type uint64;
+            }
+            leaf transmitted {
+                type uint64;
+            }
+        }
+        container bytes {
+            leaf received {
+                type uint64;
+            }
+            leaf transmitted {
+                type uint64;
+            }
+        }
+        leaf receive-drops {
+            type uint64;
+        }
+        leaf transmit-drops {
+            type uint64;
+        }
+        leaf receive-errors {
+            type uint64;
+        }
+        leaf transmit-errors {
+            type uint64;
+        }
+        leaf receive-frame-error {
+            type uint64;
+        }
+        leaf receive-over-run-error {
+            type uint64;
+        }
+        leaf receive-crc-error {
+            type uint64;
+        }
+        leaf collision-count {
+            type uint64;
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/model/model-flow/pom.xml b/opendaylight/sal/yang-prototype/sal/model/model-flow/pom.xml
new file mode 100644 (file)
index 0000000..7c878fa
--- /dev/null
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <artifactId>model-parent</artifactId>
+        <groupId>org.opendaylight.controller.model</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>model-flow</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>model-inventory</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+    <packaging>bundle</packaging>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/model/model-flow/src/main/yang/opendaylight-flow.yang b/opendaylight/sal/yang-prototype/sal/model/model-flow/src/main/yang/opendaylight-flow.yang
new file mode 100644 (file)
index 0000000..1f94ef9
--- /dev/null
@@ -0,0 +1,266 @@
+module opendaylight-flow {
+    namespace "urn:opendaylight:flow:service";
+    prefix flow;
+
+    import yang-ext {prefix ext;}
+    import ietf-inet-types {prefix inet;}
+    import ietf-yang-types {prefix yang;}
+    import opendaylight-inventory {prefix inv;}
+
+    revision "2013-08-19" {
+        description "Initial revision of flow service";
+    }
+
+    /** Base structure **/
+    container flows {
+        list flow {
+            leaf node {
+                type inv:node-id;
+            }
+            container match {
+                // Match is empty
+                leaf input-node-connector {
+                    type inv:node-connector-id; //
+                }
+            }
+            list action {
+                key id;
+                leaf id {
+                    type string;
+                }
+                choice action {
+                
+                }
+            }
+        }
+    }
+
+    /** Matches **/
+    augment "/flows/flow/match" {
+        ext:augment-identifier "ethernet-match";
+        container ethernet-source {
+            description "Ethernet source address.";
+            leaf address {
+                type yang:mac-address;
+            }
+            leaf mask {
+                type binary;
+            }
+        }
+        container ethernet-destination {
+            description "Ethernet destination address.";
+            leaf address {
+                type yang:mac-address;
+            }
+        }
+        container ethernet-type {
+            description "Ethernet frame type.";
+            leaf type {
+                type uint16; // Needs to define that as general model
+            }
+            leaf mask {
+                type binary;
+            }
+        }
+    }
+
+    augment "/flows/flow/match" {
+        ext:augment-identifier "vlan-match";
+
+        container vlan-id {
+            description "VLAN id.";
+            leaf vlan-id {
+                type uint16; // TODO: Define proper vlan id type.
+            }
+            leaf mask {
+                type binary;
+            }
+        }
+        leaf vlan-pcp {
+            description "VLAN priority.";
+            type uint8; // TODO: Define PCP type
+        }
+        
+
+    }
+
+    augment "/flows/flow/match" {
+        ext:augment-identifier "ip-match";
+
+        leaf ip-protocol {
+                description "IP protocol.";
+                type uint8; // TODO define IP protocol number
+        }
+
+        leaf ip-dscp {
+            description "IP DSCP (6 bits in ToS field).";
+            type inet:dscp; // TODO: Define DSCP type
+        }
+        leaf ip-ecn {
+            description "IP ECN (2 bits in ToS field).";
+            type uint8; // TODO define ECN
+        }
+    }
+
+    augment "/flows/flow/match" {
+        ext:augment-identifier "ipv4-match";
+        leaf ipv4-source {
+            description "IPv4 source address.";
+            type inet:ipv4-prefix;
+        }
+        leaf ipv4-destination {
+            description "IPv4 destination address.";
+            type inet:ipv4-prefix;
+        }
+    }
+
+    augment "/flows/flow/match" {
+        ext:augment-identifier "ipv6-match";
+        leaf ipv6-source {
+            description "IPv6 source address.";
+            type inet:ipv6-prefix;
+        }
+        leaf ipv6-destination {
+            description "IPv6 destination address.";
+            type inet:ipv6-prefix;
+        }
+    }
+
+
+    augment "/flows/flow/match" {
+        ext:augment-identifier "udp-match";
+        
+        leaf udp-source-port {
+            description "UDP source port.";
+            type inet:port-number;
+        }
+        leaf udp-destination-port {
+            description "UDP destination port.";
+                type inet:port-number;
+        }
+    }
+
+    augment "/flows/flow/match" {
+        ext:augment-identifier "tcp-match";
+        leaf tcp-source-port {
+            description "TCP source port.";
+            type inet:port-number;
+        }
+        leaf tcp-destination-port {
+            description "TCP destination port.";
+            type inet:port-number;
+        }
+    }
+
+    augment "/flows/flow/match" {
+        ext:augment-identifier "sctp-match";
+        leaf sctp-source-port {
+            description "SCTP source port.";
+            type inet:port-number;
+        }
+        leaf sctp-destination-dst {
+            description "SCTP destination port.";
+            type inet:port-number;
+        }
+    }
+
+    augment "/flows/flow/match" {
+        ext:augment-identifier "icmpv4-match";
+        leaf icmpv4-type {
+        description "ICMP type.";
+            type uint8; // Define ICMP Type
+        }
+        description "ICMP code.";
+        leaf icmpv4-code {
+            type uint8; // Define ICMP Code
+        }
+    }
+
+    augment "/flows/flow/match" {
+        ext:augment-identifier "arp-match";
+            
+        leaf arp-source-transport-address {
+            description "ARP source IPv4 address.";
+            type inet:ipv4-prefix;
+        }
+    
+        leaf arp-target-transport-address {
+            description "ARP target IPv4 address.";
+            type inet:ipv4-prefix;
+        }
+        container arp-source-hardware-address {
+            description "ARP source hardware address.";
+            leaf address {
+                type yang:mac-address;
+            }
+            leaf mask {
+                type binary;
+            }
+        }
+        container arp-target-hardware-address {
+            description "ARP target hardware address.";
+            leaf address {
+                type yang:mac-address;
+            }
+            leaf mask {
+                type binary;
+            }
+        }
+    }
+
+    /** Actions **/
+    augment "/flows/flow/action/action" {
+        case output-action {
+            leaf output-node-connector {
+                type string;
+            }
+        }
+
+        case controller-action {
+            leaf max-length {
+                type uint16 {
+                    range "0..65294";
+                }
+            }
+        }
+
+        case set-queue-action {
+            leaf queue {
+                type string; // TODO: define queues
+            }
+        }
+
+        case pop-mpls-action {
+            container pop-mpls {
+                leaf ethernet-type {
+                    type uint16; // TODO: define ethertype type
+                }
+            }
+        }
+
+        case set-mpls-ttl-action {
+            leaf mpls-ttl {
+                type uint8;
+            }
+        }
+
+        case set-nw-ttl-action {
+            leaf nw-ttl {
+                type uint8;
+            }
+        }
+
+        case push-pbb-action {
+
+        }
+
+        case push-mpls-action {
+
+        }
+
+        case push-vlan-action {
+
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/model/model-inventory/pom.xml b/opendaylight/sal/yang-prototype/sal/model/model-inventory/pom.xml
new file mode 100644 (file)
index 0000000..0de70e3
--- /dev/null
@@ -0,0 +1,13 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <artifactId>model-parent</artifactId>
+        <groupId>org.opendaylight.controller.model</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>model-inventory</artifactId>
+    <packaging>bundle</packaging>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/model/model-inventory/src/main/yang/opendaylight-inventory.yang b/opendaylight/sal/yang-prototype/sal/model/model-inventory/src/main/yang/opendaylight-inventory.yang
new file mode 100644 (file)
index 0000000..9f2590b
--- /dev/null
@@ -0,0 +1,34 @@
+module opendaylight-inventory {
+    namespace "urn:opendaylight:inventory";
+    prefix flow;
+
+    import yang-ext {prefix ext;}
+    import ietf-inet-types {prefix inet;}
+    import ietf-yang-types {prefix yang;}
+
+
+    revision "2013-08-19" {
+        description "Initial revision of Inventory model";
+    }
+
+    typedef node-id {
+        type inet:uri;
+    }
+
+    typedef node-connector-id {
+        type inet:uri;
+    }
+
+    /** Base structure **/
+    container nodes {
+        list node {
+            key id;
+            leaf id {
+                type node-id;
+            }
+            list node-connector {
+                type node-connector-id;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/model/pom.xml b/opendaylight/sal/yang-prototype/sal/model/pom.xml
new file mode 100644 (file)
index 0000000..4ce4dcb
--- /dev/null
@@ -0,0 +1,163 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.opendaylight.controller.model</groupId>
+    <artifactId>model-parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <yang.version>0.5.7-SNAPSHOT</yang.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.bundle.version>2.4.0</maven.bundle.version>
+    </properties>
+
+    <modules>
+        <module>model-inventory</module>
+        <module>model-flow</module>
+        <module>model-flow-statistics</module>
+        <!-- <module>model-topology-bgp</module> -->
+    </modules>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${maven.bundle.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>${yang.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        target/generated-sources/sal
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.yangtools</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>0.5.7-SNAPSHOT</version>
+                        <type>jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.7</version>
+                <executions>
+                    <execution>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>target/generated-sources/sal</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <pluginManagement>
+            <plugins>
+                <!--This plugin's configuration is used to store Eclipse 
+                    m2e settings only. It has no influence on the Maven build itself. -->
+                <plugin>
+                    <groupId>org.eclipse.m2e</groupId>
+                    <artifactId>lifecycle-mapping</artifactId>
+                    <version>1.0.0</version>
+                    <configuration>
+                        <lifecycleMappingMetadata>
+                            <pluginExecutions>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>
+                                            org.opendaylight.yangtools
+                                        </groupId>
+                                        <artifactId>
+                                            yang-maven-plugin
+                                        </artifactId>
+                                        <versionRange>
+                                            [0.5,)
+                                        </versionRange>
+                                        <goals>
+                                            <goal>
+                                                generate-sources
+                                            </goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <ignore></ignore>
+                                    </action>
+                                </pluginExecution>
+                            </pluginExecutions>
+                        </lifecycleMappingMetadata>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-binding</artifactId>
+            <version>${yang.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-common</artifactId>
+            <version>${yang.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-inet-types</artifactId>
+            <version>2010.09.24-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-yang-types</artifactId>
+            <version>2010.09.24-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-ext</artifactId>
+            <version>2013.09.07-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/opendaylight/sal/yang-prototype/sal/model/src/main/yang/.gitignore b/opendaylight/sal/yang-prototype/sal/model/src/main/yang/.gitignore
new file mode 100644 (file)
index 0000000..d40e041
--- /dev/null
@@ -0,0 +1 @@
+*.yang
\ No newline at end of file
index 677372e295eab8d2479bbeef086f82b433736658..a2690826eeaeaad499d7b1f88661322fd8d0abb2 100644 (file)
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>org.opendaylight.controller</groupId>
-    <artifactId>sal</artifactId>
-    <version>1.0-SNAPSHOT</version>
-    <packaging>pom</packaging>
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <groupId>org.opendaylight.controller</groupId>
+       <artifactId>sal-parent</artifactId>
+       <version>1.0-SNAPSHOT</version>
+       <packaging>pom</packaging>
 
-    <modules>
-        <module>sal-common</module>
-        <module>sal-common-util</module>
-        <module>sal-core-api</module>
-        <module>sal-data-api</module>
-        <module>sal-binding-api</module>
-        <module>sal-binding-spi</module>
-        <module>sal-binding-broker-impl</module>
-        <module>sal-schema-repository-api</module>
-        <module>sal-core-spi</module>
-        <module>sal-broker-impl</module>
-    </modules>
+       <modules>
+               <module>sal-common</module>
+               <module>sal-common-util</module>
+               <module>sal-data-api</module>
+               <module>sal-binding-api</module>
+               <module>sal-binding-broker-impl</module>
+        <module>samples</module>
+        <module>model</module>
+       </modules>
 
-    <properties>
-        <yang.version>0.5.5-SNAPSHOT</yang.version>
-    </properties>
+       <properties>
+               <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+               <slf4j.version>1.7.2</slf4j.version>
+               <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
+               <yang.version>0.5.7-SNAPSHOT</yang.version>
+               <maven.bundle.version>2.4.0</maven.bundle.version>
+       </properties>
 
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>com.google.guava</groupId>
-                <artifactId>guava</artifactId>
-                <version>14.0.1</version>
-                <type>jar</type>
-            </dependency>
-            <dependency>
-                <groupId>org.slf4j</groupId>
-                <artifactId>slf4j-api</artifactId>
-                <version>1.7.2</version>
-            </dependency>
-            <dependency>
-                <groupId>junit</groupId>
-                <artifactId>junit</artifactId>
-                <version>4.10</version>
-            </dependency>
-            <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-binding</artifactId>
-                <version>${yang.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-common</artifactId>
-                <version>${yang.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-data-api</artifactId>
-                <version>${yang.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-model-api</artifactId>
-                <version>${yang.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-data-util</artifactId>
-                <version>${yang.version}</version>
-            </dependency>
-        </dependencies>
+    <pluginRepositories>
+        <pluginRepository>
+            <id>central</id>
+            <name>central</name>
+            <url>${nexusproxy}/repositories/central/</url>
+        </pluginRepository>
+        <pluginRepository>
+            <id>central2</id>
+            <name>central2</name>
+            <url>${nexusproxy}/repositories/central2/</url>
+        </pluginRepository>
+        <pluginRepository>
+            <id>opendaylight.snapshot</id>
+            <name>opendaylight.snapshot</name>
+            <url>${nexusproxy}/repositories/opendaylight.snapshot/</url>
+        </pluginRepository>
+    </pluginRepositories>
 
-    </dependencyManagement>
 
-    <dependencies>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <scope>test</scope>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-all</artifactId>
-            <version>1.9.5</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <version>2.0</version>
-                <inherited>true</inherited>
-                <configuration>
-                    <source>1.7</source>
-                    <target>1.7</target>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-javadoc-plugin</artifactId>
-                <version>2.8.1</version>
-                <configuration>
-                    <stylesheet>maven</stylesheet>
-                </configuration>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>aggregate</goal>
-                        </goals>
-                        <phase>site</phase>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-    <reporting>
-        <plugins>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>findbugs-maven-plugin</artifactId>
-                <version>2.4.0</version>
-                <configuration>
-                    <effort>Max</effort>
-                    <threshold>Low</threshold>
-                    <goal>site</goal>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>jdepend-maven-plugin</artifactId>
-                <version>2.0-beta-2</version>
-            </plugin>
-        </plugins>
-    </reporting>
+       <repositories>
+               <!-- EBR release -->
+               <!-- http://repository.springsource.com/maven/bundles/release -->
+               <repository>
+                       <id>ebr-bundles-release</id>
+                       <name>ebr-bundles-release</name>
+                       <url>${nexusproxy}/repositories/ebr-bundles-release/</url>
+               </repository>
+               <!-- EBR external -->
+               <!-- http://repository.springsource.com/maven/bundles/external -->
+               <repository>
+                       <id>ebr-bundles-external</id>
+                       <name>ebr-bundles-external</name>
+                       <url>${nexusproxy}/repositories/ebr-bundles-external/</url>
+               </repository>
+               <!-- Maven repo2 mirror -->
+               <!-- http://repo2.maven.org/maven2 -->
+               <repository>
+                       <id>central2</id>
+                       <name>central2</name>
+                       <url>${nexusproxy}/repositories/central2/</url>
+               </repository>
+               <!-- Maven repo1 mirror -->
+               <!-- http://repo1.maven.org/maven2 -->
+               <repository>
+                       <id>central</id>
+                       <name>central</name>
+                       <url>${nexusproxy}/repositories/central/</url>
+               </repository>
+               <!-- Pax mirror -->
+               <!-- https://oss.sonatype.org/content/repositories/ops4j-releases -->
+               <repository>
+                       <id>ops4j-releases</id>
+                       <name>ops4j-releases</name>
+                       <url>${nexusproxy}/repositories/ops4j-releases/</url>
+               </repository>
+               <!-- Third Packages hosted in local maven because not available in other 
+                       places -->
+               <repository>
+                       <id>thirdparty</id>
+                       <name>thirdparty</name>
+                       <url>${nexusproxy}/repositories/thirdparty/</url>
+               </repository>
+               <!-- Jboss mirror -->
+               <!-- https://repository.jboss.org/nexus/content/repositories/releases -->
+               <repository>
+                       <id>jboss.releases</id>
+                       <name>jboss.releases</name>
+                       <url>${nexusproxy}/repositories/jboss.releases/</url>
+               </repository>
+               <!-- OpenDayLight Released artifact -->
+               <repository>
+                       <id>opendaylight-release</id>
+                       <name>opendaylight-release</name>
+                       <url>${nexusproxy}/repositories/opendaylight.release/</url>
+               </repository>
+               <!-- OpenDayLight Snapshot artifact -->
+               <repository>
+                       <id>opendaylight-snapshot</id>
+                       <name>opendaylight-snapshot</name>
+                       <url>${nexusproxy}/repositories/opendaylight.snapshot/</url>
+               </repository>
+       </repositories>
+
+  <distributionManagement>
+    <!-- OpenDayLight Released artifact -->
+    <repository>
+      <id>opendaylight-release</id>
+      <url>${nexusproxy}/repositories/opendaylight.release/</url>
+    </repository>
+    <!-- OpenDayLight Snapshot artifact -->
+    <snapshotRepository>
+      <id>opendaylight-snapshot</id>
+      <url>${nexusproxy}/repositories/opendaylight.snapshot/</url>
+    </snapshotRepository>
+    <!-- Site deployment -->
+    <site>
+      <id>website</id>
+      <url>${sitedeploy}</url>
+    </site>
+  </distributionManagement>
+
+
+       <dependencyManagement>
+               <dependencies>
+                       <dependency>
+                               <groupId>com.google.guava</groupId>
+                               <artifactId>guava</artifactId>
+                               <version>14.0.1</version>
+                               <type>jar</type>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.slf4j</groupId>
+                               <artifactId>slf4j-api</artifactId>
+                               <version>1.7.2</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>junit</groupId>
+                               <artifactId>junit</artifactId>
+                               <version>4.10</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.opendaylight.yangtools</groupId>
+                               <artifactId>yang-binding</artifactId>
+                               <version>${yang.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.opendaylight.yangtools</groupId>
+                               <artifactId>yang-common</artifactId>
+                               <version>${yang.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.opendaylight.yangtools</groupId>
+                               <artifactId>yang-data-api</artifactId>
+                               <version>${yang.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.opendaylight.yangtools</groupId>
+                               <artifactId>yang-model-api</artifactId>
+                               <version>${yang.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.opendaylight.yangtools</groupId>
+                               <artifactId>yang-data-util</artifactId>
+                               <version>${yang.version}</version>
+                       </dependency>
+               </dependencies>
+
+       </dependencyManagement>
+
+       <dependencies>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <scope>test</scope>
+                       <optional>true</optional>
+               </dependency>
+               <dependency>
+                       <groupId>org.mockito</groupId>
+                       <artifactId>mockito-all</artifactId>
+                       <version>1.9.5</version>
+                       <scope>test</scope>
+               </dependency>
+       </dependencies>
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.felix</groupId>
+                               <artifactId>maven-bundle-plugin</artifactId>
+                               <version>${maven.bundle.version}</version>
+                               <extensions>true</extensions>
+                               <configuration>
+                                       <instructions>
+                                               <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                                       </instructions>
+                                       <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-compiler-plugin</artifactId>
+                               <version>2.0</version>
+                               <inherited>true</inherited>
+                               <configuration>
+                                       <source>1.7</source>
+                                       <target>1.7</target>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-javadoc-plugin</artifactId>
+                               <version>2.8.1</version>
+                               <configuration>
+                                       <stylesheet>maven</stylesheet>
+                               </configuration>
+                               <executions>
+                                       <execution>
+                                               <goals>
+                                                       <goal>aggregate</goal>
+                                               </goals>
+                                               <phase>site</phase>
+                                       </execution>
+                               </executions>
+                       </plugin>
+               </plugins>
+       </build>
+       <reporting>
+               <plugins>
+                       <plugin>
+                               <groupId>org.codehaus.mojo</groupId>
+                               <artifactId>findbugs-maven-plugin</artifactId>
+                               <version>2.4.0</version>
+                               <configuration>
+                                       <effort>Max</effort>
+                                       <threshold>Low</threshold>
+                                       <goal>site</goal>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.codehaus.mojo</groupId>
+                               <artifactId>jdepend-maven-plugin</artifactId>
+                               <version>2.0-beta-2</version>
+                       </plugin>
+               </plugins>
+       </reporting>
 </project>
index 92cfc3ba7aa61c46c72d8b6a9640663999dfeaa5..d94a659afac56781a7ec4f6fb9943e7384d28183 100644 (file)
@@ -1,28 +1,32 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
-    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
-    <modelVersion>4.0.0</modelVersion>\r
-    <parent>\r
-        <groupId>org.opendaylight.controller</groupId>\r
-        <artifactId>sal</artifactId>\r
-        <version>1.0-SNAPSHOT</version>\r
-    </parent>\r
-    <artifactId>sal-binding-api</artifactId>\r
-\r
-    <dependencies>\r
-        <dependency>\r
-            <groupId>org.opendaylight.controller</groupId>\r
-            <artifactId>yang-common</artifactId>\r
-\r
-        </dependency>\r
-        <dependency>\r
-            <groupId>org.opendaylight.controller</groupId>\r
-            <artifactId>yang-binding</artifactId>\r
-\r
-        </dependency>\r
-        <dependency>\r
-            <groupId>org.opendaylight.controller</groupId>\r
-            <artifactId>sal-common</artifactId>\r
-            <version>1.0-SNAPSHOT</version>\r
-        </dependency>\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>sal-binding-api</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-binding</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>5.0.0</version>
+        </dependency>
     </dependencies>
 </project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareConsumer.java b/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareConsumer.java
new file mode 100644 (file)
index 0000000..a176664
--- /dev/null
@@ -0,0 +1,27 @@
+package org.opendaylight.controller.sal.binding.api;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public abstract class AbstractBindingAwareConsumer implements BindingAwareConsumer,BundleActivator {
+
+    @Override
+    public final void start(BundleContext context) throws Exception {
+        ServiceReference<BindingAwareBroker> brokerRef = context.getServiceReference(BindingAwareBroker.class);
+        BindingAwareBroker broker = context.getService(brokerRef);
+        broker.registerConsumer(this, context);
+        startImpl(context);
+        //context.ungetService(brokerRef);
+    }
+
+    @Deprecated
+    abstract protected void startImpl(BundleContext context);
+    
+    @Override
+    public final  void stop(BundleContext context) throws Exception {
+        // TODO Auto-generated method stub
+        
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareProvider.java b/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareProvider.java
new file mode 100644 (file)
index 0000000..20a7c0d
--- /dev/null
@@ -0,0 +1,25 @@
+package org.opendaylight.controller.sal.binding.api;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public abstract class AbstractBindingAwareProvider implements BindingAwareProvider, BundleActivator {
+
+    @Override
+    public final void start(BundleContext context) throws Exception {
+            ServiceReference<BindingAwareBroker> brokerRef = context.getServiceReference(BindingAwareBroker.class);
+            BindingAwareBroker broker = context.getService(brokerRef);
+            broker.registerProvider(this, context);
+            startImpl(context);
+    }
+    
+    @Deprecated
+    abstract protected void startImpl(BundleContext context);
+    
+    @Override
+    public final void stop(BundleContext context) throws Exception {
+            
+            
+    }
+}
index 24f5b25a190b2e4d8d4876ee5eb9e9a5bd794eab..87008cd14b9e8780f4185d155a675c921467faf3 100644 (file)
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.api;\r
-\r
-import org.opendaylight.controller.yang.binding.RpcService;\r
-\r
-/**\r
- * Binding-aware core of the SAL layer responsible for wiring the SAL consumers.\r
- * \r
- * The responsibility of the broker is to maintain registration of SAL\r
- * functionality {@link Consumer}s and {@link Provider}s, store provider and\r
- * consumer specific context and functionality registration via\r
- * {@link ConsumerSession} and provide access to infrastructure services, which\r
- * removes direct dependencies between providers and consumers.\r
- * \r
- * The Binding-aware broker is also responsible for translation from Java\r
- * classes modeling the functionality and data to binding-indpenedent form which\r
- * is used in SAL Core.\r
- * \r
- * \r
- * <h3>Infrastructure services</h3> Some examples of infrastructure services:\r
- * \r
- * <ul>\r
- * <li>YANG Module service - see {@link ConsumerSession#getRpcService(Class)},\r
- * {@link ProviderSession}\r
- * <li>Notification Service - see {@link NotificationService} and\r
- * {@link NotificationProviderService}\r
- * <li>Functionality and Data model\r
- * <li>Data Store access and modification - see {@link DataBrokerService} and\r
- * {@link DataProviderService}\r
- * </ul>\r
- * \r
- * The services are exposed via session.\r
- * \r
- * <h3>Session-based access</h3>\r
- * \r
- * The providers and consumers needs to register in order to use the\r
- * binding-independent SAL layer and to expose functionality via SAL layer.\r
- * \r
- * For more information about session-based access see {@link ConsumerSession}\r
- * and {@link ProviderSession}\r
- * \r
- * \r
-\r
- * \r
- */\r
-public interface BindingAwareBroker {\r
-    /**\r
-     * Registers the {@link BindingAwareConsumer}, which will use the SAL layer.\r
-     * \r
-     * <p>\r
-     * Note that consumer could register additional functionality at later point\r
-     * by using service and functionality specific APIs.\r
-     * \r
-     * <p>\r
-     * The consumer is required to use returned session for all communication\r
-     * with broker or one of the broker services. The session is announced to\r
-     * the consumer by invoking\r
-     * {@link Consumer#onSessionInitiated(ConsumerSession)}.\r
-     * \r
-     * @param cons\r
-     *            Consumer to be registered.\r
-     * @return a session specific to consumer registration\r
-     * @throws IllegalArgumentException\r
-     *             If the consumer is <code>null</code>.\r
-     * @throws IllegalStateException\r
-     *             If the consumer is already registered.\r
-     */\r
-    ConsumerSession registerConsumer(BindingAwareConsumer consumer);\r
-\r
-    /**\r
-     * Registers the {@link BindingAwareProvider}, which will use the SAL layer.\r
-     * \r
-     * <p>\r
-     * During the registration, the broker obtains the initial functionality\r
-     * from consumer, using the\r
-     * {@link BindingAwareProvider#getImplementations()}, and register that\r
-     * functionality into system and concrete infrastructure services.\r
-     * \r
-     * <p>\r
-     * Note that provider could register additional functionality at later point\r
-     * by using service and functionality specific APIs.\r
-     * \r
-     * <p>\r
-     * The consumer is <b>required to use</b> returned session for all\r
-     * communication with broker or one of the broker services. The session is\r
-     * announced to the consumer by invoking\r
-     * {@link BindingAwareProvider#onSessionInitiated(ProviderSession)}.\r
-     * \r
-     * \r
-     * @param prov\r
-     *            Provider to be registered.\r
-     * @return a session unique to the provider registration.\r
-     * @throws IllegalArgumentException\r
-     *             If the provider is <code>null</code>.\r
-     * @throws IllegalStateException\r
-     *             If the consumer is already registered.\r
-     */\r
-    ProviderSession registerProvider(BindingAwareProvider provider);\r
-\r
-    /**\r
-     * {@link BindingAwareConsumer} specific access to the SAL functionality.\r
-     * \r
-     * <p>\r
-     * ConsumerSession is {@link BindingAwareConsumer}-specific access to the\r
-     * SAL functionality and infrastructure services.\r
-     * \r
-     * <p>\r
-     * The session serves to store SAL context (e.g. registration of\r
-     * functionality) for the consumer and provides access to the SAL\r
-     * infrastructure services and other functionality provided by\r
-     * {@link Provider}s.\r
-     * \r
-\r
-     * \r
-     */\r
-    public interface ConsumerSession {\r
-\r
-        /**\r
-         * Returns a session specific instance (implementation) of requested\r
-         * binding-aware infrastructural service\r
-         * \r
-         * @param service\r
-         *            Broker service\r
-         * @return Session specific implementation of service\r
-         */\r
-        <T extends BindingAwareService> T getSALService(Class<T> service);\r
-\r
-        /**\r
-         * Returns a session specific instance (implementation) of requested\r
-         * YANG module implentation / service provided by consumer.\r
-         * \r
-         * @param service\r
-         *            Broker service\r
-         * @return Session specific implementation of service\r
-         */\r
-        <T extends RpcService> T getRpcService(Class<T> module);\r
-    }\r
-\r
-    /**\r
-     * {@link BindingAwareProvider} specific access to the SAL functionality.\r
-     * \r
-     * <p>\r
-     * ProviderSession is {@link BindingAwareProvider}-specific access to the\r
-     * SAL functionality and infrastructure services, which also allows for\r
-     * exposing the provider's functionality to the other\r
-     * {@link BindingAwareConsumer}s.\r
-     * \r
-     * <p>\r
-     * The session serves to store SAL context (e.g. registration of\r
-     * functionality) for the providers and exposes access to the SAL\r
-     * infrastructure services, dynamic functionality registration and any other\r
-     * functionality provided by other {@link BindingAwareConsumer}s.\r
-     * \r
-     */\r
-    public interface ProviderSession extends ConsumerSession {\r
-\r
-        void addRpcImplementation(RpcService implementation);\r
-\r
-        void removeRpcImplementation(RpcService implementation);\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.api;
 
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Binding-aware core of the SAL layer responsible for wiring the SAL consumers.
+ * 
+ * The responsibility of the broker is to maintain registration of SAL
+ * functionality {@link Consumer}s and {@link Provider}s, store provider and
+ * consumer specific context and functionality registration via
+ * {@link ConsumerContext} and provide access to infrastructure services, which
+ * removes direct dependencies between providers and consumers.
+ * 
+ * The Binding-aware broker is also responsible for translation from Java
+ * classes modeling the functionality and data to binding-indpenedent form which
+ * is used in SAL Core.
+ * 
+ * 
+ * <h3>Infrastructure services</h3> Some examples of infrastructure services:
+ * 
+ * <ul>
+ * <li>YANG Module service - see {@link ConsumerContext#getRpcService(Class)},
+ * {@link ProviderContext}
+ * <li>Notification Service - see {@link NotificationService} and
+ * {@link NotificationProviderService}
+ * <li>Functionality and Data model
+ * <li>Data Store access and modification - see {@link DataBrokerService} and
+ * {@link DataProviderService}
+ * </ul>
+ * 
+ * The services are exposed via session.
+ * 
+ * <h3>Session-based access</h3>
+ * 
+ * The providers and consumers needs to register in order to use the
+ * binding-independent SAL layer and to expose functionality via SAL layer.
+ * 
+ * For more information about session-based access see {@link ConsumerContext}
+ * and {@link ProviderContext}
+ * 
+ * 
+ * 
+ */
+public interface BindingAwareBroker {
+    /**
+     * Registers the {@link BindingAwareConsumer}, which will use the SAL layer.
+     * 
+     * <p>
+     * Note that consumer could register additional functionality at later point
+     * by using service and functionality specific APIs.
+     * 
+     * <p>
+     * The consumer is required to use returned session for all communication
+     * with broker or one of the broker services. The session is announced to
+     * the consumer by invoking
+     * {@link Consumer#onSessionInitiated(ConsumerContext)}.
+     * 
+     * @param cons
+     *            Consumer to be registered.
+     * @return a session specific to consumer registration
+     * @throws IllegalArgumentException
+     *             If the consumer is <code>null</code>.
+     * @throws IllegalStateException
+     *             If the consumer is already registered.
+     */
+    ConsumerContext registerConsumer(BindingAwareConsumer consumer, BundleContext ctx);
+
+    /**
+     * Registers the {@link BindingAwareProvider}, which will use the SAL layer.
+     * 
+     * <p>
+     * During the registration, the broker obtains the initial functionality
+     * from consumer, using the
+     * {@link BindingAwareProvider#getImplementations()}, and register that
+     * functionality into system and concrete infrastructure services.
+     * 
+     * <p>
+     * Note that provider could register additional functionality at later point
+     * by using service and functionality specific APIs.
+     * 
+     * <p>
+     * The consumer is <b>required to use</b> returned session for all
+     * communication with broker or one of the broker services. The session is
+     * announced to the consumer by invoking
+     * {@link BindingAwareProvider#onSessionInitiated(ProviderContext)}.
+     * 
+     * 
+     * @param prov
+     *            Provider to be registered.
+     * @return a session unique to the provider registration.
+     * @throws IllegalArgumentException
+     *             If the provider is <code>null</code>.
+     * @throws IllegalStateException
+     *             If the consumer is already registered.
+     */
+    ProviderContext registerProvider(BindingAwareProvider provider, BundleContext ctx);
+
+    /**
+     * {@link BindingAwareConsumer} specific access to the SAL functionality.
+     * 
+     * <p>
+     * ConsumerSession is {@link BindingAwareConsumer}-specific access to the
+     * SAL functionality and infrastructure services.
+     * 
+     * <p>
+     * The session serves to store SAL context (e.g. registration of
+     * functionality) for the consumer and provides access to the SAL
+     * infrastructure services and other functionality provided by
+     * {@link Provider}s.
+     * 
+     * 
+     * 
+     */
+    public interface ConsumerContext {
+
+        /**
+         * Returns a session specific instance (implementation) of requested
+         * binding-aware infrastructural service
+         * 
+         * @param service
+         *            Broker service
+         * @return Session specific implementation of service
+         */
+        <T extends BindingAwareService> T getSALService(Class<T> service);
+
+        /**
+         * Returns a session specific instance (implementation) of requested
+         * YANG module implentation / service provided by consumer.
+         * 
+         * @param service
+         *            Broker service
+         * @return Session specific implementation of service
+         */
+        <T extends RpcService> T getRpcService(Class<T> module);
+    }
+
+    /**
+     * {@link BindingAwareProvider} specific access to the SAL functionality.
+     * 
+     * <p>
+     * ProviderSession is {@link BindingAwareProvider}-specific access to the
+     * SAL functionality and infrastructure services, which also allows for
+     * exposing the provider's functionality to the other
+     * {@link BindingAwareConsumer}s.
+     * 
+     * <p>
+     * The session serves to store SAL context (e.g. registration of
+     * functionality) for the providers and exposes access to the SAL
+     * infrastructure services, dynamic functionality registration and any other
+     * functionality provided by other {@link BindingAwareConsumer}s.
+     * 
+     */
+    public interface ProviderContext extends ConsumerContext {
+
+        <T extends RpcService> RpcServiceRegistration<T> addRpcImplementation(Class<T> type, T implementation);
+    }
+
+    public interface RpcServiceRegistration<T extends RpcService> {
+
+        T getService();
+
+        void unregister();
+    }
+}
index e32f8bc9f9fd23e29e722da7d6b221d143bded5f..fc297261b780f3b173604be2c9c4ca751324e2cc 100644 (file)
@@ -1,40 +1,40 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.api;\r
-\r
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerSession;\r
-\r
-/**\r
- * \r
- * Defines the component of controller and supplies additional metadata. A\r
- * component of the controller or application supplies a concrete implementation\r
- * of this interface.\r
- * \r
- * A user-implemented component (application) which faciliates the SAL and SAL\r
- * services to access infrastructure services or providers' functionality.\r
- * \r
-\r
- * \r
- */\r
-public interface BindingAwareConsumer {\r
-\r
-    /**\r
-     * Callback signaling initialization of the consumer session to the SAL.\r
-     * \r
-     * The consumer MUST use the session for all communication with SAL or\r
-     * retrieving SAL infrastructure services.\r
-     * \r
-     * This method is invoked by\r
-     * {@link BindingAwareBroker#registerConsumer(BindingAwareConsumer)}\r
-     * \r
-     * @param session\r
-     *            Unique session between consumer and SAL.\r
-     */\r
-    void onSessionInitialized(ConsumerSession session);\r
-\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.api;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+
+/**
+ * 
+ * Defines the component of controller and supplies additional metadata. A
+ * component of the controller or application supplies a concrete implementation
+ * of this interface.
+ * 
+ * A user-implemented component (application) which faciliates the SAL and SAL
+ * services to access infrastructure services or providers' functionality.
+ * 
+ * 
+ * 
+ */
+public interface BindingAwareConsumer {
+
+    /**
+     * Callback signaling initialization of the consumer session to the SAL.
+     * 
+     * The consumer MUST use the session for all communication with SAL or
+     * retrieving SAL infrastructure services.
+     * 
+     * This method is invoked by
+     * {@link BindingAwareBroker#registerConsumer(BindingAwareConsumer)}
+     * 
+     * @param session
+     *            Unique session between consumer and SAL.
+     */
+    void onSessionInitialized(ConsumerContext session);
+
+}
index d324b83c5330b517d34447442313577c4163fd5a..3641d7697042a7f53d8f5f01058dcd8c724d4be4 100644 (file)
@@ -1,72 +1,69 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.api;\r
-\r
-import java.util.Collection;\r
-\r
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerSession;\r
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderSession;\r
-import org.opendaylight.controller.yang.binding.RpcService;\r
-\r
-\r
-/**\r
- * \r
- * Defines the component of controller and supplies additional metadata. A\r
- * component of the controller or application supplies a concrete implementation\r
- * of this interface.\r
- * \r
- * <p>\r
- * A user-implemented component (application) which facilitates the SAL and SAL\r
- * services to access infrastructure services and to provide functionality to\r
- * {@link Consumer}s and other providers.\r
- * \r
-\r
- * \r
- */\r
-public interface BindingAwareProvider {\r
-\r
-    void onSessionInitialized(ConsumerSession session);\r
-\r
-    /**\r
-     * Returns a set of provided implementations of YANG modules and their rpcs.\r
-     * \r
-     * \r
-     * @return Set of provided implementation of YANG modules and their Rpcs\r
-     */\r
-    Collection<? extends RpcService> getImplementations();\r
-\r
-    /**\r
-     * Gets a set of implementations of provider functionality to be registered\r
-     * into system during the provider registration to the SAL.\r
-     * \r
-     * <p>\r
-     * This method is invoked by {@link Broker#registerProvider(Provider)} to\r
-     * learn the initial provided functionality\r
-     * \r
-     * @return Set of provider's functionality.\r
-     */\r
-    Collection<? extends ProviderFunctionality> getFunctionality();\r
-\r
-    /**\r
-     * Functionality provided by the {@link BindingAwareProvider}\r
-     * \r
-     * <p>\r
-     * Marker interface used to mark the interfaces describing specific\r
-     * functionality which could be exposed by providers to other components.\r
-     * \r
-\r
-     * \r
-     */\r
-    public interface ProviderFunctionality {\r
-\r
-    }\r
-\r
-    void onSessionInitiated(ProviderSession session);\r
-\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.api;
 
+import java.util.Collection;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+
+/**
+ * 
+ * Defines the component of controller and supplies additional metadata. A
+ * component of the controller or application supplies a concrete implementation
+ * of this interface.
+ * 
+ * <p>
+ * A user-implemented component (application) which facilitates the SAL and SAL
+ * services to access infrastructure services and to provide functionality to
+ * {@link Consumer}s and other providers.
+ * 
+ * 
+ */
+public interface BindingAwareProvider {
+
+    void onSessionInitialized(ConsumerContext session);
+
+    /**
+     * Returns a set of provided implementations of YANG modules and their rpcs.
+     * 
+     * 
+     * @return Set of provided implementation of YANG modules and their Rpcs
+     */
+    Collection<? extends RpcService> getImplementations();
+
+    /**
+     * Gets a set of implementations of provider functionality to be registered
+     * into system during the provider registration to the SAL.
+     * 
+     * <p>
+     * This method is invoked by {@link Broker#registerProvider(Provider)} to
+     * learn the initial provided functionality
+     * 
+     * @return Set of provider's functionality.
+     */
+    Collection<? extends ProviderFunctionality> getFunctionality();
+
+    /**
+     * Functionality provided by the {@link BindingAwareProvider}
+     * 
+     * <p>
+     * Marker interface used to mark the interfaces describing specific
+     * functionality which could be exposed by providers to other components.
+     * 
+     * 
+     * 
+     */
+    public interface ProviderFunctionality {
+
+    }
+
+    void onSessionInitiated(ProviderContext session);
+
+}
index e4d86e7bfdab8c7418ae8ffde41bf4b532baf09f..b3680568bba9a9d1ed3ae59bc3eb0e03d4eaf17a 100644 (file)
@@ -1,40 +1,40 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.api;\r
-\r
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerSession;\r
-\r
-/**\r
- * \r
- * Session-specific instance of the broker functionality.\r
- * \r
- * <p>\r
- * BindingAwareService is marker interface for infrastructure services provided\r
- * by the SAL. These services are session-specific, each\r
- * {@link BindingAwareConsumer} and {@link BindingAwareProvider} usually has own\r
- * instance of the service with it's own context.\r
- * \r
- * <p>\r
- * The consumer's (or provider's) instance of specific service could be obtained\r
- * by invoking {@link ConsumerSession#getSALService(Class)} method on session\r
- * assigned to the consumer.\r
- * \r
- * <p>\r
- * {@link BindingAwareService} and {@link BindingAwareProvider} may seem\r
- * similar, but provider provides YANG model-based functionality and\r
- * {@link BindingAwareProvider} exposes the necessary supporting functionality\r
- * to implement specific functionality of YANG and to reuse it in the\r
- * development of {@link BindingAwareConsumer}s and {@link BindingAwareProvider}\r
- * s.\r
- * \r
-\r
- * \r
- */\r
-public interface BindingAwareService {\r
-\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.api;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+
+/**
+ * 
+ * Session-specific instance of the broker functionality.
+ * 
+ * <p>
+ * BindingAwareService is marker interface for infrastructure services provided
+ * by the SAL. These services are session-specific, each
+ * {@link BindingAwareConsumer} and {@link BindingAwareProvider} usually has own
+ * instance of the service with it's own context.
+ * 
+ * <p>
+ * The consumer's (or provider's) instance of specific service could be obtained
+ * by invoking {@link ConsumerContext#getSALService(Class)} method on session
+ * assigned to the consumer.
+ * 
+ * <p>
+ * {@link BindingAwareService} and {@link BindingAwareProvider} may seem
+ * similar, but provider provides YANG model-based functionality and
+ * {@link BindingAwareProvider} exposes the necessary supporting functionality
+ * to implement specific functionality of YANG and to reuse it in the
+ * development of {@link BindingAwareConsumer}s and {@link BindingAwareProvider}
+ * s.
+ * 
+ * 
+ * 
+ */
+public interface BindingAwareService {
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationListener.java b/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationListener.java
new file mode 100644 (file)
index 0000000..ccc7391
--- /dev/null
@@ -0,0 +1,6 @@
+package org.opendaylight.controller.sal.binding.api;
+
+public interface NotificationListener<T> {
+
+    void onNotification(T notification);
+}
index c5fc405f512a5260f0e948292a7759780195bedd..86c9eebecd0b9b17b78c957e7ef30ecead94a0a5 100644 (file)
@@ -1,15 +1,15 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.api;\r
-\r
-import org.opendaylight.controller.yang.binding.Notification;\r
-\r
-public interface NotificationProviderService extends NotificationService {\r
-\r
-    void notify(Notification notification);\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.api;
+
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public interface NotificationProviderService extends NotificationService {
+
+    void notify(Notification notification);
+}
index 92e30a52361de9f3650ed5c8dc281f1e2d9c31d6..3723c70e8c371115e44b1bf5f0bbeaa9e7da225a 100644 (file)
@@ -1,22 +1,17 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.api;\r
-\r
-import org.opendaylight.controller.yang.binding.Notification;\r
-import org.opendaylight.controller.yang.binding.NotificationListener;\r
-\r
-public interface NotificationService extends BindingAwareService {\r
-\r
-    void addNotificationListener(\r
-            Class<? extends Notification> notificationType,\r
-            NotificationListener listener);\r
-\r
-    void removeNotificationListener(\r
-            Class<? extends Notification> notificationType,\r
-            NotificationListener listener);\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.api;
+
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public interface NotificationService extends BindingAwareService {
+
+    <T extends Notification> void addNotificationListener(Class<T> notificationType, NotificationListener<T> listener);
+
+    <T extends Notification> void removeNotificationListener(Class<T> notificationType, NotificationListener<T> listener);
+}
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.api;\r
-\r
-import java.util.concurrent.Future;\r
-\r
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;\r
-import org.opendaylight.controller.yang.binding.DataRoot;\r
-import org.opendaylight.controller.yang.common.RpcResult;\r
-\r
-\r
-/**\r
- * DataBrokerService provides unified access to the data stores available in the\r
- * system.\r
- * \r
- * \r
- * @see DataProviderService\r
-\r
- */\r
-public interface DataBrokerService extends BindingAwareService {\r
-\r
-    /**\r
-     * Returns a data from specified Data Store.\r
-     * \r
-     * Returns all the data visible to the consumer from specified Data Store.\r
-     * \r
-     * @param <T>\r
-     *            Interface generated from YANG module representing root of data\r
-     * @param store\r
-     *            Identifier of the store, from which will be data retrieved\r
-     * @return data visible to the consumer\r
-     */\r
-    <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType);\r
-\r
-    /**\r
-     * Returns a filtered subset of data from specified Data Store.\r
-     * \r
-     * <p>\r
-     * The filter is modeled as an hierarchy of Java TOs starting with\r
-     * implementation of {@link DataRoot} representing data root. The semantics\r
-     * of the filter tree is the same as filter semantics defined in the NETCONF\r
-     * protocol for rpc operations <code>get</code> and <code>get-config</code>\r
-     * in Section 6 of RFC6241.\r
-     * \r
-     * \r
-     * @see http://tools.ietf.org/html/rfc6241#section-6\r
-     * @param <T>\r
-     *            Interface generated from YANG module representing root of data\r
-     * @param store\r
-     *            Identifier of the store, from which will be data retrieved\r
-     * @param filter\r
-     *            Data tree filter similar to the NETCONF filter\r
-     * @return\r
-     */\r
-    <T extends DataRoot> T getData(DataStoreIdentifier store, T filter);\r
-\r
-    /**\r
-     * Returns a candidate data which are not yet commited.\r
-     * \r
-     * \r
-     * @param <T>\r
-     *            Interface generated from YANG module representing root of data\r
-     * @param store\r
-     *            Identifier of the store, from which will be data retrieved\r
-     * @return\r
-     */\r
-    <T extends DataRoot> T getCandidateData(DataStoreIdentifier store,\r
-            Class<T> rootType);\r
-\r
-    /**\r
-     * Returns a filtered subset of candidate data from specified Data Store.\r
-     * \r
-     * <p>\r
-     * The filter is modeled as an hierarchy of {@link Node} starting with\r
-     * {@link CompositeNode} representing data root. The semantics of the filter\r
-     * tree is the same as filter semantics defined in the NETCONF protocol for\r
-     * rpc operations <code>get</code> and <code>get-config</code> in Section 6\r
-     * of RFC6241.\r
-     * \r
-     * \r
-     * @see http://tools.ietf.org/html/rfc6241#section-6\r
-     * @param <T>\r
-     *            Interface generated from YANG module representing root of data\r
-     * @param store\r
-     *            Identifier of the store, from which will be data retrieved\r
-     * @param filter\r
-     *            A filter data root\r
-     * @return\r
-     */\r
-    <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter);\r
-\r
-    /**\r
-     * \r
-     * @param <T>\r
-     *            Interface generated from YANG module representing root of data\r
-     * @param store\r
-     *            Identifier of the store, in which will be the candidate data\r
-     *            modified\r
-     * @param changeSet\r
-     *            Modification of data tree.\r
-     * @return Result object containing the modified data tree if the operation\r
-     *         was successful, otherwise list of the encountered errors.\r
-     */\r
-    RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store,\r
-            DataRoot changeSet);\r
-\r
-    /**\r
-     * Initiates a two-phase commit of candidate data.\r
-     * \r
-     * <p>\r
-     * The {@link Consumer} could initiate a commit of candidate data\r
-     * \r
-     * <p>\r
-     * The successful commit changes the state of the system and may affect\r
-     * several components.\r
-     * \r
-     * <p>\r
-     * The effects of successful commit of data are described in the\r
-     * specifications and YANG models describing the {@link Provider} components\r
-     * of controller. It is assumed that {@link Consumer} has an understanding\r
-     * of this changes.\r
-     * \r
-     * \r
-     * @see DataCommitHandler for further information how two-phase commit is\r
-     *      processed.\r
-     * @param store\r
-     *            Identifier of the store, where commit should occur.\r
-     * @return Result of the commit, containing success information or list of\r
-     *         encountered errors, if commit was not successful.\r
-     */\r
-    Future<RpcResult<Void>> commit(DataStoreIdentifier store);\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.api.data;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareService;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.yangtools.yang.binding.DataRoot;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+/**
+ * DataBrokerService provides unified access to the data stores available in the
+ * system.
+ * 
+ * 
+ * @see DataProviderService
+ */
+public interface DataBrokerService extends BindingAwareService {
+
+    /**
+     * Returns a data from specified Data Store.
+     * 
+     * Returns all the data visible to the consumer from specified Data Store.
+     * 
+     * @param <T>
+     *            Interface generated from YANG module representing root of data
+     * @param store
+     *            Identifier of the store, from which will be data retrieved
+     * @return data visible to the consumer
+     */
+    <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType);
+
+    /**
+     * Returns a filtered subset of data from specified Data Store.
+     * 
+     * <p>
+     * The filter is modeled as an hierarchy of Java TOs starting with
+     * implementation of {@link DataRoot} representing data root. The semantics
+     * of the filter tree is the same as filter semantics defined in the NETCONF
+     * protocol for rpc operations <code>get</code> and <code>get-config</code>
+     * in Section 6 of RFC6241.
+     * 
+     * 
+     * @see http://tools.ietf.org/html/rfc6241#section-6
+     * @param <T>
+     *            Interface generated from YANG module representing root of data
+     * @param store
+     *            Identifier of the store, from which will be data retrieved
+     * @param filter
+     *            Data tree filter similar to the NETCONF filter
+     * @return
+     */
+    <T extends DataRoot> T getData(DataStoreIdentifier store, T filter);
+
+    /**
+     * Returns a candidate data which are not yet commited.
+     * 
+     * 
+     * @param <T>
+     *            Interface generated from YANG module representing root of data
+     * @param store
+     *            Identifier of the store, from which will be data retrieved
+     * @return
+     */
+    <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType);
+
+    /**
+     * Returns a filtered subset of candidate data from specified Data Store.
+     * 
+     * <p>
+     * The filter is modeled as an hierarchy of {@link Node} starting with
+     * {@link CompositeNode} representing data root. The semantics of the filter
+     * tree is the same as filter semantics defined in the NETCONF protocol for
+     * rpc operations <code>get</code> and <code>get-config</code> in Section 6
+     * of RFC6241.
+     * 
+     * 
+     * @see http://tools.ietf.org/html/rfc6241#section-6
+     * @param <T>
+     *            Interface generated from YANG module representing root of data
+     * @param store
+     *            Identifier of the store, from which will be data retrieved
+     * @param filter
+     *            A filter data root
+     * @return
+     */
+    <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter);
+
+    /**
+     * 
+     * @param <T>
+     *            Interface generated from YANG module representing root of data
+     * @param store
+     *            Identifier of the store, in which will be the candidate data
+     *            modified
+     * @param changeSet
+     *            Modification of data tree.
+     * @return Result object containing the modified data tree if the operation
+     *         was successful, otherwise list of the encountered errors.
+     */
+    RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet);
+
+    /**
+     * Initiates a two-phase commit of candidate data.
+     * 
+     * <p>
+     * The {@link Consumer} could initiate a commit of candidate data
+     * 
+     * <p>
+     * The successful commit changes the state of the system and may affect
+     * several components.
+     * 
+     * <p>
+     * The effects of successful commit of data are described in the
+     * specifications and YANG models describing the {@link Provider} components
+     * of controller. It is assumed that {@link Consumer} has an understanding
+     * of this changes.
+     * 
+     * 
+     * @see DataCommitHandler for further information how two-phase commit is
+     *      processed.
+     * @param store
+     *            Identifier of the store, where commit should occur.
+     * @return Result of the commit, containing success information or list of
+     *         encountered errors, if commit was not successful.
+     */
+    Future<RpcResult<Void>> commit(DataStoreIdentifier store);
+}
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.api;\r
-\r
-import java.util.Set;\r
-\r
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;\r
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;\r
-import org.opendaylight.controller.yang.common.RpcResult;\r
-\r
-\r
-/**\r
- * Two phase commit handler (cohort) of the two-phase commit protocol of data.\r
- * \r
- * <p>\r
- * The provider should expose the implementation of DataCommitHandler if it's\r
- * functionality depends on any subset of data stored in data repositories, in\r
- * order to participate in {@link DataBrokerService#commit(DataStoreIdentifier)\r
- * operation.\r
- * \r
- * <p>\r
- * Operations of two-phase commit handlers should not change data in data store,\r
- * this is responsibility of the coordinator (broker or some component of the\r
- * broker).\r
- * \r
- * The commit handlers are responsible for changing the internal state of the\r
- * provider to reflect the commited changes in data.\r
- * \r
- * <h3>Two-phase commit</h3>\r
- * \r
- * <h4>Commit Request Phase</h4>\r
- * \r
- * <ol>\r
- * <li> <code>Consumer</code> edits data by invocation of\r
- * <code>DataBrokerService.editCandidateData(DataStoreIdentifier, DataRoot)</code>\r
- * <li> <code>Consumer</code> starts a commit by invoking\r
- * <code>DataBrokerService.commit(DataStoreIdentifier)</code>\r
- * <li> <code>Broker</code> retrieves a list of all registered\r
- * <code>DataCommitHandlers</code>\r
- * <li>For each <code>DataCommitHandler</code>\r
- * <ol>\r
- * <li><code>Broker</code> invokes a\r
- * <code>DataCommitHandler.requestCommit(DataStoreIdentifier)</code> operation.\r
- * <li><code>DataCommitHandler</code> returns a <code>RpcResult</code> with\r
- * <code>CommitTransaction</code>\r
- * <li>If the result was successful, broker adds <code>CommitTransaction</code>\r
- * to the list of opened transactions. If not, brokers stops a commit request\r
- * phase and starts a rollback phase.\r
- * </ol>\r
- * <li><code>Broker</code> starts a commit finish phase\r
- * </ol>\r
- * \r
- * <h4>Commit Finish Phase</h4>\r
- * \r
- * <ol>\r
- * <li>For each <code>CommitTransaction</code> from Commit Request phase\r
- * <ol>\r
- * <li><code>Broker</code> broker invokes a\r
- * <code>CommitTransaction.finish()</code>\r
- * <li>The provider finishes a commit (applies the change) and returns an\r
- * <code>RpcResult</code>.\r
- * </ol>\r
- * <li>\r
- * <ul>\r
- * <li>If all returned results means successful, the brokers end two-phase\r
- * commit by returning a success commit result to the Consumer.\r
- * <li>If error occured, the broker starts a commit rollback phase.\r
- * </ul>\r
- * </ol>\r
- * \r
- * <h4>Commit Rollback Phase</h4>\r
- * <li>For each <code>CommitTransaction</code> from Commit Request phase\r
- * <ol>\r
- * <li><code>Broker</code>\r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * \r
- * broker invokes a {@link CommitTransaction#finish()}\r
- * <li>The provider rollbacks a commit and returns an {@link RpcResult} of\r
- * rollback. </ol>\r
- * <li>Broker returns a error result to the consumer.\r
- * \r
- * \r
- * <h3>Registration of functionality</h3>\r
- * The registration could be done by :\r
- * <ul>\r
- * <li>returning an instance of implementation in the return value of\r
- * {@link Provider#getProviderFunctionality()}\r
- * <li>passing an instance of implementation and {@link DataStoreIdentifier} of\r
- * rpc as arguments to the\r
- * {@link DataProviderService#addCommitHandler(DataStoreIdentifier, DataCommitHandler)}\r
- * </ul>\r
- * \r
-\r
- * \r
- */\r
-public interface DataCommitHandler extends ProviderFunctionality {\r
-    /**\r
-     * A set of Data Stores supported by implementation.\r
-     * \r
-     * The set of {@link DataStoreIdentifier}s which identifies target data\r
-     * stores which are supported by this commit handler. This set is used, when\r
-     * {@link Provider} is registered to the SAL, to register and expose the\r
-     * commit handler functionality to affected data stores.\r
-     * \r
-     * @return Set of Data Store identifiers\r
-     */\r
-    Set<DataStoreIdentifier> getSupportedDataStores();\r
-\r
-    /**\r
-     * The provider (commit handler) starts a commit transaction.\r
-     * \r
-     * <p>\r
-     * The commit handler (provider) prepares an commit scenario, rollback\r
-     * scenario and validates data.\r
-     * \r
-     * <p>\r
-     * If the provider is aware that at this point the commit would not be\r
-     * successful, the transaction is not created, but list of errors which\r
-     * prevented the start of transaction are returned.\r
-     * \r
-     * @param store\r
-     * @return Transaction object representing this commit, errors otherwise.\r
-     */\r
-    RpcResult<CommitTransaction> requestCommit(DataStoreIdentifier store);\r
-\r
-    public interface CommitTransaction {\r
-        /**\r
-         * \r
-         * @return Data store affected by the transaction\r
-         */\r
-        DataStoreIdentifier getDataStore();\r
-\r
-        /**\r
-         * Returns the handler associated with this transaction.\r
-         * \r
-         * @return Handler\r
-         */\r
-        DataCommitHandler getHandler();\r
-\r
-        /**\r
-         * \r
-         * Finishes a commit.\r
-         * \r
-         * The provider (commit handler) should apply all changes to its state\r
-         * which are a result of data change-\r
-         * \r
-         * @return\r
-         */\r
-        RpcResult<Void> finish() throws IllegalStateException;\r
-\r
-        /**\r
-         * Rollbacks a commit.\r
-         * \r
-         * @return\r
-         * @throws IllegalStateException\r
-         *             If the method is invoked after {@link #finish()}\r
-         */\r
-        RpcResult<Void> rollback() throws IllegalStateException;\r
-    }\r
-\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.api.data;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+/**
+ * Two phase commit handler (cohort) of the two-phase commit protocol of data.
+ * 
+ * <p>
+ * The provider should expose the implementation of DataCommitHandler if it's
+ * functionality depends on any subset of data stored in data repositories, in
+ * order to participate in {@link DataBrokerService#commit(DataStoreIdentifier)
+ * operation.
+ * 
+ * <p>
+ * Operations of two-phase commit handlers should not change data in data store,
+ * this is responsibility of the coordinator (broker or some component of the
+ * broker).
+ * 
+ * The commit handlers are responsible for changing the internal state of the
+ * provider to reflect the commited changes in data.
+ * 
+ * <h3>Two-phase commit</h3>
+ * 
+ * <h4>Commit Request Phase</h4>
+ * 
+ * <ol>
+ * <li> <code>Consumer</code> edits data by invocation of
+ * <code>DataBrokerService.editCandidateData(DataStoreIdentifier, DataRoot)</code>
+ * <li> <code>Consumer</code> starts a commit by invoking
+ * <code>DataBrokerService.commit(DataStoreIdentifier)</code>
+ * <li> <code>Broker</code> retrieves a list of all registered
+ * <code>DataCommitHandlers</code>
+ * <li>For each <code>DataCommitHandler</code>
+ * <ol>
+ * <li><code>Broker</code> invokes a
+ * <code>DataCommitHandler.requestCommit(DataStoreIdentifier)</code> operation.
+ * <li><code>DataCommitHandler</code> returns a <code>RpcResult</code> with
+ * <code>CommitTransaction</code>
+ * <li>If the result was successful, broker adds <code>CommitTransaction</code>
+ * to the list of opened transactions. If not, brokers stops a commit request
+ * phase and starts a rollback phase.
+ * </ol>
+ * <li><code>Broker</code> starts a commit finish phase
+ * </ol>
+ * 
+ * <h4>Commit Finish Phase</h4>
+ * 
+ * <ol>
+ * <li>For each <code>CommitTransaction</code> from Commit Request phase
+ * <ol>
+ * <li><code>Broker</code> broker invokes a
+ * <code>CommitTransaction.finish()</code>
+ * <li>The provider finishes a commit (applies the change) and returns an
+ * <code>RpcResult</code>.
+ * </ol>
+ * <li>
+ * <ul>
+ * <li>If all returned results means successful, the brokers end two-phase
+ * commit by returning a success commit result to the Consumer.
+ * <li>If error occured, the broker starts a commit rollback phase.
+ * </ul>
+ * </ol>
+ * 
+ * <h4>Commit Rollback Phase</h4>
+ * <li>For each <code>CommitTransaction</code> from Commit Request phase
+ * <ol>
+ * <li><code>Broker</code>
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * broker invokes a {@link CommitTransaction#finish()}
+ * <li>The provider rollbacks a commit and returns an {@link RpcResult} of
+ * rollback. </ol>
+ * <li>Broker returns a error result to the consumer.
+ * 
+ * 
+ * <h3>Registration of functionality</h3>
+ * The registration could be done by :
+ * <ul>
+ * <li>returning an instance of implementation in the return value of
+ * {@link Provider#getProviderFunctionality()}
+ * <li>passing an instance of implementation and {@link DataStoreIdentifier} of
+ * rpc as arguments to the
+ * {@link DataProviderService#addCommitHandler(DataStoreIdentifier, DataCommitHandler)}
+ * </ul>
+ * 
+ * 
+ * 
+ */
+public interface DataCommitHandler extends ProviderFunctionality {
+    /**
+     * A set of Data Stores supported by implementation.
+     * 
+     * The set of {@link DataStoreIdentifier}s which identifies target data
+     * stores which are supported by this commit handler. This set is used, when
+     * {@link Provider} is registered to the SAL, to register and expose the
+     * commit handler functionality to affected data stores.
+     * 
+     * @return Set of Data Store identifiers
+     */
+    Set<DataStoreIdentifier> getSupportedDataStores();
+
+    /**
+     * The provider (commit handler) starts a commit transaction.
+     * 
+     * <p>
+     * The commit handler (provider) prepares an commit scenario, rollback
+     * scenario and validates data.
+     * 
+     * <p>
+     * If the provider is aware that at this point the commit would not be
+     * successful, the transaction is not created, but list of errors which
+     * prevented the start of transaction are returned.
+     * 
+     * @param store
+     * @return Transaction object representing this commit, errors otherwise.
+     */
+    RpcResult<CommitTransaction> requestCommit(DataStoreIdentifier store);
+
+    public interface CommitTransaction {
+        /**
+         * 
+         * @return Data store affected by the transaction
+         */
+        DataStoreIdentifier getDataStore();
+
+        /**
+         * Returns the handler associated with this transaction.
+         * 
+         * @return Handler
+         */
+        DataCommitHandler getHandler();
+
+        /**
+         * 
+         * Finishes a commit.
+         * 
+         * The provider (commit handler) should apply all changes to its state
+         * which are a result of data change-
+         * 
+         * @return
+         */
+        RpcResult<Void> finish() throws IllegalStateException;
+
+        /**
+         * Rollbacks a commit.
+         * 
+         * @return
+         * @throws IllegalStateException
+         *             If the method is invoked after {@link #finish()}
+         */
+        RpcResult<Void> rollback() throws IllegalStateException;
+    }
+
+}
@@ -1,67 +1,65 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.api;\r
-\r
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;\r
-\r
-public interface DataProviderService extends DataBrokerService {\r
-\r
-    /**\r
-     * Adds {@link DataValidator} for specified Data Store\r
-     * \r
-     * @param store\r
-     *            Data Store\r
-     * @param validator\r
-     *            Validator\r
-     */\r
-    public void addValidator(DataStoreIdentifier store, DataValidator validator);\r
-\r
-    /**\r
-     * Removes {@link DataValidator} from specified Data Store\r
-     * \r
-     * @param store\r
-     * @param validator\r
-     *            Validator\r
-     */\r
-    public void removeValidator(DataStoreIdentifier store,\r
-            DataValidator validator);\r
-\r
-    /**\r
-     * Adds {@link DataCommitHandler} for specified data store\r
-     * \r
-     * @param store\r
-     * @param provider\r
-     */\r
-    void addCommitHandler(DataStoreIdentifier store, DataCommitHandler provider);\r
-\r
-    /**\r
-     * Removes {@link DataCommitHandler} from specified data store\r
-     * \r
-     * @param store\r
-     * @param provider\r
-     */\r
-    void removeCommitHandler(DataStoreIdentifier store,\r
-            DataCommitHandler provider);\r
-\r
-    /**\r
-     * Adds {@link DataRefresher} for specified data store\r
-     * \r
-     * @param store\r
-     * @param refresher\r
-     */\r
-    void addRefresher(DataStoreIdentifier store, DataRefresher refresher);\r
-\r
-    /**\r
-     * Removes {@link DataRefresher} from specified data store\r
-     * \r
-     * @param store\r
-     * @param refresher\r
-     */\r
-   void removeRefresher(DataStoreIdentifier store, DataRefresher refresher);\r
-\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.api.data;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+
+public interface DataProviderService extends DataBrokerService {
+
+    /**
+     * Adds {@link DataValidator} for specified Data Store
+     * 
+     * @param store
+     *            Data Store
+     * @param validator
+     *            Validator
+     */
+    public void addValidator(DataStoreIdentifier store, DataValidator validator);
+
+    /**
+     * Removes {@link DataValidator} from specified Data Store
+     * 
+     * @param store
+     * @param validator
+     *            Validator
+     */
+    public void removeValidator(DataStoreIdentifier store, DataValidator validator);
+
+    /**
+     * Adds {@link DataCommitHandler} for specified data store
+     * 
+     * @param store
+     * @param provider
+     */
+    void addCommitHandler(DataStoreIdentifier store, DataCommitHandler provider);
+
+    /**
+     * Removes {@link DataCommitHandler} from specified data store
+     * 
+     * @param store
+     * @param provider
+     */
+    void removeCommitHandler(DataStoreIdentifier store, DataCommitHandler provider);
+
+    /**
+     * Adds {@link DataRefresher} for specified data store
+     * 
+     * @param store
+     * @param refresher
+     */
+    void addRefresher(DataStoreIdentifier store, DataRefresher refresher);
+
+    /**
+     * Removes {@link DataRefresher} from specified data store
+     * 
+     * @param store
+     * @param refresher
+     */
+    void removeRefresher(DataStoreIdentifier store, DataRefresher refresher);
+
+}
@@ -1,26 +1,28 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.api;\r
-\r
-/**\r
- * Trigger for refreshing of the data exposed by the {@link Provider}\r
- * \r
- * \r
- * \r
- */\r
-public interface DataRefresher extends\r
-        BindingAwareProvider.ProviderFunctionality {\r
-\r
-    /**\r
-     * Fired when some component explicitly requested the data refresh.\r
-     * \r
-     * The provider which exposed the {@link DataRefresher} should republish its\r
-     * provided data by editing the data in all affected data stores.\r
-     */\r
-    void refreshData();\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.api.data;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
+
+/**
+ * Trigger for refreshing of the data exposed by the {@link Provider}
+ * 
+ * 
+ * 
+ */
+public interface DataRefresher extends BindingAwareProvider.ProviderFunctionality {
+
+    /**
+     * Fired when some component explicitly requested the data refresh.
+     * 
+     * The provider which exposed the {@link DataRefresher} should republish its
+     * provided data by editing the data in all affected data stores.
+     */
+    void refreshData();
 }
\ No newline at end of file
@@ -1,18 +1,18 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.api;\r
-\r
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;\r
-import org.opendaylight.controller.yang.binding.DataRoot;\r
-import org.opendaylight.controller.yang.common.RpcResult;\r
-\r
-\r
-public interface DataValidator extends ProviderFunctionality {\r
-\r
-    RpcResult<Void> validate(DataRoot data);\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.api.data;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
+import org.opendaylight.yangtools.yang.binding.DataRoot;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public interface DataValidator extends ProviderFunctionality {
+
+    RpcResult<Void> validate(DataRoot data);
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/RuntimeDataProvider.java b/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/RuntimeDataProvider.java
new file mode 100644 (file)
index 0000000..4b01aed
--- /dev/null
@@ -0,0 +1,51 @@
+package org.opendaylight.controller.sal.binding.api.data;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataRoot;
+
+public interface RuntimeDataProvider {
+
+    Set<DataStoreIdentifier> getSupportedStores();
+    
+    
+    Set<Class<? extends DataRoot>> getProvidedDataRoots();
+    
+    
+    /**
+     * Returns a data from specified Data Store.
+     * 
+     * Returns all the data visible to the consumer from specified Data Store.
+     * 
+     * @param <T>
+     *            Interface generated from YANG module representing root of data
+     * @param store
+     *            Identifier of the store, from which will be data retrieved
+     * @return data visible to the consumer
+     */
+    <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType);
+
+    /**
+     * Returns a filtered subset of data from specified Data Store.
+     * 
+     * <p>
+     * The filter is modeled as an hierarchy of Java TOs starting with
+     * implementation of {@link DataRoot} representing data root. The semantics
+     * of the filter tree is the same as filter semantics defined in the NETCONF
+     * protocol for rpc operations <code>get</code> and <code>get-config</code>
+     * in Section 6 of RFC6241.
+     * 
+     * 
+     * @see http://tools.ietf.org/html/rfc6241#section-6
+     * @param <T>
+     *            Interface generated from YANG module representing root of data
+     * @param store
+     *            Identifier of the store, from which will be data retrieved
+     * @param filter
+     *            Data tree filter similar to the NETCONF filter
+     * @return
+     */
+    <T extends DataRoot> T getData(DataStoreIdentifier store, T filter);
+}
index 552ac6a450c916bcd3943b34e992ddaf3f832e01..31eec6b5e8a79702f3088292bbd6dcefc1d15cb9 100644 (file)
@@ -1,9 +1,9 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.api;\r
-\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.api;
+
index 3073bec988c128f307c82b2d7fdcc87eaa39a87a..70f2e6c3789c3880eb304c40ba84ee4c233bb1c2 100644 (file)
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
-    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
-    <modelVersion>4.0.0</modelVersion>\r
-    <parent>\r
-        <groupId>org.opendaylight.controller</groupId>\r
-        <artifactId>sal</artifactId>\r
-        <version>1.0-SNAPSHOT</version>\r
-    </parent>\r
-    <artifactId>sal-binding-broker-impl</artifactId>\r
-\r
-\r
-\r
-    <dependencies>\r
-        <dependency>\r
-            <groupId>org.opendaylight.controller</groupId>\r
-            <artifactId>sal-common-util</artifactId>\r
-            <version>1.0-SNAPSHOT</version>\r
-        </dependency>\r
-        <dependency>\r
-            <groupId>org.opendaylight.controller</groupId>\r
-            <artifactId>sal-binding-api</artifactId>\r
-            <version>1.0-SNAPSHOT</version>\r
-        </dependency>\r
-        <dependency>\r
-            <groupId>org.opendaylight.controller</groupId>\r
-            <artifactId>sal-binding-spi</artifactId>\r
-            <version>1.0-SNAPSHOT</version>\r
-        </dependency>\r
-        <dependency>\r
-            <groupId>org.opendaylight.controller</groupId>\r
-            <artifactId>sal-core-api</artifactId>\r
-            <version>1.0-SNAPSHOT</version>\r
-        </dependency>\r
-\r
-        <dependency>\r
-            <groupId>org.slf4j</groupId>\r
-            <artifactId>slf4j-api</artifactId>\r
-        </dependency>\r
-\r
-        <dependency>\r
-            <groupId>com.google.guava</groupId>\r
-            <artifactId>guava</artifactId>\r
-            <type>jar</type>\r
-        </dependency>\r
-    </dependencies>\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.opendaylight.controller</groupId>
+               <artifactId>sal-parent</artifactId>
+               <version>1.0-SNAPSHOT</version>
+       </parent>
+       <artifactId>sal-binding-broker-impl</artifactId>
+       <packaging>bundle</packaging>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.felix</groupId>
+                               <artifactId>maven-bundle-plugin</artifactId>
+                               <version>${maven.bundle.version}</version>
+                               <extensions>true</extensions>
+                               <configuration>
+                                       <instructions>
+                                               <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                                               <Bundle-Activator>org.opendaylight.controller.sal.binding.impl.BrokerActivator</Bundle-Activator>
+                                               <Private-Package>
+                                                       org.opendaylight.controller.sal.binding.impl,
+                                                       org.opendaylight.controller.sal.binding.impl.utils,
+                                                       org.eclipse.xtend2.lib,
+                                                       org.eclipse.xtext.xbase.*
+                                               </Private-Package>
+                                       </instructions>
+                               </configuration>
+                       </plugin>
+
+                       <plugin>
+                               <groupId>org.eclipse.xtend</groupId>
+                               <artifactId>xtend-maven-plugin</artifactId>
+                               <version>2.4.2</version>
+                               <executions>
+                                       <execution>
+                                               <goals>
+                                                       <goal>compile</goal>
+                                               </goals>
+                                               <configuration>
+                                                       <outputDirectory>${basedir}/src/main/xtend-gen</outputDirectory>
+                                               </configuration>
+                                       </execution>
+                               </executions>
+                       </plugin>
+                       <plugin>
+                               <artifactId>maven-clean-plugin</artifactId>
+                               <version>2.4.1</version>
+                               <configuration>
+                                       <filesets>
+                                               <fileset>
+                                                       <directory>${basedir}/src/main/xtend-gen</directory>
+                                                       <includes>
+                                                               <include>**</include>
+                                                       </includes>
+                                               </fileset>
+                                       </filesets>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+
+       <dependencies>
+               <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>sal-common-util</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>sal-binding-api</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+               <!-- >dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-core-api</artifactId> 
+                       <version>1.0-SNAPSHOT</version> </dependency -->
+
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>slf4j-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>org.osgi.core</artifactId>
+                       <version>5.0.0</version>
+               </dependency>
+               <dependency>
+                       <groupId>com.google.guava</groupId>
+                       <artifactId>guava</artifactId>
+                       <type>jar</type>
+               </dependency>
+               <dependency>
+                       <groupId>org.reflections</groupId>
+                       <artifactId>reflections</artifactId>
+                       <version>0.9.9-RC1</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.javassist</groupId>
+                       <artifactId>javassist</artifactId>
+                       <version>3.17.1-GA</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.eclipse.xtend</groupId>
+                       <artifactId>org.eclipse.xtend.lib</artifactId>
+                       <version>2.4.2</version>
+               </dependency>
+       </dependencies>
 </project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/.gitignore b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/.gitignore
new file mode 100644 (file)
index 0000000..04b73cb
--- /dev/null
@@ -0,0 +1 @@
+/xtend-gen
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend
new file mode 100644 (file)
index 0000000..2953466
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider
+import org.opendaylight.yangtools.yang.binding.RpcService
+import javassist.ClassPool
+import javassist.CtMethod
+import javassist.CtField
+import org.osgi.framework.BundleContext
+import java.util.Map
+import java.util.HashMap
+import javassist.LoaderClassPath
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker
+import java.util.Hashtable
+
+import static extension org.opendaylight.controller.sal.binding.impl.utils.PropertiesUtils.*
+import static extension org.opendaylight.controller.sal.binding.impl.utils.GeneratorUtils.*
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService
+import org.osgi.framework.ServiceRegistration
+import org.opendaylight.controller.sal.binding.impl.utils.PropertiesUtils
+import org.opendaylight.controller.sal.binding.api.NotificationService
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
+import javassist.Modifier
+import org.slf4j.LoggerFactory
+
+class BindingAwareBrokerImpl implements BindingAwareBroker {
+    private static val DELEGATE_FIELD = "_delegate"
+    private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl)
+    
+    private val clsPool = ClassPool.getDefault()
+    private Map<Class<? extends RpcService>, RpcProxyContext> managedProxies = new HashMap();
+    private var NotificationBrokerImpl notifyBroker
+    private var ServiceRegistration<NotificationProviderService> notifyBrokerRegistration
+    
+    @Property
+    var BundleContext brokerBundleContext
+
+    def start() {
+        initGenerator();
+
+        // Initialization of notificationBroker
+        notifyBroker = new NotificationBrokerImpl(null);
+        val brokerProperties = PropertiesUtils.newProperties();
+        notifyBrokerRegistration = brokerBundleContext.registerService(NotificationProviderService, notifyBroker,
+            brokerProperties)
+        brokerBundleContext.registerService(NotificationService, notifyBroker, brokerProperties)
+    }
+
+    def initGenerator() {
+
+        // YANG Binding Class Loader
+        clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader))
+    }
+
+    override registerConsumer(BindingAwareConsumer consumer, BundleContext bundleCtx) {
+        val ctx = consumer.createContext(bundleCtx)
+        consumer.onSessionInitialized(ctx)
+        return ctx
+    }
+
+    override registerProvider(BindingAwareProvider provider, BundleContext bundleCtx) {
+        val ctx = provider.createContext(bundleCtx)
+        provider.onSessionInitialized(ctx)
+        provider.onSessionInitiated(ctx as ProviderContext)
+        return ctx
+    }
+
+    private def createContext(BindingAwareConsumer consumer, BundleContext consumerCtx) {
+        new OsgiConsumerContext(consumerCtx, this)
+    }
+
+    private def createContext(BindingAwareProvider provider, BundleContext providerCtx) {
+        new OsgiProviderContext(providerCtx, this)
+    }
+
+    /**
+     * Returns a Managed Direct Proxy for supplied class
+     * 
+     * Managed direct proxy is a generated proxy class conforming to the supplied interface
+     * which delegates all calls to the backing delegate.
+     * 
+     * Proxy does not do any validation, null pointer checks or modifies data in any way, it
+     * is only use to avoid exposing direct references to backing implementation of service.
+     * 
+     * If proxy class does not exist for supplied service class it will be generated automatically.
+     */
+    def <T extends RpcService> getManagedDirectProxy(Class<T> service) {
+        
+        var RpcProxyContext existing = null
+        if ((existing = managedProxies.get(service)) != null) {
+            return existing.proxy
+        }
+        val proxyClass = service.generateDirectProxy()
+        val rpcProxyCtx = new RpcProxyContext(proxyClass)
+        val properties = new Hashtable<String, String>()
+        rpcProxyCtx.proxy = proxyClass.newInstance as RpcService
+
+        properties.salServiceType = Constants.SAL_SERVICE_TYPE_CONSUMER_PROXY
+        rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties)
+        managedProxies.put(service, rpcProxyCtx)
+        return rpcProxyCtx.proxy
+    }
+
+    protected def generateDirectProxy(Class<? extends RpcService> delegate) {
+        val targetFqn = delegate.generatedName(Constants.PROXY_DIRECT_SUFFIX)
+        log.debug("Generating DirectProxy for {} Proxy name: {}",delegate,targetFqn);
+        val objCls = clsPool.get(Object)
+        val delegateCls = clsPool.get(delegate)
+        val proxyCls = clsPool.makeClass(targetFqn)
+        proxyCls.addInterface(delegateCls)
+        val delField = new CtField(delegateCls, DELEGATE_FIELD, proxyCls);
+        delField.modifiers = Modifier.PUBLIC
+        proxyCls.addField(delField)
+        delegateCls.methods.filter[it.declaringClass != objCls].forEach [
+            val proxyMethod = new CtMethod(it, proxyCls, null);
+            proxyMethod.body = '''return ($r) Â«DELEGATE_FIELD».«it.name»($$);'''
+            proxyCls.addMethod(proxyMethod)
+        ]
+        return proxyCls.toClass(delegate.classLoader)
+    }
+
+    /**
+     * Registers RPC Implementation
+     * 
+     */
+    def <T extends RpcService> registerRpcImplementation(Class<T> type, T service, OsgiProviderContext context,
+        Hashtable<String, String> properties) {
+        val proxy = getManagedDirectProxy(type)
+        if(proxy.delegate != null) {
+            throw new IllegalStateException("Service " + type + "is already registered");
+        }
+        val osgiReg = context.bundleContext.registerService(type, service, properties);
+        proxy.delegate = service;
+        return new RpcServiceRegistrationImpl<T>(type, service, osgiReg);
+    }
+    
+    /**
+     * Helper method to return delegate from ManagedDirectedProxy with use of reflection.
+     * 
+     * Note: This method uses reflection, but access to delegate field should be 
+     * avoided and called only if neccessary.
+     * 
+     */
+    def <T extends RpcService> getDelegate(RpcService proxy) {
+        val field = proxy.class.getField(DELEGATE_FIELD)
+        if(field == null) throw new UnsupportedOperationException("Unable to get delegate from proxy");
+        return field.get(proxy) as T
+    }
+    
+        /**
+     * Helper method to set delegate to ManagedDirectedProxy with use of reflection.
+     * 
+     * Note: This method uses reflection, but setting delegate field should not occur too much
+     * to introduce any significant performance hits.
+     * 
+     */
+    def void setDelegate(RpcService proxy, RpcService delegate) {
+        val field = proxy.class.getField(DELEGATE_FIELD)
+        if(field == null) throw new UnsupportedOperationException("Unable to set delegate to proxy");
+        if (field.type.isAssignableFrom(delegate.class)) {
+            field.set(proxy,delegate)
+        } else throw new IllegalArgumentException("delegate class is not assignable to proxy");
+    }
+    
+    
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingBrokerImpl.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingBrokerImpl.java
deleted file mode 100644 (file)
index 32eff18..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.binding.impl;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.opendaylight.controller.sal.binding.api.BindingAwareService;
-import org.opendaylight.controller.sal.binding.spi.Mapper;
-import org.opendaylight.controller.sal.binding.spi.MappingProvider;
-import org.opendaylight.controller.sal.binding.spi.RpcMapper;
-import org.opendaylight.controller.sal.binding.spi.RpcMapper.RpcProxyInvocationHandler;
-import org.opendaylight.controller.sal.binding.spi.SALBindingModule;
-import org.opendaylight.controller.sal.common.util.Rpcs;
-import org.opendaylight.controller.sal.core.api.Provider;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.controller.yang.binding.DataObject;
-import org.opendaylight.controller.yang.binding.RpcService;
-import org.opendaylight.controller.yang.common.QName;
-import org.opendaylight.controller.yang.common.RpcResult;
-import org.opendaylight.controller.yang.data.api.CompositeNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class BindingBrokerImpl implements BindingAwareBroker {
-
-    private static Logger log = LoggerFactory
-            .getLogger(BindingBrokerImpl.class);
-
-    private Set<ConsumerSessionImpl> sessions = new HashSet<ConsumerSessionImpl>();
-    private Set<ProviderSessionImpl> providerSessions = new HashSet<ProviderSessionImpl>();
-
-    private Set<SALBindingModule> modules = new HashSet<SALBindingModule>();
-    private Map<Class<? extends BindingAwareService>, SALBindingModule> salServiceProviders = new HashMap<Class<? extends BindingAwareService>, SALBindingModule>();
-    private MappingProvider mapping;
-    private BIFacade biFacade = new BIFacade();
-    private org.opendaylight.controller.sal.core.api.Broker.ProviderSession biSession;
-    private ExecutorService executor;
-
-    Map<Class<? extends RpcService>, RpcService> rpcImpls = Collections
-            .synchronizedMap(new HashMap<Class<? extends RpcService>, RpcService>());
-
-    private RpcProxyInvocationHandler rpcProxyHandler = new RpcProxyInvocationHandler() {
-
-        @Override
-        public Future<RpcResult<? extends DataObject>> invokeRpc(
-                RpcService proxy, QName rpc, DataObject input) {
-            return rpcProxyInvoked(proxy, rpc, input);
-        }
-    };
-
-    @Override
-    public ConsumerSession registerConsumer(BindingAwareConsumer consumer) {
-        checkPredicates(consumer);
-        log.info("Registering consumer " + consumer);
-
-        ConsumerSessionImpl session = newSessionFor(consumer);
-        consumer.onSessionInitialized(session);
-
-        sessions.add(session);
-        return session;
-    }
-
-    @Override
-    public ProviderSession registerProvider(BindingAwareProvider provider) {
-        checkPredicates(provider);
-
-        ProviderSessionImpl session = newSessionFor(provider);
-        provider.onSessionInitiated(session);
-
-        providerSessions.add(session);
-        return session;
-    }
-
-    public void addModule(SALBindingModule module) {
-        log.info("Registering broker module " + module);
-        if (modules.contains(module)) {
-            log.error("Module already registered");
-            throw new IllegalArgumentException("Module already exists.");
-        }
-
-        Set<Class<? extends BindingAwareService>> provServices = module
-                .getProvidedServices();
-        for (Class<? extends BindingAwareService> serviceType : provServices) {
-            log.info("  Registering session service implementation: "
-                    + serviceType.getCanonicalName());
-            salServiceProviders.put(serviceType, module);
-        }
-    }
-
-    public void consumerSessionClosed(ConsumerSessionImpl consumerSessionImpl) {
-        sessions.remove(consumerSessionImpl);
-        providerSessions.remove(consumerSessionImpl);
-    }
-
-    private void checkPredicates(BindingAwareProvider prov) {
-        if (prov == null)
-            throw new IllegalArgumentException("Provider should not be null.");
-        for (ProviderSessionImpl session : providerSessions) {
-            if (prov.equals(session.getProvider()))
-                throw new IllegalStateException("Provider already registered");
-        }
-
-    }
-
-    private void checkPredicates(BindingAwareConsumer cons) {
-        if (cons == null)
-            throw new IllegalArgumentException("Consumer should not be null.");
-        for (ConsumerSessionImpl session : sessions) {
-            if (cons.equals(session.getConsumer()))
-                throw new IllegalStateException("Consumer already registered");
-        }
-    }
-
-    private ConsumerSessionImpl newSessionFor(BindingAwareConsumer cons) {
-        return new ConsumerSessionImpl(cons);
-    }
-
-    private ProviderSessionImpl newSessionFor(BindingAwareProvider provider) {
-        return new ProviderSessionImpl(provider);
-    }
-
-    private <T extends BindingAwareService> T newSALServiceForSession(
-            Class<T> service, ConsumerSession session) {
-
-        SALBindingModule serviceProvider = salServiceProviders.get(service);
-        if (serviceProvider == null) {
-            return null;
-        }
-        return serviceProvider.getServiceForSession(service, session);
-
-    }
-
-    private <T extends RpcService> T newRpcProxyForSession(Class<T> service) {
-
-        RpcMapper<T> mapper = mapping.rpcMapperForClass(service);
-        if (mapper == null) {
-            log.error("Mapper for " + service + "is unavailable.");
-            return null;
-        }
-        T proxy = mapper.getConsumerProxy(rpcProxyHandler);
-
-        return proxy;
-    }
-
-    private Future<RpcResult<? extends DataObject>> rpcProxyInvoked(
-            RpcService rpcProxy, QName rpcType, DataObject inputData) {
-        if (rpcProxy == null) {
-            throw new IllegalArgumentException("Proxy must not be null");
-        }
-        if (rpcType == null) {
-            throw new IllegalArgumentException(
-                    "rpcType (QName) should not be null");
-        }
-        Future<RpcResult<? extends DataObject>> ret = null;
-
-        // Real invocation starts here
-        RpcMapper<? extends RpcService> mapper = mapping
-                .rpcMapperForProxy(rpcProxy);
-        RpcService impl = rpcImpls.get(mapper.getServiceClass());
-
-        if (impl == null) {
-            // RPC is probably remote
-            CompositeNode inputNode = null;
-            Mapper<? extends DataObject> inputMapper = mapper.getInputMapper();
-            if (inputMapper != null) {
-                inputNode = inputMapper.domFromObject(inputData);
-            }
-            Future<RpcResult<CompositeNode>> biResult = biSession.rpc(rpcType,
-                    inputNode);
-            ret = new TranslatedFuture(biResult, mapper);
-
-        } else {
-            // RPC is local
-            Callable<RpcResult<? extends DataObject>> invocation = localRpcCallableFor(
-                    impl, mapper, rpcType, inputData);
-            ret = executor.submit(invocation);
-        }
-        return ret;
-    }
-
-    private Callable<RpcResult<? extends DataObject>> localRpcCallableFor(
-            final RpcService impl,
-            final RpcMapper<? extends RpcService> mapper, final QName rpcType,
-            final DataObject inputData) {
-
-        return new Callable<RpcResult<? extends DataObject>>() {
-
-            @Override
-            public RpcResult<? extends DataObject> call() throws Exception {
-                return mapper.invokeRpcImplementation(rpcType, impl, inputData);
-            }
-        };
-    }
-
-    // Binding Independent invocation of Binding Aware RPC
-    private RpcResult<CompositeNode> invokeLocalRpc(QName rpc,
-            CompositeNode inputNode) {
-        RpcMapper<? extends RpcService> mapper = mapping.rpcMapperForData(rpc,
-                inputNode);
-
-        DataObject inputTO = mapper.getInputMapper().objectFromDom(inputNode);
-
-        RpcService impl = rpcImpls.get(mapper.getServiceClass());
-        if (impl == null) {
-            log.warn("Implementation for rpc: " + rpc + "not available.");
-        }
-        RpcResult<? extends DataObject> result = mapper
-                .invokeRpcImplementation(rpc, impl, inputTO);
-        DataObject outputTO = result.getResult();
-
-        CompositeNode outputNode = null;
-        if (outputTO != null) {
-            outputNode = mapper.getOutputMapper().domFromObject(outputTO);
-        }
-        return Rpcs.getRpcResult(result.isSuccessful(), outputNode,
-                result.getErrors());
-    }
-
-    private class ConsumerSessionImpl implements
-            BindingAwareBroker.ConsumerSession {
-
-        private final BindingAwareConsumer consumer;
-        private Map<Class<? extends BindingAwareService>, BindingAwareService> sessionSalServices = Collections
-                .synchronizedMap(new HashMap<Class<? extends BindingAwareService>, BindingAwareService>());
-
-        private Map<Class<? extends RpcService>, RpcService> sessionRpcProxies = Collections
-                .synchronizedMap(new HashMap<Class<? extends RpcService>, RpcService>());
-
-        public ConsumerSessionImpl(BindingAwareConsumer cons) {
-            this.consumer = cons;
-        }
-
-        @Override
-        public <T extends BindingAwareService> T getSALService(Class<T> service) {
-
-            BindingAwareService serv = sessionSalServices.get(service);
-            if (serv != null) {
-                if (service.isInstance(serv)) {
-                    @SuppressWarnings("unchecked")
-                    T ret = (T) serv;
-                    return ret;
-                } else {
-                    log.error("Implementation for service " + service.getName()
-                            + " does not implement the service interface");
-                    throw new IllegalStateException("Service implementation "
-                            + serv.getClass().getName() + "does not implement "
-                            + service.getName());
-                }
-            } else {
-                T ret = BindingBrokerImpl.this.newSALServiceForSession(service,
-                        this);
-                if (ret != null) {
-                    sessionSalServices.put(service, ret);
-                }
-                return ret;
-            }
-        }
-
-        @Override
-        public <T extends RpcService> T getRpcService(Class<T> service) {
-            RpcService current = sessionRpcProxies.get(service);
-            if (current != null) {
-                if (service.isInstance(current)) {
-                    @SuppressWarnings("unchecked")
-                    T ret = (T) current;
-                    return ret;
-                } else {
-                    log.error("Proxy  for rpc service " + service.getName()
-                            + " does not implement the service interface");
-                    throw new IllegalStateException("Service implementation "
-                            + current.getClass().getName()
-                            + "does not implement " + service.getName());
-                }
-            } else {
-                T ret = BindingBrokerImpl.this.newRpcProxyForSession(service);
-                if (ret != null) {
-                    sessionRpcProxies.put(service, ret);
-                }
-                return ret;
-            }
-        }
-
-        public BindingAwareConsumer getConsumer() {
-            return this.consumer;
-        }
-
-    }
-
-    private class ProviderSessionImpl extends ConsumerSessionImpl implements
-            BindingAwareBroker.ProviderSession {
-
-        private final BindingAwareProvider provider;
-
-        public ProviderSessionImpl(BindingAwareProvider provider2) {
-            super(null);
-            this.provider = provider2;
-        }
-
-        @Override
-        public void addRpcImplementation(RpcService implementation) {
-            if (implementation == null) {
-                throw new IllegalArgumentException(
-                        "Implementation should not be null");
-            }
-            // TODO Implement this method
-            throw new UnsupportedOperationException("Not implemented");
-        }
-
-        @Override
-        public void removeRpcImplementation(RpcService implementation) {
-            if (implementation == null) {
-                throw new IllegalArgumentException(
-                        "Implementation should not be null");
-            }
-            // TODO Implement this method
-            throw new UnsupportedOperationException("Not implemented");
-        }
-
-        public BindingAwareProvider getProvider() {
-            return this.provider;
-        }
-
-    }
-
-    private class BIFacade implements Provider,RpcImplementation {
-
-        @Override
-        public Set<QName> getSupportedRpcs() {
-            return Collections.emptySet();
-        }
-
-        @Override
-        public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
-            if (rpc == null) {
-                throw new IllegalArgumentException(
-                        "Rpc type should not be null");
-            }
-
-            return BindingBrokerImpl.this.invokeLocalRpc(rpc, input);
-        }
-
-        @Override
-        public void onSessionInitiated(
-                org.opendaylight.controller.sal.core.api.Broker.ProviderSession session) {
-            
-            BindingBrokerImpl.this.biSession = session;
-            for (SALBindingModule module : modules) {
-                try {
-                    module.onBISessionAvailable(biSession);
-                } catch(Exception e) {
-                    log.error("Module " +module +" throwed unexpected exception",e);
-                }
-            }
-        }
-
-        @Override
-        public Collection<ProviderFunctionality> getProviderFunctionality() {
-            return Collections.emptySet();
-        }
-
-    }
-
-    private static class TranslatedFuture implements
-            Future<RpcResult<? extends DataObject>> {
-        private final Future<RpcResult<CompositeNode>> realFuture;
-        private final RpcMapper<?> mapper;
-
-        public TranslatedFuture(Future<RpcResult<CompositeNode>> future,
-                RpcMapper<?> mapper) {
-            realFuture = future;
-            this.mapper = mapper;
-        }
-
-        @Override
-        public boolean cancel(boolean mayInterruptIfRunning) {
-            return realFuture.cancel(mayInterruptIfRunning);
-        }
-
-        @Override
-        public boolean isCancelled() {
-            return realFuture.isCancelled();
-        }
-
-        @Override
-        public boolean isDone() {
-            return realFuture.isDone();
-        }
-
-        @Override
-        public RpcResult<? extends DataObject> get()
-                throws InterruptedException, ExecutionException {
-            RpcResult<CompositeNode> val = realFuture.get();
-            return tranlate(val);
-        }
-
-        @Override
-        public RpcResult<? extends DataObject> get(long timeout, TimeUnit unit)
-                throws InterruptedException, ExecutionException,
-                TimeoutException {
-            RpcResult<CompositeNode> val = realFuture.get(timeout, unit);
-            return tranlate(val);
-        }
-
-        private RpcResult<? extends DataObject> tranlate(
-                RpcResult<CompositeNode> result) {
-            CompositeNode outputNode = result.getResult();
-            DataObject outputTO = null;
-            if (outputNode != null) {
-                Mapper<?> outputMapper = mapper.getOutputMapper();
-                outputTO = outputMapper.objectFromDom(outputNode);
-            }
-            return Rpcs.getRpcResult(result.isSuccessful(), outputTO,
-                    result.getErrors());
-        }
-
-    }
-}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BrokerActivator.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BrokerActivator.java
new file mode 100644 (file)
index 0000000..c5d54ec
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.impl;
+
+import java.util.Hashtable;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BrokerActivator implements BundleActivator {
+
+       private static final Logger log = LoggerFactory.getLogger(BrokerActivator.class);
+       private BindingAwareBrokerImpl baSal;
+       private ServiceRegistration<BindingAwareBroker> baSalRegistration;
+       
+       
+       @Override
+       public void start(BundleContext context) throws Exception {
+               log.info("Binding Aware Broker initialized");
+               baSal = new BindingAwareBrokerImpl();
+               baSal.setBrokerBundleContext(context);
+               baSal.start();
+               
+               BindingAwareBroker baSalService = baSal;
+               Hashtable<String, String> properties = new Hashtable<>();
+               this.baSalRegistration = context.registerService(BindingAwareBroker.class,baSalService, properties);
+               
+       }
+
+       @Override
+       public void stop(BundleContext context) throws Exception {
+               log.info("Binding Aware Broker stopped");
+               baSalRegistration.unregister();
+       }
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/Constants.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/Constants.xtend
new file mode 100644 (file)
index 0000000..668635a
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+class Constants {
+
+    private new() {
+    }
+
+    public static val SAL_SERVICE_TYPE = "salServiceType"
+    public static val SAL_SERVICE_TYPE_CONSUMER_PROXY = "consumerProxy"
+    public static val SAL_SERVICE_TYPE_PROVIDER = "provider"
+    public static val SAL_SERVICE_TYPE_CONNECTOR = "connector"
+
+    public static val PROXY_DIRECT_SUFFIX = "DirectProxy";
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataModule.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataModule.java
deleted file mode 100644 (file)
index cbd6b00..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-package org.opendaylight.controller.sal.binding.impl;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.Future;
-
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerSession;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
-import org.opendaylight.controller.sal.binding.api.BindingAwareService;
-import org.opendaylight.controller.sal.binding.api.DataBrokerService;
-import org.opendaylight.controller.sal.binding.api.DataCommitHandler;
-import org.opendaylight.controller.sal.binding.api.DataProviderService;
-import org.opendaylight.controller.sal.binding.api.DataValidator;
-import org.opendaylight.controller.sal.binding.spi.MappingProvider;
-import org.opendaylight.controller.sal.binding.spi.SALBindingModule;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
-import org.opendaylight.controller.sal.binding.api.DataRefresher;
-import org.opendaylight.controller.yang.binding.DataRoot;
-import org.opendaylight.controller.yang.common.RpcResult;
-import org.opendaylight.controller.yang.data.api.CompositeNode;
-
-public class DataModule implements SALBindingModule {
-
-    private BindingAwareBroker broker;
-    private org.opendaylight.controller.sal.core.api.Broker.ProviderSession biSession;
-    private MappingProvider mappingProvider;
-    private final BIFacade biFacade = new BIFacade();
-    private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
-
-    @Override
-    public void setBroker(BindingAwareBroker broker) {
-        this.broker = broker;
-    }
-
-    @Override
-    public void onBISessionAvailable(
-            org.opendaylight.controller.sal.core.api.Broker.ProviderSession session) {
-        this.biSession = session;
-        this.biDataService = session
-                .getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class);
-        // biDataService.addRefresher(store, refresher)
-
-    }
-
-    @Override
-    public void setMappingProvider(MappingProvider provider) {
-        this.mappingProvider = provider;
-
-    }
-
-    @Override
-    public Set<Class<? extends BindingAwareService>> getProvidedServices() {
-        Set<Class<? extends BindingAwareService>> ret = new HashSet<Class<? extends BindingAwareService>>();
-        ret.add(DataBrokerService.class);
-        ret.add(DataProviderService.class);
-        return ret;
-    }
-
-    @Override
-    public <T extends BindingAwareService> T getServiceForSession(
-            Class<T> service, ConsumerSession session) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality() {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    private class DataBrokerSession implements DataBrokerService {
-
-        @Override
-        public <T extends DataRoot> T getData(DataStoreIdentifier store,
-                Class<T> rootType) {
-            // TODO Auto-generated method stub
-            return null;
-        }
-
-        @Override
-        public <T extends DataRoot> T getData(DataStoreIdentifier store,
-                T filter) {
-            // TODO Auto-generated method stub
-            return null;
-        }
-
-        @Override
-        public <T extends DataRoot> T getCandidateData(
-                DataStoreIdentifier store, Class<T> rootType) {
-            // TODO Auto-generated method stub
-            return null;
-        }
-
-        @Override
-        public <T extends DataRoot> T getCandidateData(
-                DataStoreIdentifier store, T filter) {
-            // TODO Auto-generated method stub
-            return null;
-        }
-
-        @Override
-        public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store,
-                DataRoot changeSet) {
-            // TODO Auto-generated method stub
-            return null;
-        }
-
-        @Override
-        public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
-            // TODO Auto-generated method stub
-            return null;
-        }
-
-    }
-
-    private class DataProviderSession extends DataBrokerSession implements
-            DataProviderService {
-
-        @Override
-        public void addValidator(DataStoreIdentifier store,
-                DataValidator validator) {
-            // TODO Auto-generated method stub
-
-        }
-
-        @Override
-        public void removeValidator(DataStoreIdentifier store,
-                DataValidator validator) {
-            // TODO Auto-generated method stub
-
-        }
-
-        @Override
-        public void addCommitHandler(DataStoreIdentifier store,
-                DataCommitHandler provider) {
-            // TODO Auto-generated method stub
-
-        }
-
-        @Override
-        public void removeCommitHandler(DataStoreIdentifier store,
-                DataCommitHandler provider) {
-            // TODO Auto-generated method stub
-
-        }
-
-        @Override
-        public void addRefresher(DataStoreIdentifier store,
-                DataRefresher refresher) {
-            // TODO Auto-generated method stub
-
-        }
-
-        @Override
-        public void removeRefresher(DataStoreIdentifier store,
-                DataRefresher refresher) {
-            // TODO Auto-generated method stub
-
-        }
-
-    }
-
-    private class BIFacade
-            implements
-            org.opendaylight.controller.sal.core.api.data.DataCommitHandler,
-            org.opendaylight.controller.sal.core.api.data.DataValidator,
-            org.opendaylight.controller.sal.core.api.data.DataProviderService.DataRefresher {
-
-        @Override
-        public RpcResult<Void> validate(CompositeNode toValidate) {
-            // TODO Auto-generated method stub
-            return null;
-        }
-
-        @Override
-        public Set<DataStoreIdentifier> getSupportedDataStores() {
-            // TODO Auto-generated method stub
-            return null;
-        }
-
-        @Override
-        public RpcResult<CommitTransaction> requestCommit(
-                DataStoreIdentifier store) {
-            // TODO Auto-generated method stub
-            return null;
-        }
-
-        @Override
-        public void refreshData() {
-            // TODO Auto-generated method stub
-            
-        }
-
-    }
-
-}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend
new file mode 100644 (file)
index 0000000..da1ba79
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService
+import org.opendaylight.yangtools.yang.binding.Notification
+import com.google.common.collect.Multimap
+import org.opendaylight.controller.sal.binding.api.NotificationListener
+import com.google.common.collect.HashMultimap
+import java.util.concurrent.ExecutorService
+import java.util.Collection
+
+class NotificationBrokerImpl implements NotificationProviderService {
+
+    val Multimap<Class<? extends Notification>, NotificationListener<?>> listeners;
+    val ExecutorService executor;
+
+    new(ExecutorService executor) {
+        listeners = HashMultimap.create()
+        this.executor = executor;
+    }
+
+    override <T extends Notification> addNotificationListener(Class<T> notificationType,
+        NotificationListener<T> listener) {
+        listeners.put(notificationType, listener)
+    }
+
+    override <T extends Notification> removeNotificationListener(Class<T> notificationType,
+        NotificationListener<T> listener) {
+        listeners.remove(notificationType, listener)
+    }
+
+    override notify(Notification notification) {
+        notification.notificationTypes.forEach [
+            listeners.get(it as Class<? extends Notification>)?.notifyAll(notification)
+        ]
+    }
+
+    def getNotificationTypes(Notification notification) {
+        notification.class.interfaces.filter[it != Notification && Notification.isAssignableFrom(it)]
+    }
+
+    def notifyAll(Collection<NotificationListener<?>> listeners, Notification notification) {
+        listeners.forEach[(it as NotificationListener).onNotification(notification)]
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationInvoker.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationInvoker.java
deleted file mode 100644 (file)
index 640089a..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.binding.impl;
-
-import org.opendaylight.controller.sal.binding.spi.MappingProvider.MappingExtension;
-import org.opendaylight.controller.yang.binding.Notification;
-import org.opendaylight.controller.yang.binding.NotificationListener;
-
-public interface NotificationInvoker extends MappingExtension {
-    void notify(Notification notification, NotificationListener listener);
-}
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationModule.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationModule.java
deleted file mode 100644 (file)
index 89c4464..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.binding.impl;\r
-\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.HashSet;\r
-import java.util.Set;\r
-\r
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;\r
-import org.opendaylight.controller.sal.binding.api.BindingAwareService;\r
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService;\r
-import org.opendaylight.controller.sal.binding.api.NotificationService;\r
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerSession;\r
-import org.opendaylight.controller.sal.binding.spi.SALBindingModule;\r
-import org.opendaylight.controller.sal.binding.spi.Mapper;\r
-import org.opendaylight.controller.sal.binding.spi.MappingProvider;\r
-import org.opendaylight.controller.sal.binding.spi.MappingProvider.MappingExtensionFactory;\r
-\r
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;\r
-import org.opendaylight.controller.yang.binding.DataObject;\r
-import org.opendaylight.controller.yang.binding.Notification;\r
-import org.opendaylight.controller.yang.binding.NotificationListener;\r
-import org.opendaylight.controller.yang.common.QName;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-import com.google.common.collect.HashMultimap;\r
-import com.google.common.collect.Multimap;\r
-\r
-public class NotificationModule implements SALBindingModule {\r
-\r
-    private ProviderSession biSession;\r
-    private org.opendaylight.controller.sal.core.api.notify.NotificationProviderService biNotifyService;\r
-    private MappingProvider mappingProvider;\r
-\r
-    private Multimap<Class<? extends Notification>, NotificationListener> listeners = HashMultimap\r
-            .create();\r
-    private Set<QName> biNotifications = new HashSet<QName>();\r
-    private static final Logger log = LoggerFactory\r
-            .getLogger(NotificationModule.class);\r
-    private final BindingIndependentListener biListener = new BindingIndependentListener();\r
-    private BindingAwareBroker broker;\r
-\r
-    @Override\r
-    public Set<Class<? extends BindingAwareService>> getProvidedServices() {\r
-\r
-        Set<Class<? extends BindingAwareService>> ret = new HashSet<Class<? extends BindingAwareService>>();\r
-        ret.add(NotificationService.class);\r
-        ret.add(NotificationProviderService.class);\r
-        return ret;\r
-    }\r
-\r
-    @Override\r
-    public <T extends BindingAwareService> T getServiceForSession(\r
-            Class<T> service, ConsumerSession session) {\r
-        if (service == null)\r
-            throw new IllegalArgumentException("Service should not be null");\r
-        if (session == null)\r
-            throw new IllegalArgumentException("Session should not be null");\r
-\r
-        if (NotificationProviderSession.class.equals(service)) {\r
-            if (session instanceof org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderSession) {\r
-                @SuppressWarnings("unchecked")\r
-                T ret = (T) new NotificationProviderSession(session);\r
-                return ret;\r
-            } else {\r
-                throw new IllegalArgumentException(\r
-                        "NotificationProviderService is available only to ProviderSession");\r
-            }\r
-        }\r
-\r
-        if (NotificationService.class.equals(service)) {\r
-            @SuppressWarnings("unchecked")\r
-            T ret = (T) new NotificationSession(session);\r
-            return ret;\r
-        }\r
-        return null;\r
-    }\r
-\r
-    @Override\r
-    public Set<Class<? extends org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality>> getSupportedProviderFunctionality() {\r
-        return Collections.emptySet();\r
-    }\r
-\r
-    @Override\r
-    public void setBroker(BindingAwareBroker broker) {\r
-        this.broker = broker;\r
-    }\r
-\r
-    @Override\r
-    public void setMappingProvider(MappingProvider provider) {\r
-        this.mappingProvider = provider;\r
-    }\r
-\r
-    @Override\r
-    public void onBISessionAvailable(ProviderSession session) {\r
-        biSession = session;\r
-        if (biSession != null) {\r
-            biNotifyService = session\r
-                    .getService(org.opendaylight.controller.sal.core.api.notify.NotificationProviderService.class);\r
-        }\r
-    }\r
-\r
-    private void notify(Notification notification) {\r
-        notifyBindingIndependent(notification);\r
-        notifyBindingAware(notification);\r
-    }\r
-\r
-    private void notifyBindingAware(Notification notification) {\r
-        Class<? extends Notification> type = notification.getClass();\r
-        Collection<NotificationListener> toNotify = listeners.get(type);\r
-\r
-        // Invocation of notification on registered listeners\r
-        if (toNotify != null) {\r
-\r
-            // We get factory for Notification Invoker\r
-            MappingExtensionFactory<NotificationInvoker> invokerFactory = mappingProvider\r
-                    .getExtensionFactory(NotificationInvoker.class);\r
-\r
-            // We get generated invoker for NoficiationListener interface\r
-            // associated to Notification Type\r
-            NotificationInvoker invoker = invokerFactory.forClass(type);\r
-            for (NotificationListener listener : toNotify) {\r
-                try {\r
-                    // Invoker invokes the right method on subtype of\r
-                    // NotificationListener\r
-                    // associated to the type of notification\r
-                    invoker.notify(notification, listener);\r
-                } catch (Exception e) {\r
-\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    private void notifyBindingIndependent(Notification notification) {\r
-        Class<? extends Notification> type = notification.getClass();\r
-\r
-        if (biSession == null) {\r
-            return;\r
-        }\r
-        if (biSession.isClosed()) {\r
-            return;\r
-        }\r
-        if (biNotifyService == null) {\r
-            return;\r
-        }\r
-\r
-        // FIXME: Somehow we need to resolve this for class hierarchy.\r
-        // probably use type.getInterfaces()\r
-        Mapper<? extends Notification> mapper = mappingProvider\r
-                .mapperForClass(type);\r
-        CompositeNode domNotification = mapper.domFromObject(notification);\r
-\r
-        biNotifyService.sendNotification(domNotification);\r
-    }\r
-\r
-    private void addBAListener(Class<? extends Notification> notificationType,\r
-            NotificationListener listener) {\r
-\r
-        listeners.put(notificationType, listener);\r
-        Mapper<? extends Notification> mapper = mappingProvider\r
-                .mapperForClass(notificationType);\r
-        QName biType = mapper.getQName();\r
-        if (false == biNotifications.contains(biType)) {\r
-            // The listener is not registered for binding independent\r
-            // notification\r
-            biNotifications.add(biType);\r
-\r
-            if (biNotifyService != null) {\r
-                biNotifyService.addNotificationListener(biType, biListener);\r
-            }\r
-        }\r
-\r
-    }\r
-\r
-    private void removeBAListener(\r
-            Class<? extends Notification> notificationType,\r
-            NotificationListener listener) {\r
-        listeners.remove(notificationType, listener);\r
-    }\r
-\r
-    private class NotificationSession implements NotificationService {\r
-        private final ConsumerSession session;\r
-        private Multimap<Class<? extends Notification>, NotificationListener> sessionListeners = HashMultimap\r
-                .create();\r
-\r
-        public NotificationSession(ConsumerSession session) {\r
-            this.session = session;\r
-        }\r
-\r
-        @Override\r
-        public void addNotificationListener(\r
-                Class<? extends Notification> notificationType,\r
-                NotificationListener listener) {\r
-\r
-            NotificationModule.this.addBAListener(notificationType, listener);\r
-            sessionListeners.put(notificationType, listener);\r
-\r
-        }\r
-\r
-        @Override\r
-        public void removeNotificationListener(\r
-                Class<? extends Notification> notificationType,\r
-                NotificationListener listener) {\r
-            sessionListeners.remove(notificationType, listener);\r
-            NotificationModule.this\r
-                    .removeBAListener(notificationType, listener);\r
-        }\r
-\r
-    }\r
-\r
-    private class NotificationProviderSession extends NotificationSession\r
-            implements NotificationProviderService {\r
-\r
-        public NotificationProviderSession(ConsumerSession session) {\r
-            super(session);\r
-        }\r
-\r
-        @Override\r
-        public void notify(Notification notification) {\r
-            NotificationModule.this.notify(notification);\r
-        }\r
-\r
-    }\r
-\r
-    private class BindingIndependentListener\r
-            implements\r
-            org.opendaylight.controller.sal.core.api.notify.NotificationListener {\r
-\r
-        @Override\r
-        public Set<QName> getSupportedNotifications() {\r
-            return biNotifications;\r
-        }\r
-\r
-        @Override\r
-        public void onNotification(CompositeNode notification) {\r
-            NotificationModule.this\r
-                    .onBindingIndependentNotification(notification);\r
-        }\r
-\r
-    }\r
-\r
-    private void onBindingIndependentNotification(CompositeNode biNotification) {\r
-        QName biType = biNotification.getNodeType();\r
-\r
-        Mapper<DataObject> mapper = mappingProvider.mapperForQName(biType);\r
-        if (mapper == null) {\r
-            log.info("Received notification does not have a binding defined.");\r
-            return;\r
-        }\r
-        Class<DataObject> type = mapper.getDataObjectClass();\r
-\r
-        // We check if the received QName / type is really Notification\r
-        if (Notification.class.isAssignableFrom(type)) {\r
-            Notification notification = (Notification) mapper\r
-                    .objectFromDom(biNotification);\r
-            notifyBindingAware(notification);\r
-        } else {\r
-            // The generated type for this QName does not inherits from\r
-            // notification something went wrong - generated APIs and/or\r
-            // provider sending notification\r
-            // which was incorectly described in the YANG schema.\r
-            log.error("Received notification " + biType\r
-                    + " is not binded as notification");\r
-        }\r
-\r
-    }\r
-}\r
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.xtend
new file mode 100644 (file)
index 0000000..fb35ee3
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+import org.opendaylight.controller.sal.binding.api.NotificationService
+import org.opendaylight.controller.sal.binding.api.NotificationListener
+import org.opendaylight.yangtools.yang.binding.Notification
+import com.google.common.collect.Multimap
+import com.google.common.collect.HashMultimap
+
+class NotificationServiceImpl implements NotificationService {
+    val Multimap<Class<? extends Notification>, NotificationListener<?>> listeners;
+
+    new() {
+        listeners = HashMultimap.create()
+    }
+
+    override <T extends Notification> addNotificationListener(Class<T> notificationType,
+        NotificationListener<T> listener) {
+        listeners.put(notificationType, listener)
+    }
+
+    override <T extends Notification> removeNotificationListener(Class<T> notificationType,
+        NotificationListener<T> listener) {
+        listeners.remove(notificationType, listener)
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend
new file mode 100644 (file)
index 0000000..a87fa06
--- /dev/null
@@ -0,0 +1,53 @@
+package org.opendaylight.controller.sal.binding.impl;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareService;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.LoggerFactory
+
+class OsgiConsumerContext implements ConsumerContext {
+
+       static val log = LoggerFactory.getLogger(OsgiConsumerContext)
+       protected val BundleContext bundleContext;
+       protected val BindingAwareBrokerImpl broker;
+       
+       new(BundleContext ctx,BindingAwareBrokerImpl broker) {
+               this.bundleContext = ctx;
+               this.broker = broker;
+       }
+
+       
+       override def <T extends BindingAwareService> getSALService(Class<T> service) {
+               // SAL Services are global
+               var ref =  bundleContext.getServiceReference(service);
+               return bundleContext.getService(ref) as T;
+       }
+       
+       
+
+       override def <T extends RpcService> T getRpcService(Class<T> module) {
+               try {
+                       
+                       val services = bundleContext.getServiceReferences(module, getProxyFilter());
+                       
+                       // Proxy service found / using first implementation
+                       // FIXME: Add advanced logic to retrieve service with right set of models
+                       if(false == services.empty) {
+                               val ref = services.iterator().next() as ServiceReference<T>;
+                               return bundleContext.getService(ref) as T;
+                       } 
+               } catch (InvalidSyntaxException e) {
+                       log.error("Created filter was invalid:", e.message,e)
+               }
+               return null;
+               
+
+       }
+
+       private def getProxyFilter() {
+               return '''(«Constants.SAL_SERVICE_TYPE»=«Constants.SAL_SERVICE_TYPE_CONSUMER_PROXY»)'''
+       }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiProviderContext.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiProviderContext.xtend
new file mode 100644 (file)
index 0000000..195fa8b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.impl;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcServiceRegistration;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.framework.BundleContext;
+
+import static extension org.opendaylight.controller.sal.binding.impl.utils.PropertiesUtils.*;
+
+class OsgiProviderContext extends OsgiConsumerContext implements ProviderContext {
+
+    @Property
+    val Map<Class<? extends RpcService>, RpcServiceRegistrationImpl<? extends RpcService>> registeredServices
+
+    new(BundleContext ctx, BindingAwareBrokerImpl broker) {
+        super(ctx, broker);
+        _registeredServices = new HashMap();
+    }
+
+    override def <T extends RpcService> RpcServiceRegistration<T> addRpcImplementation(Class<T> type, T implementation) {
+
+        // TODO Auto-generated method stub
+        val properties = new Hashtable<String, String>();
+        properties.salServiceType = Constants.SAL_SERVICE_TYPE_PROVIDER
+
+        // Fill requirements
+        val salReg = broker.registerRpcImplementation(type, implementation, this, properties)
+        registeredServices.put(type, salReg)
+        return salReg;
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProxyContext.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProxyContext.xtend
new file mode 100644 (file)
index 0000000..0749459
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+import org.opendaylight.yangtools.yang.binding.RpcService
+import org.osgi.framework.ServiceRegistration
+
+class RpcProxyContext {
+       
+       new(Class<? extends RpcService> proxyClass) {
+               this.proxyClass = proxyClass
+       }
+       
+       protected val Class<? extends RpcService> proxyClass;
+       
+       @Property
+       protected var RpcService proxy;
+       
+       @Property
+       protected var ServiceRegistration<? extends RpcService> registration;
+}
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcServiceRegistrationImpl.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcServiceRegistrationImpl.xtend
new file mode 100644 (file)
index 0000000..afb27b4
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcServiceRegistration
+import org.osgi.framework.ServiceRegistration
+import org.opendaylight.yangtools.yang.binding.RpcService
+
+class RpcServiceRegistrationImpl<T extends RpcService> implements RpcServiceRegistration<T> {
+
+    val ServiceRegistration<T> osgiRegistration;
+    private val T service;
+    val Class<T> cls;
+
+    public new(Class<T> type, T service, ServiceRegistration<T> osgiReg) {
+        this.cls = type;
+        this.osgiRegistration = osgiReg;
+        this.service = service;
+    }
+
+    override getService() {
+        this.service
+    }
+
+    override unregister() {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/GeneratorUtils.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/GeneratorUtils.xtend
new file mode 100644 (file)
index 0000000..c888121
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.impl.utils
+
+import javassist.ClassPool
+import javassist.NotFoundException
+import javassist.LoaderClassPath
+
+class GeneratorUtils {
+
+    static val PREFIX = "_gen.";
+
+    public static def generatedName(Class<?> cls, String suffix) {
+        '''«PREFIX»«cls.package.name».«cls.simpleName»$«suffix»'''.toString()
+    }
+
+    public static def get(ClassPool pool, Class<?> cls) {
+        try {
+            return pool.get(cls.name)
+        } catch (NotFoundException e) {
+            pool.appendClassPath(new LoaderClassPath(cls.classLoader));
+            return pool.get(cls.name)
+        }
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/PropertiesUtils.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/PropertiesUtils.xtend
new file mode 100644 (file)
index 0000000..7ba62f5
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.impl.utils
+
+import java.util.Hashtable
+import org.opendaylight.controller.sal.binding.impl.Constants
+
+class PropertiesUtils {
+       
+       private new() {}
+       
+       static def setSalServiceType(Hashtable<String,String> properties, String value) {
+               properties.put(Constants.SAL_SERVICE_TYPE,value)
+               return properties
+       }
+       
+       static def getSalServiceType(Hashtable<String,String> properties) {
+               return properties.get(Constants.SAL_SERVICE_TYPE)
+       }
+       
+       static def newProperties() {
+               new Hashtable<String,String>()
+       }
+       
+}
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/package-info.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/package-info.java
new file mode 100644 (file)
index 0000000..5110238
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+  *
+  * This program and the accompanying materials are made available under the
+  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  * and is available at http://www.eclipse.org/legal/epl-v10.html
+  */
+package org.opendaylight.controller.sal.binding.impl.utils;
\ No newline at end of file
index fd7fad6f14f411c8195b8e5c292c350859b04c55..8d0ddad9fef8bbb154217ef8bde1c5d969ee1017 100644 (file)
@@ -3,7 +3,7 @@
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.opendaylight.controller</groupId>
-        <artifactId>sal</artifactId>
+        <artifactId>sal-parent</artifactId>
         <version>1.0-SNAPSHOT</version>
     </parent>
     <artifactId>sal-binding-spi</artifactId>
index db35de1ab75901d95e8e6a8dc8ef454c8f0a5045..bdcb2c21716d32aff9ca0131ff4ca30e0f83b450 100644 (file)
@@ -8,9 +8,9 @@
 package org.opendaylight.controller.sal.binding.spi;
 
 import org.opendaylight.controller.concepts.lang.Transformer;
-import org.opendaylight.controller.yang.binding.DataObject;
-import org.opendaylight.controller.yang.common.QName;
-import org.opendaylight.controller.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 public interface DataDomToJavaTransformer<P extends DataObject> extends Transformer<CompositeNode, P> {
 
index 3c4d48601253de8011523e20dd772ba65c27d338..21154b4078faaddc7158d123526666768c49a2ed 100644 (file)
@@ -8,8 +8,8 @@
 package org.opendaylight.controller.sal.binding.spi;
 
 import org.opendaylight.controller.concepts.lang.InputClassBasedTransformer;
-import org.opendaylight.controller.yang.binding.DataObject;
-import org.opendaylight.controller.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 public interface JavaToDataDomTransformer<I extends DataObject> extends
         InputClassBasedTransformer<DataObject, I, CompositeNode> {
index 701e72c9dc64e2a5e806531efe4343da3c7980d2..44ca27e89fbceb496dac60e32d186990ba738864 100644 (file)
@@ -7,9 +7,9 @@
  */
 package org.opendaylight.controller.sal.binding.spi;
 
-import org.opendaylight.controller.yang.binding.DataObject;
-import org.opendaylight.controller.yang.common.QName;
-import org.opendaylight.controller.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 /**
  * Translator between Binding-Independent format and generated Binding Data Objects
  * 
index b29eac2871c2a1534ead86f552a4acf5a3ddabf9..b3eded9939b98380584ce97581fb5f60f15d2451 100644 (file)
@@ -7,10 +7,10 @@
  */
 package org.opendaylight.controller.sal.binding.spi;
 
-import org.opendaylight.controller.yang.binding.DataObject;
-import org.opendaylight.controller.yang.binding.RpcService;
-import org.opendaylight.controller.yang.common.QName;
-import org.opendaylight.controller.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 public interface MappingProvider {
 
index 0db1bc277571ca7dde8da1bbb2c27d1d525fdf0e..3e32ebc4792004fe609f045ed5823a7b5bbcdf87 100644 (file)
@@ -11,10 +11,10 @@ import java.util.Set;
 import java.util.concurrent.Future;
 
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.controller.yang.binding.DataObject;
-import org.opendaylight.controller.yang.binding.RpcService;
-import org.opendaylight.controller.yang.common.QName;
-import org.opendaylight.controller.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
 
 public interface RpcMapper<T extends RpcService> {
     
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/SALBindingModule.java b/opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/SALBindingModule.java
deleted file mode 100644 (file)
index f3ecf80..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.binding.spi;
-
-import java.util.Set;
-
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.controller.sal.binding.api.BindingAwareService;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerSession;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-
-public interface SALBindingModule {
-
-    void setBroker(BindingAwareBroker broker);
-    void onBISessionAvailable(ProviderSession session);
-    
-    void setMappingProvider(MappingProvider provider);
-
-    Set<Class<? extends BindingAwareService>> getProvidedServices();
-
-    <T extends BindingAwareService> T getServiceForSession(Class<T> service,
-            ConsumerSession session);
-
-    Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality();
-}
index 779a6dc6ab9fffe8092a7ef9af49becce3e1b948..0bb4041b9f336190f2d2c7b4640b485ee0d4df52 100644 (file)
@@ -3,7 +3,7 @@
     <modelVersion>4.0.0</modelVersion>\r
     <parent>\r
         <groupId>org.opendaylight.controller</groupId>\r
-        <artifactId>sal</artifactId>\r
+        <artifactId>sal-parent</artifactId>\r
         <version>1.0-SNAPSHOT</version>\r
     </parent>\r
     <artifactId>sal-broker-impl</artifactId>\r
@@ -32,5 +32,5 @@
             <artifactId>guava</artifactId>\r
             <type>jar</type>\r
         </dependency>\r
-    </dependencies>
+    </dependencies>\r
 </project>
\ No newline at end of file
index b8a0b97eab9abb81b851eeda349ec6156709442a..f0d1cc609d22a54230bed5c2136ae2f32ba701e7 100644 (file)
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.impl;\r
-\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.concurrent.Callable;\r
-import java.util.concurrent.ExecutorService;\r
-import java.util.concurrent.Future;\r
-import org.opendaylight.controller.sal.core.api.Broker;\r
-import org.opendaylight.controller.sal.core.api.BrokerService;\r
-import org.opendaylight.controller.sal.core.api.Consumer;\r
-import org.opendaylight.controller.sal.core.api.Provider;\r
-import org.opendaylight.controller.sal.core.api.RpcImplementation;\r
-import org.opendaylight.controller.sal.core.spi.BrokerModule;\r
-import org.opendaylight.controller.yang.common.QName;\r
-import org.opendaylight.controller.yang.common.RpcResult;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-public class BrokerImpl implements Broker {\r
-    private static Logger log = LoggerFactory.getLogger(BrokerImpl.class);\r
-\r
-    // Broker Generic Context\r
-    private Set<ConsumerSessionImpl> sessions = Collections\r
-            .synchronizedSet(new HashSet<ConsumerSessionImpl>());\r
-    private Set<ProviderSessionImpl> providerSessions = Collections\r
-            .synchronizedSet(new HashSet<ProviderSessionImpl>());\r
-    private Set<BrokerModule> modules = Collections\r
-            .synchronizedSet(new HashSet<BrokerModule>());\r
-    private Map<Class<? extends BrokerService>, BrokerModule> serviceProviders = Collections\r
-            .synchronizedMap(new HashMap<Class<? extends BrokerService>, BrokerModule>());\r
-\r
-    // RPC Context\r
-    private Map<QName, RpcImplementation> rpcImpls = Collections\r
-            .synchronizedMap(new HashMap<QName, RpcImplementation>());\r
-\r
-    // Implementation specific\r
-    private ExecutorService executor;\r
-\r
-    @Override\r
-    public ConsumerSession registerConsumer(Consumer consumer) {\r
-        checkPredicates(consumer);\r
-        log.info("Registering consumer " + consumer);\r
-        ConsumerSessionImpl session = newSessionFor(consumer);\r
-        consumer.onSessionInitiated(session);\r
-        sessions.add(session);\r
-        return session;\r
-    }\r
-\r
-    @Override\r
-    public ProviderSession registerProvider(Provider provider) {\r
-        checkPredicates(provider);\r
-\r
-        ProviderSessionImpl session = newSessionFor(provider);\r
-        provider.onSessionInitiated(session);\r
-        providerSessions.add(session);\r
-        return session;\r
-    }\r
-\r
-    public void addModule(BrokerModule module) {\r
-        log.info("Registering broker module " + module);\r
-        if (modules.contains(module)) {\r
-            log.error("Module already registered");\r
-            throw new IllegalArgumentException("Module already exists.");\r
-        }\r
-    \r
-        Set<Class<? extends BrokerService>> provServices = module\r
-                .getProvidedServices();\r
-        for (Class<? extends BrokerService> serviceType : provServices) {\r
-            log.info("  Registering session service implementation: "\r
-                    + serviceType.getCanonicalName());\r
-            serviceProviders.put(serviceType, module);\r
-        }\r
-    }\r
-\r
-    public <T extends BrokerService> T serviceFor(Class<T> service,\r
-            ConsumerSessionImpl session) {\r
-        BrokerModule prov = serviceProviders.get(service);\r
-        if (prov == null) {\r
-            log.warn("Service " + service.toString() + " is not supported");\r
-            return null;\r
-        }\r
-        return prov.getServiceForSession(service, session);\r
-    }\r
-\r
-    // RPC Functionality\r
-    \r
-    private void addRpcImplementation(QName rpcType,\r
-            RpcImplementation implementation) {\r
-        synchronized (rpcImpls) {\r
-            if (rpcImpls.get(rpcType) != null) {\r
-                throw new IllegalStateException("Implementation for rpc "\r
-                        + rpcType + " is already registered.");\r
-            }\r
-            rpcImpls.put(rpcType, implementation);\r
-        }\r
-        // TODO Add notification for availability of Rpc Implementation\r
-    }\r
-\r
-    private void removeRpcImplementation(QName rpcType,\r
-            RpcImplementation implToRemove) {\r
-        synchronized (rpcImpls) {\r
-            if (implToRemove == rpcImpls.get(rpcType)) {\r
-                rpcImpls.remove(rpcType);\r
-            }\r
-        }\r
-        // TODO Add notification for removal of Rpc Implementation\r
-    }\r
-\r
-    private Future<RpcResult<CompositeNode>> invokeRpc(QName rpc,\r
-            CompositeNode input) {\r
-        RpcImplementation impl = rpcImpls.get(rpc);\r
-        // if()\r
-\r
-        Callable<RpcResult<CompositeNode>> call = callableFor(impl,\r
-                rpc, input);\r
-        Future<RpcResult<CompositeNode>> result = executor.submit(call);\r
-\r
-        return result;\r
-    }\r
-    \r
-    // Validation\r
-\r
-    private void checkPredicates(Provider prov) {\r
-        if (prov == null)\r
-            throw new IllegalArgumentException("Provider should not be null.");\r
-        for (ProviderSessionImpl session : providerSessions) {\r
-            if (prov.equals(session.getProvider()))\r
-                throw new IllegalStateException("Provider already registered");\r
-        }\r
-\r
-    }\r
-\r
-    private void checkPredicates(Consumer cons) {\r
-        if (cons == null)\r
-            throw new IllegalArgumentException("Consumer should not be null.");\r
-        for (ConsumerSessionImpl session : sessions) {\r
-            if (cons.equals(session.getConsumer()))\r
-                throw new IllegalStateException("Consumer already registered");\r
-        }\r
-    }\r
-\r
-    // Private Factory methods\r
-    \r
-    private ConsumerSessionImpl newSessionFor(Consumer cons) {\r
-        return new ConsumerSessionImpl(cons);\r
-    }\r
-\r
-    private ProviderSessionImpl newSessionFor(Provider provider) {\r
-        return new ProviderSessionImpl(provider);\r
-    }\r
-\r
-    private void consumerSessionClosed(ConsumerSessionImpl consumerSessionImpl) {\r
-        sessions.remove(consumerSessionImpl);\r
-        providerSessions.remove(consumerSessionImpl);\r
-    }\r
-\r
-    private static Callable<RpcResult<CompositeNode>> callableFor(\r
-            final RpcImplementation implemenation, final QName rpc,\r
-            final CompositeNode input) {\r
-\r
-        return new Callable<RpcResult<CompositeNode>>() {\r
-\r
-            @Override\r
-            public RpcResult<CompositeNode> call() throws Exception {\r
-                return implemenation.invokeRpc(rpc, input);\r
-            }\r
-        };\r
-    }\r
-    \r
-    private class ConsumerSessionImpl implements ConsumerSession {\r
-\r
-        private final Consumer consumer;\r
-\r
-        private Map<Class<? extends BrokerService>, BrokerService> instantiatedServices = Collections\r
-                .synchronizedMap(new HashMap<Class<? extends BrokerService>, BrokerService>());\r
-        private boolean closed = false;\r
-\r
-        public Consumer getConsumer() {\r
-            return consumer;\r
-        }\r
-\r
-        public ConsumerSessionImpl(Consumer consumer) {\r
-            this.consumer = consumer;\r
-        }\r
-\r
-        @Override\r
-        public Future<RpcResult<CompositeNode>> rpc(QName rpc,\r
-                CompositeNode input) {\r
-            return BrokerImpl.this.invokeRpc(rpc, input);\r
-        }\r
-\r
-        @Override\r
-        public <T extends BrokerService> T getService(Class<T> service) {\r
-            BrokerService potential = instantiatedServices.get(service);\r
-            if (potential != null) {\r
-                @SuppressWarnings("unchecked")\r
-                T ret = (T) potential;\r
-                return ret;\r
-            }\r
-            T ret = BrokerImpl.this.serviceFor(service, this);\r
-            if (ret != null) {\r
-                instantiatedServices.put(service, ret);\r
-            }\r
-            return ret;\r
-        }\r
-\r
-        @Override\r
-        public void close() {\r
-            Collection<BrokerService> toStop = instantiatedServices.values();\r
-            this.closed = true;\r
-            for (BrokerService brokerService : toStop) {\r
-                brokerService.closeSession();\r
-            }\r
-            BrokerImpl.this.consumerSessionClosed(this);\r
-        }\r
-\r
-        @Override\r
-        public boolean isClosed() {\r
-            return closed;\r
-        }\r
-\r
-    }\r
-\r
-    private class ProviderSessionImpl extends ConsumerSessionImpl implements\r
-            ProviderSession {\r
-\r
-        private Provider provider;\r
-        private Map<QName, RpcImplementation> sessionRpcImpls = Collections.synchronizedMap(new HashMap<QName, RpcImplementation>());\r
-\r
-        public ProviderSessionImpl(Provider provider) {\r
-            super(null);\r
-            this.provider = provider;\r
-        }\r
-\r
-        @Override\r
-        public void addRpcImplementation(QName rpcType,\r
-                RpcImplementation implementation)\r
-                throws IllegalArgumentException {\r
-            if (rpcType == null) {\r
-                throw new IllegalArgumentException("rpcType must not be null");\r
-            }\r
-            if (implementation == null) {\r
-                throw new IllegalArgumentException(\r
-                        "Implementation must not be null");\r
-            }\r
-            BrokerImpl.this.addRpcImplementation(rpcType, implementation);\r
-            sessionRpcImpls.put(rpcType, implementation);\r
-        }\r
-\r
-        @Override\r
-        public void removeRpcImplementation(QName rpcType,\r
-                RpcImplementation implToRemove) throws IllegalArgumentException {\r
-            RpcImplementation localImpl = rpcImpls.get(rpcType);\r
-            if (localImpl != implToRemove) {\r
-                throw new IllegalStateException(\r
-                        "Implementation was not registered in this session");\r
-            }\r
-\r
-            BrokerImpl.this.removeRpcImplementation(rpcType, implToRemove);\r
-            sessionRpcImpls.remove(rpcType);\r
-        }\r
-\r
-        public Provider getProvider() {\r
-            return this.provider;\r
-        }\r
-\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.impl;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.Consumer;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.spi.BrokerModule;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BrokerImpl implements Broker {
+    private static Logger log = LoggerFactory.getLogger(BrokerImpl.class);
+
+    // Broker Generic Context
+    private Set<ConsumerSessionImpl> sessions = Collections
+            .synchronizedSet(new HashSet<ConsumerSessionImpl>());
+    private Set<ProviderSessionImpl> providerSessions = Collections
+            .synchronizedSet(new HashSet<ProviderSessionImpl>());
+    private Set<BrokerModule> modules = Collections
+            .synchronizedSet(new HashSet<BrokerModule>());
+    private Map<Class<? extends BrokerService>, BrokerModule> serviceProviders = Collections
+            .synchronizedMap(new HashMap<Class<? extends BrokerService>, BrokerModule>());
+
+    // RPC Context
+    private Map<QName, RpcImplementation> rpcImpls = Collections
+            .synchronizedMap(new HashMap<QName, RpcImplementation>());
+
+    // Implementation specific
+    private ExecutorService executor;
+
+    @Override
+    public ConsumerSession registerConsumer(Consumer consumer) {
+        checkPredicates(consumer);
+        log.info("Registering consumer " + consumer);
+        ConsumerSessionImpl session = newSessionFor(consumer);
+        consumer.onSessionInitiated(session);
+        sessions.add(session);
+        return session;
+    }
+
+    @Override
+    public ProviderSession registerProvider(Provider provider) {
+        checkPredicates(provider);
+
+        ProviderSessionImpl session = newSessionFor(provider);
+        provider.onSessionInitiated(session);
+        providerSessions.add(session);
+        return session;
+    }
+
+    public void addModule(BrokerModule module) {
+        log.info("Registering broker module " + module);
+        if (modules.contains(module)) {
+            log.error("Module already registered");
+            throw new IllegalArgumentException("Module already exists.");
+        }
+    
+        Set<Class<? extends BrokerService>> provServices = module
+                .getProvidedServices();
+        for (Class<? extends BrokerService> serviceType : provServices) {
+            log.info("  Registering session service implementation: "
+                    + serviceType.getCanonicalName());
+            serviceProviders.put(serviceType, module);
+        }
+    }
+
+    public <T extends BrokerService> T serviceFor(Class<T> service,
+            ConsumerSessionImpl session) {
+        BrokerModule prov = serviceProviders.get(service);
+        if (prov == null) {
+            log.warn("Service " + service.toString() + " is not supported");
+            return null;
+        }
+        return prov.getServiceForSession(service, session);
+    }
+
+    // RPC Functionality
+    
+    private void addRpcImplementation(QName rpcType,
+            RpcImplementation implementation) {
+        synchronized (rpcImpls) {
+            if (rpcImpls.get(rpcType) != null) {
+                throw new IllegalStateException("Implementation for rpc "
+                        + rpcType + " is already registered.");
+            }
+            rpcImpls.put(rpcType, implementation);
+        }
+        // TODO Add notification for availability of Rpc Implementation
+    }
+
+    private void removeRpcImplementation(QName rpcType,
+            RpcImplementation implToRemove) {
+        synchronized (rpcImpls) {
+            if (implToRemove == rpcImpls.get(rpcType)) {
+                rpcImpls.remove(rpcType);
+            }
+        }
+        // TODO Add notification for removal of Rpc Implementation
+    }
+
+    private Future<RpcResult<CompositeNode>> invokeRpc(QName rpc,
+            CompositeNode input) {
+        RpcImplementation impl = rpcImpls.get(rpc);
+        // if()
+
+        Callable<RpcResult<CompositeNode>> call = callableFor(impl,
+                rpc, input);
+        Future<RpcResult<CompositeNode>> result = executor.submit(call);
+
+        return result;
+    }
+    
+    // Validation
+
+    private void checkPredicates(Provider prov) {
+        if (prov == null)
+            throw new IllegalArgumentException("Provider should not be null.");
+        for (ProviderSessionImpl session : providerSessions) {
+            if (prov.equals(session.getProvider()))
+                throw new IllegalStateException("Provider already registered");
+        }
+
+    }
+
+    private void checkPredicates(Consumer cons) {
+        if (cons == null)
+            throw new IllegalArgumentException("Consumer should not be null.");
+        for (ConsumerSessionImpl session : sessions) {
+            if (cons.equals(session.getConsumer()))
+                throw new IllegalStateException("Consumer already registered");
+        }
+    }
+
+    // Private Factory methods
+    
+    private ConsumerSessionImpl newSessionFor(Consumer cons) {
+        return new ConsumerSessionImpl(cons);
+    }
+
+    private ProviderSessionImpl newSessionFor(Provider provider) {
+        return new ProviderSessionImpl(provider);
+    }
+
+    private void consumerSessionClosed(ConsumerSessionImpl consumerSessionImpl) {
+        sessions.remove(consumerSessionImpl);
+        providerSessions.remove(consumerSessionImpl);
+    }
+
+    private static Callable<RpcResult<CompositeNode>> callableFor(
+            final RpcImplementation implemenation, final QName rpc,
+            final CompositeNode input) {
+
+        return new Callable<RpcResult<CompositeNode>>() {
+
+            @Override
+            public RpcResult<CompositeNode> call() throws Exception {
+                return implemenation.invokeRpc(rpc, input);
+            }
+        };
+    }
+    
+    private class ConsumerSessionImpl implements ConsumerSession {
+
+        private final Consumer consumer;
+
+        private Map<Class<? extends BrokerService>, BrokerService> instantiatedServices = Collections
+                .synchronizedMap(new HashMap<Class<? extends BrokerService>, BrokerService>());
+        private boolean closed = false;
+
+        public Consumer getConsumer() {
+            return consumer;
+        }
+
+        public ConsumerSessionImpl(Consumer consumer) {
+            this.consumer = consumer;
+        }
+
+        @Override
+        public Future<RpcResult<CompositeNode>> rpc(QName rpc,
+                CompositeNode input) {
+            return BrokerImpl.this.invokeRpc(rpc, input);
+        }
+
+        @Override
+        public <T extends BrokerService> T getService(Class<T> service) {
+            BrokerService potential = instantiatedServices.get(service);
+            if (potential != null) {
+                @SuppressWarnings("unchecked")
+                T ret = (T) potential;
+                return ret;
+            }
+            T ret = BrokerImpl.this.serviceFor(service, this);
+            if (ret != null) {
+                instantiatedServices.put(service, ret);
+            }
+            return ret;
+        }
+
+        @Override
+        public void close() {
+            Collection<BrokerService> toStop = instantiatedServices.values();
+            this.closed = true;
+            for (BrokerService brokerService : toStop) {
+                brokerService.closeSession();
+            }
+            BrokerImpl.this.consumerSessionClosed(this);
+        }
+
+        @Override
+        public boolean isClosed() {
+            return closed;
+        }
+
+    }
+
+    private class ProviderSessionImpl extends ConsumerSessionImpl implements
+            ProviderSession {
+
+        private Provider provider;
+        private Map<QName, RpcImplementation> sessionRpcImpls = Collections.synchronizedMap(new HashMap<QName, RpcImplementation>());
+
+        public ProviderSessionImpl(Provider provider) {
+            super(null);
+            this.provider = provider;
+        }
+
+        @Override
+        public void addRpcImplementation(QName rpcType,
+                RpcImplementation implementation)
+                throws IllegalArgumentException {
+            if (rpcType == null) {
+                throw new IllegalArgumentException("rpcType must not be null");
+            }
+            if (implementation == null) {
+                throw new IllegalArgumentException(
+                        "Implementation must not be null");
+            }
+            BrokerImpl.this.addRpcImplementation(rpcType, implementation);
+            sessionRpcImpls.put(rpcType, implementation);
+        }
+
+        @Override
+        public void removeRpcImplementation(QName rpcType,
+                RpcImplementation implToRemove) throws IllegalArgumentException {
+            RpcImplementation localImpl = rpcImpls.get(rpcType);
+            if (localImpl != implToRemove) {
+                throw new IllegalStateException(
+                        "Implementation was not registered in this session");
+            }
+
+            BrokerImpl.this.removeRpcImplementation(rpcType, implToRemove);
+            sessionRpcImpls.remove(rpcType);
+        }
+
+        public Provider getProvider() {
+            return this.provider;
+        }
+
+    }
+}
index 852f6b6e879bb3d26799a9ae12f2265d774aa7f8..34eba18fcecaa6add7f6bcfe93d844928faec879 100644 (file)
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.impl;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collections;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.concurrent.ExecutorService;\r
-import java.util.concurrent.Future;\r
-\r
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;\r
-import org.opendaylight.controller.sal.common.util.Rpcs;\r
-import org.opendaylight.controller.sal.core.api.BrokerService;\r
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;\r
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;\r
-import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;\r
-import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;\r
-import org.opendaylight.controller.sal.core.api.data.DataBrokerService;\r
-import org.opendaylight.controller.sal.core.api.data.DataCommitHandler;\r
-import org.opendaylight.controller.sal.core.api.data.DataProviderService;\r
-import org.opendaylight.controller.sal.core.api.data.DataValidator;\r
-import org.opendaylight.controller.sal.core.api.data.DataCommitHandler.CommitTransaction;\r
-import org.opendaylight.controller.sal.core.api.data.DataProviderService.DataRefresher;\r
-import org.opendaylight.controller.sal.core.spi.BrokerModule;\r
-import org.opendaylight.controller.yang.common.RpcError;\r
-import org.opendaylight.controller.yang.common.RpcResult;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-import org.opendaylight.controller.yang.data.api.CompositeNodeModification;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-import com.google.common.collect.ImmutableSet;\r
-\r
-public class DataBrokerModule implements BrokerModule {\r
-\r
-    private static final Logger log = LoggerFactory\r
-            .getLogger(DataBrokerModule.class);\r
-\r
-    private static final Set<Class<? extends ProviderFunctionality>> SUPPORTED_PROVIDER_FUNCTIONALITY = ImmutableSet\r
-            .of((Class<? extends ProviderFunctionality>) DataValidator.class,\r
-                    DataRefresher.class, DataCommitHandler.class);\r
-\r
-    private static final Set<Class<? extends BrokerService>> PROVIDED_SESSION_SERVICES = ImmutableSet\r
-            .of((Class<? extends BrokerService>) DataBrokerService.class,\r
-                    DataProviderService.class);\r
-\r
-    private Map<DataStoreIdentifier, StoreContext> storeContext;\r
-\r
-    private ExecutorService executor;\r
-    \r
-    private SequentialCommitHandlerCoordinator coordinator = new SequentialCommitHandlerCoordinator();\r
-\r
-    @Override\r
-    public Set<Class<? extends BrokerService>> getProvidedServices() {\r
-        return PROVIDED_SESSION_SERVICES;\r
-    }\r
-\r
-    @Override\r
-    public Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality() {\r
-        return SUPPORTED_PROVIDER_FUNCTIONALITY;\r
-    }\r
-\r
-    @Override\r
-    public Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality() {\r
-        return Collections.emptySet();\r
-    }\r
-\r
-    @Override\r
-    public <T extends BrokerService> T getServiceForSession(Class<T> service,\r
-            ConsumerSession session) {\r
-        if (DataProviderService.class.equals(service)\r
-                && session instanceof ProviderSession) {\r
-            @SuppressWarnings("unchecked")\r
-            T ret = (T) newDataProviderService(session);\r
-            return ret;\r
-        } else if (DataBrokerService.class.equals(service)) {\r
-\r
-            @SuppressWarnings("unchecked")\r
-            T ret = (T) newDataConsumerService(session);\r
-            return ret;\r
-        }\r
-\r
-        throw new IllegalArgumentException(\r
-                "The requested session-specific service is not provided by this module.");\r
-    }\r
-\r
-    private DataProviderService newDataProviderService(ConsumerSession session) {\r
-        return new DataProviderSession();\r
-    }\r
-\r
-    private DataBrokerService newDataConsumerService(ConsumerSession session) {\r
-        return new DataConsumerSession();\r
-    }\r
-\r
-    private StoreContext context(DataStoreIdentifier store) {\r
-        return storeContext.get(store);\r
-    }\r
-\r
-    private static class StoreContext {\r
-        private Set<DataCommitHandler> commitHandlers = Collections\r
-                .synchronizedSet(new HashSet<DataCommitHandler>());\r
-        private Set<DataValidator> validators = Collections\r
-                .synchronizedSet(new HashSet<DataValidator>());\r
-        private Set<DataRefresher> refreshers = Collections\r
-                .synchronizedSet(new HashSet<DataRefresher>());\r
-    }\r
-\r
-    private class DataConsumerSession implements DataBrokerService {\r
-\r
-        @Override\r
-        public CompositeNode getData(DataStoreIdentifier store) {\r
-            // TODO Implement this method\r
-            throw new UnsupportedOperationException("Not implemented");\r
-        }\r
-\r
-        @Override\r
-        public CompositeNode getData(DataStoreIdentifier store,\r
-                CompositeNode filter) {\r
-            // TODO Implement this method\r
-            throw new UnsupportedOperationException("Not implemented");\r
-        }\r
-\r
-        @Override\r
-        public CompositeNode getCandidateData(DataStoreIdentifier store) {\r
-            // TODO Implement this method\r
-            throw new UnsupportedOperationException("Not implemented");\r
-        }\r
-\r
-        @Override\r
-        public CompositeNode getCandidateData(DataStoreIdentifier store,\r
-                CompositeNode filter) {\r
-            // TODO Implement this method\r
-            throw new UnsupportedOperationException("Not implemented");\r
-        }\r
-\r
-        @Override\r
-        public RpcResult<CompositeNode> editCandidateData(\r
-                DataStoreIdentifier store, CompositeNodeModification changeSet) {\r
-            // TODO Implement this method\r
-            throw new UnsupportedOperationException("Not implemented");\r
-        }\r
-\r
-        @Override\r
-        public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {\r
-            // TODO Implement this method\r
-            throw new UnsupportedOperationException("Not implemented");\r
-        }\r
-\r
-        @Override\r
-        public void closeSession() {\r
-            // TODO Implement this method\r
-            throw new UnsupportedOperationException("Not implemented");\r
-        }\r
-\r
-        @Override\r
-        public Set<DataStoreIdentifier> getDataStores() {\r
-            // TODO Auto-generated method stub\r
-            return null;\r
-        }\r
-\r
-    }\r
-\r
-    private class DataProviderSession extends DataConsumerSession implements\r
-            DataProviderService {\r
-\r
-        private Set<DataCommitHandler> providerCommitHandlers = new HashSet<DataCommitHandler>();\r
-        private Set<DataValidator> providerValidators = new HashSet<DataValidator>();\r
-        private Set<DataRefresher> providerRefreshers = new HashSet<DataRefresher>();\r
-\r
-        @Override\r
-        public void addValidator(DataStoreIdentifier store,\r
-                DataValidator validator) {\r
-            if (validator == null)\r
-                throw new IllegalArgumentException(\r
-                        "Validator should not be null");\r
-\r
-            providerValidators.add(validator);\r
-            context(store).validators.add(validator);\r
-        }\r
-\r
-        @Override\r
-        public void removeValidator(DataStoreIdentifier store,\r
-                DataValidator validator) {\r
-            if (validator == null)\r
-                throw new IllegalArgumentException(\r
-                        "Validator should not be null");\r
-\r
-            providerValidators.remove(validator);\r
-            context(store).validators.remove(validator);\r
-        }\r
-\r
-        @Override\r
-        public void addCommitHandler(DataStoreIdentifier store,\r
-                DataCommitHandler provider) {\r
-            if (provider == null)\r
-                throw new IllegalArgumentException(\r
-                        "CommitHandler should not be null");\r
-\r
-            providerCommitHandlers.add(provider);\r
-            context(store).commitHandlers.add(provider);\r
-        }\r
-\r
-        @Override\r
-        public void removeCommitHandler(DataStoreIdentifier store,\r
-                DataCommitHandler provider) {\r
-            if (provider == null)\r
-                throw new IllegalArgumentException(\r
-                        "CommitHandler should not be null");\r
-\r
-            providerCommitHandlers.remove(provider);\r
-            context(store).commitHandlers.remove(provider);\r
-        }\r
-\r
-        @Override\r
-        public void addRefresher(DataStoreIdentifier store,\r
-                DataRefresher provider) {\r
-            if (provider == null)\r
-                throw new IllegalArgumentException(\r
-                        "Refresher should not be null");\r
-\r
-            providerRefreshers.add(provider);\r
-            context(store).refreshers.add(provider);\r
-        }\r
-\r
-        @Override\r
-        public void removeRefresher(DataStoreIdentifier store,\r
-                DataRefresher provider) {\r
-            if (provider == null)\r
-                throw new IllegalArgumentException(\r
-                        "Refresher should not be null");\r
-\r
-            providerRefreshers.remove(provider);\r
-            context(store).refreshers.remove(provider);\r
-        }\r
-\r
-    }\r
-\r
-    private class SequentialCommitHandlerCoordinator implements\r
-            DataCommitHandler {\r
-\r
-        @Override\r
-        public RpcResult<CommitTransaction> requestCommit(\r
-                DataStoreIdentifier store) {\r
-            List<RpcError> errors = new ArrayList<RpcError>();\r
-            Set<CommitTransaction> transactions = new HashSet<DataCommitHandler.CommitTransaction>();\r
-            boolean successful = true;\r
-\r
-            for (DataCommitHandler commitHandler : context(store).commitHandlers) {\r
-                try {\r
-                    RpcResult<CommitTransaction> partialResult = commitHandler\r
-                            .requestCommit(store);\r
-                    successful = partialResult.isSuccessful() & successful;\r
-                    if (partialResult.isSuccessful()) {\r
-                        transactions.add(partialResult.getResult());\r
-                    }\r
-\r
-                    errors.addAll(partialResult.getErrors());\r
-                } catch (Exception e) {\r
-                    log.error("Uncaught exception prevented commit request."\r
-                            + e.getMessage(), e);\r
-                    successful = false;\r
-                    // FIXME: Add RPC Error with exception.\r
-                }\r
-                if (successful == false)\r
-                    break;\r
-            }\r
-            CommitTransaction transaction = new SequentialCommitTransaction(\r
-                    store, transactions);\r
-            return Rpcs.getRpcResult(successful, transaction, errors);\r
-        }\r
-\r
-        @Override\r
-        public Set<DataStoreIdentifier> getSupportedDataStores() {\r
-            return Collections.emptySet();\r
-        }\r
-    }\r
-\r
-    private class SequentialCommitTransaction implements CommitTransaction {\r
-\r
-        final Set<CommitTransaction> transactions;\r
-        final DataStoreIdentifier store;\r
-\r
-        public SequentialCommitTransaction(DataStoreIdentifier s,\r
-                Set<CommitTransaction> t) {\r
-            transactions = t;\r
-            store = s;\r
-        }\r
-\r
-        @Override\r
-        public RpcResult<Void> finish() {\r
-            List<RpcError> errors = new ArrayList<RpcError>();\r
-            boolean successful = true;\r
-\r
-            for (CommitTransaction commitHandler : transactions) {\r
-                try {\r
-                    RpcResult<Void> partialResult = commitHandler.finish();\r
-                    successful = partialResult.isSuccessful() & successful;\r
-                    errors.addAll(partialResult.getErrors());\r
-                } catch (Exception e) {\r
-                    log.error(\r
-                            "Uncaught exception prevented finishing of commit."\r
-                                    + e.getMessage(), e);\r
-                    successful = false;\r
-                    // FIXME: Add RPC Error with exception.\r
-                }\r
-                if (successful == false)\r
-                    break;\r
-            }\r
-\r
-            return Rpcs.getRpcResult(successful, null, errors);\r
-        }\r
-\r
-        @Override\r
-        public RpcResult<Void> rollback() {\r
-            List<RpcError> errors = new ArrayList<RpcError>();\r
-            boolean successful = true;\r
-\r
-            for (CommitTransaction commitHandler : transactions) {\r
-                try {\r
-                    RpcResult<Void> partialResult = commitHandler.rollback();\r
-                    successful = partialResult.isSuccessful() & successful;\r
-                    errors.addAll(partialResult.getErrors());\r
-                } catch (Exception e) {\r
-                    log.error(\r
-                            "Uncaught exception prevented rollback of commit."\r
-                                    + e.getMessage(), e);\r
-                    successful = false;\r
-                    // FIXME: Add RPC Error with exception.\r
-                }\r
-                if (successful == false)\r
-                    break;\r
-            }\r
-\r
-            return Rpcs.getRpcResult(successful, null, errors);\r
-        }\r
-\r
-        @Override\r
-        public DataStoreIdentifier getDataStore() {\r
-            return this.store;\r
-        }\r
-\r
-        @Override\r
-        public DataCommitHandler getHandler() {\r
-            return coordinator;\r
-        }\r
-    }\r
-\r
-    private class ValidationCoordinator implements DataValidator {\r
-\r
-        private final DataStoreIdentifier store;\r
-\r
-        ValidationCoordinator(DataStoreIdentifier store) {\r
-            this.store = store;\r
-        }\r
-\r
-        @Override\r
-        public RpcResult<Void> validate(CompositeNode toValidate) {\r
-            List<RpcError> errors = new ArrayList<RpcError>();\r
-            boolean successful = true;\r
-\r
-            for (DataValidator validator : context(store).validators) {\r
-                try {\r
-                    RpcResult<Void> partialResult = validator\r
-                            .validate(toValidate);\r
-                    successful = partialResult.isSuccessful() & successful;\r
-                    errors.addAll(partialResult.getErrors());\r
-                } catch (Exception e) {\r
-                    log.error(\r
-                            "Uncaught exception prevented validation."\r
-                                    + e.getMessage(), e);\r
-                    successful = false;\r
-                    // FIXME: Add RPC Error with exception.\r
-                }\r
-                if (successful == false)\r
-                    break;\r
-            }\r
-\r
-            return Rpcs.getRpcResult(successful, null, errors);\r
-        }\r
-\r
-        @Override\r
-        public Set<DataStoreIdentifier> getSupportedDataStores() {\r
-            return Collections.emptySet();\r
-        }\r
-\r
-    }\r
-\r
-    private class DataRefreshCoordinator implements DataRefresher {\r
-\r
-        private final DataStoreIdentifier store;\r
-\r
-        DataRefreshCoordinator(DataStoreIdentifier store) {\r
-            this.store = store;\r
-        }\r
-\r
-        @Override\r
-        public void refreshData() {\r
-\r
-            for (DataRefresher refresher : context(store).refreshers) {\r
-                try {\r
-                    refresher.refreshData();\r
-                } catch (Exception e) {\r
-                    log.error(\r
-                            "Uncaught exception during refresh of data: "\r
-                                    + e.getMessage(), e);\r
-                }\r
-\r
-            }\r
-        }\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;
+import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.data.DataCommitHandler;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.data.DataValidator;
+import org.opendaylight.controller.sal.core.api.data.DataCommitHandler.CommitTransaction;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService.DataRefresher;
+import org.opendaylight.controller.sal.core.spi.BrokerModule;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableSet;
+
+public class DataBrokerModule implements BrokerModule {
+
+    private static final Logger log = LoggerFactory
+            .getLogger(DataBrokerModule.class);
+
+    private static final Set<Class<? extends ProviderFunctionality>> SUPPORTED_PROVIDER_FUNCTIONALITY = ImmutableSet
+            .of((Class<? extends ProviderFunctionality>) DataValidator.class,
+                    DataRefresher.class, DataCommitHandler.class);
+
+    private static final Set<Class<? extends BrokerService>> PROVIDED_SESSION_SERVICES = ImmutableSet
+            .of((Class<? extends BrokerService>) DataBrokerService.class,
+                    DataProviderService.class);
+
+    private Map<DataStoreIdentifier, StoreContext> storeContext;
+
+    private ExecutorService executor;
+    
+    private SequentialCommitHandlerCoordinator coordinator = new SequentialCommitHandlerCoordinator();
+
+    @Override
+    public Set<Class<? extends BrokerService>> getProvidedServices() {
+        return PROVIDED_SESSION_SERVICES;
+    }
+
+    @Override
+    public Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality() {
+        return SUPPORTED_PROVIDER_FUNCTIONALITY;
+    }
+
+    @Override
+    public Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public <T extends BrokerService> T getServiceForSession(Class<T> service,
+            ConsumerSession session) {
+        if (DataProviderService.class.equals(service)
+                && session instanceof ProviderSession) {
+            @SuppressWarnings("unchecked")
+            T ret = (T) newDataProviderService(session);
+            return ret;
+        } else if (DataBrokerService.class.equals(service)) {
+
+            @SuppressWarnings("unchecked")
+            T ret = (T) newDataConsumerService(session);
+            return ret;
+        }
+
+        throw new IllegalArgumentException(
+                "The requested session-specific service is not provided by this module.");
+    }
+
+    private DataProviderService newDataProviderService(ConsumerSession session) {
+        return new DataProviderSession();
+    }
+
+    private DataBrokerService newDataConsumerService(ConsumerSession session) {
+        return new DataConsumerSession();
+    }
+
+    private StoreContext context(DataStoreIdentifier store) {
+        return storeContext.get(store);
+    }
+
+    private static class StoreContext {
+        private Set<DataCommitHandler> commitHandlers = Collections
+                .synchronizedSet(new HashSet<DataCommitHandler>());
+        private Set<DataValidator> validators = Collections
+                .synchronizedSet(new HashSet<DataValidator>());
+        private Set<DataRefresher> refreshers = Collections
+                .synchronizedSet(new HashSet<DataRefresher>());
+    }
+
+    private class DataConsumerSession implements DataBrokerService {
+
+        @Override
+        public CompositeNode getData(DataStoreIdentifier store) {
+            // TODO Implement this method
+            throw new UnsupportedOperationException("Not implemented");
+        }
+
+        @Override
+        public CompositeNode getData(DataStoreIdentifier store,
+                CompositeNode filter) {
+            // TODO Implement this method
+            throw new UnsupportedOperationException("Not implemented");
+        }
+
+        @Override
+        public CompositeNode getCandidateData(DataStoreIdentifier store) {
+            // TODO Implement this method
+            throw new UnsupportedOperationException("Not implemented");
+        }
+
+        @Override
+        public CompositeNode getCandidateData(DataStoreIdentifier store,
+                CompositeNode filter) {
+            // TODO Implement this method
+            throw new UnsupportedOperationException("Not implemented");
+        }
+
+        @Override
+        public RpcResult<CompositeNode> editCandidateData(
+                DataStoreIdentifier store, MutableCompositeNode changeSet) {
+            // TODO Implement this method
+            throw new UnsupportedOperationException("Not implemented");
+        }
+
+        @Override
+        public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
+            // TODO Implement this method
+            throw new UnsupportedOperationException("Not implemented");
+        }
+
+        @Override
+        public void closeSession() {
+            // TODO Implement this method
+            throw new UnsupportedOperationException("Not implemented");
+        }
+
+        @Override
+        public Set<DataStoreIdentifier> getDataStores() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+    }
+
+    private class DataProviderSession extends DataConsumerSession implements
+            DataProviderService {
+
+        private Set<DataCommitHandler> providerCommitHandlers = new HashSet<DataCommitHandler>();
+        private Set<DataValidator> providerValidators = new HashSet<DataValidator>();
+        private Set<DataRefresher> providerRefreshers = new HashSet<DataRefresher>();
+
+        @Override
+        public void addValidator(DataStoreIdentifier store,
+                DataValidator validator) {
+            if (validator == null)
+                throw new IllegalArgumentException(
+                        "Validator should not be null");
+
+            providerValidators.add(validator);
+            context(store).validators.add(validator);
+        }
+
+        @Override
+        public void removeValidator(DataStoreIdentifier store,
+                DataValidator validator) {
+            if (validator == null)
+                throw new IllegalArgumentException(
+                        "Validator should not be null");
+
+            providerValidators.remove(validator);
+            context(store).validators.remove(validator);
+        }
+
+        @Override
+        public void addCommitHandler(DataStoreIdentifier store,
+                DataCommitHandler provider) {
+            if (provider == null)
+                throw new IllegalArgumentException(
+                        "CommitHandler should not be null");
+
+            providerCommitHandlers.add(provider);
+            context(store).commitHandlers.add(provider);
+        }
+
+        @Override
+        public void removeCommitHandler(DataStoreIdentifier store,
+                DataCommitHandler provider) {
+            if (provider == null)
+                throw new IllegalArgumentException(
+                        "CommitHandler should not be null");
+
+            providerCommitHandlers.remove(provider);
+            context(store).commitHandlers.remove(provider);
+        }
+
+        @Override
+        public void addRefresher(DataStoreIdentifier store,
+                DataRefresher provider) {
+            if (provider == null)
+                throw new IllegalArgumentException(
+                        "Refresher should not be null");
+
+            providerRefreshers.add(provider);
+            context(store).refreshers.add(provider);
+        }
+
+        @Override
+        public void removeRefresher(DataStoreIdentifier store,
+                DataRefresher provider) {
+            if (provider == null)
+                throw new IllegalArgumentException(
+                        "Refresher should not be null");
+
+            providerRefreshers.remove(provider);
+            context(store).refreshers.remove(provider);
+        }
+
+    }
+
+    private class SequentialCommitHandlerCoordinator implements
+            DataCommitHandler {
+
+        @Override
+        public RpcResult<CommitTransaction> requestCommit(
+                DataStoreIdentifier store) {
+            List<RpcError> errors = new ArrayList<RpcError>();
+            Set<CommitTransaction> transactions = new HashSet<DataCommitHandler.CommitTransaction>();
+            boolean successful = true;
+
+            for (DataCommitHandler commitHandler : context(store).commitHandlers) {
+                try {
+                    RpcResult<CommitTransaction> partialResult = commitHandler
+                            .requestCommit(store);
+                    successful = partialResult.isSuccessful() & successful;
+                    if (partialResult.isSuccessful()) {
+                        transactions.add(partialResult.getResult());
+                    }
+
+                    errors.addAll(partialResult.getErrors());
+                } catch (Exception e) {
+                    log.error("Uncaught exception prevented commit request."
+                            + e.getMessage(), e);
+                    successful = false;
+                    // FIXME: Add RPC Error with exception.
+                }
+                if (successful == false)
+                    break;
+            }
+            CommitTransaction transaction = new SequentialCommitTransaction(
+                    store, transactions);
+            return Rpcs.getRpcResult(successful, transaction, errors);
+        }
+
+        @Override
+        public Set<DataStoreIdentifier> getSupportedDataStores() {
+            return Collections.emptySet();
+        }
+    }
+
+    private class SequentialCommitTransaction implements CommitTransaction {
+
+        final Set<CommitTransaction> transactions;
+        final DataStoreIdentifier store;
+
+        public SequentialCommitTransaction(DataStoreIdentifier s,
+                Set<CommitTransaction> t) {
+            transactions = t;
+            store = s;
+        }
+
+        @Override
+        public RpcResult<Void> finish() {
+            List<RpcError> errors = new ArrayList<RpcError>();
+            boolean successful = true;
+
+            for (CommitTransaction commitHandler : transactions) {
+                try {
+                    RpcResult<Void> partialResult = commitHandler.finish();
+                    successful = partialResult.isSuccessful() & successful;
+                    errors.addAll(partialResult.getErrors());
+                } catch (Exception e) {
+                    log.error(
+                            "Uncaught exception prevented finishing of commit."
+                                    + e.getMessage(), e);
+                    successful = false;
+                    // FIXME: Add RPC Error with exception.
+                }
+                if (successful == false)
+                    break;
+            }
+
+            return Rpcs.getRpcResult(successful, null, errors);
+        }
+
+        @Override
+        public RpcResult<Void> rollback() {
+            List<RpcError> errors = new ArrayList<RpcError>();
+            boolean successful = true;
+
+            for (CommitTransaction commitHandler : transactions) {
+                try {
+                    RpcResult<Void> partialResult = commitHandler.rollback();
+                    successful = partialResult.isSuccessful() & successful;
+                    errors.addAll(partialResult.getErrors());
+                } catch (Exception e) {
+                    log.error(
+                            "Uncaught exception prevented rollback of commit."
+                                    + e.getMessage(), e);
+                    successful = false;
+                    // FIXME: Add RPC Error with exception.
+                }
+                if (successful == false)
+                    break;
+            }
+
+            return Rpcs.getRpcResult(successful, null, errors);
+        }
+
+        @Override
+        public DataStoreIdentifier getDataStore() {
+            return this.store;
+        }
+
+        @Override
+        public DataCommitHandler getHandler() {
+            return coordinator;
+        }
+    }
+
+    private class ValidationCoordinator implements DataValidator {
+
+        private final DataStoreIdentifier store;
+
+        ValidationCoordinator(DataStoreIdentifier store) {
+            this.store = store;
+        }
+
+        @Override
+        public RpcResult<Void> validate(CompositeNode toValidate) {
+            List<RpcError> errors = new ArrayList<RpcError>();
+            boolean successful = true;
+
+            for (DataValidator validator : context(store).validators) {
+                try {
+                    RpcResult<Void> partialResult = validator
+                            .validate(toValidate);
+                    successful = partialResult.isSuccessful() & successful;
+                    errors.addAll(partialResult.getErrors());
+                } catch (Exception e) {
+                    log.error(
+                            "Uncaught exception prevented validation."
+                                    + e.getMessage(), e);
+                    successful = false;
+                    // FIXME: Add RPC Error with exception.
+                }
+                if (successful == false)
+                    break;
+            }
+
+            return Rpcs.getRpcResult(successful, null, errors);
+        }
+
+        @Override
+        public Set<DataStoreIdentifier> getSupportedDataStores() {
+            return Collections.emptySet();
+        }
+
+    }
+
+    private class DataRefreshCoordinator implements DataRefresher {
+
+        private final DataStoreIdentifier store;
+
+        DataRefreshCoordinator(DataStoreIdentifier store) {
+            this.store = store;
+        }
+
+        @Override
+        public void refreshData() {
+
+            for (DataRefresher refresher : context(store).refreshers) {
+                try {
+                    refresher.refreshData();
+                } catch (Exception e) {
+                    log.error(
+                            "Uncaught exception during refresh of data: "
+                                    + e.getMessage(), e);
+                }
+
+            }
+        }
+    }
+}
index bd70ee14a58dfc0c85340243897b508feb4a2ab1..2bbbde632b73a34364cded77aed1e4a5644c85e7 100644 (file)
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.impl;\r
-\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.HashSet;\r
-import java.util.Map;\r
-import java.util.Map.Entry;\r
-import java.util.Set;\r
-\r
-import org.opendaylight.controller.sal.core.api.BrokerService;\r
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;\r
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;\r
-import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;\r
-import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;\r
-import org.opendaylight.controller.sal.core.api.notify.NotificationListener;\r
-import org.opendaylight.controller.sal.core.api.notify.NotificationProviderService;\r
-import org.opendaylight.controller.sal.core.api.notify.NotificationService;\r
-import org.opendaylight.controller.sal.core.spi.BrokerModule;\r
-import org.opendaylight.controller.yang.common.QName;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-import com.google.common.collect.HashMultimap;\r
-import com.google.common.collect.ImmutableSet;\r
-import com.google.common.collect.Multimap;\r
-\r
-public class NotificationModule implements BrokerModule {\r
-    private static Logger log = LoggerFactory\r
-            .getLogger(NotificationModule.class);\r
-\r
-    private Multimap<QName, NotificationListener> listeners = HashMultimap\r
-            .create();\r
-\r
-    private static final Set<Class<? extends BrokerService>> PROVIDED_SERVICE_TYPE = ImmutableSet\r
-            .of((Class<? extends BrokerService>) NotificationService.class,\r
-                    NotificationProviderService.class);\r
-\r
-    private static final Set<Class<? extends ConsumerFunctionality>> SUPPORTED_CONSUMER_FUNCTIONALITY = ImmutableSet\r
-            .of((Class<? extends ConsumerFunctionality>) NotificationListener.class,\r
-                    NotificationListener.class); // Workaround: if we use the\r
-                                                 // version of method with only\r
-                                                 // one argument, the generics\r
-                                                 // inference will not work\r
-\r
-    @Override\r
-    public Set<Class<? extends BrokerService>> getProvidedServices() {\r
-        return PROVIDED_SERVICE_TYPE;\r
-    }\r
-\r
-    @Override\r
-    public Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality() {\r
-        return SUPPORTED_CONSUMER_FUNCTIONALITY;\r
-    }\r
-\r
-    @Override\r
-    public <T extends BrokerService> T getServiceForSession(Class<T> service,\r
-            ConsumerSession session) {\r
-        if (NotificationProviderService.class.equals(service)\r
-                && session instanceof ProviderSession) {\r
-            @SuppressWarnings("unchecked")\r
-            T ret = (T) newNotificationProviderService(session);\r
-            return ret;\r
-        } else if (NotificationService.class.equals(service)) {\r
-\r
-            @SuppressWarnings("unchecked")\r
-            T ret = (T) newNotificationConsumerService(session);\r
-            return ret;\r
-        }\r
-\r
-        throw new IllegalArgumentException(\r
-                "The requested session-specific service is not provided by this module.");\r
-    }\r
-\r
-    private void sendNotification(CompositeNode notification) {\r
-        QName type = notification.getNodeType();\r
-        Collection<NotificationListener> toNotify = listeners.get(type);\r
-        log.info("Publishing notification " + type);\r
-\r
-        if (toNotify == null) {\r
-            // No listeners were registered - returns.\r
-            return;\r
-        }\r
-\r
-        for (NotificationListener listener : toNotify) {\r
-            try {\r
-                // FIXME: ensure that notification is immutable\r
-                listener.onNotification(notification);\r
-            } catch (Exception e) {\r
-                log.error("Uncaught exception in NotificationListener", e);\r
-            }\r
-        }\r
-\r
-    }\r
-\r
-    private NotificationService newNotificationConsumerService(\r
-            ConsumerSession session) {\r
-        return new NotificationConsumerSessionImpl();\r
-    }\r
-\r
-    private NotificationProviderService newNotificationProviderService(\r
-            ConsumerSession session) {\r
-        return new NotificationProviderSessionImpl();\r
-    }\r
-\r
-    private class NotificationConsumerSessionImpl implements\r
-            NotificationService {\r
-\r
-        private Multimap<QName, NotificationListener> consumerListeners = HashMultimap\r
-                .create();\r
-        private boolean closed = false;\r
-\r
-        @Override\r
-        public void addNotificationListener(QName notification,\r
-                NotificationListener listener) {\r
-            checkSessionState();\r
-            if (notification == null) {\r
-                throw new IllegalArgumentException(\r
-                        "Notification type must not be null.");\r
-            }\r
-            if (listener == null) {\r
-                throw new IllegalArgumentException("Listener must not be null.");\r
-            }\r
-\r
-            consumerListeners.put(notification, listener);\r
-            listeners.put(notification, listener);\r
-            log.info("Registered listener for notification: " + notification);\r
-        }\r
-\r
-        @Override\r
-        public void removeNotificationListener(QName notification,\r
-                NotificationListener listener) {\r
-            checkSessionState();\r
-            if (notification == null) {\r
-                throw new IllegalArgumentException(\r
-                        "Notification type must not be null.");\r
-            }\r
-            if (listener == null) {\r
-                throw new IllegalArgumentException("Listener must not be null.");\r
-            }\r
-            consumerListeners.remove(notification, listener);\r
-            listeners.remove(notification, listener);\r
-        }\r
-\r
-        @Override\r
-        public void closeSession() {\r
-            closed = true;\r
-            Map<QName, Collection<NotificationListener>> toRemove = consumerListeners\r
-                    .asMap();\r
-            for (Entry<QName, Collection<NotificationListener>> entry : toRemove\r
-                    .entrySet()) {\r
-                listeners.remove(entry.getKey(), entry.getValue());\r
-            }\r
-        }\r
-\r
-        protected void checkSessionState() {\r
-            if (closed)\r
-                throw new IllegalStateException("Session is closed");\r
-        }\r
-    }\r
-\r
-    private class NotificationProviderSessionImpl extends\r
-            NotificationConsumerSessionImpl implements\r
-            NotificationProviderService {\r
-\r
-        @Override\r
-        public void sendNotification(CompositeNode notification) {\r
-            checkSessionState();\r
-            if (notification == null)\r
-                throw new IllegalArgumentException(\r
-                        "Notification must not be null.");\r
-            NotificationModule.this.sendNotification(notification);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality() {\r
-        return Collections.emptySet();\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.impl;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;
+import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
+import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
+import org.opendaylight.controller.sal.core.api.notify.NotificationProviderService;
+import org.opendaylight.controller.sal.core.api.notify.NotificationService;
+import org.opendaylight.controller.sal.core.spi.BrokerModule;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+
+public class NotificationModule implements BrokerModule {
+    private static Logger log = LoggerFactory
+            .getLogger(NotificationModule.class);
+
+    private Multimap<QName, NotificationListener> listeners = HashMultimap
+            .create();
+
+    private static final Set<Class<? extends BrokerService>> PROVIDED_SERVICE_TYPE = ImmutableSet
+            .of((Class<? extends BrokerService>) NotificationService.class,
+                    NotificationProviderService.class);
+
+    private static final Set<Class<? extends ConsumerFunctionality>> SUPPORTED_CONSUMER_FUNCTIONALITY = ImmutableSet
+            .of((Class<? extends ConsumerFunctionality>) NotificationListener.class,
+                    NotificationListener.class); // Workaround: if we use the
+                                                 // version of method with only
+                                                 // one argument, the generics
+                                                 // inference will not work
+
+    @Override
+    public Set<Class<? extends BrokerService>> getProvidedServices() {
+        return PROVIDED_SERVICE_TYPE;
+    }
+
+    @Override
+    public Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality() {
+        return SUPPORTED_CONSUMER_FUNCTIONALITY;
+    }
+
+    @Override
+    public <T extends BrokerService> T getServiceForSession(Class<T> service,
+            ConsumerSession session) {
+        if (NotificationProviderService.class.equals(service)
+                && session instanceof ProviderSession) {
+            @SuppressWarnings("unchecked")
+            T ret = (T) newNotificationProviderService(session);
+            return ret;
+        } else if (NotificationService.class.equals(service)) {
+
+            @SuppressWarnings("unchecked")
+            T ret = (T) newNotificationConsumerService(session);
+            return ret;
+        }
+
+        throw new IllegalArgumentException(
+                "The requested session-specific service is not provided by this module.");
+    }
+
+    private void sendNotification(CompositeNode notification) {
+        QName type = notification.getNodeType();
+        Collection<NotificationListener> toNotify = listeners.get(type);
+        log.info("Publishing notification " + type);
+
+        if (toNotify == null) {
+            // No listeners were registered - returns.
+            return;
+        }
+
+        for (NotificationListener listener : toNotify) {
+            try {
+                // FIXME: ensure that notification is immutable
+                listener.onNotification(notification);
+            } catch (Exception e) {
+                log.error("Uncaught exception in NotificationListener", e);
+            }
+        }
+
+    }
+
+    private NotificationService newNotificationConsumerService(
+            ConsumerSession session) {
+        return new NotificationConsumerSessionImpl();
+    }
+
+    private NotificationProviderService newNotificationProviderService(
+            ConsumerSession session) {
+        return new NotificationProviderSessionImpl();
+    }
+
+    private class NotificationConsumerSessionImpl implements
+            NotificationService {
+
+        private Multimap<QName, NotificationListener> consumerListeners = HashMultimap
+                .create();
+        private boolean closed = false;
+
+        @Override
+        public void addNotificationListener(QName notification,
+                NotificationListener listener) {
+            checkSessionState();
+            if (notification == null) {
+                throw new IllegalArgumentException(
+                        "Notification type must not be null.");
+            }
+            if (listener == null) {
+                throw new IllegalArgumentException("Listener must not be null.");
+            }
+
+            consumerListeners.put(notification, listener);
+            listeners.put(notification, listener);
+            log.info("Registered listener for notification: " + notification);
+        }
+
+        @Override
+        public void removeNotificationListener(QName notification,
+                NotificationListener listener) {
+            checkSessionState();
+            if (notification == null) {
+                throw new IllegalArgumentException(
+                        "Notification type must not be null.");
+            }
+            if (listener == null) {
+                throw new IllegalArgumentException("Listener must not be null.");
+            }
+            consumerListeners.remove(notification, listener);
+            listeners.remove(notification, listener);
+        }
+
+        @Override
+        public void closeSession() {
+            closed = true;
+            Map<QName, Collection<NotificationListener>> toRemove = consumerListeners
+                    .asMap();
+            for (Entry<QName, Collection<NotificationListener>> entry : toRemove
+                    .entrySet()) {
+                listeners.remove(entry.getKey(), entry.getValue());
+            }
+        }
+
+        protected void checkSessionState() {
+            if (closed)
+                throw new IllegalStateException("Session is closed");
+        }
+    }
+
+    private class NotificationProviderSessionImpl extends
+            NotificationConsumerSessionImpl implements
+            NotificationProviderService {
+
+        @Override
+        public void sendNotification(CompositeNode notification) {
+            checkSessionState();
+            if (notification == null)
+                throw new IllegalArgumentException(
+                        "Notification must not be null.");
+            NotificationModule.this.sendNotification(notification);
+        }
+    }
+
+    @Override
+    public Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality() {
+        return Collections.emptySet();
+    }
+}
index fedd6d12f05af7d95e1569313b304a4c990c5773..f1bed65fd108c9360dfe7ce7b8e6b1675ae6d65d 100644 (file)
@@ -1,23 +1,24 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
-    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
-    <modelVersion>4.0.0</modelVersion>\r
-    <parent>\r
-        <groupId>org.opendaylight.controller</groupId>\r
-        <artifactId>sal</artifactId>\r
-        <version>1.0-SNAPSHOT</version>\r
-    </parent>\r
-    <artifactId>sal-common-util</artifactId>\r
-\r
-    <dependencies>\r
-        <dependency>\r
-            <groupId>org.opendaylight.controller</groupId>\r
-            <artifactId>yang-common</artifactId>\r
-        </dependency>\r
-        <dependency>\r
-            <groupId>org.opendaylight.controller</groupId>\r
-            <artifactId>sal-common</artifactId>\r
-            <version>1.0-SNAPSHOT</version>\r
-        </dependency>\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>sal-common-util</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
     </dependencies>
 
+    <packaging>bundle</packaging>
 </project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Futures.java b/opendaylight/sal/yang-prototype/sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Futures.java
new file mode 100644 (file)
index 0000000..c942159
--- /dev/null
@@ -0,0 +1,51 @@
+package org.opendaylight.controller.sal.common.util;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class Futures {
+
+       private Futures(){}
+       
+       public static <T> Future<T> immediateFuture(T result) {
+               return new ImmediateFuture<T>(result);
+       }
+       
+       private static class ImmediateFuture<T> implements Future<T> {
+
+               private final T result;
+               
+               public ImmediateFuture(T result) {
+                       this.result = result;
+               }
+               
+               @Override
+               public boolean cancel(boolean mayInterruptIfRunning) {
+                       return false;
+               }
+
+               @Override
+               public boolean isCancelled() {
+                       return false;
+               }
+
+               @Override
+               public boolean isDone() {
+                       return true;
+               }
+
+               @Override
+               public T get() throws InterruptedException, ExecutionException {
+                       return result;
+               }
+
+               @Override
+               public T get(long timeout, TimeUnit unit) throws InterruptedException,
+                               ExecutionException, TimeoutException {
+                       return result;
+               }
+               
+       }
+}
index d397bff0d64533a0944134c3c799da3fb30ca294..e46b566522e26232081cd1fd72a96d873bdebae5 100644 (file)
@@ -1,53 +1,53 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.common.util;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import org.opendaylight.controller.yang.common.RpcError;\r
-import org.opendaylight.controller.yang.common.RpcResult;\r
-\r
-public class Rpcs {\r
-    public static <T> RpcResult<T> getRpcResult(boolean successful, T result,\r
-            Collection<RpcError> errors) {\r
-        RpcResult<T> ret = new RpcResultTO<T>(successful, result, errors);\r
-        return ret;\r
-    }\r
-\r
-    private static class RpcResultTO<T> implements RpcResult<T> {\r
-\r
-        private final Collection<RpcError> errors;\r
-        private final T result;\r
-        private final boolean successful;\r
-\r
-        public RpcResultTO(boolean successful, T result,\r
-                Collection<RpcError> errors) {\r
-            this.successful = successful;\r
-            this.result = result;\r
-            this.errors = Collections.unmodifiableList(new ArrayList<RpcError>(\r
-                    errors));\r
-        }\r
-\r
-        @Override\r
-        public boolean isSuccessful() {\r
-            return successful;\r
-        }\r
-\r
-        @Override\r
-        public T getResult() {\r
-            return result;\r
-        }\r
-\r
-        @Override\r
-        public Collection<RpcError> getErrors() {\r
-            return errors;\r
-        }\r
-\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.common.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class Rpcs {
+    public static <T> RpcResult<T> getRpcResult(boolean successful, T result,
+            Collection<RpcError> errors) {
+        RpcResult<T> ret = new RpcResultTO<T>(successful, result, errors);
+        return ret;
+    }
+
+    private static class RpcResultTO<T> implements RpcResult<T> {
+
+        private final Collection<RpcError> errors;
+        private final T result;
+        private final boolean successful;
+
+        public RpcResultTO(boolean successful, T result,
+                Collection<RpcError> errors) {
+            this.successful = successful;
+            this.result = result;
+            this.errors = Collections.unmodifiableList(new ArrayList<RpcError>(
+                    errors));
+        }
+
+        @Override
+        public boolean isSuccessful() {
+            return successful;
+        }
+
+        @Override
+        public T getResult() {
+            return result;
+        }
+
+        @Override
+        public Collection<RpcError> getErrors() {
+            return errors;
+        }
+
+    }
+}
index 89cf5207edda8be9125f8af4bebf501c228a8864..a4b2c7d51b083a32020247e19aa9d0afe761482f 100644 (file)
@@ -1,14 +1,15 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
-    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
-    <modelVersion>4.0.0</modelVersion>\r
-    <parent>\r
-        <groupId>org.opendaylight.controller</groupId>\r
-        <artifactId>sal</artifactId>\r
-        <version>1.0-SNAPSHOT</version>\r
-    </parent>\r
-    <artifactId>sal-common</artifactId>\r
-\r
-    <dependencies>\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>sal-common</artifactId>
+
+    <dependencies>
     </dependencies>
 
+    <packaging>bundle</packaging>
 </project>
\ No newline at end of file
index e82392d24aef70827f20838cd5e798758f63bcd7..15e90ec8c57a9c9d1b41d928711be8a8cdc65d9a 100644 (file)
@@ -1,27 +1,27 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
-    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
-    <modelVersion>4.0.0</modelVersion>\r
-    <parent>\r
-        <groupId>org.opendaylight.controller</groupId>\r
-        <artifactId>sal</artifactId>\r
-        <version>1.0-SNAPSHOT</version>\r
-    </parent>\r
-    <artifactId>sal-core-api</artifactId>\r
-\r
-    <dependencies>\r
-        <dependency>\r
-            <groupId>org.opendaylight.controller</groupId>\r
-            <artifactId>sal-common</artifactId>\r
-            <version>1.0-SNAPSHOT</version>\r
-        </dependency>\r
-\r
-        <dependency>\r
-            <groupId>org.opendaylight.controller</groupId>\r
-            <artifactId>yang-data-api</artifactId>\r
-        </dependency>\r
-        <dependency>\r
-            <groupId>org.opendaylight.controller</groupId>\r
-            <artifactId>yang-model-api</artifactId>\r
-        </dependency>\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>sal-core-api</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-model-api</artifactId>
+        </dependency>
     </dependencies>
 </project>
\ No newline at end of file
index 9b3b47f8b17e8f312cb77b0688973b0d702e129a..f26ed901a569f9c585b9b18be456acbb055de257 100644 (file)
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api;\r
-\r
-import java.util.concurrent.Future;\r
-\r
-import org.opendaylight.controller.sal.core.api.data.DataBrokerService;\r
-import org.opendaylight.controller.sal.core.api.data.DataProviderService;\r
-import org.opendaylight.controller.sal.core.api.notify.NotificationProviderService;\r
-import org.opendaylight.controller.sal.core.api.notify.NotificationService;\r
-import org.opendaylight.controller.yang.common.QName;\r
-import org.opendaylight.controller.yang.common.RpcResult;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-\r
-\r
-/**\r
- * Core component of the SAL layer responsible for wiring the SAL consumers.\r
- * \r
- * The responsibility of the broker is to maintain registration of SAL\r
- * functionality {@link Consumer}s and {@link Provider}s, store provider and\r
- * consumer specific context and functionality registration via\r
- * {@link ConsumerSession} and provide access to infrastructure services, which\r
- * removes direct dependencies between providers and consumers.\r
- * \r
- * \r
- * <h3>Infrastructure services</h3> Some examples of infrastructure services:\r
- * \r
- * <ul>\r
- * <li>RPC Invocation - see {@link ConsumerSession#rpc(QName, CompositeNode)},\r
- * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)} and\r
- * {@link RpcImplementation}\r
- * <li>Notification Service - see {@link NotificationService} and\r
- * {@link NotificationProviderService}\r
- * <li>Functionality and Data model\r
- * <li>Data Store access and modification - see {@link DataBrokerService} and\r
- * {@link DataProviderService}\r
- * </ul>\r
- * \r
- * The services are exposed via session.\r
- * \r
- * <h3>Session-based access</h3>\r
- * \r
- * The providers and consumers needs to register in order to use the\r
- * binding-independent SAL layer and to expose functionality via SAL layer.\r
- * \r
- * For more information about session-based access see {@link ConsumerSession}\r
- * and {@link ProviderSession}\r
- * \r
- * \r
- * \r
- */\r
-public interface Broker {\r
-\r
-    /**\r
-     * Registers the {@link Consumer}, which will use the SAL layer.\r
-     * \r
-     * <p>\r
-     * During the registration, the broker obtains the initial functionality\r
-     * from consumer, using the {@link Consumer#getConsumerFunctionality()}, and\r
-     * register that functionality into system and concrete infrastructure\r
-     * services.\r
-     * \r
-     * <p>\r
-     * Note that consumer could register additional functionality at later point\r
-     * by using service and functionality specific APIs.\r
-     * \r
-     * <p>\r
-     * The consumer is required to use returned session for all communication\r
-     * with broker or one of the broker services. The session is announced to\r
-     * the consumer by invoking\r
-     * {@link Consumer#onSessionInitiated(ConsumerSession)}.\r
-     * \r
-     * @param cons\r
-     *            Consumer to be registered.\r
-     * @return a session specific to consumer registration\r
-     * @throws IllegalArgumentException\r
-     *             If the consumer is <code>null</code>.\r
-     * @throws IllegalStateException\r
-     *             If the consumer is already registered.\r
-     */\r
-    ConsumerSession registerConsumer(Consumer cons);\r
-\r
-    /**\r
-     * Registers the {@link Provider}, which will use the SAL layer.\r
-     * \r
-     * <p>\r
-     * During the registration, the broker obtains the initial functionality\r
-     * from consumer, using the {@link Provider#getProviderFunctionality()}, and\r
-     * register that functionality into system and concrete infrastructure\r
-     * services.\r
-     * \r
-     * <p>\r
-     * Note that consumer could register additional functionality at later point\r
-     * by using service and functionality specific APIs (e.g.\r
-     * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}\r
-     * \r
-     * <p>\r
-     * The consumer is <b>required to use</b> returned session for all\r
-     * communication with broker or one of the broker services. The session is\r
-     * announced to the consumer by invoking\r
-     * {@link Provider#onSessionInitiated(ProviderSession)}.\r
-     * \r
-     * \r
-     * @param prov\r
-     *            Provider to be registered.\r
-     * @return a session unique to the provider registration.\r
-     * @throws IllegalArgumentException\r
-     *             If the provider is <code>null</code>.\r
-     * @throws IllegalStateException\r
-     *             If the consumer is already registered.\r
-     */\r
-    ProviderSession registerProvider(Provider prov);\r
-\r
-    /**\r
-     * {@link Consumer} specific access to the SAL functionality.\r
-     * \r
-     * <p>\r
-     * ConsumerSession is {@link Consumer}-specific access to the SAL\r
-     * functionality and infrastructure services.\r
-     * \r
-     * <p>\r
-     * The session serves to store SAL context (e.g. registration of\r
-     * functionality) for the consumer and provides access to the SAL\r
-     * infrastructure services and other functionality provided by\r
-     * {@link Provider}s.\r
-     * \r
-\r
-     * \r
-     */\r
-    public interface ConsumerSession {\r
-\r
-        /**\r
-         * Sends an RPC to other components registered to the broker.\r
-         * \r
-         * @see RpcImplementation\r
-         * @param rpc\r
-         *            Name of RPC\r
-         * @param input\r
-         *            Input data to the RPC\r
-         * @return Result of the RPC call\r
-         */\r
-        Future<RpcResult<CompositeNode>> rpc(QName rpc, CompositeNode input);\r
-\r
-        boolean isClosed();\r
-\r
-        /**\r
-         * Returns a session specific instance (implementation) of requested\r
-         * service\r
-         * \r
-         * @param service\r
-         *            Broker service\r
-         * @return Session specific implementation of service\r
-         */\r
-        <T extends BrokerService> T getService(Class<T> service);\r
-\r
-        /**\r
-         * Closes a session between consumer and broker.\r
-         * \r
-         * <p>\r
-         * The close operation unregisters a consumer and remove all registered\r
-         * functionality of the consumer from the system.\r
-         * \r
-         */\r
-        void close();\r
-    }\r
-\r
-    /**\r
-     * {@link Provider} specific access to the SAL functionality.\r
-     * \r
-     * <p>\r
-     * ProviderSession is {@link Provider}-specific access to the SAL\r
-     * functionality and infrastructure services, which also allows for exposing\r
-     * the provider's functionality to the other {@link Consumer}s.\r
-     * \r
-     * <p>\r
-     * The session serves to store SAL context (e.g. registration of\r
-     * functionality) for the providers and exposes access to the SAL\r
-     * infrastructure services, dynamic functionality registration and any other\r
-     * functionality provided by other {@link Provider}s.\r
-     * \r
-     */\r
-    public interface ProviderSession extends ConsumerSession {\r
-        /**\r
-         * Registers an implementation of the rpc.\r
-         * \r
-         * <p>\r
-         * The registered rpc functionality will be available to all other\r
-         * consumers and providers registered to the broker, which are aware of\r
-         * the {@link QName} assigned to the rpc.\r
-         * \r
-         * <p>\r
-         * There is no assumption that rpc type is in the set returned by\r
-         * invoking {@link RpcImplementation#getSupportedRpcs()}. This allows\r
-         * for dynamic rpc implementations.\r
-         * \r
-         * @param rpcType\r
-         *            Name of Rpc\r
-         * @param implementation\r
-         *            Provider's Implementation of the RPC functionality\r
-         * @throws IllegalArgumentException\r
-         *             If the name of RPC is invalid\r
-         */\r
-        void addRpcImplementation(QName rpcType,\r
-                RpcImplementation implementation)\r
-                throws IllegalArgumentException;\r
-\r
-        /**\r
-         * Unregisters an Rpc implementation\r
-         * \r
-         * @param rpcType\r
-         *            Name of Rpc\r
-         * @param implementation\r
-         *            Registered Implementation of the Rpc functionality\r
-         * @throws IllegalArgumentException\r
-         */\r
-        void removeRpcImplementation(QName rpcType,\r
-                RpcImplementation implementation)\r
-                throws IllegalArgumentException;\r
-\r
-        /**\r
-         * Closes a session between provider and SAL.\r
-         * \r
-         * <p>\r
-         * The close operation unregisters a provider and remove all registered\r
-         * functionality of the provider from the system.\r
-         */\r
-        @Override\r
-        public void close();\r
-\r
-        @Override\r
-        boolean isClosed();\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.notify.NotificationProviderService;
+import org.opendaylight.controller.sal.core.api.notify.NotificationService;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+
+/**
+ * Core component of the SAL layer responsible for wiring the SAL consumers.
+ * 
+ * The responsibility of the broker is to maintain registration of SAL
+ * functionality {@link Consumer}s and {@link Provider}s, store provider and
+ * consumer specific context and functionality registration via
+ * {@link ConsumerSession} and provide access to infrastructure services, which
+ * removes direct dependencies between providers and consumers.
+ * 
+ * 
+ * <h3>Infrastructure services</h3> Some examples of infrastructure services:
+ * 
+ * <ul>
+ * <li>RPC Invocation - see {@link ConsumerSession#rpc(QName, CompositeNode)},
+ * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)} and
+ * {@link RpcImplementation}
+ * <li>Notification Service - see {@link NotificationService} and
+ * {@link NotificationProviderService}
+ * <li>Functionality and Data model
+ * <li>Data Store access and modification - see {@link DataBrokerService} and
+ * {@link DataProviderService}
+ * </ul>
+ * 
+ * The services are exposed via session.
+ * 
+ * <h3>Session-based access</h3>
+ * 
+ * The providers and consumers needs to register in order to use the
+ * binding-independent SAL layer and to expose functionality via SAL layer.
+ * 
+ * For more information about session-based access see {@link ConsumerSession}
+ * and {@link ProviderSession}
+ * 
+ * 
+ * 
+ */
+public interface Broker {
+
+    /**
+     * Registers the {@link Consumer}, which will use the SAL layer.
+     * 
+     * <p>
+     * During the registration, the broker obtains the initial functionality
+     * from consumer, using the {@link Consumer#getConsumerFunctionality()}, and
+     * register that functionality into system and concrete infrastructure
+     * services.
+     * 
+     * <p>
+     * Note that consumer could register additional functionality at later point
+     * by using service and functionality specific APIs.
+     * 
+     * <p>
+     * The consumer is required to use returned session for all communication
+     * with broker or one of the broker services. The session is announced to
+     * the consumer by invoking
+     * {@link Consumer#onSessionInitiated(ConsumerSession)}.
+     * 
+     * @param cons
+     *            Consumer to be registered.
+     * @return a session specific to consumer registration
+     * @throws IllegalArgumentException
+     *             If the consumer is <code>null</code>.
+     * @throws IllegalStateException
+     *             If the consumer is already registered.
+     */
+    ConsumerSession registerConsumer(Consumer cons);
+
+    /**
+     * Registers the {@link Provider}, which will use the SAL layer.
+     * 
+     * <p>
+     * During the registration, the broker obtains the initial functionality
+     * from consumer, using the {@link Provider#getProviderFunctionality()}, and
+     * register that functionality into system and concrete infrastructure
+     * services.
+     * 
+     * <p>
+     * Note that consumer could register additional functionality at later point
+     * by using service and functionality specific APIs (e.g.
+     * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}
+     * 
+     * <p>
+     * The consumer is <b>required to use</b> returned session for all
+     * communication with broker or one of the broker services. The session is
+     * announced to the consumer by invoking
+     * {@link Provider#onSessionInitiated(ProviderSession)}.
+     * 
+     * 
+     * @param prov
+     *            Provider to be registered.
+     * @return a session unique to the provider registration.
+     * @throws IllegalArgumentException
+     *             If the provider is <code>null</code>.
+     * @throws IllegalStateException
+     *             If the consumer is already registered.
+     */
+    ProviderSession registerProvider(Provider prov);
+
+    /**
+     * {@link Consumer} specific access to the SAL functionality.
+     * 
+     * <p>
+     * ConsumerSession is {@link Consumer}-specific access to the SAL
+     * functionality and infrastructure services.
+     * 
+     * <p>
+     * The session serves to store SAL context (e.g. registration of
+     * functionality) for the consumer and provides access to the SAL
+     * infrastructure services and other functionality provided by
+     * {@link Provider}s.
+     * 
+
+     * 
+     */
+    public interface ConsumerSession {
+
+        /**
+         * Sends an RPC to other components registered to the broker.
+         * 
+         * @see RpcImplementation
+         * @param rpc
+         *            Name of RPC
+         * @param input
+         *            Input data to the RPC
+         * @return Result of the RPC call
+         */
+        Future<RpcResult<CompositeNode>> rpc(QName rpc, CompositeNode input);
+
+        boolean isClosed();
+
+        /**
+         * Returns a session specific instance (implementation) of requested
+         * service
+         * 
+         * @param service
+         *            Broker service
+         * @return Session specific implementation of service
+         */
+        <T extends BrokerService> T getService(Class<T> service);
+
+        /**
+         * Closes a session between consumer and broker.
+         * 
+         * <p>
+         * The close operation unregisters a consumer and remove all registered
+         * functionality of the consumer from the system.
+         * 
+         */
+        void close();
+    }
+
+    /**
+     * {@link Provider} specific access to the SAL functionality.
+     * 
+     * <p>
+     * ProviderSession is {@link Provider}-specific access to the SAL
+     * functionality and infrastructure services, which also allows for exposing
+     * the provider's functionality to the other {@link Consumer}s.
+     * 
+     * <p>
+     * The session serves to store SAL context (e.g. registration of
+     * functionality) for the providers and exposes access to the SAL
+     * infrastructure services, dynamic functionality registration and any other
+     * functionality provided by other {@link Provider}s.
+     * 
+     */
+    public interface ProviderSession extends ConsumerSession {
+        /**
+         * Registers an implementation of the rpc.
+         * 
+         * <p>
+         * The registered rpc functionality will be available to all other
+         * consumers and providers registered to the broker, which are aware of
+         * the {@link QName} assigned to the rpc.
+         * 
+         * <p>
+         * There is no assumption that rpc type is in the set returned by
+         * invoking {@link RpcImplementation#getSupportedRpcs()}. This allows
+         * for dynamic rpc implementations.
+         * 
+         * @param rpcType
+         *            Name of Rpc
+         * @param implementation
+         *            Provider's Implementation of the RPC functionality
+         * @throws IllegalArgumentException
+         *             If the name of RPC is invalid
+         */
+        void addRpcImplementation(QName rpcType,
+                RpcImplementation implementation)
+                throws IllegalArgumentException;
+
+        /**
+         * Unregisters an Rpc implementation
+         * 
+         * @param rpcType
+         *            Name of Rpc
+         * @param implementation
+         *            Registered Implementation of the Rpc functionality
+         * @throws IllegalArgumentException
+         */
+        void removeRpcImplementation(QName rpcType,
+                RpcImplementation implementation)
+                throws IllegalArgumentException;
+
+        /**
+         * Closes a session between provider and SAL.
+         * 
+         * <p>
+         * The close operation unregisters a provider and remove all registered
+         * functionality of the provider from the system.
+         */
+        @Override
+        public void close();
+
+        @Override
+        boolean isClosed();
+    }
+}
index b854188f616248809f1f422ef85285006b0261d4..b4253680528f1b4d029dff2ad88eae8230946d66 100644 (file)
@@ -1,39 +1,39 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api;\r
-\r
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;\r
-\r
-/**\r
- * \r
- * Session-specific instance of the broker functionality.\r
- * \r
- * <p>\r
- * BrokerService is marker interface for infrastructure services provided by the\r
- * SAL. These services are session-specific, each {@link Provider} and\r
- * {@link Consumer} usually has own instance of the service with it's own\r
- * context.\r
- * \r
- * <p>\r
- * The consumer's (or provider's) instance of specific service could be obtained\r
- * by invoking {@link ConsumerSession#getService(Class)} method on session\r
- * assigned to the consumer.\r
- * \r
- * <p>\r
- * {@link BrokerService} and {@link Provider} may seem similar, but provider\r
- * provides YANG model-based functionality and {@link BrokerService} exposes the\r
- * necessary supporting functionality to implement specific functionality of\r
- * YANG and to reuse it in the development of {@link Consumer}s and\r
- * {@link Provider}s.\r
- * \r
- * \r
- */\r
-public interface BrokerService {\r
-\r
-    void closeSession();\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api;
+
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+
+/**
+ * 
+ * Session-specific instance of the broker functionality.
+ * 
+ * <p>
+ * BrokerService is marker interface for infrastructure services provided by the
+ * SAL. These services are session-specific, each {@link Provider} and
+ * {@link Consumer} usually has own instance of the service with it's own
+ * context.
+ * 
+ * <p>
+ * The consumer's (or provider's) instance of specific service could be obtained
+ * by invoking {@link ConsumerSession#getService(Class)} method on session
+ * assigned to the consumer.
+ * 
+ * <p>
+ * {@link BrokerService} and {@link Provider} may seem similar, but provider
+ * provides YANG model-based functionality and {@link BrokerService} exposes the
+ * necessary supporting functionality to implement specific functionality of
+ * YANG and to reuse it in the development of {@link Consumer}s and
+ * {@link Provider}s.
+ * 
+ * 
+ */
+public interface BrokerService {
+
+    void closeSession();
+}
index 1b223f9e667656926e924cc6f0c21a43ecfa6d2a..0006953542bb698cff7bd06fe4c85133012da047 100644 (file)
@@ -1,59 +1,59 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api;\r
-\r
-import java.util.Collection;\r
-\r
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;\r
-\r
-/**\r
- * \r
- * Defines the component of controller and supplies additional metadata. A\r
- * component of the controller or application supplies a concrete implementation\r
- * of this interface.\r
- * \r
- * A user-implemented component (application) which faciliates the SAL and SAL\r
- * services to access infrastructure services or providers' functionality.\r
- * \r
- * \r
- */\r
-public interface Consumer {\r
-\r
-    /**\r
-     * Callback signaling initialization of the consumer session to the SAL.\r
-     * \r
-     * The consumer MUST use the session for all communication with SAL or\r
-     * retrieving SAL infrastructure services.\r
-     * \r
-     * This method is invoked by {@link Broker#registerConsumer(Consumer)}\r
-     * \r
-     * @param session\r
-     *            Unique session between consumer and SAL.\r
-     */\r
-    public void onSessionInitiated(ConsumerSession session);\r
-\r
-    /**\r
-     * Get a set of implementations of consumer functionality to be registered\r
-     * into system during the consumer registration to the SAL.\r
-     * \r
-     * This method is invoked by {@link Broker#registerConsumer(Consumer)}.\r
-     * \r
-     * @return Set of consumer functionality.\r
-     */\r
-    public Collection<ConsumerFunctionality> getConsumerFunctionality();\r
-\r
-    /**\r
-     * The marker interface for the interfaces describing the consumer\r
-     * functionality contracts.\r
-     * \r
-     * \r
-     */\r
-    public interface ConsumerFunctionality {\r
-\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+
+/**
+ * 
+ * Defines the component of controller and supplies additional metadata. A
+ * component of the controller or application supplies a concrete implementation
+ * of this interface.
+ * 
+ * A user-implemented component (application) which faciliates the SAL and SAL
+ * services to access infrastructure services or providers' functionality.
+ * 
+ * 
+ */
+public interface Consumer {
+
+    /**
+     * Callback signaling initialization of the consumer session to the SAL.
+     * 
+     * The consumer MUST use the session for all communication with SAL or
+     * retrieving SAL infrastructure services.
+     * 
+     * This method is invoked by {@link Broker#registerConsumer(Consumer)}
+     * 
+     * @param session
+     *            Unique session between consumer and SAL.
+     */
+    public void onSessionInitiated(ConsumerSession session);
+
+    /**
+     * Get a set of implementations of consumer functionality to be registered
+     * into system during the consumer registration to the SAL.
+     * 
+     * This method is invoked by {@link Broker#registerConsumer(Consumer)}.
+     * 
+     * @return Set of consumer functionality.
+     */
+    public Collection<ConsumerFunctionality> getConsumerFunctionality();
+
+    /**
+     * The marker interface for the interfaces describing the consumer
+     * functionality contracts.
+     * 
+     * 
+     */
+    public interface ConsumerFunctionality {
+
+    }
+}
index dff636fd4b14a01ffcdc6bb01df2de5b9be7aa52..e2df70baeac05a3a1fc113de6205a0ccc504206c 100644 (file)
@@ -1,69 +1,69 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api;\r
-\r
-import java.util.Collection;\r
-\r
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;\r
-\r
-/**\r
- * \r
- * Defines the component of controller and supplies additional metadata. A\r
- * component of the controller or application supplies a concrete implementation\r
- * of this interface.\r
- * \r
- * <p>\r
- * A user-implemented component (application) which faciliates the SAL and SAL\r
- * services to access infrastructure services and to provide functionality to\r
- * {@link Consumer}s and other providers.\r
- * \r
- * \r
- */\r
-public interface Provider {\r
-\r
-    /**\r
-     * Callback signaling initialization of the provider session to the SAL.\r
-     * \r
-     * <p>\r
-     * The provider <b>MUST use the session</b> for all communication with SAL\r
-     * or retrieving SAL infrastructure services.\r
-     * \r
-     * <p>\r
-     * This method is invoked by {@link Broker#registerConsumer(Consumer)}\r
-     * \r
-     * @param session\r
-     *            Unique session between provider and SAL.\r
-     */\r
-    public void onSessionInitiated(ProviderSession session);\r
-\r
-    /**\r
-     * Gets a set of implementations of provider functionality to be registered\r
-     * into system during the provider registration to the SAL.\r
-     * \r
-     * <p>\r
-     * This method is invoked by {@link Broker#registerProvider(Provider)} to\r
-     * learn the initial provided functionality\r
-     * \r
-     * @return Set of provider's functionality.\r
-     */\r
-    public Collection<ProviderFunctionality> getProviderFunctionality();\r
-\r
-    /**\r
-     * Functionality provided by the {@link Provider}\r
-     * \r
-     * <p>\r
-     * Marker interface used to mark the interfaces describing specific\r
-     * functionality which could be exposed by providers to other components.\r
-     * \r
-\r
-     * \r
-     */\r
-    public interface ProviderFunctionality {\r
-\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+
+/**
+ * 
+ * Defines the component of controller and supplies additional metadata. A
+ * component of the controller or application supplies a concrete implementation
+ * of this interface.
+ * 
+ * <p>
+ * A user-implemented component (application) which faciliates the SAL and SAL
+ * services to access infrastructure services and to provide functionality to
+ * {@link Consumer}s and other providers.
+ * 
+ * 
+ */
+public interface Provider {
+
+    /**
+     * Callback signaling initialization of the provider session to the SAL.
+     * 
+     * <p>
+     * The provider <b>MUST use the session</b> for all communication with SAL
+     * or retrieving SAL infrastructure services.
+     * 
+     * <p>
+     * This method is invoked by {@link Broker#registerConsumer(Consumer)}
+     * 
+     * @param session
+     *            Unique session between provider and SAL.
+     */
+    public void onSessionInitiated(ProviderSession session);
+
+    /**
+     * Gets a set of implementations of provider functionality to be registered
+     * into system during the provider registration to the SAL.
+     * 
+     * <p>
+     * This method is invoked by {@link Broker#registerProvider(Provider)} to
+     * learn the initial provided functionality
+     * 
+     * @return Set of provider's functionality.
+     */
+    public Collection<ProviderFunctionality> getProviderFunctionality();
+
+    /**
+     * Functionality provided by the {@link Provider}
+     * 
+     * <p>
+     * Marker interface used to mark the interfaces describing specific
+     * functionality which could be exposed by providers to other components.
+     * 
+
+     * 
+     */
+    public interface ProviderFunctionality {
+
+    }
+}
index ef5aa703b9b33e21889af7e225d1e0288299da19..0299505cdeee6bcef00315507012cbd030f384c1 100644 (file)
@@ -1,81 +1,81 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api;\r
-\r
-import java.util.Set;\r
-\r
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;\r
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;\r
-import org.opendaylight.controller.yang.common.QName;\r
-import org.opendaylight.controller.yang.common.RpcResult;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-\r
-/**\r
- * {@link Provider}'s implementation of rpc.\r
- * \r
- * In order to expose the rpc to other components, the provider MUST register\r
- * concrete implementation of this interface\r
- * \r
- * The registration could be done by :\r
- * <ul>\r
- * <li>returning an instance of implementation in the return value of\r
- * {@link Provider#getProviderFunctionality()}\r
- * <li>passing an instance of implementation and {@link QName} of rpc as\r
- * arguments to the\r
- * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}\r
- * </ul>\r
- * \r
- * The simplified process of the invocation of rpc is following:\r
- * \r
- * <ol>\r
- * <li> {@link Consumer} invokes\r
- * {@link ConsumerSession#rpc(QName, CompositeNode)}\r
- * <li> {@link Broker} finds registered {@link RpcImplementation}s\r
- * <li> {@link Broker} invokes\r
- * {@link RpcImplementation#invokeRpc(QName, CompositeNode)}\r
- * <li> {@link RpcImplementation} processes the data and returns a\r
- * {@link RpcResult}\r
- * <li> {@link Broker} returns the {@link RpcResult} to {@link Consumer}\r
- * </ol>\r
- * \r
- * \r
- */\r
-public interface RpcImplementation extends Provider.ProviderFunctionality {\r
-\r
-    /**\r
-     * A set of rpc types supported by implementation.\r
-     * \r
-     * The set of rpc {@link QName}s which are supported by this implementation.\r
-     * This set is used, when {@link Provider} is registered to the SAL, to\r
-     * register and expose the implementation of the returned rpcs.\r
-     * \r
-     * @return Set of QNames identifying supported RPCs\r
-     */\r
-    Set<QName> getSupportedRpcs();\r
-\r
-    /**\r
-     * Invokes a implementation of specified rpc.\r
-     * \r
-     * \r
-     * @param rpc\r
-     *            Rpc to be invoked\r
-     * @param input\r
-     *            Input data for rpc.\r
-     * \r
-     * @throws IllegalArgumentException\r
-     *             <ul>\r
-     *             <li>If rpc is null.\r
-     *             <li>If input is not <code>null</code> and\r
-     *             <code>false == rpc.equals(input.getNodeType)</code>\r
-     *             </ul>\r
-     * @return RpcResult containing the output of rpc if was executed\r
-     *         successfully, the list of errors otherwise.\r
-     */\r
-    RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input);\r
-\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+/**
+ * {@link Provider}'s implementation of rpc.
+ * 
+ * In order to expose the rpc to other components, the provider MUST register
+ * concrete implementation of this interface
+ * 
+ * The registration could be done by :
+ * <ul>
+ * <li>returning an instance of implementation in the return value of
+ * {@link Provider#getProviderFunctionality()}
+ * <li>passing an instance of implementation and {@link QName} of rpc as
+ * arguments to the
+ * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}
+ * </ul>
+ * 
+ * The simplified process of the invocation of rpc is following:
+ * 
+ * <ol>
+ * <li> {@link Consumer} invokes
+ * {@link ConsumerSession#rpc(QName, CompositeNode)}
+ * <li> {@link Broker} finds registered {@link RpcImplementation}s
+ * <li> {@link Broker} invokes
+ * {@link RpcImplementation#invokeRpc(QName, CompositeNode)}
+ * <li> {@link RpcImplementation} processes the data and returns a
+ * {@link RpcResult}
+ * <li> {@link Broker} returns the {@link RpcResult} to {@link Consumer}
+ * </ol>
+ * 
+ * 
+ */
+public interface RpcImplementation extends Provider.ProviderFunctionality {
+
+    /**
+     * A set of rpc types supported by implementation.
+     * 
+     * The set of rpc {@link QName}s which are supported by this implementation.
+     * This set is used, when {@link Provider} is registered to the SAL, to
+     * register and expose the implementation of the returned rpcs.
+     * 
+     * @return Set of QNames identifying supported RPCs
+     */
+    Set<QName> getSupportedRpcs();
+
+    /**
+     * Invokes a implementation of specified rpc.
+     * 
+     * 
+     * @param rpc
+     *            Rpc to be invoked
+     * @param input
+     *            Input data for rpc.
+     * 
+     * @throws IllegalArgumentException
+     *             <ul>
+     *             <li>If rpc is null.
+     *             <li>If input is not <code>null</code> and
+     *             <code>false == rpc.equals(input.getNodeType)</code>
+     *             </ul>
+     * @return RpcResult containing the output of rpc if was executed
+     *         successfully, the list of errors otherwise.
+     */
+    RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input);
+
+}
index d74a7d146ddf7dd63d502aab9d720624566105d9..fef894ba5c52b2bd13132136ac1c07e35c5aeaf0 100644 (file)
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api.data;\r
-\r
-import java.util.Set;\r
-import java.util.concurrent.Future;\r
-\r
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;\r
-import org.opendaylight.controller.sal.core.api.BrokerService;\r
-import org.opendaylight.controller.sal.core.api.Consumer;\r
-import org.opendaylight.controller.sal.core.api.Provider;\r
-import org.opendaylight.controller.yang.common.RpcResult;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-import org.opendaylight.controller.yang.data.api.CompositeNodeModification;\r
-import org.opendaylight.controller.yang.data.api.Node;\r
-\r
-\r
-/**\r
- * DataBrokerService provides unified access to the data stores available in the\r
- * system.\r
- * \r
- * \r
- * @see DataProviderService\r
- * \r
- */\r
-public interface DataBrokerService extends BrokerService {\r
-\r
-    \r
-    Set<DataStoreIdentifier> getDataStores();\r
-    \r
-    /**\r
-     * Returns a data from specified Data Store.\r
-     * \r
-     * Returns all the data visible to the consumer from specified Data Store.\r
-     * \r
-     * @param store\r
-     *            Identifier of the store, from which will be data retrieved\r
-     * @return data visible to the consumer\r
-     */\r
-    CompositeNode getData(DataStoreIdentifier store);\r
-\r
-    /**\r
-     * Returns a filtered subset of data from specified Data Store.\r
-     * \r
-     * <p>\r
-     * The filter is modeled as an hierarchy of {@link Node} starting with\r
-     * {@link CompositeNode} representing data root. The semantics of the filter\r
-     * tree is the same as filter semantics defined in the NETCONF protocol for\r
-     * rpc operations <code>get</code> and <code>get-config</code> in Section 6\r
-     * of RFC6241.\r
-     * \r
-     * \r
-     * @see http://tools.ietf.org/html/rfc6241#section-6\r
-     * @param store\r
-     *            Identifier of the store, from which will be data retrieved\r
-     * @param filter\r
-     *            Data tree filter similar to the NETCONF filter\r
-     * @return\r
-     */\r
-    CompositeNode getData(DataStoreIdentifier store, CompositeNode filter);\r
-\r
-    /**\r
-     * Returns a candidate data which are not yet commited.\r
-     * \r
-     * \r
-     * @param store\r
-     *            Identifier of the store, from which will be data retrieved\r
-     * @return\r
-     */\r
-    CompositeNode getCandidateData(DataStoreIdentifier store);\r
-\r
-    /**\r
-     * Returns a filtered subset of candidate data from specified Data Store.\r
-     * \r
-     * <p>\r
-     * The filter is modeled as an hierarchy of {@link Node} starting with\r
-     * {@link CompositeNode} representing data root. The semantics of the filter\r
-     * tree is the same as filter semantics defined in the NETCONF protocol for\r
-     * rpc operations <code>get</code> and <code>get-config</code> in Section 6\r
-     * of RFC6241.\r
-     * \r
-     * \r
-     * @see http://tools.ietf.org/html/rfc6241#section-6\r
-     * @param store\r
-     *            Identifier of the store, from which will be data retrieved\r
-     * @param filter\r
-     *            A CompositeNode filter\r
-     * @return\r
-     */\r
-    CompositeNode getCandidateData(DataStoreIdentifier store,\r
-            CompositeNode filter);\r
-\r
-    /**\r
-     * \r
-     * @param store\r
-     *            Identifier of the store, in which will be the candidate data\r
-     *            modified\r
-     * @param changeSet\r
-     *            Modification of data tree.\r
-     * @return Result object containing the modified data tree if the operation\r
-     *         was successful, otherwise list of the encountered errors.\r
-     */\r
-    RpcResult<CompositeNode> editCandidateData(DataStoreIdentifier store,\r
-            CompositeNodeModification changeSet);\r
-\r
-    /**\r
-     * Initiates a two-phase commit of candidate data.\r
-     * \r
-     * <p>\r
-     * The {@link Consumer} could initiate a commit of candidate data\r
-     * \r
-     * <p>\r
-     * The successful commit changes the state of the system and may affect\r
-     * several components.\r
-     * \r
-     * <p>\r
-     * The effects of successful commit of data are described in the\r
-     * specifications and YANG models describing the {@link Provider} components\r
-     * of controller. It is assumed that {@link Consumer} has an understanding\r
-     * of this changes.\r
-     * \r
-     * \r
-     * @see DataCommitHandler for further information how two-phase commit is\r
-     *      processed.\r
-     * @param store\r
-     *            Identifier of the store, where commit should occur.\r
-     * @return Result of the commit, containing success information or list of\r
-     *         encountered errors, if commit was not successful.\r
-     */\r
-    Future<RpcResult<Void>> commit(DataStoreIdentifier store);\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api.data;
+
+import java.util.Set;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.Consumer;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+
+/**
+ * DataBrokerService provides unified access to the data stores available in the
+ * system.
+ * 
+ * 
+ * @see DataProviderService
+ * 
+ */
+public interface DataBrokerService extends BrokerService {
+
+    
+    Set<DataStoreIdentifier> getDataStores();
+    
+    /**
+     * Returns a data from specified Data Store.
+     * 
+     * Returns all the data visible to the consumer from specified Data Store.
+     * 
+     * @param store
+     *            Identifier of the store, from which will be data retrieved
+     * @return data visible to the consumer
+     */
+    CompositeNode getData(DataStoreIdentifier store);
+
+    /**
+     * Returns a filtered subset of data from specified Data Store.
+     * 
+     * <p>
+     * The filter is modeled as an hierarchy of {@link Node} starting with
+     * {@link CompositeNode} representing data root. The semantics of the filter
+     * tree is the same as filter semantics defined in the NETCONF protocol for
+     * rpc operations <code>get</code> and <code>get-config</code> in Section 6
+     * of RFC6241.
+     * 
+     * 
+     * @see http://tools.ietf.org/html/rfc6241#section-6
+     * @param store
+     *            Identifier of the store, from which will be data retrieved
+     * @param filter
+     *            Data tree filter similar to the NETCONF filter
+     * @return
+     */
+    CompositeNode getData(DataStoreIdentifier store, CompositeNode filter);
+
+    /**
+     * Returns a candidate data which are not yet commited.
+     * 
+     * 
+     * @param store
+     *            Identifier of the store, from which will be data retrieved
+     * @return
+     */
+    CompositeNode getCandidateData(DataStoreIdentifier store);
+
+    /**
+     * Returns a filtered subset of candidate data from specified Data Store.
+     * 
+     * <p>
+     * The filter is modeled as an hierarchy of {@link Node} starting with
+     * {@link CompositeNode} representing data root. The semantics of the filter
+     * tree is the same as filter semantics defined in the NETCONF protocol for
+     * rpc operations <code>get</code> and <code>get-config</code> in Section 6
+     * of RFC6241.
+     * 
+     * 
+     * @see http://tools.ietf.org/html/rfc6241#section-6
+     * @param store
+     *            Identifier of the store, from which will be data retrieved
+     * @param filter
+     *            A CompositeNode filter
+     * @return
+     */
+    CompositeNode getCandidateData(DataStoreIdentifier store,
+            CompositeNode filter);
+
+    /**
+     * 
+     * @param store
+     *            Identifier of the store, in which will be the candidate data
+     *            modified
+     * @param changeSet
+     *            Modification of data tree.
+     * @return Result object containing the modified data tree if the operation
+     *         was successful, otherwise list of the encountered errors.
+     */
+    RpcResult<CompositeNode> editCandidateData(DataStoreIdentifier store,
+            MutableCompositeNode changeSet);
+
+    /**
+     * Initiates a two-phase commit of candidate data.
+     * 
+     * <p>
+     * The {@link Consumer} could initiate a commit of candidate data
+     * 
+     * <p>
+     * The successful commit changes the state of the system and may affect
+     * several components.
+     * 
+     * <p>
+     * The effects of successful commit of data are described in the
+     * specifications and YANG models describing the {@link Provider} components
+     * of controller. It is assumed that {@link Consumer} has an understanding
+     * of this changes.
+     * 
+     * 
+     * @see DataCommitHandler for further information how two-phase commit is
+     *      processed.
+     * @param store
+     *            Identifier of the store, where commit should occur.
+     * @return Result of the commit, containing success information or list of
+     *         encountered errors, if commit was not successful.
+     */
+    Future<RpcResult<Void>> commit(DataStoreIdentifier store);
+}
index f0cc02d3cebf019b8762136f95dfebffe2b6ce9e..fc1894a3d9100f2895048da54b9e9d4c927e4a71 100644 (file)
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api.data;\r
-\r
-import java.util.Set;\r
-\r
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;\r
-import org.opendaylight.controller.sal.core.api.Provider;\r
-import org.opendaylight.controller.yang.common.RpcResult;\r
-\r
-\r
-/**\r
- * Two phase commit handler (cohort) of the two-phase commit protocol of data.\r
- * \r
- * <p>\r
- * The provider should expose the implementation of DataCommitHandler if it's\r
- * functionality depends on any subset of data stored in data repositories, in\r
- * order to participate in {@link DataBrokerService#commit(DataStoreIdentifier)\r
- * operation.\r
- * \r
- * <p>\r
- * Operations of two-phase commit handlers should not change data in data store,\r
- * this is responsibility of the coordinator (broker or some component of the\r
- * broker).\r
- * \r
- * The commit handlers are responsible for changing the internal state of the\r
- * provider to reflect the commited changes in data.\r
- * \r
- * <h3>Two-phase commit</h3>\r
- * \r
- * <h4>Commit Request Phase</h4>\r
- * \r
- * <ol>\r
- * <li> <code>Consumer</code> edits data by invocation of\r
- * <code>DataBrokerService.editCandidateData(DataStoreIdentifier, CompositeNodeModification)</code>\r
- * <li> <code>Consumer</code> starts a commit by invoking\r
- * <code>DataBrokerService.commit(DataStoreIdentifier)</code>\r
- * <li> <code>Broker</code> retrieves a list of all registered\r
- * <code>DataCommitHandlers</code>\r
- * <li>For each <code>DataCommitHandler</code>\r
- * <ol>\r
- * <li><code>Broker</code> invokes a\r
- * <code>DataCommitHandler.requestCommit(DataStoreIdentifier)</code> operation.\r
- * <li><code>DataCommitHandler</code> returns a <code>RpcResult</code> with\r
- * <code>CommitTransaction</code>\r
- * <li>If the result was successful, broker adds <code>CommitTransaction</code>\r
- * to the list of opened transactions. If not, brokers stops a commit request\r
- * phase and starts a rollback phase.\r
- * </ol>\r
- * <li><code>Broker</code> starts a commit finish phase\r
- * </ol>\r
- * \r
- * <h4>Commit Finish Phase</h4>\r
- * \r
- * <ol>\r
- * <li>For each <code>CommitTransaction</code> from Commit Request phase\r
- * <ol>\r
- * <li><code>Broker</code> broker invokes a\r
- * <code>CommitTransaction.finish()</code>\r
- * <li>The provider finishes a commit (applies the change) and returns an\r
- * <code>RpcResult</code>.\r
- * </ol>\r
- * <li>\r
- * <ul>\r
- * <li>If all returned results means successful, the brokers end two-phase\r
- * commit by returning a success commit result to the Consumer.\r
- * <li>If error occured, the broker starts a commit rollback phase.\r
- * </ul>\r
- * </ol>\r
- * \r
- * <h4>Commit Rollback Phase</h4>\r
- * <li>For each <code>CommitTransaction</code> from Commit Request phase\r
- * <ol>\r
- * <li><code>Broker</code>\r
- * \r
- * broker invokes a {@link CommitTransaction#finish()}\r
- * <li>The provider rollbacks a commit and returns an {@link RpcResult} of\r
- * rollback. </ol>\r
- * <li>Broker returns a error result to the consumer.\r
- * \r
- * \r
- * <h3>Registration of functionality</h3>\r
- * The registration could be done by :\r
- * <ul>\r
- * <li>returning an instance of implementation in the return value of\r
- * {@link Provider#getProviderFunctionality()}\r
- * <li>passing an instance of implementation and {@link DataStoreIdentifier} of\r
- * rpc as arguments to the\r
- * {@link DataProviderService#addCommitHandler(DataStoreIdentifier, DataCommitHandler)}\r
- * </ul>\r
- * \r
- * \r
- */\r
-public interface DataCommitHandler extends Provider.ProviderFunctionality {\r
-\r
-    /**\r
-     * A set of Data Stores supported by implementation.\r
-     * \r
-     * The set of {@link DataStoreIdentifier}s which identifies target data\r
-     * stores which are supported by this commit handler. This set is used, when\r
-     * {@link Provider} is registered to the SAL, to register and expose the\r
-     * commit handler functionality to affected data stores.\r
-     * \r
-     * @return Set of Data Store identifiers\r
-     */\r
-    Set<DataStoreIdentifier> getSupportedDataStores();\r
-\r
-    /**\r
-     * The provider (commit handler) starts a commit transaction.\r
-     * \r
-     * <p>\r
-     * The commit handler (provider) prepares an commit scenario, rollback\r
-     * scenario and validates data.\r
-     * \r
-     * <p>\r
-     * If the provider is aware that at this point the commit would not be\r
-     * successful, the transaction is not created, but list of errors which\r
-     * prevented the start of transaction are returned.\r
-     * \r
-     * @param store\r
-     * @return Transaction object representing this commit, errors otherwise.\r
-     */\r
-    RpcResult<CommitTransaction> requestCommit(DataStoreIdentifier store);\r
-\r
-    public interface CommitTransaction {\r
-        /**\r
-         * \r
-         * @return Data store affected by the transaction\r
-         */\r
-        DataStoreIdentifier getDataStore();\r
-\r
-        /**\r
-         * Returns the handler associated with this transaction.\r
-         * \r
-         * @return Handler\r
-         */\r
-        DataCommitHandler getHandler();\r
-\r
-        /**\r
-         * \r
-         * Finishes a commit.\r
-         * \r
-         * The provider (commit handler) should apply all changes to its state\r
-         * which are a result of data change-\r
-         * \r
-         * @return\r
-         */\r
-        RpcResult<Void> finish() throws IllegalStateException;\r
-\r
-        /**\r
-         * Rollbacks a commit.\r
-         * \r
-         * @return\r
-         * @throws IllegalStateException\r
-         *             If the method is invoked after {@link #finish()}\r
-         */\r
-        RpcResult<Void> rollback() throws IllegalStateException;\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api.data;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+
+/**
+ * Two phase commit handler (cohort) of the two-phase commit protocol of data.
+ * 
+ * <p>
+ * The provider should expose the implementation of DataCommitHandler if it's
+ * functionality depends on any subset of data stored in data repositories, in
+ * order to participate in {@link DataBrokerService#commit(DataStoreIdentifier)
+ * operation.
+ * 
+ * <p>
+ * Operations of two-phase commit handlers should not change data in data store,
+ * this is responsibility of the coordinator (broker or some component of the
+ * broker).
+ * 
+ * The commit handlers are responsible for changing the internal state of the
+ * provider to reflect the commited changes in data.
+ * 
+ * <h3>Two-phase commit</h3>
+ * 
+ * <h4>Commit Request Phase</h4>
+ * 
+ * <ol>
+ * <li> <code>Consumer</code> edits data by invocation of
+ * <code>DataBrokerService.editCandidateData(DataStoreIdentifier, CompositeNodeModification)</code>
+ * <li> <code>Consumer</code> starts a commit by invoking
+ * <code>DataBrokerService.commit(DataStoreIdentifier)</code>
+ * <li> <code>Broker</code> retrieves a list of all registered
+ * <code>DataCommitHandlers</code>
+ * <li>For each <code>DataCommitHandler</code>
+ * <ol>
+ * <li><code>Broker</code> invokes a
+ * <code>DataCommitHandler.requestCommit(DataStoreIdentifier)</code> operation.
+ * <li><code>DataCommitHandler</code> returns a <code>RpcResult</code> with
+ * <code>CommitTransaction</code>
+ * <li>If the result was successful, broker adds <code>CommitTransaction</code>
+ * to the list of opened transactions. If not, brokers stops a commit request
+ * phase and starts a rollback phase.
+ * </ol>
+ * <li><code>Broker</code> starts a commit finish phase
+ * </ol>
+ * 
+ * <h4>Commit Finish Phase</h4>
+ * 
+ * <ol>
+ * <li>For each <code>CommitTransaction</code> from Commit Request phase
+ * <ol>
+ * <li><code>Broker</code> broker invokes a
+ * <code>CommitTransaction.finish()</code>
+ * <li>The provider finishes a commit (applies the change) and returns an
+ * <code>RpcResult</code>.
+ * </ol>
+ * <li>
+ * <ul>
+ * <li>If all returned results means successful, the brokers end two-phase
+ * commit by returning a success commit result to the Consumer.
+ * <li>If error occured, the broker starts a commit rollback phase.
+ * </ul>
+ * </ol>
+ * 
+ * <h4>Commit Rollback Phase</h4>
+ * <li>For each <code>CommitTransaction</code> from Commit Request phase
+ * <ol>
+ * <li><code>Broker</code>
+ * 
+ * broker invokes a {@link CommitTransaction#finish()}
+ * <li>The provider rollbacks a commit and returns an {@link RpcResult} of
+ * rollback. </ol>
+ * <li>Broker returns a error result to the consumer.
+ * 
+ * 
+ * <h3>Registration of functionality</h3>
+ * The registration could be done by :
+ * <ul>
+ * <li>returning an instance of implementation in the return value of
+ * {@link Provider#getProviderFunctionality()}
+ * <li>passing an instance of implementation and {@link DataStoreIdentifier} of
+ * rpc as arguments to the
+ * {@link DataProviderService#addCommitHandler(DataStoreIdentifier, DataCommitHandler)}
+ * </ul>
+ * 
+ * 
+ */
+public interface DataCommitHandler extends Provider.ProviderFunctionality {
+
+    /**
+     * A set of Data Stores supported by implementation.
+     * 
+     * The set of {@link DataStoreIdentifier}s which identifies target data
+     * stores which are supported by this commit handler. This set is used, when
+     * {@link Provider} is registered to the SAL, to register and expose the
+     * commit handler functionality to affected data stores.
+     * 
+     * @return Set of Data Store identifiers
+     */
+    Set<DataStoreIdentifier> getSupportedDataStores();
+
+    /**
+     * The provider (commit handler) starts a commit transaction.
+     * 
+     * <p>
+     * The commit handler (provider) prepares an commit scenario, rollback
+     * scenario and validates data.
+     * 
+     * <p>
+     * If the provider is aware that at this point the commit would not be
+     * successful, the transaction is not created, but list of errors which
+     * prevented the start of transaction are returned.
+     * 
+     * @param store
+     * @return Transaction object representing this commit, errors otherwise.
+     */
+    RpcResult<CommitTransaction> requestCommit(DataStoreIdentifier store);
+
+    public interface CommitTransaction {
+        /**
+         * 
+         * @return Data store affected by the transaction
+         */
+        DataStoreIdentifier getDataStore();
+
+        /**
+         * Returns the handler associated with this transaction.
+         * 
+         * @return Handler
+         */
+        DataCommitHandler getHandler();
+
+        /**
+         * 
+         * Finishes a commit.
+         * 
+         * The provider (commit handler) should apply all changes to its state
+         * which are a result of data change-
+         * 
+         * @return
+         */
+        RpcResult<Void> finish() throws IllegalStateException;
+
+        /**
+         * Rollbacks a commit.
+         * 
+         * @return
+         * @throws IllegalStateException
+         *             If the method is invoked after {@link #finish()}
+         */
+        RpcResult<Void> rollback() throws IllegalStateException;
+    }
+}
index 5c5423d80f40fea969c68f8ff22e51edb34d1de4..32035ea489f985997dfcb99b66d729edc11f14b7 100644 (file)
@@ -1,78 +1,78 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api.data;\r
-\r
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;\r
-import org.opendaylight.controller.sal.core.api.Provider;\r
-\r
-public interface DataProviderService extends DataBrokerService {\r
-\r
-    /**\r
-     * Adds {@link DataValidator} for specified Data Store\r
-     * \r
-     * @param store\r
-     *            Data Store\r
-     * @param validator\r
-     *            Validator\r
-     */\r
-    public void addValidator(DataStoreIdentifier store, DataValidator validator);\r
-\r
-    /**\r
-     * Removes {@link DataValidator} from specified Data Store\r
-     * \r
-     * @param store\r
-     * @param validator\r
-     *            Validator\r
-     */\r
-    public void removeValidator(DataStoreIdentifier store,\r
-            DataValidator validator);\r
-\r
-    /**\r
-     * Adds {@link DataCommitHandler} for specified data store\r
-     * \r
-     * @param store\r
-     * @param provider\r
-     */\r
-    void addCommitHandler(DataStoreIdentifier store, DataCommitHandler provider);\r
-\r
-    /**\r
-     * Removes {@link DataCommitHandler} from specified data store\r
-     * \r
-     * @param store\r
-     * @param provider\r
-     */\r
-    void removeCommitHandler(DataStoreIdentifier store,\r
-            DataCommitHandler provider);\r
-\r
-    /**\r
-     * Adds {@link DataRefresher} for specified data store\r
-     * \r
-     * @param store\r
-     * @param refresher\r
-     */\r
-    void addRefresher(DataStoreIdentifier store, DataRefresher refresher);\r
-\r
-    /**\r
-     * Removes {@link DataRefresher} from specified data store\r
-     * \r
-     * @param store\r
-     * @param refresher\r
-     */\r
-    void removeRefresher(DataStoreIdentifier store, DataRefresher refresher);\r
-\r
-    public interface DataRefresher extends Provider.ProviderFunctionality {\r
-\r
-        /**\r
-         * Fired when some component explicitly requested the data refresh.\r
-         * \r
-         * The provider which exposed the {@link DataRefresher} should republish\r
-         * its provided data by editing the data in all affected data stores.\r
-         */\r
-        void refreshData();\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api.data;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.core.api.Provider;
+
+public interface DataProviderService extends DataBrokerService {
+
+    /**
+     * Adds {@link DataValidator} for specified Data Store
+     * 
+     * @param store
+     *            Data Store
+     * @param validator
+     *            Validator
+     */
+    public void addValidator(DataStoreIdentifier store, DataValidator validator);
+
+    /**
+     * Removes {@link DataValidator} from specified Data Store
+     * 
+     * @param store
+     * @param validator
+     *            Validator
+     */
+    public void removeValidator(DataStoreIdentifier store,
+            DataValidator validator);
+
+    /**
+     * Adds {@link DataCommitHandler} for specified data store
+     * 
+     * @param store
+     * @param provider
+     */
+    void addCommitHandler(DataStoreIdentifier store, DataCommitHandler provider);
+
+    /**
+     * Removes {@link DataCommitHandler} from specified data store
+     * 
+     * @param store
+     * @param provider
+     */
+    void removeCommitHandler(DataStoreIdentifier store,
+            DataCommitHandler provider);
+
+    /**
+     * Adds {@link DataRefresher} for specified data store
+     * 
+     * @param store
+     * @param refresher
+     */
+    void addRefresher(DataStoreIdentifier store, DataRefresher refresher);
+
+    /**
+     * Removes {@link DataRefresher} from specified data store
+     * 
+     * @param store
+     * @param refresher
+     */
+    void removeRefresher(DataStoreIdentifier store, DataRefresher refresher);
+
+    public interface DataRefresher extends Provider.ProviderFunctionality {
+
+        /**
+         * Fired when some component explicitly requested the data refresh.
+         * 
+         * The provider which exposed the {@link DataRefresher} should republish
+         * its provided data by editing the data in all affected data stores.
+         */
+        void refreshData();
+    }
+}
index a2105b41d7a1ba5e4297c818ea0e770ca7f1d427..2bcb84be34f375486f4791dab794ff58d168c4d7 100644 (file)
@@ -1,57 +1,57 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api.data;\r
-\r
-import java.util.Set;\r
-\r
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;\r
-import org.opendaylight.controller.sal.core.api.Provider;\r
-import org.opendaylight.controller.yang.common.RpcResult;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-\r
-\r
-/**\r
- * {@link Provider}-supplied Validator of the data.\r
- * \r
- * <p>\r
- * The registration could be done by :\r
- * <ul>\r
- * <li>returning an instance of implementation in the return value of\r
- * {@link Provider#getProviderFunctionality()}\r
- * <li>passing an instance of implementation and {@link DataStoreIdentifier} rpc\r
- * as arguments to the\r
- * {@link DataProviderService#addValidator(DataStoreIdentifier, DataValidator)}\r
- * </ul>\r
- * \r
- **/\r
-public interface DataValidator extends Provider.ProviderFunctionality {\r
-\r
-    /**\r
-     * A set of Data Stores supported by implementation.\r
-     * \r
-     * The set of {@link DataStoreIdentifier}s which identifies target data\r
-     * stores which are supported by this implementation. This set is used, when\r
-     * {@link Provider} is registered to the SAL, to register and expose the\r
-     * validation functionality to affected data stores.\r
-     * \r
-     * @return Set of Data Store identifiers\r
-     */\r
-    Set<DataStoreIdentifier> getSupportedDataStores();\r
-\r
-    /**\r
-     * Performs validation on supplied data.\r
-     * \r
-     * @param toValidate\r
-     *            Data to validate\r
-     * @return Validation result. The\r
-     *         <code>{@link RpcResult#isSuccessful()} == true</code> if the data\r
-     *         passed validation, otherwise contains list of errors.\r
-     */\r
-    RpcResult<Void> validate(CompositeNode toValidate);\r
-\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api.data;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+
+/**
+ * {@link Provider}-supplied Validator of the data.
+ * 
+ * <p>
+ * The registration could be done by :
+ * <ul>
+ * <li>returning an instance of implementation in the return value of
+ * {@link Provider#getProviderFunctionality()}
+ * <li>passing an instance of implementation and {@link DataStoreIdentifier} rpc
+ * as arguments to the
+ * {@link DataProviderService#addValidator(DataStoreIdentifier, DataValidator)}
+ * </ul>
+ * 
+ **/
+public interface DataValidator extends Provider.ProviderFunctionality {
+
+    /**
+     * A set of Data Stores supported by implementation.
+     * 
+     * The set of {@link DataStoreIdentifier}s which identifies target data
+     * stores which are supported by this implementation. This set is used, when
+     * {@link Provider} is registered to the SAL, to register and expose the
+     * validation functionality to affected data stores.
+     * 
+     * @return Set of Data Store identifiers
+     */
+    Set<DataStoreIdentifier> getSupportedDataStores();
+
+    /**
+     * Performs validation on supplied data.
+     * 
+     * @param toValidate
+     *            Data to validate
+     * @return Validation result. The
+     *         <code>{@link RpcResult#isSuccessful()} == true</code> if the data
+     *         passed validation, otherwise contains list of errors.
+     */
+    RpcResult<Void> validate(CompositeNode toValidate);
+
+}
index b58659a7267e4aacfb1cbbca10cc9a8ff87469a3..17911962ff35566229ecf5d2b4eec0b560aa8521 100644 (file)
@@ -1,8 +1,8 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
 package org.opendaylight.controller.sal.core.api.data;
\ No newline at end of file
index 22abdc2a004245758e155e3f0e1a89d98ee18317..52f60b3cc28728a7dce4a2435bfe1e97bb6a2e0c 100644 (file)
@@ -1,42 +1,42 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api.model;\r
-\r
-import org.opendaylight.controller.sal.core.api.BrokerService;\r
-import org.opendaylight.controller.yang.model.api.Module;\r
-import org.opendaylight.controller.yang.model.api.SchemaContext;\r
-\r
-public interface SchemaService extends BrokerService {\r
-\r
-    /**\r
-     * Registers a YANG module to session and global context \r
-     * \r
-     * @param module\r
-     */\r
-    void addModule(Module module);\r
-    \r
-    /**\r
-     * Unregisters a YANG module from session context\r
-     * \r
-     * @param module\r
-     */\r
-    void removeModule(Module module);\r
-    \r
-    /**\r
-     * Returns session specific YANG schema context\r
-     * @return\r
-     */\r
-    SchemaContext getSessionContext();\r
-    \r
-    /**\r
-     * Returns global schema context\r
-     * \r
-     * @return\r
-     */\r
-    SchemaContext getGlobalContext();\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api.model;
+
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public interface SchemaService extends BrokerService {
+
+    /**
+     * Registers a YANG module to session and global context 
+     * 
+     * @param module
+     */
+    void addModule(Module module);
+    
+    /**
+     * Unregisters a YANG module from session context
+     * 
+     * @param module
+     */
+    void removeModule(Module module);
+    
+    /**
+     * Returns session specific YANG schema context
+     * @return
+     */
+    SchemaContext getSessionContext();
+    
+    /**
+     * Returns global schema context
+     * 
+     * @return
+     */
+    SchemaContext getGlobalContext();
+}
index 5f72c628051ad339fa0423e50501d8ba186bb579..5b0c992a006aedfd0fd99cfe87f30bf48323e56b 100644 (file)
@@ -1,42 +1,42 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api.notify;\r
-\r
-import java.util.Set;\r
-\r
-import org.opendaylight.controller.sal.core.api.Consumer;\r
-import org.opendaylight.controller.yang.common.QName;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-\r
-\r
-/**\r
- * Notification listener for SAL notifications.\r
- */\r
-public interface NotificationListener extends Consumer.ConsumerFunctionality {\r
-    /**\r
-     * A set of notification types supported by listeners.\r
-     * \r
-     * The set of notification {@link QName}s which are supported by this\r
-     * listener. This set is used, when {@link Consumer} is registered to the\r
-     * SAL, to automatically register the listener.\r
-     * \r
-     * @return Set of QNames identifying supported notifications.\r
-     */\r
-    Set<QName> getSupportedNotifications();\r
-\r
-    /**\r
-     * Fired when the notification occurs.\r
-     * \r
-     * The type of the notification could be learned by\r
-     * <code>QName type = notification.getNodeType();</code>\r
-     * \r
-     * @param notification\r
-     *            Notification content\r
-     */\r
-    void onNotification(CompositeNode notification);\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api.notify;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.core.api.Consumer;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+
+/**
+ * Notification listener for SAL notifications.
+ */
+public interface NotificationListener extends Consumer.ConsumerFunctionality {
+    /**
+     * A set of notification types supported by listeners.
+     * 
+     * The set of notification {@link QName}s which are supported by this
+     * listener. This set is used, when {@link Consumer} is registered to the
+     * SAL, to automatically register the listener.
+     * 
+     * @return Set of QNames identifying supported notifications.
+     */
+    Set<QName> getSupportedNotifications();
+
+    /**
+     * Fired when the notification occurs.
+     * 
+     * The type of the notification could be learned by
+     * <code>QName type = notification.getNodeType();</code>
+     * 
+     * @param notification
+     *            Notification content
+     */
+    void onNotification(CompositeNode notification);
+}
index 6f7e740cdf6fd5300179b84091e3fddcb57d1c20..51871a770be06eb8e33c061d7e792f06339398fa 100644 (file)
@@ -1,46 +1,46 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api.notify;\r
-\r
-import org.opendaylight.controller.sal.core.api.Broker;\r
-import org.opendaylight.controller.sal.core.api.Provider;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-\r
-\r
-/**\r
- * Notification Publishing Service\r
- * \r
- * The simplified process of the notification publishing is following:\r
- * \r
- * <ol>\r
- * <li> {@link Provider} invokes {@link #sendNotification(CompositeNode)}\r
- * <li> {@link Broker} finds {@link NotificationListener}s which subscribed for\r
- * the notification type.\r
- * \r
- * <li>For each subscriber {@link Broker} invokes\r
- * {@link NotificationListener#onNotification(CompositeNode)}\r
- * </ol>\r
- * \r
- * \r
- * \r
- */\r
-public interface NotificationProviderService extends NotificationService {\r
-\r
-    /**\r
-     * Publishes a notification.\r
-     * \r
-     * Notification type is determined by the\r
-     * {@link CompositeNode#getNodeType()} of the\r
-     * <code>notification<code> parameter.\r
-     * \r
-     * @param notification\r
-     *            Notification to publish\r
-     */\r
-    void sendNotification(CompositeNode notification);\r
-\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api.notify;
+
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+
+/**
+ * Notification Publishing Service
+ * 
+ * The simplified process of the notification publishing is following:
+ * 
+ * <ol>
+ * <li> {@link Provider} invokes {@link #sendNotification(CompositeNode)}
+ * <li> {@link Broker} finds {@link NotificationListener}s which subscribed for
+ * the notification type.
+ * 
+ * <li>For each subscriber {@link Broker} invokes
+ * {@link NotificationListener#onNotification(CompositeNode)}
+ * </ol>
+ * 
+ * 
+ * 
+ */
+public interface NotificationProviderService extends NotificationService {
+
+    /**
+     * Publishes a notification.
+     * 
+     * Notification type is determined by the
+     * {@link CompositeNode#getNodeType()} of the
+     * <code>notification<code> parameter.
+     * 
+     * @param notification
+     *            Notification to publish
+     */
+    void sendNotification(CompositeNode notification);
+
+}
index 98a4925afb0ef21089b4a0bfd1e076924056bfac..3bf10546e50fc70331e943514defbad6999189a5 100644 (file)
@@ -1,54 +1,54 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
-package org.opendaylight.controller.sal.core.api.notify;\r
-\r
-import org.opendaylight.controller.sal.core.api.BrokerService;\r
-import org.opendaylight.controller.sal.core.api.Provider;\r
-import org.opendaylight.controller.sal.core.api.RpcImplementation;\r
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;\r
-import org.opendaylight.controller.yang.common.QName;\r
-\r
-\r
-/**\r
- * NotificationService provides access to the notification functionality of the\r
- * SAL.\r
- * \r
- * NotificationService allows for consumption of notifications by registering\r
- * implementations of NotificationListener.\r
- * \r
- * The registration of notification listeners could be done by:\r
- * <ul>\r
- * <li>returning an instance of implementation in the return value of\r
- * {@link Provider#getProviderFunctionality()}\r
- * <li>passing an instance of implementation and {@link QName} of rpc as an\r
- * arguments to the\r
- * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}\r
- * </ul>\r
- * \r
- * \r
- */\r
-public interface NotificationService extends BrokerService {\r
-\r
-    /**\r
-     * Registers a notification listener for supplied notification type.\r
-     * \r
-     * @param notification\r
-     * @param listener\r
-     */\r
-    void addNotificationListener(QName notification,\r
-            NotificationListener listener);\r
-\r
-    /**\r
-     * Removes a notification listener for supplied notification type.\r
-     * \r
-     * @param notification\r
-     * @param listener\r
-     */\r
-    void removeNotificationListener(QName notification,\r
-            NotificationListener listener);\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.api.notify;
+
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.yangtools.yang.common.QName;
+
+
+/**
+ * NotificationService provides access to the notification functionality of the
+ * SAL.
+ * 
+ * NotificationService allows for consumption of notifications by registering
+ * implementations of NotificationListener.
+ * 
+ * The registration of notification listeners could be done by:
+ * <ul>
+ * <li>returning an instance of implementation in the return value of
+ * {@link Provider#getProviderFunctionality()}
+ * <li>passing an instance of implementation and {@link QName} of rpc as an
+ * arguments to the
+ * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}
+ * </ul>
+ * 
+ * 
+ */
+public interface NotificationService extends BrokerService {
+
+    /**
+     * Registers a notification listener for supplied notification type.
+     * 
+     * @param notification
+     * @param listener
+     */
+    void addNotificationListener(QName notification,
+            NotificationListener listener);
+
+    /**
+     * Removes a notification listener for supplied notification type.
+     * 
+     * @param notification
+     * @param listener
+     */
+    void removeNotificationListener(QName notification,
+            NotificationListener listener);
+}
index b6868340bb45ea551e056e0787ab2089428039dd..61426a3fd8cdee6a26b41976432302d70c450db0 100644 (file)
@@ -1,11 +1,11 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
- * SAL Notification functionality\r
- */\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+/**
+ * SAL Notification functionality
+ */
 package org.opendaylight.controller.sal.core.api.notify;
\ No newline at end of file
index a058df363df0f8339e2791d9032532bfff47ffd0..395c09a40fc386db9750fc2807a3d3f5b6fc9e61 100644 (file)
@@ -1,11 +1,11 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. 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
- * Core binding-independent SAL contracts and components\r
- */\r
-package org.opendaylight.controller.sal.core.api;\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+/**
+ * Core binding-independent SAL contracts and components
+ */
+package org.opendaylight.controller.sal.core.api;
index 96af32bc7ae394ba385f54b95fd8c3cbd38decfa..1162b0d99a7f5edcdf9f9c413a28088435ef6a7a 100644 (file)
@@ -3,7 +3,7 @@
        <modelVersion>4.0.0</modelVersion>\r
        <parent>\r
                <groupId>org.opendaylight.controller</groupId>\r
-               <artifactId>sal</artifactId>\r
+               <artifactId>sal-parent</artifactId>\r
                <version>1.0-SNAPSHOT</version>\r
        </parent>\r
        <artifactId>sal-core-demo</artifactId>\r
@@ -54,5 +54,5 @@
 \r
                </plugins>\r
 \r
-       </build>
+       </build>\r
 </project>
\ No newline at end of file
index 3378a36fbc0c3ee55f8bea577aa3b9f8127a197d..aab58123f47eeab6610a1f94aa149f278791d968 100644 (file)
@@ -2,7 +2,7 @@
   <modelVersion>4.0.0</modelVersion>\r
   <parent>\r
     <groupId>org.opendaylight.controller</groupId>\r
-    <artifactId>sal</artifactId>\r
+    <artifactId>sal-parent</artifactId>\r
     <version>1.0-SNAPSHOT</version>\r
   </parent>\r
    <artifactId>sal-core-spi</artifactId>\r
index 74230e5f7c38230ce9cb34a677b904a4aa68ba42..eeea2920d55d74ef2ace39955f4b2e6b82858e12 100644 (file)
@@ -2,7 +2,7 @@
   <modelVersion>4.0.0</modelVersion>\r
   <parent>\r
     <groupId>org.opendaylight.controller</groupId>\r
-    <artifactId>sal</artifactId>\r
+    <artifactId>sal-parent</artifactId>\r
     <version>1.0-SNAPSHOT</version>\r
   </parent>\r
    <artifactId>sal-data-api</artifactId>\r
index b67529ac35938b2c5b6e8d706e37c2a03dc22acc..b5c42ed74a2931069ad1648d482c4b824fe01995 100644 (file)
@@ -2,7 +2,7 @@
   <modelVersion>4.0.0</modelVersion>\r
   <parent>\r
     <groupId>org.opendaylight.controller</groupId>\r
-    <artifactId>sal</artifactId>\r
+    <artifactId>sal-parent</artifactId>\r
     <version>1.0-SNAPSHOT</version>\r
   </parent>\r
   <artifactId>sal-schema-repository-api</artifactId>\r
diff --git a/opendaylight/sal/yang-prototype/sal/samples/pom.xml b/opendaylight/sal/yang-prototype/sal/samples/pom.xml
new file mode 100644 (file)
index 0000000..dc06185
--- /dev/null
@@ -0,0 +1,18 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <artifactId>sal-parent</artifactId>
+               <version>1.0-SNAPSHOT</version>
+               <groupId>org.opendaylight.controller</groupId>
+       </parent>
+       <packaging>pom</packaging>
+       <artifactId>sal-samples</artifactId>
+       <modules>
+               <module>toaster</module>
+               <module>toaster-consumer</module>
+               <module>toaster-it</module>
+               <module>toaster-provider</module>
+       </modules>
+       <groupId>org.opendaylight.controller.samples</groupId>
+</project>
diff --git a/opendaylight/sal/yang-prototype/sal/samples/toaster-consumer/pom.xml b/opendaylight/sal/yang-prototype/sal/samples/toaster-consumer/pom.xml
new file mode 100644 (file)
index 0000000..914accd
--- /dev/null
@@ -0,0 +1,40 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <artifactId>sal-samples</artifactId>
+               <groupId>org.opendaylight.controller.samples</groupId>
+               <version>1.0-SNAPSHOT</version>
+       </parent>
+       <artifactId>sample-toaster-consumer</artifactId>
+       <packaging>bundle</packaging>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.felix</groupId>
+                               <artifactId>maven-bundle-plugin</artifactId>
+                               <configuration>
+                                       <instructions>
+                                               <Export-Package>org.opendaylight.controller.sample.toaster.provider.api</Export-Package>
+                                               <Private-Package>org.opendaylight.controller.sample.toaster.provider.impl</Private-Package>
+                                               <Bundle-Activator>org.opendaylight.controller.sample.toaster.provider.impl.ToastConsumerImpl</Bundle-Activator>
+                                       </instructions>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+
+       <dependencies>
+               <dependency>
+                       <groupId>${project.groupId}</groupId>
+                       <artifactId>sample-toaster</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>sal-binding-api</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/opendaylight/sal/yang-prototype/sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/api/ToastConsumer.java b/opendaylight/sal/yang-prototype/sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/api/ToastConsumer.java
new file mode 100644 (file)
index 0000000..b236c0e
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.toaster.provider.api;
+
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToastType;
+
+public interface ToastConsumer {
+       
+       boolean createToast(Class<? extends ToastType> type,int doneness);
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java b/opendaylight/sal/yang-prototype/sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java
new file mode 100644 (file)
index 0000000..3fc9b0d
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.toaster.provider.impl;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareConsumer;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
+import org.opendaylight.controller.sal.binding.api.NotificationListener;
+import org.opendaylight.controller.sal.binding.api.NotificationService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.common.GlobalDataStore;
+import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.MakeToastInputBuilder;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToastDone;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToastType;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.Toaster;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterData;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ToastConsumerImpl extends AbstractBindingAwareConsumer implements BundleActivator, BindingAwareConsumer, ToastConsumer,
+        NotificationListener<ToastDone> {
+
+    private static final Logger log = LoggerFactory.getLogger(ToastConsumerImpl.class);
+
+    private ToasterService toaster;
+
+    private ConsumerContext session;
+
+    @Override
+    public boolean createToast(Class<? extends ToastType> type, int doneness) {
+        MakeToastInputBuilder toastInput = new MakeToastInputBuilder();
+        toastInput.setToasterDoneness((long) doneness);
+        toastInput.setToasterToastType(type);
+
+        try {
+            RpcResult<Void> result = getToastService().makeToast(toastInput.build()).get();
+
+            if (result.isSuccessful()) {
+                log.info("Toast was successfuly finished");
+            } else {
+                log.info("Toast was not successfuly finished");
+            }
+            return result.isSuccessful();
+        } catch (InterruptedException | ExecutionException e) {
+            log.info("Error occured during toast creation");
+        }
+        return false;
+
+    }
+    
+    @Override
+    @Deprecated
+    protected void startImpl(BundleContext context) {
+        context.registerService(ToastConsumer.class, this, new Hashtable<String,String>());
+    }
+
+    @Override
+    public void onSessionInitialized(ConsumerContext session) {
+        this.session = session;
+        NotificationService notificationService = session.getSALService(NotificationService.class);
+        notificationService.addNotificationListener(ToastDone.class, this);
+        
+        
+    }
+
+    private void loadToasterData() {
+        // We request data store service implementation
+        DataBrokerService brokerService = session.getSALService(DataBrokerService.class);
+        
+        ToasterData data = brokerService.getData(GlobalDataStore.RuntimeInfo, ToasterData.class);
+        Toaster toaster = data.getToaster();
+        log.info("Available toaster is: ", toaster.getToasterManufacturer(),toaster.getToasterModelNumber());
+    }
+
+    @Override
+    public void onNotification(ToastDone notification) {
+        log.info("ToastDone Notification Received: {} ",notification.getToastStatus());
+
+    }
+
+    private ToasterService getToastService() {
+        if (toaster == null) {
+            toaster = session.getRpcService(ToasterService.class);
+        }
+        return toaster;
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/samples/toaster-it/pom.xml b/opendaylight/sal/yang-prototype/sal/samples/toaster-it/pom.xml
new file mode 100644 (file)
index 0000000..edce9a0
--- /dev/null
@@ -0,0 +1,132 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <artifactId>sal-samples</artifactId>
+               <groupId>org.opendaylight.controller.samples</groupId>
+               <version>1.0-SNAPSHOT</version>
+       </parent>
+       <artifactId>sample-toaster-it</artifactId>
+
+       <properties>
+               <exam.version>3.0.0</exam.version>
+               <url.version>1.5.0</url.version>
+       </properties>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.ops4j.pax.exam</groupId>
+                               <artifactId>maven-paxexam-plugin</artifactId>
+                               <executions>
+                                       <execution>
+                                               <id>generate-config</id>
+                                               <goals>
+                                                       <goal>generate-depends-file</goal>
+                                               </goals>
+                                       </execution>
+                               </executions>
+                       </plugin>
+               </plugins>
+               <pluginManagement>
+                       <plugins>
+                               <!--This plugin's configuration is used to store Eclipse m2e settings 
+                                       only. It has no influence on the Maven build itself. -->
+                               <plugin>
+                                       <groupId>org.eclipse.m2e</groupId>
+                                       <artifactId>lifecycle-mapping</artifactId>
+                                       <version>1.0.0</version>
+                                       <configuration>
+                                               <lifecycleMappingMetadata>
+                                                       <pluginExecutions>
+                                                               <pluginExecution>
+                                                                       <pluginExecutionFilter>
+                                                                               <groupId>
+                                                                                       org.ops4j.pax.exam
+                                                                               </groupId>
+                                                                               <artifactId>
+                                                                                       maven-paxexam-plugin
+                                                                               </artifactId>
+                                                                               <versionRange>
+                                                                                       [1.2.4,)
+                                                                               </versionRange>
+                                                                               <goals>
+                                                                                       <goal>
+                                                                                               generate-depends-file
+                                                                                       </goal>
+                                                                               </goals>
+                                                                       </pluginExecutionFilter>
+                                                                       <action>
+                                                                               <ignore></ignore>
+                                                                       </action>
+                                                               </pluginExecution>
+                                                       </pluginExecutions>
+                                               </lifecycleMappingMetadata>
+                                       </configuration>
+                               </plugin>
+                       </plugins>
+               </pluginManagement>
+       </build>
+
+       <dependencies>
+               <dependency>
+                       <groupId>org.opendaylight.controller.samples</groupId>
+                       <artifactId>sample-toaster</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller.samples</groupId>
+                       <artifactId>sample-toaster-consumer</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller.samples</groupId>
+                       <artifactId>sample-toaster-provider</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>sal-binding-broker-impl</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.ops4j.pax.exam</groupId>
+                       <artifactId>pax-exam-container-native</artifactId>
+                       <version>${exam.version}</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.ops4j.pax.exam</groupId>
+                       <artifactId>pax-exam-junit4</artifactId>
+                       <version>${exam.version}</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.ops4j.pax.exam</groupId>
+                       <artifactId>pax-exam-link-mvn</artifactId>
+                       <version>${exam.version}</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>equinoxSDK381</groupId>
+                       <artifactId>org.eclipse.osgi</artifactId>
+                       <version>3.8.1.v20120830-144521</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>log4j-over-slf4j</artifactId>
+                       <version>1.7.2</version>
+               </dependency>
+               <dependency>
+                       <groupId>ch.qos.logback</groupId>
+                       <artifactId>logback-core</artifactId>
+                       <version>1.0.9</version>
+               </dependency>
+               <dependency>
+                       <groupId>ch.qos.logback</groupId>
+                       <artifactId>logback-classic</artifactId>
+                       <version>1.0.9</version>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/opendaylight/sal/yang-prototype/sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java b/opendaylight/sal/yang-prototype/sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java
new file mode 100644 (file)
index 0000000..663e81a
--- /dev/null
@@ -0,0 +1,84 @@
+package org.opendaylight.controller.sample.toaster.it;
+
+import static org.junit.Assert.*;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemPackages;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+
+import java.util.Collection;
+
+import javax.inject.Inject;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sample.toaster.provider.ToasterProvider;
+import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterService;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.WhiteBread;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+@RunWith(PaxExam.class)
+public class ToasterTest {
+
+       public static final String ODL = "org.opendaylight.controller";
+       public static final String YANG = "org.opendaylight.yangtools";
+       public static final String SAMPLE = "org.opendaylight.controller.samples";
+
+       @Test
+       public void properInitialized() throws Exception {
+
+               Collection<ServiceReference<ToasterService>> references = ctx
+                               .getServiceReferences(ToasterService.class, null);
+               assertEquals(2, references.size());
+               
+               consumer.createToast(WhiteBread.class, 5);
+               
+       }
+
+       @Inject
+       BindingAwareBroker broker;
+
+       @Inject
+       ToastConsumer consumer;
+
+       @Inject
+       BundleContext ctx;
+
+       @Configuration
+       public Option[] config() {
+               return options(systemProperty("osgi.console").value("2401"),
+                               mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),
+                               mavenBundle("org.slf4j", "log4j-over-slf4j")
+                                               .versionAsInProject(),
+                               mavenBundle("ch.qos.logback", "logback-core")
+                                               .versionAsInProject(),
+                               mavenBundle("ch.qos.logback", "logback-classic")
+                                               .versionAsInProject(),
+                               mavenBundle(ODL, "sal-binding-api").versionAsInProject(),
+                               mavenBundle(ODL, "sal-binding-broker-impl")
+                                               .versionAsInProject(), mavenBundle(ODL, "sal-common")
+                                               .versionAsInProject(),
+                               mavenBundle(ODL, "sal-common-util").versionAsInProject(),
+                               mavenBundle(SAMPLE, "sample-toaster").versionAsInProject(),
+                               mavenBundle(SAMPLE, "sample-toaster-consumer")
+                                               .versionAsInProject(),
+                               mavenBundle(SAMPLE, "sample-toaster-provider")
+                                               .versionAsInProject(),
+                               mavenBundle(YANG, "yang-binding").versionAsInProject(),
+                               mavenBundle(YANG, "yang-common").versionAsInProject(),
+                               mavenBundle("com.google.guava", "guava").versionAsInProject(),
+                               junitBundles(), mavenBundle("org.javassist", "javassist")
+                                               .versionAsInProject());
+       }
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/samples/toaster-provider/pom.xml b/opendaylight/sal/yang-prototype/sal/samples/toaster-provider/pom.xml
new file mode 100644 (file)
index 0000000..49d142c
--- /dev/null
@@ -0,0 +1,44 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <artifactId>sal-samples</artifactId>
+               <groupId>org.opendaylight.controller.samples</groupId>
+               <version>1.0-SNAPSHOT</version>
+       </parent>
+       <artifactId>sample-toaster-provider</artifactId>
+       <packaging>bundle</packaging>
+
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.felix</groupId>
+                               <artifactId>maven-bundle-plugin</artifactId>
+                               <configuration>
+                                       <instructions>
+                                       <Bundle-Activator>org.opendaylight.controller.sample.toaster.provider.ToasterProvider</Bundle-Activator>
+                                       </instructions>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+
+       <dependencies>
+               <dependency>
+                       <groupId>${project.groupId}</groupId>
+                       <artifactId>sample-toaster</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>sal-binding-api</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>sal-common-util</artifactId>
+                       <version>1.0-SNAPSHOT</version>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/opendaylight/sal/yang-prototype/sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java b/opendaylight/sal/yang-prototype/sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java
new file mode 100644 (file)
index 0000000..404734b
--- /dev/null
@@ -0,0 +1,118 @@
+package org.opendaylight.controller.sample.toaster.provider;
+
+import java.util.Collections;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.controller.sal.common.util.Futures;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.DisplayString;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.MakeToastInput;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToastDone.ToastStatus;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToastDoneBuilder;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.Toaster;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.Toaster.ToasterStatus;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterBuilder;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterData;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterService;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OpendaylightToaster implements ToasterData, ToasterService {
+
+    private static final Logger log = LoggerFactory.getLogger(OpendaylightToaster.class);
+
+    private static final DisplayString toasterManufacturer = new DisplayString("Opendaylight");
+    private static final DisplayString toasterModelNumber = new DisplayString("Model 1 - Binding Aware");
+    private ToasterStatus toasterStatus;
+
+    private NotificationProviderService notificationProvider;
+    private final ExecutorService executor;
+
+    private Future<RpcResult<Void>> currentTask;
+
+    public OpendaylightToaster() {
+        toasterStatus = ToasterStatus.Down;
+        executor = Executors.newFixedThreadPool(1);
+    }
+
+    @Override
+    public Toaster getToaster() {
+        ToasterBuilder tb = new ToasterBuilder();
+        tb //
+        .setToasterManufacturer(toasterManufacturer) //
+                .setToasterModelNumber(toasterModelNumber) //
+                .setToasterStatus(toasterStatus);
+
+        return tb.build();
+    }
+
+    @Override
+    public Future<RpcResult<Void>> cancelToast() {
+        if (currentTask != null) {
+            cancelToastImpl();
+        }
+        return null;
+    }
+
+    @Override
+    public Future<RpcResult<Void>> makeToast(MakeToastInput input) {
+        // TODO Auto-generated method stub
+        log.info("makeToast - Received input for toast");
+        logToastInput(input);
+        if (currentTask != null) {
+            return inProgressError();
+        }
+        currentTask = executor.submit(new MakeToastTask(input));
+        return currentTask;
+    }
+
+    private Future<RpcResult<Void>> inProgressError() {
+        RpcResult<Void> result = Rpcs.<Void> getRpcResult(false, null, Collections.<RpcError> emptySet());
+        return Futures.immediateFuture(result);
+    }
+
+    private void cancelToastImpl() {
+        currentTask.cancel(true);
+        ToastDoneBuilder toastDone = new ToastDoneBuilder();
+        toastDone.setToastStatus(ToastStatus.Cancelled);
+        notificationProvider.notify(toastDone.build());
+    }
+
+    public void setNotificationProvider(NotificationProviderService salService) {
+        this.notificationProvider = salService;
+    }
+
+    private void logToastInput(MakeToastInput input) {
+        String toastType = input.getToasterToastType().getName();
+        String toastDoneness = input.getToasterDoneness().toString();
+        log.info("Toast: {} doneness: {}", toastType, toastDoneness);
+    }
+
+    private class MakeToastTask implements Callable<RpcResult<Void>> {
+
+        final MakeToastInput toastRequest;
+
+        public MakeToastTask(MakeToastInput toast) {
+            toastRequest = toast;
+        }
+
+        @Override
+        public RpcResult<Void> call() throws Exception {
+            Thread.sleep(1000);
+
+            ToastDoneBuilder notifyBuilder = new ToastDoneBuilder();
+            notifyBuilder.setToastStatus(ToastStatus.Done);
+            notificationProvider.notify(notifyBuilder.build());
+            log.info("Toast Done");
+            logToastInput(toastRequest);
+            return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
+        }
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterActivator.java b/opendaylight/sal/yang-prototype/sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterActivator.java
new file mode 100644 (file)
index 0000000..010023a
--- /dev/null
@@ -0,0 +1,5 @@
+package org.opendaylight.controller.sample.toaster.provider;
+
+public class ToasterActivator {
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java b/opendaylight/sal/yang-prototype/sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java
new file mode 100644 (file)
index 0000000..7b5af8f
--- /dev/null
@@ -0,0 +1,66 @@
+package org.opendaylight.controller.sample.toaster.provider;
+import java.util.Collection;
+import java.util.Collections;
+
+
+import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterService;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class ToasterProvider extends AbstractBindingAwareProvider {
+    private static final Logger log = LoggerFactory.getLogger(ToasterProvider.class);
+
+       private ConsumerContext consumerContext;
+       private ProviderContext providerContext;
+       private OpendaylightToaster toaster;
+       
+       
+       public ToasterProvider() {
+               toaster = new OpendaylightToaster();
+       }
+       
+       @Override
+       public void onSessionInitialized(ConsumerContext session) {
+               log.info("Consumer Session initialized");
+               this.consumerContext = session;
+
+       }
+
+       @Override
+       public void onSessionInitiated(ProviderContext session) {
+               log.info("Provider Session initialized");
+               
+               this.providerContext = session;
+               toaster.setNotificationProvider(session.getSALService(NotificationProviderService.class));
+               providerContext.addRpcImplementation(ToasterService.class, toaster);
+       }       
+       
+       
+       @Override
+       public Collection<? extends RpcService> getImplementations() {
+               return Collections.emptySet();
+       }
+
+       @Override
+       public Collection<? extends ProviderFunctionality> getFunctionality() {
+               return Collections.emptySet();
+       }
+       
+       @Override
+       @Deprecated
+       protected void startImpl(BundleContext context) {
+           // TODO Auto-generated method stub
+           
+       }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/samples/toaster/pom.xml b/opendaylight/sal/yang-prototype/sal/samples/toaster/pom.xml
new file mode 100644 (file)
index 0000000..d434275
--- /dev/null
@@ -0,0 +1,117 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>sal-samples</artifactId>
+        <groupId>org.opendaylight.controller.samples</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>sample-toaster</artifactId>
+    <packaging>bundle</packaging>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.7-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        target/generated-sources/sal
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>false</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.yangtools</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>0.5.7-SNAPSHOT</version>
+                        <type>jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.7</version>
+                <executions>
+                    <execution>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>target/generated-sources/sal</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <pluginManagement>
+            <plugins>
+                <!--This plugin's configuration is used to store Eclipse 
+                    m2e settings only. It has no influence on the Maven build itself. -->
+                <plugin>
+                    <groupId>org.eclipse.m2e</groupId>
+                    <artifactId>lifecycle-mapping</artifactId>
+                    <version>1.0.0</version>
+                    <configuration>
+                        <lifecycleMappingMetadata>
+                            <pluginExecutions>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>
+                                            org.opendaylight.yangtools
+                                        </groupId>
+                                        <artifactId>
+                                            yang-maven-plugin
+                                        </artifactId>
+                                        <versionRange>
+                                            [0.5,)
+                                        </versionRange>
+                                        <goals>
+                                            <goal>
+                                                generate-sources
+                                            </goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <ignore></ignore>
+                                    </action>
+                                </pluginExecution>
+                            </pluginExecutions>
+                        </lifecycleMappingMetadata>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-binding</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-common</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/opendaylight/sal/yang-prototype/sal/samples/toaster/src/main/yang/toaster.yang b/opendaylight/sal/yang-prototype/sal/samples/toaster/src/main/yang/toaster.yang
new file mode 100644 (file)
index 0000000..fc9b665
--- /dev/null
@@ -0,0 +1,187 @@
+module toaster {
+
+    yang-version 1;
+
+    namespace
+      "http://netconfcentral.org/ns/toaster";
+
+    prefix toast;
+
+    organization "Netconf Central";
+
+    contact
+      "Andy Bierman <andy@netconfcentral.org>";
+
+    description
+      "YANG version of the TOASTER-MIB.";
+
+    revision "2009-11-20" {
+      description
+        "Toaster module in progress.";
+    }
+
+
+    identity toast-type {
+      description
+          "Base for all bread types supported by the toaster.
+           New bread types not listed here nay be added in the 
+           future.";
+    }
+
+    identity white-bread {
+      base toast:toast-type;
+      description "White bread.";
+    }
+
+    identity wheat-bread {
+      base toast-type;
+      description "Wheat bread.";
+    }
+
+    identity wonder-bread {
+      base toast-type;
+      description "Wonder bread.";
+    }
+
+    identity frozen-waffle {
+      base toast-type;
+      description "Frozen waffle.";
+    }
+
+    identity frozen-bagel {
+      base toast-type;
+      description "Frozen bagel.";
+    }
+
+    identity hash-brown {
+      base toast-type;
+      description "Hash browned potatos.";
+    }
+
+    typedef DisplayString {
+      type string;
+      description
+        "YANG version of the SMIv2 DisplayString TEXTUAL-CONVENTION.";
+      reference
+        "RFC 2579, section 2.";
+
+    }
+
+    container toaster {
+      presence
+        "Indicates the toaster service is available";
+      description
+        "Top-level container for all toaster database objects.";
+      leaf toasterManufacturer {
+        type DisplayString;
+        config false;
+        mandatory true;
+        description
+          "The name of the toaster's manufacturer. For instance, 
+                Microsoft Toaster.";
+      }
+
+      leaf toasterModelNumber {
+        type DisplayString;
+        config false;
+        mandatory true;
+        description
+          "The name of the toaster's model. For instance,
+               Radiant Automatic.";
+      }
+
+      leaf toasterStatus {
+        type enumeration {
+          enum "up" {
+            value 1;
+            description
+              "The toaster knob position is up.
+                      No toast is being made now.";
+          }
+          enum "down" {
+            value 2;
+            description
+              "The toaster knob position is down.
+                      Toast is being made now.";
+          }
+        }
+        config false;
+        mandatory true;
+        description
+          "This variable indicates the current state of 
+               the toaster.";
+      }
+    }  // container toaster
+
+    rpc make-toast {
+      description
+        "Make some toast.
+           The toastDone notification will be sent when 
+           the toast is finished.
+           An 'in-use' error will be returned if toast
+           is already being made.
+           A 'resource-denied' error will be returned 
+           if the toaster service is disabled.";
+      input {
+        leaf toasterDoneness {
+          type uint32 {
+            range "1 .. 10";
+          }
+          default '5';
+          description
+            "This variable controls how well-done is the 
+                   ensuing toast. It should be on a scale of 1 to 10.
+                   Toast made at 10 generally is considered unfit 
+                   for human consumption; toast made at 1 is warmed 
+                   lightly.";
+        }
+
+        leaf toasterToastType {
+          type identityref {
+            base toast:toast-type;
+          }
+          default 'wheat-bread';
+          description
+            "This variable informs the toaster of the type of 
+                   material that is being toasted. The toaster 
+                   uses this information, combined with 
+                   toasterDoneness, to compute for how 
+                   long the material must be toasted to achieve 
+                   the required doneness.";
+        }
+      }
+    }  // rpc make-toast
+
+    rpc cancel-toast {
+      description
+        "Stop making toast, if any is being made.
+           A 'resource-denied' error will be returned 
+           if the toaster service is disabled.";
+    }  // rpc cancel-toast
+
+    notification toastDone {
+      description
+        "Indicates that the toast in progress has completed.";
+      leaf toastStatus {
+        type enumeration {
+          enum "done" {
+            value 0;
+            description "The toast is done.";
+          }
+          enum "cancelled" {
+            value 1;
+            description
+              "The toast was cancelled.";
+          }
+          enum "error" {
+            value 2;
+            description
+              "The toaster service was disabled or
+                     the toaster is broken.";
+          }
+        }
+        description
+          "Indicates the final toast status";
+      }
+    }  // notification toastDone
+  }  // module toaster
index 7f4c98a6483969fabfd14f6bc54219873ae00cd8..02b5cffe04696df6f9f811e4d736ee04a4d293a8 100644 (file)
@@ -158,7 +158,7 @@ public class SimpleForwardingImpl implements IfNewHostNotify,
 
         try {
             clusterContainerService.createCache("forwarding.ipswitch.rules",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
         } catch (CacheExistException cee) {
             log.error("\nCache already exists - destroy and recreate if needed");
         } catch (CacheConfigException cce) {
index 57dfa91b964956e68336673debbca76288d5a00d..02b6251e9f7076073b576b398df18a641d690582 100644 (file)
@@ -77,13 +77,13 @@ public class StatisticsManager implements IStatisticsManager, IReadServiceListen
 
         try {
             clusterContainerService.createCache("statisticsmanager.flowStatistics",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
             clusterContainerService.createCache("statisticsmanager.nodeConnectorStatistics",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
             clusterContainerService.createCache("statisticsmanager.tableStatistics",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
             clusterContainerService.createCache("statisticsmanager.descriptionStatistics",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
         } catch (CacheConfigException cce) {
             log.error("Statistics cache configuration invalid - check cache mode");
index 0cb55d6555903498b52a29aa492680d58bcf4780..e81b4cd27e9d2713db0c787eebdb27531d04de28 100644 (file)
@@ -15,7 +15,6 @@ import java.util.Hashtable;
 import java.util.Set;
 
 import org.apache.felix.dm.Component;
-import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
@@ -90,16 +89,11 @@ public class Activator extends ComponentActivatorAbstractBase {
     @Override
     public void configureInstance(Component c, Object imp, String containerName) {
         if (imp.equals(SwitchManager.class)) {
-            Dictionary<String, Set<String>> props = new Hashtable<String, Set<String>>();
-            Set<String> propSet = new HashSet<String>();
-            propSet.add("switchmanager.configSaveEvent");
-            props.put("cachenames", propSet);
             // export the service
             c.setInterface(new String[] {
                     IListenInventoryUpdates.class.getName(),
                     ISwitchManager.class.getName(),
-                    ICacheUpdateAware.class.getName(),
-                    IConfigurationContainerAware.class.getName() }, props);
+                    IConfigurationContainerAware.class.getName() }, null);
 
             // Now lets add a service dependency to make sure the
             // provider of service exists
index 6bd89a806e3174b13c074038a2fecef86859bf97..d3d41be19f8d6061d2f5f9502c0678fe71cf332e 100644 (file)
@@ -16,7 +16,6 @@ import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Date;
 import java.util.Dictionary;
 import java.util.EnumSet;
 import java.util.Enumeration;
@@ -34,7 +33,6 @@ import org.eclipse.osgi.framework.console.CommandInterpreter;
 import org.eclipse.osgi.framework.console.CommandProvider;
 import org.opendaylight.controller.clustering.services.CacheConfigException;
 import org.opendaylight.controller.clustering.services.CacheExistException;
-import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
 import org.opendaylight.controller.clustering.services.IClusterServices;
 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
@@ -85,13 +83,10 @@ import org.slf4j.LoggerFactory;
  * instance per container of the network. All the node/nodeConnector properties
  * are maintained in the default container only.
  */
-public class SwitchManager implements ISwitchManager,
-IConfigurationContainerAware, IObjectReader,
-ICacheUpdateAware<Long, String>, IListenInventoryUpdates,
-CommandProvider {
+public class SwitchManager implements ISwitchManager, IConfigurationContainerAware,
+                                      IObjectReader, IListenInventoryUpdates, CommandProvider {
     private static Logger log = LoggerFactory.getLogger(SwitchManager.class);
     private static String ROOT = GlobalConstants.STARTUPHOME.toString();
-    private static final String SAVE = "Save";
     private String subnetFileName, spanFileName, switchConfigFileName;
     private final List<NodeConnector> spanNodeConnectors = new CopyOnWriteArrayList<NodeConnector>();
     // Collection of Subnets keyed by the InetAddress
@@ -100,7 +95,6 @@ CommandProvider {
     private ConcurrentMap<SpanConfig, SpanConfig> spanConfigList;
     // manually configured parameters for the node such as name, tier, mode
     private ConcurrentMap<String, SwitchConfig> nodeConfigList;
-    private ConcurrentMap<Long, String> configSaveEvent;
     private ConcurrentMap<Node, Map<String, Property>> nodeProps;
     private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps;
     private ConcurrentMap<Node, Map<String, NodeConnector>> nodeConnectorNames;
@@ -210,27 +204,27 @@ CommandProvider {
         try {
             clusterContainerService.createCache(
                     "switchmanager.subnetsConfigList",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
             clusterContainerService.createCache("switchmanager.spanConfigList",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
             clusterContainerService.createCache("switchmanager.nodeConfigList",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
             clusterContainerService.createCache("switchmanager.subnets",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
             clusterContainerService.createCache(
                     "switchmanager.configSaveEvent",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
             clusterContainerService.createCache("switchmanager.nodeProps",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
             clusterContainerService.createCache(
                     "switchmanager.nodeConnectorProps",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
             clusterContainerService.createCache(
                     "switchmanager.nodeConnectorNames",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
             clusterContainerService.createCache(
                     "switchmanager.controllerProps",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
         } catch (CacheConfigException cce) {
             log.error("\nCache configuration invalid - check cache mode");
         } catch (CacheExistException ce) {
@@ -269,12 +263,6 @@ CommandProvider {
             log.error("\nFailed to get cache for subnets");
         }
 
-        configSaveEvent = (ConcurrentMap<Long, String>) clusterContainerService
-                .getCache("switchmanager.configSaveEvent");
-        if (configSaveEvent == null) {
-            log.error("\nFailed to get cache for configSaveEvent");
-        }
-
         nodeProps = (ConcurrentMap<Node, Map<String, Property>>) clusterContainerService
                 .getCache("switchmanager.nodeProps");
         if (nodeProps == null) {
@@ -305,7 +293,6 @@ CommandProvider {
         spanConfigList = new ConcurrentHashMap<SpanConfig, SpanConfig>();
         nodeConfigList = new ConcurrentHashMap<String, SwitchConfig>();
         subnets = new ConcurrentHashMap<InetAddress, Subnet>();
-        configSaveEvent = new ConcurrentHashMap<Long, String>();
         nodeProps = new ConcurrentHashMap<Node, Map<String, Property>>();
         nodeConnectorProps = new ConcurrentHashMap<NodeConnector, Map<String, Property>>();
         nodeConnectorNames = new ConcurrentHashMap<Node, Map<String, NodeConnector>>();
@@ -725,7 +712,8 @@ CommandProvider {
                 switchConfig = new SwitchConfig(nodeId, updateProperties);
             } else {
                 // check if description is configured or was published by any other node
-                for (Node n : nodeProps.keySet()) {
+                for (Map.Entry<Node, Map<String, Property>> entry : nodeProps.entrySet()) {
+                    Node n = entry.getKey();
                     Description desc = (Description) getNodeProp(n, Description.propertyName);
                     NodeDescription nDesc = (this.statisticsManager == null) ? null : this.statisticsManager
                             .getNodeDescription(n);
@@ -775,7 +763,8 @@ CommandProvider {
             return new Status(StatusCode.SUCCESS);
         }
         Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
-        for (String prop : prevNodeProperties.keySet()) {
+        for (Map.Entry<String, Property> entry : prevNodeProperties.entrySet()) {
+            String prop = entry.getKey();
             if (!updateProperties.containsKey(prop)) {
                 if (prop.equals(Description.propertyName)) {
                     if (!advertisedDesc.isEmpty()) {
@@ -808,7 +797,8 @@ CommandProvider {
         Map<String, Property> propMapCurr = nodeProps.get(node);
         if ((propMapCurr != null) && (nodeProperties != null) && (!nodeProperties.isEmpty())) {
             Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
-            for (String prop : nodeProperties.keySet()) {
+            for (Map.Entry<String, Property> entry : nodeProperties.entrySet()) {
+                String prop = entry.getKey();
                 if (prop.equals(Description.propertyName)) {
                     Map<Node, Map<String, Property>> nodeProp = this.inventoryService.getNodeProps();
                     if (nodeProp.get(node) != null) {
@@ -830,8 +820,6 @@ CommandProvider {
 
     @Override
     public Status saveSwitchConfig() {
-        // Publish the save config event to the cluster nodes
-        configSaveEvent.put(new Date().getTime(), SAVE);
         return saveSwitchConfigInternal();
     }
 
@@ -906,20 +894,6 @@ CommandProvider {
         return ncList;
     }
 
-    @Override
-    public void entryCreated(Long key, String cacheName, boolean local) {
-    }
-
-    @Override
-    public void entryUpdated(Long key, String newValue, String cacheName,
-            boolean originLocal) {
-        saveSwitchConfigInternal();
-    }
-
-    @Override
-    public void entryDeleted(Long key, String cacheName, boolean originLocal) {
-    }
-
     private void addNode(Node node, Set<Property> props) {
         log.trace("{} added, props: {}", node, props);
         if (nodeProps == null) {
@@ -984,6 +958,17 @@ CommandProvider {
             return;
         }
         nodeProps.remove(node);
+        nodeConnectorNames.remove(node);
+        Set<NodeConnector> removeNodeConnectorSet = new HashSet<NodeConnector>();
+        for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
+            NodeConnector nodeConnector = entry.getKey();
+            if (nodeConnector.getNode().equals(node)) {
+                removeNodeConnectorSet.add(nodeConnector);
+            }
+        }
+        for (NodeConnector nc : removeNodeConnectorSet) {
+            nodeConnectorProps.remove(nc);
+        }
 
         // check if span ports need to be cleaned up
         removeSpanPorts(node);
@@ -1057,6 +1042,7 @@ CommandProvider {
     public void updateNodeConnector(NodeConnector nodeConnector,
             UpdateType type, Set<Property> props) {
         Map<String, Property> propMap = new HashMap<String, Property>();
+        boolean update = true;
 
         log.debug("updateNodeConnector: {} type {} props {} for container {}",
                 new Object[] { nodeConnector, type, props, containerName });
@@ -1067,7 +1053,6 @@ CommandProvider {
 
         switch (type) {
         case ADDED:
-        case CHANGED:
             if (props != null) {
                 for (Property prop : props) {
                     addNodeConnectorProp(nodeConnector, prop);
@@ -1079,17 +1064,33 @@ CommandProvider {
 
             addSpanPort(nodeConnector);
             break;
+        case CHANGED:
+            if (!nodeConnectorProps.containsKey(nodeConnector) || (props == null)) {
+                update = false;
+            } else {
+                for (Property prop : props) {
+                    addNodeConnectorProp(nodeConnector, prop);
+                    propMap.put(prop.getName(), prop);
+                }
+            }
+            break;
         case REMOVED:
+            if (!nodeConnectorProps.containsKey(nodeConnector)) {
+                update = false;
+            }
             removeNodeConnectorAllProps(nodeConnector);
 
             // clean up span config
             removeSpanPort(nodeConnector);
             break;
         default:
+            update = false;
             break;
         }
 
-        notifyNodeConnector(nodeConnector, type, propMap);
+        if (update) {
+            notifyNodeConnector(nodeConnector, type, propMap);
+        }
     }
 
     @Override
@@ -1190,7 +1191,8 @@ CommandProvider {
         }
 
         Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
-        for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
+        for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
+            NodeConnector nodeConnector = entry.getKey();
             if (!nodeConnector.getNode().equals(node)) {
                 continue;
             }
@@ -1209,7 +1211,8 @@ CommandProvider {
         }
 
         Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
-        for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
+        for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
+            NodeConnector nodeConnector = entry.getKey();
             if (!nodeConnector.getNode().equals(node)) {
                 continue;
             }
@@ -1226,7 +1229,8 @@ CommandProvider {
         }
 
         Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
-        for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
+        for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
+            NodeConnector nodeConnector = entry.getKey();
             if (!nodeConnector.getNode().equals(node)
                     || isSpecial(nodeConnector)) {
                 continue;
@@ -1365,9 +1369,10 @@ CommandProvider {
                 Map<String, NodeConnector> mapCurr = nodeConnectorNames.get(node);
                 Map<String, NodeConnector> map = new HashMap<String, NodeConnector>();
                 if (mapCurr != null) {
-                    for (String s : mapCurr.keySet()) {
+                    for (Map.Entry<String, NodeConnector> entry : mapCurr.entrySet()) {
+                        String s = entry.getKey();
                         try {
-                            map.put(s, new NodeConnector(mapCurr.get(s)));
+                            map.put(s, new NodeConnector(entry.getValue()));
                         } catch (ConstructionException e) {
                             e.printStackTrace();
                         }
@@ -1426,9 +1431,10 @@ CommandProvider {
                     Map<String, NodeConnector> mapCurr = nodeConnectorNames.get(node);
                     if (mapCurr != null) {
                         Map<String, NodeConnector> map = new HashMap<String, NodeConnector>();
-                        for (String s : mapCurr.keySet()) {
+                        for (Map.Entry<String, NodeConnector> entry : mapCurr.entrySet()) {
+                            String s = entry.getKey();
                             try {
-                                map.put(s, new NodeConnector(mapCurr.get(s)));
+                                map.put(s, new NodeConnector(entry.getValue()));
                             } catch (ConstructionException e) {
                                 e.printStackTrace();
                             }
@@ -1462,9 +1468,10 @@ CommandProvider {
                 Map<String, NodeConnector> mapCurr = nodeConnectorNames.get(node);
                 if (mapCurr != null) {
                     Map<String, NodeConnector> map = new HashMap<String, NodeConnector>();
-                    for (String s : mapCurr.keySet()) {
+                    for (Map.Entry<String, NodeConnector> entry : mapCurr.entrySet()) {
+                        String s = entry.getKey();
                         try {
-                            map.put(s, new NodeConnector(mapCurr.get(s)));
+                            map.put(s, new NodeConnector(entry.getValue()));
                         } catch (ConstructionException e) {
                             e.printStackTrace();
                         }
@@ -1711,7 +1718,8 @@ CommandProvider {
             service.notifyNode(node, type, propMap);
         }
 
-        for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
+        for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
+            NodeConnector nodeConnector = entry.getKey();
             propMap = nodeConnectorProps.get(nodeConnector);
             service.notifyNodeConnector(nodeConnector, type, propMap);
         }
index 4bd295c62a2bc641ca877136b26992222ef39e4e..004d1b98db3eff61292937888a6fa34b1f9a4ee6 100644 (file)
@@ -192,7 +192,7 @@ public class TopologyManagerImpl implements
         try {
             this.edgesDB =
                     (ConcurrentMap<Edge, Set<Property>>) this.clusterContainerService.createCache(TOPOEDGESDB,
-                            EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                            EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
         } catch (CacheExistException cee) {
             log.debug(TOPOEDGESDB + " Cache already exists - destroy and recreate if needed");
         } catch (CacheConfigException cce) {
@@ -202,7 +202,7 @@ public class TopologyManagerImpl implements
         try {
             this.hostsDB =
                     (ConcurrentMap<NodeConnector, Set<ImmutablePair<Host, Set<Property>>>>) this.clusterContainerService.createCache(
-                            TOPOHOSTSDB, EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                            TOPOHOSTSDB, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
         } catch (CacheExistException cee) {
             log.debug(TOPOHOSTSDB + " Cache already exists - destroy and recreate if needed");
         } catch (CacheConfigException cce) {
@@ -212,7 +212,7 @@ public class TopologyManagerImpl implements
         try {
             this.nodeConnectorsDB =
                     (ConcurrentMap<NodeConnector, Set<Property>>) this.clusterContainerService.createCache(
-                            TOPONODECONNECTORDB, EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                            TOPONODECONNECTORDB, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
         } catch (CacheExistException cee) {
             log.debug(TOPONODECONNECTORDB + " Cache already exists - destroy and recreate if needed");
         } catch (CacheConfigException cce) {
@@ -222,7 +222,7 @@ public class TopologyManagerImpl implements
         try {
             this.userLinksDB =
                     (ConcurrentMap<String, TopologyUserLinkConfig>) this.clusterContainerService.createCache(
-                            TOPOUSERLINKSDB, EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                            TOPOUSERLINKSDB, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
         } catch (CacheExistException cee) {
             log.debug(TOPOUSERLINKSDB + " Cache already exists - destroy and recreate if needed");
         } catch (CacheConfigException cce) {
index a1fdce5d587e9e99cad23ac401773accd85e4286..e54953f697508a35508b07a5b3b810d0d67e9515 100644 (file)
@@ -15,7 +15,6 @@ import java.util.Hashtable;
 import java.util.Set;
 
 import org.apache.felix.dm.Component;
-import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
 import org.opendaylight.controller.configuration.IConfigurationAware;
 import org.opendaylight.controller.containermanager.IContainerAuthorization;
@@ -111,18 +110,11 @@ public class Activator extends ComponentActivatorAbstractBase {
      */
     protected void configureGlobalInstance(Component c, Object imp) {
         if (imp.equals(UserManagerImpl.class)) {
-            // export the service
-            Dictionary<String, Set<String>> props = new Hashtable<String, Set<String>>();
-            Set<String> propSet = new HashSet<String>();
-            propSet.add("usermanager.localUserSaveConfigEvent");
-            propSet.add("usermanager.remoteServerSaveConfigEvent");
-            propSet.add("usermanager.authorizationSaveConfigEvent");
-            props.put("cachenames", propSet);
 
             // export the service
-            c.setInterface(new String[] { ICacheUpdateAware.class.getName(),
+            c.setInterface(new String[] {
                     IUserManager.class.getName(),
-                    IConfigurationAware.class.getName() }, props);
+                    IConfigurationAware.class.getName() }, null);
 
             c.add(createServiceDependency().setService(
                     IClusterGlobalServices.class).setCallbacks(
index 9d2ad05765dcc5085247c1aa23025a45aad3d3b5..fedc432f207d6514cc040ebdb527d5530cf679da 100644 (file)
@@ -13,7 +13,6 @@ import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Date;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -28,7 +27,6 @@ import org.eclipse.osgi.framework.console.CommandInterpreter;
 import org.eclipse.osgi.framework.console.CommandProvider;
 import org.opendaylight.controller.clustering.services.CacheConfigException;
 import org.opendaylight.controller.clustering.services.CacheExistException;
-import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
 import org.opendaylight.controller.clustering.services.IClusterServices;
 import org.opendaylight.controller.configuration.IConfigurationAware;
@@ -72,8 +70,7 @@ import org.springframework.security.web.context.SecurityContextRepository;
  * The internal implementation of the User Manager.
  */
 public class UserManagerImpl implements IUserManager, IObjectReader,
-        IConfigurationAware, ICacheUpdateAware<Long, String>, CommandProvider,
-        AuthenticationProvider {
+        IConfigurationAware, CommandProvider, AuthenticationProvider {
     private static final Logger logger = LoggerFactory
             .getLogger(UserManagerImpl.class);
     private static final String defaultAdmin = "admin";
@@ -136,30 +133,30 @@ public class UserManagerImpl implements IUserManager, IObjectReader,
 
         try {
             clusterGlobalService.createCache("usermanager.localUserConfigList",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterGlobalService.createCache(
                     "usermanager.remoteServerConfigList",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterGlobalService.createCache(
                     "usermanager.authorizationConfList",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterGlobalService.createCache("usermanager.activeUsers",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterGlobalService.createCache(
                     "usermanager.localUserSaveConfigEvent",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterGlobalService.createCache(
                     "usermanager.remoteServerSaveConfigEvent",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterGlobalService.createCache(
                     "usermanager.authorizationSaveConfigEvent",
-                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
         } catch (CacheConfigException cce) {
             logger.error("Cache configuration invalid - check cache mode");
         } catch (CacheExistException ce) {
@@ -398,8 +395,6 @@ public class UserManagerImpl implements IUserManager, IObjectReader,
 
     @Override
     public Status saveLocalUserList() {
-        // Publish the save config event to the cluster nodes
-        localUserListSaveConfigEvent.put(new Date().getTime(), SAVE);
         return saveLocalUserListInternal();
     }
 
@@ -411,8 +406,6 @@ public class UserManagerImpl implements IUserManager, IObjectReader,
 
     @Override
     public Status saveAAAServerList() {
-        // Publish the save config event to the cluster nodes
-        remoteServerSaveConfigEvent.put(new Date().getTime(), SAVE);
         return saveAAAServerListInternal();
     }
 
@@ -424,8 +417,6 @@ public class UserManagerImpl implements IUserManager, IObjectReader,
 
     @Override
     public Status saveAuthorizationList() {
-        // Publish the save config event to the cluster nodes
-        authorizationSaveConfigEvent.put(new Date().getTime(), SAVE);
         return saveAuthorizationListInternal();
     }
 
@@ -455,7 +446,7 @@ public class UserManagerImpl implements IUserManager, IObjectReader,
         }
 
         for (UserConfig conf : confList.values()) {
-            addLocalUser(conf);
+            addRemoveLocalUserInternal(conf, false);
         }
     }
 
@@ -492,21 +483,44 @@ public class UserManagerImpl implements IUserManager, IObjectReader,
     /*
      * Interaction with GUI START
      */
-    public Status addRemoveLocalUser(UserConfig AAAconf, boolean delete) {
+    private Status addRemoveLocalUser(UserConfig AAAconf, boolean delete) {
         // UserConfig Validation check
         Status validCheck = AAAconf.validate();
         if (!validCheck.isSuccess()) {
             return validCheck;
         }
 
+        String user = AAAconf.getUser();
+
+        // Check default admin user
+        if (user.equals(UserManagerImpl.defaultAdmin)) {
+            String msg = "Invalid Request: Default Network Admin  User cannot be " + ((delete)? "removed" : "added");
+            logger.debug(msg);
+            return new Status(StatusCode.NOTALLOWED, msg);
+        }
+
+        // Check user presence/conflict
+        StatusCode statusCode = null;
+        String reason = null;
+        if (delete && !localUserConfigList.containsKey(user)) {
+            reason = "not found";
+            statusCode = StatusCode.NOTFOUND;
+        } else if (!delete && localUserConfigList.containsKey(user)) {
+            reason = "already present";
+            statusCode = StatusCode.CONFLICT;
+        }
+        if (statusCode != null) {
+            String msg = String.format("User %s %s in configuration database", user, reason);
+            logger.debug(msg);
+            return new Status(statusCode, msg);
+        }
+
+        return addRemoveLocalUserInternal(AAAconf, delete);
+    }
+
+    private Status addRemoveLocalUserInternal(UserConfig AAAconf, boolean delete) {
         // Update Config database
         if (delete) {
-            if (AAAconf.getUser().equals(UserManagerImpl.defaultAdmin)) {
-                String msg = "Invalid Request: Default Network Admin  User "
-                        + "cannot be deleted";
-                logger.debug(msg);
-                return new Status(StatusCode.NOTALLOWED, msg);
-            }
             localUserConfigList.remove(AAAconf.getUser());
             /*
              * A user account has been removed form local database, we assume
@@ -515,16 +529,10 @@ public class UserManagerImpl implements IUserManager, IObjectReader,
              */
             removeUserFromActiveList(AAAconf.getUser());
         } else {
-            if (AAAconf.getUser().equals(UserManagerImpl.defaultAdmin)) {
-                String msg = "Invalid Request: Default Network Admin  User "
-                        + "cannot be added";
-                logger.debug(msg);
-                return new Status(StatusCode.NOTALLOWED, msg);
-            }
             localUserConfigList.put(AAAconf.getUser(), AAAconf);
         }
 
-        return new Status(StatusCode.SUCCESS, null);
+        return new Status(StatusCode.SUCCESS);
     }
 
     private Status addRemoveAAAServer(ServerConfig AAAconf, boolean delete) {
@@ -542,7 +550,7 @@ public class UserManagerImpl implements IUserManager, IObjectReader,
             remoteServerConfigList.put(AAAconf.getAddress(), AAAconf);
         }
 
-        return new Status(StatusCode.SUCCESS, null);
+        return new Status(StatusCode.SUCCESS);
     }
 
     private Status addRemoveAuthInfo(AuthorizationConfig AAAconf, boolean delete) {
@@ -561,7 +569,7 @@ public class UserManagerImpl implements IUserManager, IObjectReader,
             authorizationConfList.put(AAAconf.getUser(), AAAconf);
         }
 
-        return new Status(StatusCode.SUCCESS, null);
+        return new Status(StatusCode.SUCCESS);
     }
 
     @Override
@@ -579,9 +587,11 @@ public class UserManagerImpl implements IUserManager, IObjectReader,
         if (userName == null || userName.trim().isEmpty()) {
             return new Status(StatusCode.BADREQUEST, "Invalid user name");
         }
+
         if (!localUserConfigList.containsKey(userName)) {
             return new Status(StatusCode.NOTFOUND, "User does not exist");
         }
+
         return addRemoveLocalUser(localUserConfigList.get(userName), true);
     }
 
@@ -678,36 +688,6 @@ public class UserManagerImpl implements IUserManager, IObjectReader,
         return loggedInList;
     }
 
-    /*
-     * Interaction with GUI END
-     */
-
-    /*
-     * Cluster notifications
-     */
-
-    @Override
-    public void entryCreated(Long key, String cacheName, boolean originLocal) {
-        // don't react on this event
-    }
-
-    @Override
-    public void entryUpdated(Long key, String new_value, String cacheName,
-            boolean originLocal) {
-        if (cacheName.equals("localUserSaveConfigEvent")) {
-            this.saveLocalUserListInternal();
-        } else if (cacheName.equals("remoteServerSaveConfigEvent")) {
-            this.saveAAAServerListInternal();
-        } else if (cacheName.equals("authorizationSaveConfigEvent")) {
-            this.saveAuthorizationListInternal();
-        }
-    }
-
-    @Override
-    public void entryDeleted(Long key, String cacheName, boolean originLocal) {
-        // don't react on this event
-    }
-
     public void _umAddUser(CommandInterpreter ci) {
         String userName = ci.nextArgument();
         String password = ci.nextArgument();
@@ -989,11 +969,10 @@ public class UserManagerImpl implements IUserManager, IObjectReader,
         }
 
         if (success) {
-            return new Status(StatusCode.SUCCESS, null);
+            return new Status(StatusCode.SUCCESS);
         }
 
-        return new Status(StatusCode.INTERNALERROR,
-                "Failed to save user configurations");
+        return new Status(StatusCode.INTERNALERROR, "Failed to save user configurations");
     }
 
     @Override
index 15ad9e9887d8eb2aba1250bc278a48f7441db00a..f6704775029d178233795e6afb075a4b1030892f 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.controller.devices.web;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -145,7 +146,6 @@ public class Devices implements IDaylightWeb {
                         State portState = ((State) switchManager
                                 .getNodeConnectorProp(nodeConnector,
                                         State.StatePropName));
-
                         String nodeConnectorName = (ncName != null) ? ncName
                                 .getValue() : "";
                         nodeConnectorName += " (" + nodeConnector.getID() + ")";
@@ -416,7 +416,22 @@ public class Devices implements IDaylightWeb {
                     Map<String, String> subnet = new HashMap<String, String>();
                     subnet.put("name", conf.getName());
                     subnet.put("subnet", conf.getSubnet());
-                    subnet.put("json", gson.toJson(conf));
+                    List<SubnetGatewayPortBean> portsList = new ArrayList<SubnetGatewayPortBean>();
+                    Iterator<NodeConnector> itor = conf.getSubnetNodeConnectors().iterator();
+                    while(itor.hasNext()) {
+                        SubnetGatewayPortBean bean = new SubnetGatewayPortBean();
+                        NodeConnector nodeConnector = itor.next();
+                        String nodeName = getNodeDesc(nodeConnector.getNode().toString(), containerName);
+                        Name ncName = ((Name) switchManager.getNodeConnectorProp(nodeConnector, Name.NamePropName));
+                        String nodeConnectorName = (ncName != null) ? ncName.getValue() : "";
+                        nodeConnectorName += " (" + nodeConnector.getID() + ")";
+                        bean.setNodeName(nodeName);
+                        bean.setNodePortName(nodeConnectorName);
+                        bean.setNodeId(nodeConnector.getNode().toString());
+                        bean.setNodePortId(nodeConnector.getID().toString());
+                        portsList.add(bean);
+                    }
+                    subnet.put("nodePorts", gson.toJson(portsList));
                     subnets.add(subnet);
                 }
             }
@@ -636,7 +651,7 @@ public class Devices implements IDaylightWeb {
 
     @RequestMapping(value = "/nodeports")
     @ResponseBody
-    public Map<String, Object> getNodePorts(HttpServletRequest request,
+    public List<NodeJsonBean> getNodePorts(HttpServletRequest request,
             @RequestParam(required = false) String container) {
         String containerName = (container == null) ? GlobalConstants.DEFAULT
                 .toString() : container;
@@ -647,18 +662,16 @@ public class Devices implements IDaylightWeb {
             return null;
         }
 
-
         ISwitchManager switchManager = (ISwitchManager) ServiceHelper
                 .getInstance(ISwitchManager.class, containerName, this);
         if (switchManager == null) {
             return null;
         }
-
-        Map<String, Object> nodes = new HashMap<String, Object>();
-        Map<Short, String> port;
+        List<NodeJsonBean> nodeJsonBeans = new ArrayList<NodeJsonBean>();
 
         for (Switch node : switchManager.getNetworkDevices()) {
-            port = new HashMap<Short, String>(); // new port
+            NodeJsonBean nodeJsonBean = new NodeJsonBean();
+            List<String> port = new ArrayList<String>();
             Set<NodeConnector> nodeConnectorSet = node.getNodeConnectors();
 
             if (nodeConnectorSet != null) {
@@ -666,15 +679,17 @@ public class Devices implements IDaylightWeb {
                     String nodeConnectorName = ((Name) switchManager
                             .getNodeConnectorProp(nodeConnector,
                                     Name.NamePropName)).getValue();
-                    port.put((Short) nodeConnector.getID(), nodeConnectorName
+                    port.add(nodeConnectorName
                             + "(" + nodeConnector.getID() + ")");
                 }
             }
-
-            nodes.put(node.getNode().toString(), port);
+            nodeJsonBean.setNodeId(node.getNode().toString());
+            nodeJsonBean.setNodeName(getNodeDesc(node.getNode().toString(), containerName));
+            nodeJsonBean.setNodePorts(port);
+            nodeJsonBeans.add(nodeJsonBean);
         }
 
-        return nodes;
+        return nodeJsonBeans;
     }
 
     @RequestMapping(value = "/spanPorts/add", method = RequestMethod.GET)
diff --git a/opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/NodeJsonBean.java b/opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/NodeJsonBean.java
new file mode 100644 (file)
index 0000000..0fd933a
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.devices.web;
+
+import java.util.List;
+
+public class NodeJsonBean {
+    String nodeId;
+    String nodeName;
+    List<String> nodePorts;
+
+    public String getNodeId() {
+        return nodeId;
+    }
+
+    public String getNodeName() {
+        return nodeName;
+    }
+
+    public List<String> getNodePorts() {
+        return nodePorts;
+    }
+
+    public void setNodeId(String nodeId) {
+        this.nodeId = nodeId;
+    }
+
+    public void setNodeName(String nodeName) {
+        this.nodeName = nodeName;
+    }
+
+    public void setNodePorts(List<String> port) {
+        this.nodePorts = port;
+    }
+
+}
diff --git a/opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/SubnetGatewayPortBean.java b/opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/SubnetGatewayPortBean.java
new file mode 100644 (file)
index 0000000..4124630
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.devices.web;
+
+public class SubnetGatewayPortBean {
+    private String nodeName;
+    private String nodeId;
+    private String nodePortId;
+    private String nodePortName;
+
+    public String getNodeName() {
+        return nodeName;
+    }
+    public void setNodeName(String nodeName) {
+        this.nodeName = nodeName;
+    }
+    public String getNodeId() {
+        return nodeId;
+    }
+    public void setNodeId(String nodeId) {
+        this.nodeId = nodeId;
+    }
+    public String getNodePortId() {
+        return nodePortId;
+    }
+    public void setNodePortId(String nodePortId) {
+        this.nodePortId = nodePortId;
+    }
+    public String getNodePortName() {
+        return nodePortName;
+    }
+    public void setNodePortName(String nodePortName) {
+        this.nodePortName = nodePortName;
+    }
+}
index 38df0455264c51d929c6ed3405a7f714ab4fe63a..b90e5cbfa03c786e504a78f0ce8a0a003a09d8ce 100644 (file)
@@ -12,10 +12,10 @@ one.f = {};
 // specify dashlets and layouts
 
 one.f.dashlet = {
-       nodesLearnt : {
-               id : 'nodesLearnt',
-           name : 'Nodes Learnt'
-       },
+    nodesLearnt : {
+        id : 'nodesLearnt',
+        name : 'Nodes Learnt'
+    },
     staticRouteConfig : {
         id : 'staticRouteConfig',
         name : 'Static Route Configuration'
@@ -50,67 +50,87 @@ one.f.menu = {
 
 /**Devices Modules */
 one.f.switchmanager = {
-       rootUrl: "controller/web/devices",
-       createTable: function(columnNames, body) {
-               var tableAttributes = ["table-striped", "table-bordered", "table-condensed"];
-               var $table = one.lib.dashlet.table.table(tableAttributes);
-               var tableHeaders = columnNames;
-               var $thead = one.lib.dashlet.table.header(tableHeaders);
-               var $tbody = one.lib.dashlet.table.body(body, tableHeaders);
-               $table.append($thead)
-               .append($tbody);
-               return $table;
-       },
-       validateName: function(name) {
+    rootUrl: "controller/web/devices",
+    createTable: function(columnNames, body) {
+        var tableAttributes = ["table-striped", "table-bordered", "table-condensed"];
+        var $table = one.lib.dashlet.table.table(tableAttributes);
+        var tableHeaders = columnNames;
+        var $thead = one.lib.dashlet.table.header(tableHeaders);
+        var $tbody = one.lib.dashlet.table.body(body, tableHeaders);
+        $table.append($thead)
+        .append($tbody);
+        return $table;
+    },
+    validateName: function(name) {
         return (name.length < 256);
-       }
+    }
 };
 
 one.f.switchmanager.nodesLearnt = {
-       id: {
-               dashlet: {
-                       popout: "one_f_switchmanager_nodesLearnt_id_dashlet_popout"
-               },
-               modal: {
-                       modal: "one_f_switchmanager_nodesLearnt_id_modal_modal",
-                       save: "one_f_switchmanager_nodesLearnt_id_modal_save",
-                       form: {
-                               nodeId: "one_f_switchmanager_nodesLearnt_id_modal_form_nodeid",
-                               nodeName : "one_f_switchmanager_nodesLearnt_id_modal_form_nodename",
-                               portStatus : "one_f_switchmanager_nodesLearnt_id_modal_form_portstatus",
-                               tier: "one_f_switchmanager_nodesLearnt_id_modal_form_tier",
-                               operationMode: "one_f_switchmanager_nodesLearnt_id_modal_form_opmode"
-                       }
-               }
-       },
-       dashlet: function($dashlet) {
-               var url = one.f.switchmanager.rootUrl + "/nodesLearnt";
-               one.lib.dashlet.empty($dashlet);
-               $dashlet.append(one.lib.dashlet.header(one.f.dashlet.nodesLearnt.name));
-
-               one.f.switchmanager.nodesLearnt.ajax.main(url, function(content) {
-                       var body = one.f.switchmanager.nodesLearnt.data.abridged(content);
-                       var $table = one.f.switchmanager.createTable(["Node Name", "Node ID", "Ports"], body);
-                       $dashlet.append($table);
-               });
-       },
-       ajax : {
-               main : function(url, callback) {
-                       $.getJSON(url, function(data) {
-                               callback(data);
-                       });
-               }
-       },
-       modal : {
-               initialize: {
-                       updateNode: function(evt) {
-                   one.f.switchmanager.nodesLearnt.ajax.main(one.f.switchmanager.rootUrl + "/tiers", function(tiers) {
+    id: {
+        dashlet: {
+            popout: "one_f_switchmanager_nodesLearnt_id_dashlet_popout",
+            datagrid: "one_f_switchmanager_nodesLearnt_id_dashlet_datagrid"
+        },
+        modal: {
+            modal: "one_f_switchmanager_nodesLearnt_id_modal_modal",
+            configure: "one_f_switchmanager_nodesLearnt_id_modal_configure",
+            ports: "one_f_switchmanager_nodesLearnt_id_modal_ports",
+            save: "one_f_switchmanager_nodesLearnt_id_modal_save",
+            datagrid: "one_f_switchmanager_nodesLearnt_id_modal_datagrid",
+            portsDatagrid: "one_f_switchmanager_nodesLearnt_id_modal_portsDatagrid",
+            form: {
+                nodeId: "one_f_switchmanager_nodesLearnt_id_modal_form_nodeid",
+                nodeName : "one_f_switchmanager_nodesLearnt_id_modal_form_nodename",
+                portStatus : "one_f_switchmanager_nodesLearnt_id_modal_form_portstatus",
+                tier: "one_f_switchmanager_nodesLearnt_id_modal_form_tier",
+                operationMode: "one_f_switchmanager_nodesLearnt_id_modal_form_opmode"
+            }
+        }
+    },
+    dashlet: function($dashlet) {
+        var url = one.f.switchmanager.rootUrl + "/nodesLearnt";
+        one.lib.dashlet.empty($dashlet);
+        $dashlet.append(one.lib.dashlet.header(one.f.dashlet.nodesLearnt.name));
+
+        one.f.switchmanager.nodesLearnt.ajax.main(url, function(content) {
+            var $gridHTML = one.lib.dashlet.datagrid.init(one.f.switchmanager.nodesLearnt.id.dashlet.datagrid, {
+                searchable: true,
+                filterable: false,
+                pagination: true,
+                flexibleRowsPerPage: true
+                }, "table-striped table-condensed");
+            $dashlet.append($gridHTML);
+            var dataSource = one.f.switchmanager.nodesLearnt.data.gridDataSource.abridged(content);
+            $("#" + one.f.switchmanager.nodesLearnt.id.dashlet.datagrid).datagrid({dataSource: dataSource}).on("loaded", function() {
+                $(this).find("tbody a").click(one.f.switchmanager.nodesLearnt.modal.initialize.updateNode);
+            });
+            
+            $("#" + one.f.switchmanager.nodesLearnt.id.dashlet.datagrid).datagrid({dataSource: dataSource}).on("loaded", function() {
+                $(this).find("tbody span").click(function(){
+                    one.f.switchmanager.nodesLearnt.modal.initialize.displayPorts($(this));
+                });
+            });
+            
+        });
+    },
+    ajax : {
+        main : function(url, callback) {
+            $.getJSON(url, function(data) {
+                callback(data);
+            });
+        }
+    },
+    modal : {
+        initialize: {
+            updateNode: function(evt) {
+                one.f.switchmanager.nodesLearnt.ajax.main(one.f.switchmanager.rootUrl + "/tiers", function(tiers) {
 
                     var nodeId = decodeURIComponent(evt.target.id);
                     var h3;
                     var footer = [];
-                    var $body = one.f.switchmanager.nodesLearnt.modal.body.updateNode(nodeId, evt.target.switchDetails, tiers);
-                    if (evt.target.privilege == 'WRITE'){
+                    var $body = one.f.switchmanager.nodesLearnt.modal.body.updateNode(nodeId, JSON.parse(decodeURIComponent(evt.target.getAttribute("switchDetails"))), tiers);
+                    if (evt.target.getAttribute("privilege") == 'WRITE'){
                         h3 = "Update Node Information";
                         footer = one.f.switchmanager.nodesLearnt.modal.footer.updateNode();
                     } else { //disable node edit
@@ -118,127 +138,274 @@ one.f.switchmanager.nodesLearnt = {
                         h3 = 'Node Information';
                     }
                     
-                    var $modal = one.lib.modal.spawn(one.f.switchmanager.nodesLearnt.id.modal.modal, h3, "", footer);
+                    var $modal = one.lib.modal.spawn(one.f.switchmanager.nodesLearnt.id.modal.configure, h3, "", footer);
                     // bind save button
                     $('#' + one.f.switchmanager.nodesLearnt.id.modal.save, $modal).click(function() {
                         one.f.switchmanager.nodesLearnt.modal.save($modal);
                     });
 
-                       // inject body (nodePorts)
-                       one.lib.modal.inject.body($modal, $body);
-                       $modal.modal();
-                   });
-                       },
-                       popout: function() {
-                               var h3 = "Nodes Learnt";
-                   var footer = one.f.switchmanager.nodesLearnt.modal.footer.popout();
-                   var $modal = one.lib.modal.spawn(one.f.switchmanager.nodesLearnt.id.modal.modal, h3, "", footer);
-                   var $body = one.f.switchmanager.nodesLearnt.modal.body.popout($modal);
-                   return $modal;
-                       }
-               },
-               body: {
-                       updateNode: function(nodeId, switchDetails, tiers) {
-                               var $form = $(document.createElement('form'));
-                               var $fieldset = $(document.createElement('fieldset'));
-                               // node ID. not editable.
-                               var $label = one.lib.form.label("Node ID");
-                               var $input = one.lib.form.input("node id");
-                               $input.attr('id', one.f.switchmanager.nodesLearnt.id.modal.form.nodeId);
-                               $input.attr("disabled", true);
-                               $input.attr("value", nodeId);
-                               $fieldset.append($label).append($input);
-                               // node name
-                               var $label = one.lib.form.label("Node Name");
-                               var $input = one.lib.form.input("Node Name");
-                               $input.attr('id', one.f.switchmanager.nodesLearnt.id.modal.form.nodeName);
-                               if(switchDetails["nodeName"] != null) {
-                                       $input.attr('value', switchDetails["nodeName"]);
-                               }
-                               $fieldset.append($label).append($input);
-                               // node tier
-                               var $label = one.lib.form.label("Tier");
-                               var $select = one.lib.form.select.create(tiers);
-                               $select.attr('id', one.f.switchmanager.nodesLearnt.id.modal.form.tier);
-                               $select.val(switchDetails["tier"]);
-                               $fieldset.append($label).append($select);
-                               // operation mode
-                               var $label = one.lib.form.label("Operation Mode");
-                               var $select = one.lib.form.select.create(
-                                               ["Allow reactive forwarding", "Proactive forwarding only"]);
-                               $select.attr('id', one.f.switchmanager.nodesLearnt.id.modal.form.operationMode);
-                               if ((one.main.registry != undefined) && (one.main.registry.container != 'default')) {
-                                       $select.attr("disabled", true);
-                               }
-                               $select.val(switchDetails["mode"]);
-                               $fieldset.append($label).append($select);
-                               $form.append($fieldset);
-                               return $form;
-                       },
-                       popout: function($modal) {
-                               var url = one.f.switchmanager.rootUrl + "/nodesLearnt";
-                               one.f.switchmanager.nodesLearnt.ajax.main(url, function(content) {
-                                       var tableContent = one.f.switchmanager.nodesLearnt.data.popout(content);
-                                       var $table = one.f.switchmanager.createTable(content.columnNames, tableContent);
-                                       one.lib.modal.inject.body($modal, $table);
-                               });
-                       }
-               },
-               save: function($modal) {
-                       var result = {};
+                    // inject body (nodePorts)
+                    one.lib.modal.inject.body($modal, $body);
+                    $modal.modal();
+                });
+            },
+            popout: function() {
+                var h3 = "Nodes Learnt";
+                var footer = one.f.switchmanager.nodesLearnt.modal.footer.popout();
+                var $modal = one.lib.modal.spawn(one.f.switchmanager.nodesLearnt.id.modal.modal, h3, "", footer);
+                var $body = one.f.switchmanager.nodesLearnt.modal.body.popout($modal);
+                return $modal;
+            },
+            displayPorts: function(ports) {
+                var content = JSON.parse(decodeURIComponent(ports.attr("ports")));
+                
+                var h3 = ((ports.attr("nodeName") == "None")? ports.attr("nodeId") : ports.attr("nodeName"))
+                var footer = [];
+                var $modal = one.lib.modal.spawn(one.f.switchmanager.nodesLearnt.id.modal.ports, h3, "", footer);
+                
+                var $gridHTML = one.lib.dashlet.datagrid.init(one.f.switchmanager.nodesLearnt.id.modal.portsDatagrid, {
+                    searchable: true,
+                    filterable: false,
+                    pagination: true,
+                    flexibleRowsPerPage: true,
+                    popout: true
+                    }, "table-striped table-condensed");
+                one.lib.modal.inject.body($modal, $gridHTML);
+                $modal.on("shown", function() {
+                    var dataSource = one.f.switchmanager.nodesLearnt.data.gridDataSource.displayPorts(content);
+                    $("#" + one.f.switchmanager.nodesLearnt.id.modal.portsDatagrid).datagrid({
+                        dataSource: dataSource,
+                        stretchHeight: false
+                    });
+                });
+                $modal.modal();
+            }
+        },
+        body: {
+            updateNode: function(nodeId, switchDetails, tiers) {
+                var $form = $(document.createElement('form'));
+                var $fieldset = $(document.createElement('fieldset'));
+                // node ID. not editable.
+                var $label = one.lib.form.label("Node ID");
+                var $input = one.lib.form.input("node id");
+                $input.attr('id', one.f.switchmanager.nodesLearnt.id.modal.form.nodeId);
+                $input.attr("disabled", true);
+                $input.attr("value", nodeId);
+                $fieldset.append($label).append($input);
+                // node name
+                var $label = one.lib.form.label("Node Name");
+                var $input = one.lib.form.input("Node Name");
+                $input.attr('id', one.f.switchmanager.nodesLearnt.id.modal.form.nodeName);
+                if(switchDetails["nodeName"] != null) {
+                    $input.attr('value', switchDetails["nodeName"]);
+                }
+                $fieldset.append($label).append($input);
+                // node tier
+                var $label = one.lib.form.label("Tier");
+                var $select = one.lib.form.select.create(tiers);
+                $select.attr('id', one.f.switchmanager.nodesLearnt.id.modal.form.tier);
+                $select.val(switchDetails["tier"]);
+                $fieldset.append($label).append($select);
+                // operation mode
+                var $label = one.lib.form.label("Operation Mode");
+                var $select = one.lib.form.select.create(
+                        ["Allow reactive forwarding", "Proactive forwarding only"]);
+                $select.attr('id', one.f.switchmanager.nodesLearnt.id.modal.form.operationMode);
+                if ((one.main.registry != undefined) && (one.main.registry.container != 'default')) {
+                    $select.attr("disabled", true);
+                }
+                $select.val(switchDetails["mode"]);
+                $fieldset.append($label).append($select);
+                $form.append($fieldset);
+                return $form;
+            },
+            popout: function($modal) {
+                var $gridHTML = one.lib.dashlet.datagrid.init(one.f.switchmanager.nodesLearnt.id.modal.datagrid, {
+                        searchable: true,
+                        filterable: false,
+                        pagination: true,
+                        flexibleRowsPerPage: true,
+                        popout: true
+                        }, "table-striped table-condensed");
+                one.lib.modal.inject.body($modal, $gridHTML);
+                // attach to shown event of modal 
+                $modal.on("shown", function() {
+                    var url = one.f.switchmanager.rootUrl + "/nodesLearnt";
+                    one.f.switchmanager.nodesLearnt.ajax.main(url, function(content) {
+                        var dataSource = one.f.switchmanager.nodesLearnt.data.gridDataSource.popout(content);
+                        $("#" + one.f.switchmanager.nodesLearnt.id.modal.datagrid).datagrid({
+                            dataSource: dataSource,
+                            stretchHeight: false
+                        })
+                        .on("loaded", function() {
+                            $("#" + one.f.switchmanager.nodesLearnt.id.modal.datagrid).find("tbody span").click(function(){
+                                one.f.switchmanager.nodesLearnt.modal.initialize.displayPorts($(this));
+                            });
+                        });
+                    });
+                });
+            }
+        },
+        save: function($modal) {
+            var result = {};
             result['nodeName'] = $('#' + one.f.switchmanager.nodesLearnt.id.modal.form.nodeName, $modal).val();
             if(!one.f.switchmanager.validateName(result['nodeName'])) {
-               alert("Node name can contain upto 255 characters");
-               return;
+                alert("Node name can contain upto 255 characters");
+                return;
             }
             result['nodeId'] = $('#' + one.f.switchmanager.nodesLearnt.id.modal.form.nodeId, $modal).val();
             result['tier'] = $('#' + one.f.switchmanager.nodesLearnt.id.modal.form.tier, $modal).val();
             result['operationMode'] = $('#' + one.f.switchmanager.nodesLearnt.id.modal.form.operationMode, $modal).val();
             one.f.switchmanager.nodesLearnt.modal.ajax(result, 
-                               function(response) {
-                       if(response.status == true) {
-                               $modal.modal('hide');
-                               one.topology.update(); // refresh visual topology with new name
-                               // TODO: Identify dashlet by inserting a nodesLearnt div 
-                                       // in the dashlet() instead
-                               one.f.switchmanager.nodesLearnt.dashlet($("#left-top .dashlet"));
-                       } else {
-                               alert(response.message);
-                       }
-                       
-                   });
-               },
-               ajax: function(requestData, callback) {
-                       $.getJSON(one.f.switchmanager.rootUrl + "/nodesLearnt/update", requestData, function(response) {
-                               callback(response);
-                       });
-               },
-               footer: {
-                       updateNode: function() {
-                               var footer = [];
+                function(response) {
+                    if(response.status == true) {
+                        $modal.modal('hide');
+                        one.topology.update(); // refresh visual topology with new name
+                        // TODO: Identify dashlet by inserting a nodesLearnt div 
+                        // in the dashlet() instead
+                        one.f.switchmanager.nodesLearnt.dashlet($("#left-top .dashlet"));
+                    } else {
+                        alert(response.message);
+                    }
+                    
+                });
+        },
+        ajax: function(requestData, callback) {
+            $.getJSON(one.f.switchmanager.rootUrl + "/nodesLearnt/update", requestData, function(response) {
+                callback(response);
+            });
+        },
+        footer: {
+            updateNode: function() {
+                var footer = [];
                 var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.nodesLearnt.id.modal.save, "btn-success", "");
                 var $saveButton = one.lib.dashlet.button.button(saveButton);
                 footer.push($saveButton);
 
-                   return footer;
-                       },
-                       popout: function() {
-                               // TODO: Maybe put a close button in the footer?
-                               return [];
-                       }
-               }
-       },
-       // data functions
-       data : {
-               abridged : function(data) {
-                       var result = [];
-                       $.each(data.nodeData, function(key, value) {
-                               var tr = {};
-                               var entry = [];
-                               var nodenameentry = value["nodeName"] ? value["nodeName"] : "Click to update";
-
-                               // TODO: Move anchor tag creation to one.lib.form.
-                               var aTag;
+                return footer;
+            },
+            popout: function() {
+                // TODO: Maybe put a close button in the footer?
+                return [];
+            }
+        }
+    },
+    // data functions
+    data : {
+        gridDataSource: {
+            abridged: function(data) {
+                var source = new StaticDataSource({
+                    columns: [
+                        {
+                            property: 'nodeName',
+                            label: 'Node Name',
+                            sortable: true
+                        },
+                        {
+                            property: 'nodeId',
+                            label: 'Node ID',
+                            sortable: true
+                        },
+                        {
+                            property: 'ports',
+                            label: 'Ports',
+                            sortable: true
+                        }
+                    ],
+                    data: data.nodeData,
+                    formatter: function(items) {
+                    $.each(items, function (index, item) {
+                        var nodeName = item.nodeName;
+                        var nodeNameEntry = item.nodeName ? item.nodeName : "Click to update";
+                        item.nodeName = '<a href="#" id="' + item.nodeId + '" switchDetails=' + encodeURIComponent(JSON.stringify(item)) + 
+                        ' privilege=' + data.privilege + '>' + nodeNameEntry + '</a>';
+                        
+                        var ports = item.ports;
+                        item.ports = '<span class="nodePorts" style="cursor:pointer;color: #08c" ports='+encodeURIComponent(JSON.stringify(item.ports)) + ' nodeId=' + item.nodeId 
+                            + ' nodeName=' + nodeName  
+                            + '>' + ports.match(/<\/span>/g).length+'</span>';
+                    }); 
+                    },
+                    delay: 0
+                });
+                return source;
+
+            },
+            popout: function(data) {
+                var source = new StaticDataSource({
+                    columns: [
+                        {
+                            property: 'nodeName',
+                            label: 'Node Name',
+                            sortable: true
+                        },
+                        {
+                            property: 'nodeId',
+                            label: 'Node ID',
+                            sortable: true
+                        },
+                        {
+                            property: 'tierName',
+                            label: 'Tier Name',
+                            sortable: true
+                        },
+                        {
+                            property: 'mac',
+                            label: 'MAC',
+                            sortable: true
+                        },
+                        {
+                            property: 'ports',
+                            label: 'Ports',
+                            sortable: true
+                        }
+                    ],
+                    data: data.nodeData,
+                    formatter: function(items) {
+                        $.each(items, function (index, item) {
+                            var ports = item.ports;
+                            item.ports = '<span class="nodePorts" style="cursor: pointer;color: #08c" ports='+encodeURIComponent(JSON.stringify(item.ports)) + ' nodeId=' + item.nodeId 
+                                + ' nodeName=' + item.nodeName  
+                                + '>' + ports.match(/<\/span>/g).length+'</span>';
+                        }); 
+                    },
+                    delay: 0
+                });
+                return source;
+            },
+            displayPorts: function(content){
+                var data=[];
+                var start=0;;
+                var finish=content.indexOf("<br>",start);
+                while(finish != -1){
+                    data.push({"ports":content.substring(start,finish)});
+                    start=finish+4
+                    finish=content.indexOf("<br>",start);
+                }
+                var source = new StaticDataSource({
+                    columns: [
+                        {
+                            property: 'ports',
+                            label: 'Ports',
+                            sortable: true
+                        }
+                    ],
+                    data:data,
+                    delay: 0
+                });
+                
+                return source;
+            }
+        },
+        abridged : function(data) {
+            var result = [];
+            $.each(data.nodeData, function(key, value) {
+                var tr = {};
+                var entry = [];
+                var nodeNameEntry = value["nodeName"] ? value["nodeName"] : "Click to update";
+
+                // TODO: Move anchor tag creation to one.lib.form.
+                var aTag;
                 aTag = document.createElement("a");
                 aTag.privilege = data.privilege;
                 aTag.addEventListener("click", one.f.switchmanager.nodesLearnt.modal.initialize.updateNode);
@@ -247,61 +414,61 @@ one.f.switchmanager.nodesLearnt = {
                 }, false);
                 aTag.setAttribute("id", encodeURIComponent(value["nodeId"]));
                 aTag.switchDetails = value;
-                               aTag.innerHTML = nodenameentry;
-                               entry.push(aTag);
-                               entry.push(value["nodeId"]);
-                               entry.push(value["ports"]);
-                               tr.entry = entry;
-                               result.push(tr);
-                       });
-                       return result;
-               },
-               popout : function(data) {
-                       var result = [];
-                       $.each(data.nodeData, function(key, value) {
-                               var tr = {};
-                               // fill up all the td's
-                               var entry = [];
-                               var nodenameentry = value["nodeName"] ? value["nodeName"] : "No name provided";
-                               entry.push(nodenameentry);
-                               entry.push(value["nodeId"]);
-                               entry.push(value["tierName"]);
-                               entry.push(value["mac"]);
-                               entry.push(value["ports"]);
-                               entry.push(value["portStatus"]);
-                               tr.entry = entry;
-                               result.push(tr);
-                       });
-                       return result;
-               }
-       }
+                aTag.innerHTML = nodeNameEntry;
+                entry.push(aTag);
+                entry.push(value["nodeId"]);
+                entry.push(value["ports"]);
+                tr.entry = entry;
+                result.push(tr);
+            });
+            return result;
+        },
+        popout : function(data) {
+            var result = [];
+            $.each(data.nodeData, function(key, value) {
+                var tr = {};
+                // fill up all the td's
+                var entry = [];
+                var nodenameentry = value["nodeName"] ? value["nodeName"] : "No name provided";
+                entry.push(nodenameentry);
+                entry.push(value["nodeId"]);
+                entry.push(value["tierName"]);
+                entry.push(value["mac"]);
+                entry.push(value["ports"]);
+                tr.entry = entry;
+                result.push(tr);
+            });
+            return result;
+        }
+    }
 };
 
 one.f.switchmanager.subnetGatewayConfig = {
-       id: {
-               dashlet: {
-                       addIPAddress: "one_f_switchmanager_subnetGatewayConfig_id_dashlet_addIP",
-                       addPorts: "one_f_switchmanager_subnetGatewayConfig_id_dashlet_addPorts",
-                       removeIPAddress: "one_f_switchmanager_subnetGatewayConfig_id_dashlet_removeIP"
-               }, 
-               modal: {
-                       modal: "one_f_switchmanager_subnetGatewayConfig_id_modal_modal",
-                       save: "one_f_switchmanager_subnetGatewayConfig_id_modal_save",
-                       form: {
-                               name : "one_f_switchmanager_subnetGatewayConfig_id_modal_form_gatewayname",
-                               gatewayIPAddress : "one_f_switchmanager_subnetGatewayConfig_id_modal_form_gatewayipaddress",
-                               nodeId: "one_f_switchmanager_subnetGatewayConfig_id_modal_form_nodeid",
-                               ports: "one_f_switchmanager_subnetGatewayConfig_id_modal_form_ports"
-                       }
-               }
-       },
-       // device ajax calls
-       dashlet: function($dashlet) {
-               one.lib.dashlet.empty($dashlet);
-               $dashlet.append(one.lib.dashlet.header(one.f.dashlet.subnetGatewayConfig.name));
-               // Add gateway IP Address button
-               var url = one.f.switchmanager.rootUrl + "/subnets";
-               one.f.switchmanager.subnetGatewayConfig.ajax.main(url, {}, function(content) {
+    id: {
+        dashlet: {
+            addIPAddress: "one_f_switchmanager_subnetGatewayConfig_id_dashlet_addIP",
+            addPorts: "one_f_switchmanager_subnetGatewayConfig_id_dashlet_addPorts",
+            removeIPAddress: "one_f_switchmanager_subnetGatewayConfig_id_dashlet_removeIP",
+            datagrid: "one_f_switchmanager_subnetGatewayConfig_id_dashlet_datagrid"
+        }, 
+        modal: {
+            modal: "one_f_switchmanager_subnetGatewayConfig_id_modal_modal",
+            save: "one_f_switchmanager_subnetGatewayConfig_id_modal_save",
+            form: {
+                name : "one_f_switchmanager_subnetGatewayConfig_id_modal_form_gatewayname",
+                gatewayIPAddress : "one_f_switchmanager_subnetGatewayConfig_id_modal_form_gatewayipaddress",
+                nodeId: "one_f_switchmanager_subnetGatewayConfig_id_modal_form_nodeid",
+                ports: "one_f_switchmanager_subnetGatewayConfig_id_modal_form_ports"
+            }
+        }
+    },
+    // device ajax calls
+    dashlet: function($dashlet) {
+        one.lib.dashlet.empty($dashlet);
+        $dashlet.append(one.lib.dashlet.header(one.f.dashlet.subnetGatewayConfig.name));
+        // Add gateway IP Address button
+        var url = one.f.switchmanager.rootUrl + "/subnets";
+        one.f.switchmanager.subnetGatewayConfig.ajax.main(url, {}, function(content) {
 
             if (content.privilege === 'WRITE') {
                 var button = one.lib.dashlet.button.single("Add Gateway IP Address",
@@ -320,7 +487,7 @@ one.f.switchmanager.subnetGatewayConfig = {
                 $button.click(function() {
                     var requestData = {};
                     var gatewaysToDelete = [];
-                    var checkedCheckBoxes = $("input:checked", $(this).closest(".dashlet").find("table"));
+                    var checkedCheckBoxes = $("#" + one.f.switchmanager.subnetGatewayConfig.id.dashlet.datagrid).find("tbody input:checked")
                     checkedCheckBoxes.each(function(index, value) {
                         gatewaysToDelete.push(checkedCheckBoxes[index].id);
                     });
@@ -349,263 +516,337 @@ one.f.switchmanager.subnetGatewayConfig = {
                 });
                 $dashlet.append($button);
             }
+            var $gridHTML = one.lib.dashlet.datagrid.init(one.f.switchmanager.subnetGatewayConfig.id.dashlet.datagrid, {
+                searchable: true,
+                filterable: false,
+                pagination: true,
+                flexibleRowsPerPage: true
+                }, "table-striped table-condensed");
+            $dashlet.append($gridHTML);
+            var dataSource = one.f.switchmanager.subnetGatewayConfig.data.devicesgrid(content);
+            $("#" + one.f.switchmanager.subnetGatewayConfig.id.dashlet.datagrid).datagrid({dataSource: dataSource});
+        });
+    },
+    ajax : {
+        main : function(url, requestData, callback) {
+            $.getJSON(url, requestData, function(data) {
+                callback(data);
+            });
+        }
+    },
+    registry: {},
+    modal : {
+        initialize: {
+            gateway: function() {
+                var h3 = "Add Gateway IP Address";
+                var footer = one.f.switchmanager.subnetGatewayConfig.modal.footer();
+                var $modal = one.lib.modal.spawn(one.f.switchmanager.subnetGatewayConfig.id.modal.modal, h3, "", footer);
+                // bind save button
+                $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.save, $modal).click(function() {
+                    one.f.switchmanager.subnetGatewayConfig.modal.save.gateway($modal);
+                });
+                var $body = one.f.switchmanager.subnetGatewayConfig.modal.body.gateway();
+                one.lib.modal.inject.body($modal, $body);
+                return $modal;
+            },
+            ports: function() {
+                var h3 = "Add Ports";
+                var footer = one.f.switchmanager.subnetGatewayConfig.modal.footer();
+                var $modal = one.lib.modal.spawn(one.f.switchmanager.subnetGatewayConfig.id.modal.modal, h3, "", footer);
+                // bind save button
+                $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.save, $modal).click(function() {
+                    one.f.switchmanager.subnetGatewayConfig.modal.save.ports($modal);
+                });
+                
+                // TODO: Change to subnetGateway instead.
+                one.f.switchmanager.spanPortConfig.modal.ajax.nodes(function(nodes, nodeports) {
+                    var $body = one.f.switchmanager.subnetGatewayConfig.modal.body.ports(nodes, nodeports);
+                    one.lib.modal.inject.body($modal, $body);
+                });
+                return $modal;
+            }
+        },
+        save: {
+            gateway: function($modal) {
+                var result = {};
+                result['gatewayName'] = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.name, $modal).val();
+                if(!one.f.switchmanager.validateName(result['gatewayName'])) {
+                    alert("Gateway name can contain upto 255 characters");
+                    return;
+                }
+                result['gatewayIPAddress'] = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.gatewayIPAddress, $modal).val();
+                one.f.switchmanager.subnetGatewayConfig.modal.ajax.gateway(result, 
+                    function(response) {
+                        if(response.status == true) {
+                            $modal.modal('hide');
+                            one.f.switchmanager.subnetGatewayConfig.dashlet($("#right-bottom .dashlet"));
+                        } else {
+                            alert(response.message);
+                        }
+                    });
+            },
+            ports: function($modal) {
+                var result = {};
+                var gatewayRegistryIndex = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.name, $modal).val();
+                result['portsName'] = one.f.switchmanager.subnetGatewayConfig.registry.gateways[gatewayRegistryIndex];
+                result['nodeId'] = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.nodeId, $modal).val();
+                result['ports'] = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.ports, $modal).val();
+                if(!result['portsName'] || result['portsName'] == "") {
+                    alert("No gateway chosen. Cannot add port");
+                    return;
+                }
+                if(!result['nodeId'] || result['nodeId'] == "") {
+                    alert("Please select a node.");
+                    return;
+                }
+                if(!result['ports'] || result['ports'] == "") {
+                    alert("Please choose a port.");
+                    return;
+                }
+                one.f.switchmanager.subnetGatewayConfig.modal.ajax.ports(result, 
+                    function(response) {
+                        if(response.status == true) {
+                            $modal.modal('hide');
+                            one.f.switchmanager.subnetGatewayConfig.dashlet($("#right-bottom .dashlet"));
+                        } else {
+                            alert(response.message);
+                        }
+                    });
+            }
+        },
+        body: {
+            gateway: function() {
+                var $form = $(document.createElement('form'));
+                var $fieldset = $(document.createElement('fieldset'));
+                // gateway name
+                var $label = one.lib.form.label("Name");
+                var $input = one.lib.form.input("Name");
+                $input.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.name);
+                $fieldset.append($label).append($input);
+                // gateway IP Mask 
+                var $label = one.lib.form.label("Gateway IP Address/Mask");
+                var $input = one.lib.form.input("Gateway IP Address/Mask");
+                $input.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.gatewayIPAddress);
+                $fieldset.append($label).append($input);
+                
+                $form.append($fieldset);
+                return $form;
+            },
+            ports: function(nodes, nodeports) {
+                var $form = $(document.createElement('form'));
+                var $fieldset = $(document.createElement('fieldset'));
+                // gateways drop down
+                var $label = one.lib.form.label("Gateway Name");
+                var $select = one.lib.form.select.create(one.f.switchmanager.subnetGatewayConfig.registry.gateways);
+                $select.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.name);
+                $select.val($select.find("option:first").val());
+                $fieldset.append($label).append($select);
 
-                       var body = one.f.switchmanager.subnetGatewayConfig.data.devices(content);
-                       // first column contains checkbox. no need for header
-                       content.columnNames.splice(0,0," ");
-                       var $table = one.f.switchmanager.createTable(content.columnNames, body);
-                       $dashlet.append($table);
-               });
-       },
-       ajax : {
-               main : function(url, requestData, callback) {
-                       $.getJSON(url, requestData, function(data) {
-                               callback(data);
-                       });
-               }
-       },
-       registry: {},
-       modal : {
-               initialize: {
-                       gateway: function() {
-                               var h3 = "Add Gateway IP Address";
-                   var footer = one.f.switchmanager.subnetGatewayConfig.modal.footer();
-                   var $modal = one.lib.modal.spawn(one.f.switchmanager.subnetGatewayConfig.id.modal.modal, h3, "", footer);
-                   // bind save button
-                   $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.save, $modal).click(function() {
-                       one.f.switchmanager.subnetGatewayConfig.modal.save.gateway($modal);
-                   });
-                   var $body = one.f.switchmanager.subnetGatewayConfig.modal.body.gateway();
-                   one.lib.modal.inject.body($modal, $body);
-                   return $modal;
-                       },
-                       ports: function() {
-                               var h3 = "Add Ports";
-                   var footer = one.f.switchmanager.subnetGatewayConfig.modal.footer();
-                   var $modal = one.lib.modal.spawn(one.f.switchmanager.subnetGatewayConfig.id.modal.modal, h3, "", footer);
-                   // bind save button
-                   $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.save, $modal).click(function() {
-                       one.f.switchmanager.subnetGatewayConfig.modal.save.ports($modal);
-                   });
-                   
-                   // TODO: Change to subnetGateway instead.
-                   one.f.switchmanager.spanPortConfig.modal.ajax.nodes(function(nodes, nodeports) {
-                       var $body = one.f.switchmanager.subnetGatewayConfig.modal.body.ports(nodes, nodeports);
-                       one.lib.modal.inject.body($modal, $body);
-                   });
-                   return $modal;
-                       }
-               },
-               save: {
-                       gateway: function($modal) {
-                               var result = {};
-                   result['gatewayName'] = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.name, $modal).val();
-                   if(!one.f.switchmanager.validateName(result['gatewayName'])) {
-                       alert("Gateway name can contain upto 255 characters");
-                       return;
-                   }
-                   result['gatewayIPAddress'] = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.gatewayIPAddress, $modal).val();
-                   one.f.switchmanager.subnetGatewayConfig.modal.ajax.gateway(result, 
-                                       function(response) {
-                               if(response.status == true) {
-                                       $modal.modal('hide');
-                                       one.f.switchmanager.subnetGatewayConfig.dashlet($("#right-bottom .dashlet"));
-                               } else {
-                                       alert(response.message);
-                               }
-                           });
-                       },
-                       ports: function($modal) {
-                               var result = {};
-                               var gatewayRegistryIndex = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.name, $modal).val();
-                   result['portsName'] = one.f.switchmanager.subnetGatewayConfig.registry.gateways[gatewayRegistryIndex];
-                   result['nodeId'] = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.nodeId, $modal).val();
-                   result['ports'] = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.ports, $modal).val();
-                   if(!result['portsName'] || result['portsName'] == "") {
-                       alert("No gateway chosen. Cannot add port");
-                       return;
-                   }
-                   if(!result['nodeId'] || result['nodeId'] == "") {
-                       alert("Please select a node.");
-                       return;
-                   }
-                   if(!result['ports'] || result['ports'] == "") {
-                       alert("Please choose a port.");
-                       return;
-                   }
-                   one.f.switchmanager.subnetGatewayConfig.modal.ajax.ports(result, 
-                                       function(response) {
-                               if(response.status == true) {
-                                       $modal.modal('hide');
-                                       one.f.switchmanager.subnetGatewayConfig.dashlet($("#right-bottom .dashlet"));
-                               } else {
-                                       alert(response.message);
-                               }
-                               });
-                       }
-               },
-               body: {
-                       gateway: function() {
-                               var $form = $(document.createElement('form'));
-                               var $fieldset = $(document.createElement('fieldset'));
-                               // gateway name
-                               var $label = one.lib.form.label("Name");
-                               var $input = one.lib.form.input("Name");
-                               $input.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.name);
-                               $fieldset.append($label).append($input);
-                               // gateway IP Mask 
-                               var $label = one.lib.form.label("Gateway IP Address/Mask");
-                               var $input = one.lib.form.input("Gateway IP Address/Mask");
-                               $input.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.gatewayIPAddress);
-                               $fieldset.append($label).append($input);
-                               
-                               $form.append($fieldset);
-                               return $form;
-                       },
-                       ports: function(nodes, nodeports) {
-                               var $form = $(document.createElement('form'));
-                               var $fieldset = $(document.createElement('fieldset'));
-                               // gateways drop down
-                               var $label = one.lib.form.label("Gateway Name");
-                               var $select = one.lib.form.select.create(one.f.switchmanager.subnetGatewayConfig.registry.gateways);
-                               $select.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.name);
-                               $select.val($select.find("option:first").val());
-                               $fieldset.append($label).append($select);
-
-                               // node ID
-                               var $label = one.lib.form.label("Node ID");
-                               var $select = one.lib.form.select.create(nodes);
-                               $select.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.nodeId);
-                               one.lib.form.select.prepend($select, { '' : 'Please Select a Node' });
-                               $select.val($select.find("option:first").val());
-                               $fieldset.append($label).append($select);
-
-                               // bind onchange
-                               $select.change(function() {
-                                   // retrieve port value
-                                   var node = $(this).find('option:selected').attr('value');
-                                   one.f.switchmanager.subnetGatewayConfig.registry['currentNode'] = node;
-                                   var $ports = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.ports);
-                                   var ports = nodeports[node];
-                                   one.lib.form.select.inject($ports, ports);
-                                   one.lib.form.select.prepend($ports, { '' : 'Please Select a Port' });
-                                   $ports.val($ports.find("option:first").val());
-                               });
-
-                               // ports
-                               var $label = one.lib.form.label("Select Port");
-                               var $select = one.lib.form.select.create();
-                               $select.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.ports);
-                               $fieldset.append($label).append($select);
-                               
-                               $form.append($fieldset);
-                               return $form;
-                       }
-               },
-               ajax: {
-                       gateway: function(requestData, callback) {
-                               $.getJSON(one.f.switchmanager.rootUrl + "/subnetGateway/add", requestData, function(data) {
-                                       callback(data);
-                       });
-                       },
-                       ports: function(requestData, callback) {
-                               $.getJSON(one.f.switchmanager.rootUrl + "/subnetGateway/ports/add", requestData, function(data) {
-                                       callback(data);
-                       });
-                       }
-               },
-               footer : function() {
+                // node ID
+                var $label = one.lib.form.label("Node ID");
+                var $select = one.lib.form.select.create(nodes);
+                $select.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.nodeId);
+                one.lib.form.select.prepend($select, { '' : 'Please Select a Node' });
+                $select.val($select.find("option:first").val());
+                $fieldset.append($label).append($select);
+
+                // bind onchange
+                $select.change(function() {
+                    // retrieve port value
+                    var node = $(this).find('option:selected').attr('value');
+                    one.f.switchmanager.subnetGatewayConfig.registry['currentNode'] = node;
+                    var $ports = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.ports);
+                    var ports = nodeports[node];
+                    one.lib.form.select.inject($ports, ports);
+                    one.lib.form.select.prepend($ports, { '' : 'Please Select a Port' });
+                    $ports.val($ports.find("option:first").val());
+                });
+
+                // ports
+                var $label = one.lib.form.label("Select Port");
+                var $select = one.lib.form.select.create();
+                $select.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.ports);
+                $fieldset.append($label).append($select);
+                
+                $form.append($fieldset);
+                return $form;
+            }
+        },
+        ajax: {
+            gateway: function(requestData, callback) {
+                $.getJSON(one.f.switchmanager.rootUrl + "/subnetGateway/add", requestData, function(data) {
+                    callback(data);
+            });
+            },
+            ports: function(requestData, callback) {
+                $.getJSON(one.f.switchmanager.rootUrl + "/subnetGateway/ports/add", requestData, function(data) {
+                    callback(data);
+            });
+            }
+        },
+        footer : function() {
             var footer = [];
             var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.subnetGatewayConfig.id.modal.save, "btn-success", "");
             var $saveButton = one.lib.dashlet.button.button(saveButton);
             footer.push($saveButton);
             return footer;
         }
-       },
-       // data functions
-       data : {
-               devices : function(data) {
-                       var result = [];
-                       one.f.switchmanager.subnetGatewayConfig.registry.gateways = [];
-                       $.each(data.nodeData, function(key, value) {
-                               var tr = {};
-                               // fill up all the td's
-                               var subnetConfigObject = $.parseJSON(value["json"]);
-                               var nodePorts = subnetConfigObject.nodePorts;
-                               var $nodePortsContainer = $(document.createElement("div"));
-                               
-                               for(var i = 0; i < nodePorts.length; i++) {
-                                       var nodePort = nodePorts[i];
-                                       $nodePortsContainer.append(nodePort + " ");
-                                       // add delete anchor tag to delete ports
-                                       var aTag = document.createElement("a");
-                                       aTag.setAttribute("id", encodeURIComponent(nodePort));
-                                       aTag.gatewayName = value["name"];
-                                       aTag.addEventListener("click", function(evt) {
-                                               var htmlPortAnchor = evt.target;
-                                               var requestData = {};
-                                               requestData["gatewayName"] = evt.target.gatewayName;
-                                               requestData["nodePort"] = decodeURIComponent(evt.target.id);
-                                               // make ajax call to delete port
-                                               var url = one.f.switchmanager.rootUrl + "/subnetGateway/ports/delete";
-                                       one.f.switchmanager.subnetGatewayConfig.ajax.main(url, requestData, function(response) {
-                                               if(response.status == true) {
-                                                       // refresh dashlet by passing dashlet div as param
-                                       one.f.switchmanager.subnetGatewayConfig.dashlet($("#right-bottom .dashlet"));
-                                               } else {
-                                                       alert(response.message);
-                                               }
-                                       });
-                                               
-                                       });
-                                       aTag.addEventListener("mouseover", function(evt) {
-                                               evt.target.style.cursor = "pointer";
-                                       }, false);
-                                       aTag.innerHTML = "Delete";
-                                       $nodePortsContainer.append(aTag);
-                                       $nodePortsContainer.append("<br/>");
-                               }
-
-                               // store gateways in the registry so that they can be used in the add ports popup
-                               one.f.switchmanager.subnetGatewayConfig.registry.gateways.push(value["name"]);
-                               var entry = [];
-                               var checkbox = document.createElement("input");
-                               checkbox.setAttribute("type", "checkbox");
-                               checkbox.setAttribute("id", value["name"]);
-                               entry.push(checkbox);
-                               entry.push(value["name"]);
-                               entry.push(value["subnet"]);
-                               entry.push($nodePortsContainer);
-                               tr.entry = entry;
-                               result.push(tr);
-                       });
-                       return result;
-               }
-       }
+    },
+    // data functions
+    data : {
+        devicesgrid: function(data) {
+            one.f.switchmanager.subnetGatewayConfig.registry.gateways = [];
+            var source = new StaticDataSource({
+                    columns: [
+                        {
+                            property: 'selector',
+                            label: ' ',
+                            sortable: false
+                        },
+                        {
+                            property: 'name',
+                            label: 'Name',
+                            sortable: true
+                        },
+                        {
+                            property: 'subnet',
+                            label: 'Gateway IP Address/Mask',
+                            sortable: true
+                        },
+                        {
+                            property: 'nodePorts',
+                            label: 'Node/Ports',
+                            sortable: false
+                        }
+                    ],
+                    data: data.nodeData,
+                    formatter: function(items) {
+                        $.each(items, function(index, tableRow) {
+                            tableRow["selector"] = '<input type="checkbox" id=' + tableRow["name"] + '></input>';
+                            var json = tableRow["nodePorts"];
+                            var nodePorts = JSON.parse(json);
+                            var nodePortHtml = "<div>";
+                            $.each(nodePorts, function(index, nodePort) {
+                                var nodePortID = nodePort["nodeId"] + "/" + nodePort["nodePortId"]; 
+                                nodePortHtml += nodePort["nodeName"] + " / " + nodePort["nodePortName"];
+                                nodePortHtml += "&nbsp;";
+                                nodePortHtml += '<a href="#" id=' + encodeURIComponent(nodePortID) + 
+                                    ' gatewayName=' + tableRow["name"] + 
+                                    ' onclick="javascript:one.f.switchmanager.subnetGatewayConfig.actions.deleteNodePort(this);">Delete</a>';
+                                nodePortHtml += "<br/>";
+                            });
+                            nodePortHtml += "</div>";
+                            tableRow["nodePorts"] = nodePortHtml;
+                        });
+
+                    },
+                    delay: 0
+                });
+                // populate the registry with subnet names
+                one.f.switchmanager.subnetGatewayConfig.registry.gateways = [];
+                $.each(data.nodeData, function(key, value) {
+                    one.f.switchmanager.subnetGatewayConfig.registry.gateways.push(value["name"]);
+                });
+                return source;          
+        },
+        devices : function(data) {
+            var result = [];
+            one.f.switchmanager.subnetGatewayConfig.registry.gateways = [];
+            $.each(data.nodeData, function(key, value) {
+                var tr = {};
+                // fill up all the td's
+                var subnetConfigObject = $.parseJSON(value["json"]);
+                var nodePorts = subnetConfigObject.nodePorts;
+                var $nodePortsContainer = $(document.createElement("div"));
+                
+                for(var i = 0; i < nodePorts.length; i++) {
+                    var nodePort = nodePorts[i];
+                    $nodePortsContainer.append(nodePort + " ");
+                    // add delete anchor tag to delete ports
+                    var aTag = document.createElement("a");
+                    aTag.setAttribute("id", encodeURIComponent(nodePort));
+                    aTag.gatewayName = value["name"];
+                    aTag.addEventListener("click", function(evt) {
+                        var htmlPortAnchor = evt.target;
+                        var requestData = {};
+                        requestData["gatewayName"] = evt.target.gatewayName;
+                        requestData["nodePort"] = decodeURIComponent(evt.target.id);
+                        // make ajax call to delete port
+                        var url = one.f.switchmanager.rootUrl + "/subnetGateway/ports/delete";
+                        one.f.switchmanager.subnetGatewayConfig.ajax.main(url, requestData, function(response) {
+                            if(response.status == true) {
+                                // refresh dashlet by passing dashlet div as param
+                                one.f.switchmanager.subnetGatewayConfig.dashlet($("#right-bottom .dashlet"));
+                            } else {
+                                alert(response.message);
+                            }
+                        });
+                        
+                    });
+                    aTag.addEventListener("mouseover", function(evt) {
+                        evt.target.style.cursor = "pointer";
+                    }, false);
+                    aTag.innerHTML = "Delete";
+                    $nodePortsContainer.append(aTag);
+                    $nodePortsContainer.append("<br/>");
+                }
+
+                // store gateways in the registry so that they can be used in the add ports popup
+                one.f.switchmanager.subnetGatewayConfig.registry.gateways.push(value["name"]);
+                var entry = [];
+                var checkbox = document.createElement("input");
+                checkbox.setAttribute("type", "checkbox");
+                checkbox.setAttribute("id", value["name"]);
+                entry.push(checkbox);
+                entry.push(value["name"]);
+                entry.push(value["subnet"]);
+                entry.push($nodePortsContainer);
+                tr.entry = entry;
+                result.push(tr);
+            });
+            return result;
+        }
+    },
+    actions: {
+        deleteNodePort: function(htmlPortAnchor) {
+            var requestData = {};
+            requestData["gatewayName"] = htmlPortAnchor.getAttribute("gatewayName");
+            requestData["nodePort"] = decodeURIComponent(htmlPortAnchor.id);
+            // make ajax call to delete port
+            var url = one.f.switchmanager.rootUrl + "/subnetGateway/ports/delete";
+            one.f.switchmanager.subnetGatewayConfig.ajax.main(url, requestData, function(response) {
+                if(response.status == true) {
+                    // refresh dashlet by passing dashlet div as param
+                    one.f.switchmanager.subnetGatewayConfig.dashlet($("#right-bottom .dashlet"));
+                } else {
+                    alert(response.message);
+                }
+            });
+        }
+    }
 }
 
 one.f.switchmanager.staticRouteConfig = {
-       id: {
-               dashlet: {
-                       add: "one_f_switchmanager_staticRouteConfig_id_dashlet_add",
-                       remove: "one_f_switchmanager_staticRouteConfig_id_dashlet_remove"
-               }, 
-               modal: {
-                       modal: "one_f_switchmanager_staticRouteConfig_id_modal_modal",
-                       save: "one_f_switchmanager_staticRouteConfig_id_modal_save",
-                       form: {
-                               routeName : "one_f_switchmanager_staticRouteConfig_id_modal_form_routename",
-                               staticRoute : "one_f_switchmanager_staticRouteConfig_id_modal_form_staticroute",
+    id: {
+        dashlet: {
+            add: "one_f_switchmanager_staticRouteConfig_id_dashlet_add",
+            remove: "one_f_switchmanager_staticRouteConfig_id_dashlet_remove",
+            datagrid: "one_f_switchmanager_staticRouteConfig_id_dashlet_datagrid"
+        }, 
+        modal: {
+            modal: "one_f_switchmanager_staticRouteConfig_id_modal_modal",
+            save: "one_f_switchmanager_staticRouteConfig_id_modal_save",
+            form: {
+                routeName : "one_f_switchmanager_staticRouteConfig_id_modal_form_routename",
+                staticRoute : "one_f_switchmanager_staticRouteConfig_id_modal_form_staticroute",
                 nextHop : "one_f_switchmanager_staticRouteConfig_id_modal_form_nexthop",
-                       }
-               }
-       },
-       dashlet: function($dashlet) {
-               one.lib.dashlet.empty($dashlet);
-               
-
-               var url = one.f.switchmanager.rootUrl + "/staticRoutes";
-               one.f.switchmanager.staticRouteConfig.ajax.main(url, {}, function(content) {
+            }
+        }
+    },
+    dashlet: function($dashlet) {
+        one.lib.dashlet.empty($dashlet);
+        var url = one.f.switchmanager.rootUrl + "/staticRoutes";
+        one.f.switchmanager.staticRouteConfig.ajax.main(url, {}, function(content) {
 
             if (content.privilege === 'WRITE') {
                 // Add static route button
@@ -624,7 +865,8 @@ one.f.switchmanager.staticRouteConfig = {
                 $button.click(function() {
                     var requestData = {};
                     var routesToDelete = [];
-                    var checkedCheckBoxes = $("input:checked", $(this).closest(".dashlet").find("table"));
+                    //var checkedCheckBoxes = $("input:checked", $(this).closest(".dashlet").find("table"));
+                    var checkedCheckBoxes = $("#" + one.f.switchmanager.staticRouteConfig.id.dashlet.datagrid).find("tbody input:checked");
                     checkedCheckBoxes.each(function(index, value) {
                         routesToDelete.push(checkedCheckBoxes[index].id);
                     });
@@ -643,143 +885,181 @@ one.f.switchmanager.staticRouteConfig = {
                 });
                 $dashlet.append($button);
             }
-
-                       var body = one.f.switchmanager.staticRouteConfig.data.staticRouteConfig(content);
-                       // first column contains checkbox. no need for header
-                       content.columnNames.splice(0,0," ");
-                       var tableHeaders = ['', 'Name', 'Static Route', 'Next Hop Address'];
-                       var $table = one.f.switchmanager.createTable(tableHeaders, body);
-                       $dashlet.append($table);
-               });
-       },
-       // device ajax calls
-       ajax : {
-               main : function(url, requestData, callback) {
-                       $.getJSON(url, requestData, function(data) {
-                               callback(data);
-                       });
-               }
-       },
-       registry: {},
-       modal : {
-               initialize: function() {
-                       var h3 = "Add Static Route";
+            var $gridHTML = one.lib.dashlet.datagrid.init(one.f.switchmanager.staticRouteConfig.id.dashlet.datagrid, {
+                searchable: true,
+                filterable: false,
+                pagination: true,
+                flexibleRowsPerPage: true
+                }, "table-striped table-condensed");
+            $dashlet.append($gridHTML);
+            var dataSource = one.f.switchmanager.staticRouteConfig.data.staticRouteConfigGrid(content);
+            $("#" + one.f.switchmanager.staticRouteConfig.id.dashlet.datagrid).datagrid({dataSource: dataSource});
+        });
+    },
+    // device ajax calls
+    ajax : {
+        main : function(url, requestData, callback) {
+            $.getJSON(url, requestData, function(data) {
+                callback(data);
+            });
+        }
+    },
+    registry: {},
+    modal : {
+        initialize: function() {
+            var h3 = "Add Static Route";
             var footer = one.f.switchmanager.staticRouteConfig.modal.footer();
             var $modal = one.lib.modal.spawn(one.f.switchmanager.staticRouteConfig.id.modal.modal, h3, "", footer);
             // bind save button
             $('#' + one.f.switchmanager.staticRouteConfig.id.modal.save, $modal).click(function() {
-               one.f.switchmanager.staticRouteConfig.modal.save($modal);
+                one.f.switchmanager.staticRouteConfig.modal.save($modal);
             });
             var $body = one.f.switchmanager.staticRouteConfig.modal.body();
             one.lib.modal.inject.body($modal, $body);
             return $modal;
-               },
-               save: function($modal) {
-                       var result = {};
+        },
+        save: function($modal) {
+            var result = {};
             result['routeName'] = $('#' + one.f.switchmanager.staticRouteConfig.id.modal.form.routeName, $modal).val();
             result['staticRoute'] = $('#' + one.f.switchmanager.staticRouteConfig.id.modal.form.staticRoute, $modal).val();
             result['nextHop'] = $('#' + one.f.switchmanager.staticRouteConfig.id.modal.form.nextHop, $modal).val();
-                       one.f.switchmanager.staticRouteConfig.modal.ajax.staticRouteConfig(result, function(response) {
-                       if(response.status == true) {
-                               $modal.modal('hide');
-                               // refresh dashlet by passing dashlet div as param
-                               one.f.switchmanager.staticRouteConfig.dashlet($("#left-bottom .dashlet"));
-                       } else {
-                               // TODO: Show error message in a error message label instead.
-                               alert(response.message);
-                       }
-                   });
-               },
-               body: function() {
-                       var $form = $(document.createElement('form'));
-                       var $fieldset = $(document.createElement('fieldset'));
-                       // static route name
-                       var $label = one.lib.form.label("Name");
-                       var $input = one.lib.form.input("Name");
-                       $input.attr('id', one.f.switchmanager.staticRouteConfig.id.modal.form.routeName);
-                       $fieldset.append($label).append($input);
-                       // static route IP Mask 
-                       var $label = one.lib.form.label("Static Route");
-                       var $input = one.lib.form.input("Static Route");
-                       $input.attr('id', one.f.switchmanager.staticRouteConfig.id.modal.form.staticRoute);
-                       $fieldset.append($label).append($input);
-                       // static route IP Mask 
-                       var $label = one.lib.form.label("Next Hop");
-                       var $input = one.lib.form.input("Next Hop");
-                       $input.attr('id', one.f.switchmanager.staticRouteConfig.id.modal.form.nextHop);
-                       $fieldset.append($label).append($input);
-                       // return
-                       $form.append($fieldset);
-                       return $form;
-               },
-               ajax: {
-                       staticRouteConfig: function(requestData, callback) {
-                               $.getJSON(one.f.switchmanager.rootUrl + "/staticRoute/add", requestData, function(data) {
-                                       callback(data);
-                               });
-                       }
-               },
-               data : {
+            one.f.switchmanager.staticRouteConfig.modal.ajax.staticRouteConfig(result, function(response) {
+                    if(response.status == true) {
+                        $modal.modal('hide');
+                        // refresh dashlet by passing dashlet div as param
+                        one.f.switchmanager.staticRouteConfig.dashlet($("#left-bottom .dashlet"));
+                    } else {
+                        // TODO: Show error message in a error message label instead.
+                        alert(response.message);
+                    }
+                });
+        },
+        body: function() {
+            var $form = $(document.createElement('form'));
+            var $fieldset = $(document.createElement('fieldset'));
+            // static route name
+            var $label = one.lib.form.label("Name");
+            var $input = one.lib.form.input("Name");
+            $input.attr('id', one.f.switchmanager.staticRouteConfig.id.modal.form.routeName);
+            $fieldset.append($label).append($input);
+            // static route IP Mask 
+            var $label = one.lib.form.label("Static Route");
+            var $input = one.lib.form.input("Static Route");
+            $input.attr('id', one.f.switchmanager.staticRouteConfig.id.modal.form.staticRoute);
+            $fieldset.append($label).append($input);
+            // static route IP Mask 
+            var $label = one.lib.form.label("Next Hop");
+            var $input = one.lib.form.input("Next Hop");
+            $input.attr('id', one.f.switchmanager.staticRouteConfig.id.modal.form.nextHop);
+            $fieldset.append($label).append($input);
+            // return
+            $form.append($fieldset);
+            return $form;
+        },
+        ajax: {
+            staticRouteConfig: function(requestData, callback) {
+                $.getJSON(one.f.switchmanager.rootUrl + "/staticRoute/add", requestData, function(data) {
+                    callback(data);
+                });
+            }
+        },
+        data : {
             
         },
-               footer : function() {
+        footer : function() {
             var footer = [];
             var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.staticRouteConfig.id.modal.save, "btn-success", "");
             var $saveButton = one.lib.dashlet.button.button(saveButton);
             footer.push($saveButton);
             return footer;
         }
-       },
-       // data functions
-       data : {
-               staticRouteConfig : function(data) {
-                       var result = [];
-                       $.each(data.nodeData, function(key, value) {
-                               var tr = {};
-                               // fill up all the td's
-                               var entry = [];
-                               var checkbox = document.createElement("input");
-                               checkbox.setAttribute("type", "checkbox");
-                               checkbox.setAttribute("id", value["name"]);
-                               entry.push(checkbox);
-                               entry.push(value["name"]);
-                               entry.push(value["staticRoute"]);
-                               entry.push(value["nextHop"]);
-                               tr.entry = entry;
-                               result.push(tr);
-                       });
-                       return result;
-               }
-       }
+    },
+    // data functions
+    data : {
+        staticRouteConfigGrid: function(data) {
+            var source = new StaticDataSource({
+                    columns: [
+                        {
+                            property: 'selector',
+                            label: ' ',
+                            sortable: false
+                        },
+                        {
+                            property: 'name',
+                            label: 'Name',
+                            sortable: true
+                        },
+                        {
+                            property: 'staticRoute',
+                            label: 'Static Route',
+                            sortable: true
+                        },
+                        {
+                            property: 'nextHop',
+                            label: 'Next Hop Address',
+                            sortable: true
+                        }
+                    ],
+                    data: data.nodeData,
+                    formatter: function(items) {
+                        $.each(items, function(index, item) {
+                            item["selector"] = '<input type="checkbox" id=' + item["name"] + '></input>';
+                        });
+
+                    },
+                    delay: 0
+                });
+            return source;              
+        },
+        staticRouteConfig : function(data) {
+            var result = [];
+            $.each(data.nodeData, function(key, value) {
+                var tr = {};
+                // fill up all the td's
+                var entry = [];
+                var checkbox = document.createElement("input");
+                checkbox.setAttribute("type", "checkbox");
+                checkbox.setAttribute("id", value["name"]);
+                entry.push(checkbox);
+                entry.push(value["name"]);
+                entry.push(value["staticRoute"]);
+                entry.push(value["nextHop"]);
+                tr.entry = entry;
+                result.push(tr);
+            });
+            return result;
+        }
+    }
 }
 
 one.f.switchmanager.spanPortConfig = {
-       id: {
-               dashlet: {
-                       add: "one_f_switchmanager_spanPortConfig_id_dashlet_add",
-                       remove: "one_f_switchmanager_spanPortConfig_id_dashlet_remove"
-               }, 
-               modal: {
-                       modal: "one_f_switchmanager_spanPortConfig_id_modal_modal",
-                       save: "one_f_switchmanager_spanPortConfig_id_modal_save",
-                       form: {
-                               name : "one_f_switchmanager_spanPortConfig_id_modal_form_name",
-                               nodes : "one_f_switchmanager_spanPortConfig_id_modal_form_nodes",
+    id: {
+        dashlet: {
+            add: "one_f_switchmanager_spanPortConfig_id_dashlet_add",
+            remove: "one_f_switchmanager_spanPortConfig_id_dashlet_remove",
+            datagrid: "one_f_switchmanager_spanPortConfig_id_dashlet_datagrid"
+        }, 
+        modal: {
+            modal: "one_f_switchmanager_spanPortConfig_id_modal_modal",
+            save: "one_f_switchmanager_spanPortConfig_id_modal_save",
+            form: {
+                name : "one_f_switchmanager_spanPortConfig_id_modal_form_name",
+                nodes : "one_f_switchmanager_spanPortConfig_id_modal_form_nodes",
                 port : "one_f_switchmanager_spanPortConfig_id_modal_form_port",
-                       }
-               }
-       },
-       dashlet: function($dashlet) {
-               one.lib.dashlet.empty($dashlet);
+            }
+        }
+    },
+    dashlet: function($dashlet) {
+        one.lib.dashlet.empty($dashlet);
         
         //populate table in dashlet
-               var url = one.f.switchmanager.rootUrl + "/spanPorts";
-               one.f.switchmanager.spanPortConfig.ajax.main(url, {}, function(content) {
+        var url = one.f.switchmanager.rootUrl + "/spanPorts";
+        one.f.switchmanager.spanPortConfig.ajax.main(url, {}, function(content) {
 
             if (content.privilege === 'WRITE') {
 
                 // Add span port button
-                var button = one.lib.dashlet.button.single("Add Span Port", one.f.switchmanager.spanPortConfig.id.dashlet.add, "btn-primary", "btn-mini");
+                var button = one.lib.dashlet.button.single("Add SPAN Port", one.f.switchmanager.spanPortConfig.id.dashlet.add, "btn-primary", "btn-mini");
                 var $button = one.lib.dashlet.button.button(button);
 
                 $button.click(function() {
@@ -794,11 +1074,11 @@ one.f.switchmanager.spanPortConfig = {
                 var $button = one.lib.dashlet.button.button(button);
                 $button.click(function() {
 
-                    var checkedCheckBoxes = $("input:checked", $(this).closest(".dashlet").find("table"));
+                    var checkedCheckBoxes = $("#" + one.f.switchmanager.spanPortConfig.id.dashlet.datagrid).find("tbody input:checked");
                     if (checkedCheckBoxes.length > 0) {
                         var spanPortsToDelete = "";
                         checkedCheckBoxes.each(function(index, value) {
-                            spanPortsToDelete += checkedCheckBoxes[index].spanPort + "###";
+                            spanPortsToDelete += decodeURIComponent(checkedCheckBoxes[index].getAttribute("spanPort")) + "###";
                         });
 
                         var requestData = {};
@@ -816,31 +1096,37 @@ one.f.switchmanager.spanPortConfig = {
                 });
                 $dashlet.append($button);
             }
+            var $gridHTML = one.lib.dashlet.datagrid.init(one.f.switchmanager.spanPortConfig.id.dashlet.datagrid, {
+                searchable: true,
+                filterable: false,
+                pagination: true,
+                flexibleRowsPerPage: true
+                }, "table-striped table-condensed");
+            $dashlet.append($gridHTML);
+            var dataSource = one.f.switchmanager.spanPortConfig.data.spanPortConfigGrid(content);
+            $("#" + one.f.switchmanager.spanPortConfig.id.dashlet.datagrid).datagrid({dataSource: dataSource});
+
+
 
-                       var body = one.f.switchmanager.spanPortConfig.data.devices(content);
-                       // first column contains the checkbox. no header required.
-                       content.columnNames.splice(0,0," ");
-                       var $table = one.f.switchmanager.createTable(content.columnNames, body);
-                       $dashlet.append($table);
-               });
-       },
-       // device ajax calls
-       ajax : {
-               main : function(url, requestData, callback) {
-                       $.getJSON(url, requestData, function(data) {
-                               callback(data);
-                       });
-               }
-       },
-       registry: {},
-       modal : {
-               initialize: function() {
-                       var h3 = "Add SPAN Port";
+        });
+    },
+    // device ajax calls
+    ajax : {
+        main : function(url, requestData, callback) {
+            $.getJSON(url, requestData, function(data) {
+                callback(data);
+            });
+        }
+    },
+    registry: {},
+    modal : {
+        initialize: function() {
+            var h3 = "Add SPAN Port";
             var footer = one.f.switchmanager.spanPortConfig.modal.footer();
             var $modal = one.lib.modal.spawn(one.f.switchmanager.spanPortConfig.id.modal.modal, h3, "", footer);
             // bind save button
             $('#' + one.f.switchmanager.spanPortConfig.id.modal.save, $modal).click(function() {
-               one.f.switchmanager.spanPortConfig.modal.save($modal);
+                one.f.switchmanager.spanPortConfig.modal.save($modal);
             });
 
             one.f.switchmanager.spanPortConfig.modal.ajax.nodes(function(nodes, nodeports) {
@@ -848,106 +1134,130 @@ one.f.switchmanager.spanPortConfig = {
                 one.lib.modal.inject.body($modal, $body);
             });
             return $modal;
-               },
-               save: function($modal) {
-                       var result = {};
+        },
+        save: function($modal) {
+            var result = {};
             result['nodeId'] = $('#' + one.f.switchmanager.spanPortConfig.id.modal.form.nodes, $modal).val();
             result['spanPort'] = $('#' + one.f.switchmanager.spanPortConfig.id.modal.form.port, $modal).val();
-                       one.f.switchmanager.spanPortConfig.modal.ajax.saveSpanPortConfig(result, 
-                               function(response) {
-                                       if(response.status == true) {
-                                               $modal.modal('hide');
-                                               one.f.switchmanager.spanPortConfig.dashlet($("#right-bottom .dashlet"));
-                                       } else {
-                                               alert(response.message);
-                                       }
-                       
-                   });
-               },
-               body: function(nodes, nodeports) {
-                       var $form = $(document.createElement('form'));
-                       var $fieldset = $(document.createElement('fieldset'));
-                       // node
-                       var $label = one.lib.form.label("Node");
-                       var $select = one.lib.form.select.create(nodes);
-                       one.lib.form.select.prepend($select, { '' : 'Please Select a Node' });
-                       $select.attr('id', one.f.switchmanager.spanPortConfig.id.modal.form.nodes);
-                       
-                       // bind onchange
-                       $select.change(function() {
-                           // retrieve port value
-                           var node = $(this).find('option:selected').attr('value');
-                           one.f.switchmanager.spanPortConfig.registry['currentNode'] = node;
-                           var $ports = $('#' + one.f.switchmanager.spanPortConfig.id.modal.form.port);
-                           var ports = nodeports[node];
-                           one.lib.form.select.inject($ports, ports);
-                       });
+            one.f.switchmanager.spanPortConfig.modal.ajax.saveSpanPortConfig(result, 
+                function(response) {
+                    if(response.status == true) {
+                        $modal.modal('hide');
+                        one.f.switchmanager.spanPortConfig.dashlet($("#right-bottom .dashlet"));
+                    } else {
+                        alert(response.message);
+                    }
+                    
+                });
+        },
+        body: function(nodes, nodeports) {
+            var $form = $(document.createElement('form'));
+            var $fieldset = $(document.createElement('fieldset'));
+            // node
+            var $label = one.lib.form.label("Node");
+            var $select = one.lib.form.select.create(nodes);
+            one.lib.form.select.prepend($select, { '' : 'Please Select a Node' });
+            $select.attr('id', one.f.switchmanager.spanPortConfig.id.modal.form.nodes);
+            
+            // bind onchange
+            $select.change(function() {
+                // retrieve port value
+                var nodeId = $(this).find('option:selected').attr('value');
+                one.f.switchmanager.spanPortConfig.registry['currentNode'] = nodeId;
+                var $ports = $('#' + one.f.switchmanager.spanPortConfig.id.modal.form.port);
+                var ports = one.f.switchmanager.spanPortConfig.registry['nodePorts'][nodeId]
+                one.lib.form.select.inject($ports, ports); 
+            });
 
             $fieldset.append($label).append($select);
-                       // input port
-                       var $label = one.lib.form.label("Input Port");
-                       var $select = one.lib.form.select.create();
-                       $select.attr('id', one.f.switchmanager.spanPortConfig.id.modal.form.port);
-                       $fieldset.append($label).append($select);
-                       
-                       // return
-                       $form.append($fieldset);
-                       return $form;
-               },
-               ajax: {
-                       nodes: function(callback) {
-                               $.getJSON(one.f.switchmanager.rootUrl + "/nodeports", function(data) {
-                    var nodes = one.f.switchmanager.spanPortConfig.modal.data.nodes(data);
-                    var nodeports = data;
-                    one.f.switchmanager.spanPortConfig.registry['nodeports'] = nodeports;
-                    callback(nodes, nodeports);
+            // input port
+            var $label = one.lib.form.label("Input Port");
+            var $select = one.lib.form.select.create();
+            $select.attr('id', one.f.switchmanager.spanPortConfig.id.modal.form.port);
+            $fieldset.append($label).append($select);
+            
+            // return
+            $form.append($fieldset);
+            return $form;
+        },
+        ajax: {
+            nodes: function(callback) {
+                $.getJSON(one.f.switchmanager.rootUrl + "/nodeports", function(data) {
+                    var nodes = {};
+                    var nodePorts = {};
+                    $(data).each(function(index, node) {
+                        nodes[node.nodeId] = node.nodeName;
+                        nodePorts[node.nodeId] = node.nodePorts;
+                    });
+                    one.f.switchmanager.spanPortConfig.registry['nodePorts'] = nodePorts;
+                    callback(nodes, nodePorts);
                 });
-                       },
-                       saveSpanPortConfig: function(requestData, callback) {
-                               var resource = {};
-                               resource["jsonData"] = JSON.stringify(requestData);
-                               $.getJSON(one.f.switchmanager.rootUrl + "/spanPorts/add", resource, function(data) {
-                                       callback(data);
-                               });
-                       }
-               },
-               data : {
-            nodes : function(data) {
-                result = {};
-                $.each(data, function(key, value) {
-                    result[key] = key;
+            },
+            saveSpanPortConfig: function(requestData, callback) {
+                var resource = {};
+                resource["jsonData"] = JSON.stringify(requestData);
+                $.getJSON(one.f.switchmanager.rootUrl + "/spanPorts/add", resource, function(data) {
+                    callback(data);
                 });
-                return result;
             }
         },
-               footer : function() {
+        footer : function() {
             var footer = [];
             var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.spanPortConfig.id.modal.save, "btn-success", "");
             var $saveButton = one.lib.dashlet.button.button(saveButton);
             footer.push($saveButton);
             return footer;
         }
-       },
-       // data functions
-       data : {
-               devices : function(data) {
-                       var result = [];
-                       $.each(data.nodeData, function(key, value) {
-                               var tr = {};
-                               // fill up all the td's
-                               var entry = [];
-                               var checkbox = document.createElement("input");
-                               checkbox.setAttribute("type", "checkbox");
-                               checkbox.spanPort = value.json;
-                               entry.push(checkbox);
-                               entry.push(value["nodeName"]);
-                               entry.push(value["spanPort"]);
-                               tr.entry = entry;
-                               result.push(tr);
-                       });
-                       return result;
-               }
-       }
+    },
+    // data functions
+    data : {
+        spanPortConfigGrid: function(data) {
+            var source = new StaticDataSource({
+                    columns: [
+                        {
+                            property: 'selector',
+                            label: ' ',
+                            sortable: false
+                        },
+                        {
+                            property: 'nodeName',
+                            label: 'Node',
+                            sortable: true
+                        },
+                        {
+                            property: 'spanPort',
+                            label: 'SPAN Port',
+                            sortable: true
+                        },
+                    ],
+                    data: data.nodeData,
+                    formatter: function(items) {
+                        $.each(items, function(index, item) {
+                            item["selector"] = '<input type="checkbox" spanPort=' + encodeURIComponent(item["json"]) + '></input>';
+                        });
+                    },
+                    delay: 0
+                });
+            return source;              
+        },
+        devices : function(data) {
+            var result = [];
+            $.each(data.nodeData, function(key, value) {
+                var tr = {};
+                // fill up all the td's
+                var entry = [];
+                var checkbox = document.createElement("input");
+                checkbox.setAttribute("type", "checkbox");
+                checkbox.spanPort = value.json;
+                entry.push(checkbox);
+                entry.push(value["nodeName"]);
+                entry.push(value["spanPort"]);
+                tr.entry = entry;
+                result.push(tr);
+            });
+            return result;
+        }
+    }
 }
 
 /** INIT **/
@@ -968,20 +1278,27 @@ $(one.f.menu.right.bottom).each(function(index, value) {
 });
 
 one.f.addPopOut = function() {
-       $img1 = $(document.createElement("img"));
-       $img1.attr("src", "/img/Expand16T.png");
-       $img1.attr("style", "float: right;");
-       $img1.hover(function() {
-               $img1.css("cursor", "pointer");
-       });
-       $img1.click(function() {
-               var $modal = one.f.switchmanager.nodesLearnt.modal.initialize.popout();
-       $modal.css('width', 'auto');
-               $modal.css('margin-left', '-40%');
+    $img1 = $(document.createElement("img"));
+    $img1.attr("src", "/img/Expand16T.png");
+    $img1.attr("style", "float: right;");
+    $img1.hover(function() {
+        $img1.css("cursor", "pointer");
+    });
+    $img1.click(function() {
+        var $modal = one.f.switchmanager.nodesLearnt.modal.initialize.popout();
+        $modal.css({
+            'margin-left': '-45%',
+            'margin-top': '-3%',
+            'width':$(document).width() * 0.8,
+            'height':$(document).height() * 0.9
+        });
+        $(".modal-body", $modal).css({
+            "max-height": $(document).height() * 0.75,
+        });
         $modal.modal();
-       });
-       $dash1 = $($("#left-top .nav")[0]);
-       $dash1.append($img1);
+    });
+    $dash1 = $($("#left-top .nav")[0]);
+    $dash1.append($img1);
 };
 one.f.addPopOut();
 
@@ -1001,16 +1318,16 @@ $('.dash .nav a', '#main').click(function() {
     var menu = one.f.dashlet;
     switch (id) {
         case menu.nodesLearnt.id:
-               one.f.switchmanager.nodesLearnt.dashlet($dashlet);
+            one.f.switchmanager.nodesLearnt.dashlet($dashlet);
             break;
         case menu.staticRouteConfig.id:
-               one.f.switchmanager.staticRouteConfig.dashlet($dashlet);
+            one.f.switchmanager.staticRouteConfig.dashlet($dashlet);
             break;
         case menu.subnetGatewayConfig.id:
-               one.f.switchmanager.subnetGatewayConfig.dashlet($dashlet);
+            one.f.switchmanager.subnetGatewayConfig.dashlet($dashlet);
             break;
         case menu.spanPortConfig.id:
-               one.f.switchmanager.spanPortConfig.dashlet($dashlet);
+            one.f.switchmanager.spanPortConfig.dashlet($dashlet);
             break;
     };
 });
index 9444360eecb7d7ae4a6e084a4fde8512c7b5ed71..a96d3efcec698d80a243969fd2c1c3df9ee1e2cf 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.controller.flows.web;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -77,13 +78,16 @@ public class Flows implements IDaylightWeb {
 
     @RequestMapping(value = "/main")
     @ResponseBody
-    public Map<String, Object> getFlows(HttpServletRequest request, @RequestParam(required = false) String container) {
-        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+    public Map<String, Object> getFlows(HttpServletRequest request,
+            @RequestParam(required = false) String container) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT
+                .toString() : container;
 
         // Derive the privilege this user has on the current container
         String userName = request.getUserPrincipal().getName();
-        Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
-        if (privilege  == Privilege.NONE) {
+        Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName,
+                containerName, this);
+        if (privilege == Privilege.NONE) {
             return null;
         }
 
@@ -114,7 +118,7 @@ public class Flows implements IDaylightWeb {
             flowSet.add(entry);
         }
 
-        Map <String, Object> output = new HashMap<String, Object>(2);
+        Map<String, Object> output = new HashMap<String, Object>(2);
         output.put("flows", flowSet);
         output.put("privilege", privilege);
         return output;
@@ -122,12 +126,15 @@ public class Flows implements IDaylightWeb {
 
     @RequestMapping(value = "/node-ports")
     @ResponseBody
-    public Map<String, Object> getNodePorts(HttpServletRequest request, @RequestParam(required = false) String container) {
-        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+    public Map<String, Object> getNodePorts(HttpServletRequest request,
+            @RequestParam(required = false) String container) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT
+                .toString() : container;
 
         // Derive the privilege this user has on the current container
         String userName = request.getUserPrincipal().getName();
-        if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) == Privilege.NONE) {
+        if (DaylightWebUtil
+                .getContainerPrivilege(userName, containerName, this) == Privilege.NONE) {
             return null;
         }
 
@@ -171,12 +178,15 @@ public class Flows implements IDaylightWeb {
 
     @RequestMapping(value = "/node-flows")
     @ResponseBody
-    public Map<String, Object> getNodeFlows(HttpServletRequest request, @RequestParam(required = false) String container) {
-        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+    public Map<String, Object> getNodeFlows(HttpServletRequest request,
+            @RequestParam(required = false) String container) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT
+                .toString() : container;
 
         // Derive the privilege this user has on the current container
         String userName = request.getUserPrincipal().getName();
-        if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) == Privilege.NONE) {
+        if (DaylightWebUtil
+                .getContainerPrivilege(userName, containerName, this) == Privilege.NONE) {
             return null;
         }
 
@@ -199,10 +209,12 @@ public class Flows implements IDaylightWeb {
             List<FlowConfig> flows = frm.getStaticFlows(node);
 
             String nodeDesc = node.toString();
-            SwitchConfig config = switchManager.getSwitchConfig(node
-                    .toString());
-            if ((config != null) && (config.getProperty(Description.propertyName) != null)) {
-                nodeDesc = ((Description) config.getProperty(Description.propertyName)).getValue();
+            SwitchConfig config = switchManager
+                    .getSwitchConfig(node.toString());
+            if ((config != null)
+                    && (config.getProperty(Description.propertyName) != null)) {
+                nodeDesc = ((Description) config
+                        .getProperty(Description.propertyName)).getValue();
             }
 
             nodes.put(nodeDesc, flows.size());
@@ -216,12 +228,15 @@ public class Flows implements IDaylightWeb {
     public String actionFlow(@RequestParam(required = true) String action,
             @RequestParam(required = false) String body,
             @RequestParam(required = true) String nodeId,
-            HttpServletRequest request, @RequestParam(required = false) String container) {
-        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+            HttpServletRequest request,
+            @RequestParam(required = false) String container) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT
+                .toString() : container;
 
         // Authorization check
         String userName = request.getUserPrincipal().getName();
-        if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
+        if (DaylightWebUtil
+                .getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
             return "Operation not authorized";
         }
 
@@ -238,7 +253,8 @@ public class Flows implements IDaylightWeb {
         Status result = new Status(StatusCode.BADREQUEST, "Invalid request");
         if (action.equals("add")) {
             result = frm.addStaticFlow(flow);
-            DaylightWebUtil.auditlog("Flow", userName, "added", flow.getName(), containerName);
+            DaylightWebUtil.auditlog("Flow", userName, "added", flow.getName(),
+                    containerName);
         }
 
         return (result.isSuccess()) ? StatusCode.SUCCESS.toString() : result
@@ -250,12 +266,15 @@ public class Flows implements IDaylightWeb {
     public String removeFlow(@PathVariable("nodeId") String nodeId,
             @PathVariable("name") String name,
             @RequestParam(required = true) String action,
-            HttpServletRequest request, @RequestParam(required = false) String container) {
-        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+            HttpServletRequest request,
+            @RequestParam(required = false) String container) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT
+                .toString() : container;
 
         // Authorization check
         String userName = request.getUserPrincipal().getName();
-        if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
+        if (DaylightWebUtil
+                .getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
             return "Operation not authorized";
         }
 
@@ -272,13 +291,15 @@ public class Flows implements IDaylightWeb {
         }
         if (action.equals("remove")) {
             result = frm.removeStaticFlow(name, node);
-            if(result.isSuccess()) {
-                DaylightWebUtil.auditlog("Flow", userName, "removed", name, containerName);
+            if (result.isSuccess()) {
+                DaylightWebUtil.auditlog("Flow", userName, "removed", name,
+                        containerName);
             }
         } else if (action.equals("toggle")) {
             result = frm.toggleStaticFlowStatus(name, node);
-            if(result.isSuccess()) {
-                DaylightWebUtil.auditlog("Flow", userName, "toggled", name, containerName);
+            if (result.isSuccess()) {
+                DaylightWebUtil.auditlog("Flow", userName, "toggled", name,
+                        containerName);
             }
         } else {
             result = new Status(StatusCode.BADREQUEST, "Unknown action");
@@ -288,10 +309,58 @@ public class Flows implements IDaylightWeb {
                 .getDescription();
     }
 
+    @SuppressWarnings("unchecked")
+    @RequestMapping(value = "/flow/deleteFlows", method = RequestMethod.POST)
+    @ResponseBody
+    public String removeSelectedFlows(
+            @RequestParam(required = false) String body,
+            HttpServletRequest request,
+            @RequestParam(required = false) String container) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT
+                .toString() : container;
+
+        // Authorization check
+        String userName = request.getUserPrincipal().getName();
+        if (DaylightWebUtil
+                .getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
+            return "Operation not authorized";
+        }
+
+        IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper
+                .getInstance(IForwardingRulesManager.class, containerName, this);
+        if (frm == null) {
+            return "Forwarding Rules Manager is not available";
+        }
+
+        Gson gson = new Gson();
+        List<Map<String, String>> flowList = new ArrayList<Map<String, String>>();
+        flowList = gson.fromJson(body, flowList.getClass());
+        Status result = new Status(StatusCode.BADREQUEST, "Invalid request");
+        String status = "";
+        for (Map<String, String> flowEntry : flowList) {
+            Node node = Node.fromString(flowEntry.get("node"));
+            result = frm.removeStaticFlow(flowEntry.get("name"), node);
+            if (result.isSuccess()) {
+                DaylightWebUtil.auditlog("Flow", userName, "removed",
+                        flowEntry.get("name"), containerName);
+            } else {
+                status = flowEntry.get("name") + ", " + status;
+            }
+        }
+        if (!status.equals("")) {
+            return "Could not remove "
+                    + status.substring(0, status.length() - 2) + " Flow(s)";
+        } else {
+            return "Success";
+        }
+    }
+
     private String getNodeDesc(Node node, ISwitchManager switchManager) {
-        Description desc = (Description) switchManager.getNodeProp(node, Description.propertyName);
+        Description desc = (Description) switchManager.getNodeProp(node,
+                Description.propertyName);
         String description = (desc == null) ? "" : desc.getValue();
-        return (description.isEmpty() || description.equalsIgnoreCase("none")) ? node.toString() : description;
+        return (description.isEmpty() || description.equalsIgnoreCase("none")) ? node
+                .toString() : description;
     }
 
 }
index 7ff54ed4dca511a6e4ba1238b1b962e004efd261..3dcf9e3006914daa3824476bf25ec1667024d455 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -47,62 +46,72 @@ one.f.address = {
     root : "/controller/web/flows",
     flows : {
         main : "/main",
-               flows : "/node-flows",
+        flows : "/node-flows",
         nodes : "/node-ports",
-        flow : "/flow"
+        flow : "/flow",
+        deleteFlows:"/flow/deleteFlows"
     }
 }
 
 /** NODES **/
 one.f.nodes = {
-    id : {},
+    id : {
+        dashlet: {
+            datagrid: "one_f_nodes_id_dashlet_datagrid"
+        }
+    },
     registry : {},
     dashlet : function($dashlet) {
         var $h4 = one.lib.dashlet.header("Nodes");
         $dashlet.append($h4);
 
-        // load body
-        one.f.nodes.ajax.dashlet(function($table) {
-                       // total nodes count
-                       var nodeCount = $table.find('tbody').find('tr').size();
-                       // prompt output
-                       var nodeText = "node";
-                       var verb = "is";
-                       if (nodeCount != 1) {
-                               nodeText += "s";
-                               verb = "are";
-                       }
-                       var out = "There "+verb+" "+nodeCount+" "+nodeText;
-                       $p = $(document.createElement('p'));
-                       $p.append(out);
-                       $dashlet.append($p);
-            // add to dashlet
-            $dashlet.append($table);
+        one.f.nodes.ajax.dashlet(function(data) {
+            var $gridHTML = one.lib.dashlet.datagrid.init(one.f.nodes.id.dashlet.datagrid, {
+                searchable: true,
+                filterable: false,
+                pagination: true,
+                flexibleRowsPerPage: true
+                }, "table-striped table-condensed");
+            $dashlet.append($gridHTML);
+            var dataSource = one.f.nodes.data.nodesDataGrid(data);
+            $("#" + one.f.nodes.id.dashlet.datagrid).datagrid({dataSource: dataSource});
         });
     },
     ajax : {
         dashlet : function(callback) {
             $.getJSON(one.f.address.root+one.f.address.flows.flows, function(data) {
-                var body = one.f.nodes.data.dashlet(data);
-                var $body = one.f.nodes.body.dashlet(body, callback);
-                callback($body);
+                callback(data);
             });
         }
     },
     data : {
-        dashlet : function(data) {
-            var body = [];
-            $.each(data, function(key, value) {
-                var tr = {};
-                var entry = [];
-                entry.push(key);
-                // parse ports
-                entry.push(value);
-                // add entry to tr
-                tr['entry'] = entry;
-                body.push(tr);
+        nodesDataGrid: function(data) {
+            var gridData = [];
+            $.each(data, function(nodeName, flow) {
+                var nodeFlowObject = {};
+                nodeFlowObject["nodeName"] = nodeName;
+                nodeFlowObject["flows"] = flow;
+                nodeFlowObject["rowData"] = nodeName + flow + "-foobar";
+                gridData.push(nodeFlowObject);
             });
-            return body;
+
+            var source = new StaticDataSource({
+                    columns: [
+                        {
+                            property: 'nodeName',
+                            label: 'Node',
+                            sortable: true
+                        },
+                        {
+                            property: 'flows',
+                            label: 'Flows',
+                            sortable: true
+                        }
+                    ],
+                    data: gridData,
+                    delay: 0
+                });
+            return source;
         }
     },
     body : {
@@ -132,109 +141,109 @@ one.f.detail = {
 
         // details
         if (details == undefined) {
-               var $none = $(document.createElement('div'));
-               $none.addClass('none');
+            var $none = $(document.createElement('div'));
+            $none.addClass('none');
             var $p = $(document.createElement('p'));
             $p.text('Please select a flow');
             $p.addClass('text-center').addClass('text-info');
 
             $dashlet.append($none)
-               .append($p);
+                .append($p);
         }
     },
     data : {
-               dashlet : function(data) {
-                       var body = [];
-                       var tr = {};
-                       var entry = [];
-
-                       entry.push(data['name']);
-                       entry.push(data['node']);
-                       entry.push(data['flow']['priority']);
-                       entry.push(data['flow']['hardTimeout']);
-                       entry.push(data['flow']['idleTimeout']);
-
-                       tr.entry = entry;
-                       body.push(tr);
-                       return body;
-               },
+        dashlet : function(data) {
+            var body = [];
+            var tr = {};
+            var entry = [];
+
+            entry.push(data['name']);
+            entry.push(data['node']);
+            entry.push(data['flow']['priority']);
+            entry.push(data['flow']['hardTimeout']);
+            entry.push(data['flow']['idleTimeout']);
+
+            tr.entry = entry;
+            body.push(tr);
+            return body;
+        },
         description : function(data) {
-                       var body = [];
-                       var tr = {};
-                       var entry = [];
+            var body = [];
+            var tr = {};
+            var entry = [];
                         entry.push(data['flow']['ingressPort']);
-                       entry.push(data['flow']['etherType']);
-                       entry.push(data['flow']['vlanId']);
-                       entry.push(data['flow']['vlanPriority']);
-                       entry.push(data['flow']['srcMac']);
-                       entry.push(data['flow']['dstMac']);
-                       entry.push(data['flow']['srcIp']);
-                       entry.push(data['flow']['dstIp']);
-                       entry.push(data['flow']['tosBits']);
-                       entry.push(data['flow']['srcPort']);
-                       entry.push(data['flow']['dstPort']);
-                       entry.push(data['flow']['protocol']);
-                       entry.push(data['flow']['cookie']);
-
-                       tr.entry = entry;
-                       body.push(tr);
-                       return body;
+            entry.push(data['flow']['etherType']);
+            entry.push(data['flow']['vlanId']);
+            entry.push(data['flow']['vlanPriority']);
+            entry.push(data['flow']['srcMac']);
+            entry.push(data['flow']['dstMac']);
+            entry.push(data['flow']['srcIp']);
+            entry.push(data['flow']['dstIp']);
+            entry.push(data['flow']['tosBits']);
+            entry.push(data['flow']['srcPort']);
+            entry.push(data['flow']['dstPort']);
+            entry.push(data['flow']['protocol']);
+            entry.push(data['flow']['cookie']);
+
+            tr.entry = entry;
+            body.push(tr);
+            return body;
         },
-               actions : function(data) {
-                       var body = [];
-                       var tr = {};
-                       var entry = [];
-
-                       var actions = '';
-                       $(data['flow']['actions']).each(function(index, value) {
-                               actions += value + ', ';
-                       });
-                       actions = actions.slice(0,-2);
-                       entry.push(actions);
-
-                       tr.entry = entry;
-                       body.push(tr);
-                       return body;
-               }
+        actions : function(data) {
+            var body = [];
+            var tr = {};
+            var entry = [];
+
+            var actions = '';
+            $(data['flow']['actions']).each(function(index, value) {
+                actions += value + ', ';
+            });
+            actions = actions.slice(0,-2);
+            entry.push(actions);
+
+            tr.entry = entry;
+            body.push(tr);
+            return body;
+        }
     },
     body : {
         dashlet : function(body) {
-                       // create table
-                       var header = ['Flow Name', 'Node', 'Priority', 'Hard Timeout', 'Idle Timeout'];
-                       var $thead = one.lib.dashlet.table.header(header);
-                       var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
-                       var $table = one.lib.dashlet.table.table(attributes);
-                       $table.append($thead);
+            // create table
+            var header = ['Flow Name', 'Node', 'Priority', 'Hard Timeout', 'Idle Timeout'];
+            var $thead = one.lib.dashlet.table.header(header);
+            var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
+            var $table = one.lib.dashlet.table.table(attributes);
+            $table.append($thead);
 
-                       var $tbody = one.lib.dashlet.table.body(body);
-                       $table.append($tbody);
+            var $tbody = one.lib.dashlet.table.body(body);
+            $table.append($tbody);
 
             return $table;
         },
-               description : function(body) {
-                       var header = ['Input Port', 'Ethernet Type', 'VLAN ID', 'VLAN Priority', 'Source MAC', 'Dest MAC', 'Source IP', 'Dest IP', 'TOS', 'Source Port', 'Dest Port', 'Protocol', 'Cookie'];
-                       var $thead = one.lib.dashlet.table.header(header);
-                       var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
-                       var $table = one.lib.dashlet.table.table(attributes);
-                       $table.append($thead);
+        description : function(body) {
+            var header = ['Input Port', 'Ethernet Type', 'VLAN ID', 'VLAN Priority', 'Source MAC', 'Dest MAC', 'Source IP', 'Dest IP', 'TOS', 'Source Port', 'Dest Port', 'Protocol', 'Cookie'];
+            var $thead = one.lib.dashlet.table.header(header);
+            var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
+            var $table = one.lib.dashlet.table.table(attributes);
+            $table.append($thead);
 
-                       var $tbody = one.lib.dashlet.table.body(body);
-                       $table.append($tbody);
+            var $tbody = one.lib.dashlet.table.body(body);
+            $table.append($tbody);
 
             return $table;
-               },
-               actions : function(body) {
-                       var header = ['Actions'];
-                       var $thead = one.lib.dashlet.table.header(header);
-                       var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
-                       var $table = one.lib.dashlet.table.table(attributes);
-                       $table.append($thead);
+        },
+        actions : function(body) {
+            var header = ['Actions'];
+            var $thead = one.lib.dashlet.table.header(header);
+            var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
+            var $table = one.lib.dashlet.table.table(attributes);
+            $table.append($thead);
 
-                       var $tbody = one.lib.dashlet.table.body(body);
-                       $table.append($tbody);
+            var $tbody = one.lib.dashlet.table.body(body);
+            $table.append($tbody);
 
             return $table;
-               }
+        }
     }
 }
 
@@ -243,16 +252,19 @@ one.f.flows = {
     id : {
         dashlet : {
             add : "one_f_flows_id_dashlet_add",
+            removeMultiple : "one_f_flows_id_dashlet_removeMultiple",
             remove : "one_f_flows_id_dashlet_remove",
-            toggle : "one_f_flows_id_dashlet_toggle"
+            toggle : "one_f_flows_id_dashlet_toggle",
+            datagrid : "one_f_flows_id_dashlet_datagrid",
+            selectAllFlows : "one_f_flows_id_dashlet_selectAllFlows"
         },
         modal : {
-                       install : "one_f_flows_id_modal_install",
+            install : "one_f_flows_id_modal_install",
             add : "one_f_flows_id_modal_add",
             close : "one_f_flows_id_modal_close",
             modal : "one_f_flows_id_modal_modal",
             dialog : {
-               modal : "one_f_flows_id_modal_dialog_modal",
+                modal : "one_f_flows_id_modal_dialog_modal",
                 remove : "one_f_flows_id_modal_dialog_remove",
                 close : "one_f_flows_id_modal_dialog_close"
             },
@@ -272,11 +284,11 @@ one.f.flows = {
                 modifyTosBits : "one_f_flows_modal_action_modifyTosBits",
                 modifyTransportSourcePort : "one_f_flows_modal_action_modifyTransportSourcePort",
                 modifyTransportDestinationPort : "one_f_flows_modal_action_modifyTransportDestinationPort",
-                               modal : {
-                                       modal : "one_f_flows_modal_action_modal_modal",
-                                       remove : "one_f_flows_modal_action_modal_remove",
-                                       cancel : "one_f_flows_modal_action_modal_cancel"
-                               }
+                modal : {
+                    modal : "one_f_flows_modal_action_modal_modal",
+                    remove : "one_f_flows_modal_action_modal_remove",
+                    cancel : "one_f_flows_modal_action_modal_cancel"
+                }
             },
             form : {
                 name : "one_f_flows_id_modal_form_name",
@@ -284,8 +296,8 @@ one.f.flows = {
                 port : "one_f_flows_id_modal_form_port",
                 priority : "one_f_flows_id_modal_form_priority",
                 hardTimeout : "one_f_flows_id_modal_form_hardTimeout",
-                               idleTimeout : "one_f_flows_id_modal_form_idleTimeout",
-                               cookie : "one_f_flows_id_modal_form_cookie",
+                idleTimeout : "one_f_flows_id_modal_form_idleTimeout",
+                cookie : "one_f_flows_id_modal_form_cookie",
                 etherType : "one_f_flows_id_modal_form_etherType",
                 vlanId : "one_f_flows_id_modal_form_vlanId",
                 vlanPriority : "one_f_flows_id_modal_form_vlanPriority",
@@ -304,7 +316,7 @@ one.f.flows = {
     dashlet : function($dashlet, callback) {
 
         // load body
-        one.f.flows.ajax.dashlet(function($table) {
+        one.f.flows.ajax.dashlet(function(data) {
 
             var $h4 = one.lib.dashlet.header("Flow Entries");
 
@@ -318,31 +330,91 @@ one.f.flows = {
                     $modal.modal();
                 });
                 $dashlet.append($button);
+                var button = one.lib.dashlet.button.single("Remove Flow Entry", one.f.flows.id.dashlet.removeMultiple, "btn-primary", "btn-mini");
+                var $button = one.lib.dashlet.button.button(button);
+
+                $button.click(function() {
+                    var checkedCheckBoxes = $('.flowEntry[type=checkbox]:checked');
+                    
+                    var requestData = [];
+                    
+                    var resource = {};
+                    checkedCheckBoxes.each(function(index, value) {
+                        var flowEntry = {};
+                        flowEntry['name'] = checkedCheckBoxes[index].name;
+                        flowEntry['node'] = checkedCheckBoxes[index].getAttribute("node");
+                        requestData.push(flowEntry);  
+                    });
+                    resource['body'] = JSON.stringify(requestData);
+
+                    $.post(one.f.address.root+one.f.address.flows.deleteFlows, resource, function(response) {
+                        if(response == "Success") {
+                            one.lib.alert("Flow(s) successfully removed");                            
+                        } else {
+                            one.lib.alert(response);
+                        }
+                        one.main.dashlet.right.bottom.empty();
+                        one.f.detail.dashlet(one.main.dashlet.right.bottom);
+                        one.main.dashlet.left.top.empty();
+                        one.f.flows.dashlet(one.main.dashlet.left.top);
+                    });                    
+                });
+                $dashlet.append($button);
 
             }
 
-            // table bindings
-            $table.find('tbody').find('tr').click(function() {
-                var id = $($(this).find('td')[0]).text();
-                var node = $(this).data('id');
-                one.f.flows.detail(id, node);
+            var $gridHTML = one.lib.dashlet.datagrid.init(one.f.flows.id.dashlet.datagrid, {
+                searchable: true,
+                filterable: false,
+                pagination: true,
+                flexibleRowsPerPage: true
+                }, "table-striped table-condensed");
+            $dashlet.append($gridHTML);
+            var dataSource = one.f.flows.data.flowsDataGrid(data);
+            $("#" + one.f.flows.id.dashlet.datagrid).datagrid({dataSource: dataSource}).on("loaded", function() {
+                    $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows).click(function() {
+                                $("#" + one.f.flows.id.dashlet.datagrid).find(':checkbox').prop('checked',
+                                        $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows).is(':checked'));
+                    });
+                    
+                    $("#" + one.f.flows.id.dashlet.datagrid).find("tbody tr").each(function(index, tr) {
+                    $tr = $(tr);
+                    $span = $("td span", $tr);
+                    var flowstatus = $span.data("flowstatus");
+                    if($span.data("installinhw") != null) {
+                        var installInHw = $span.data("installinhw").toString();
+                        if(installInHw == "true" && flowstatus == "Success") {
+                            $tr.addClass("success");
+                        } else {
+                            $tr.addClass("warning");
+                        }
+                    }
+                    // attach mouseover to show pointer cursor
+                    $tr.mouseover(function() {
+                        $(this).css("cursor", "pointer");
+                    });
+                    // attach click event
+                    $tr.click(function() {
+                        var $td = $($(this).find("td")[1]);
+                        var id = $td.text();
+                        var node = $td.find("span").data("nodeid");
+                        one.f.flows.detail(id, node);
+                    });
+                    $(".flowEntry").click(function(){
+                                if (!$('.flowEntry[type=checkbox]:not(:checked)').length) {
+                            $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows)
+                                .prop("checked",
+                              true);
+                        } else {
+                            $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows)
+                                .prop("checked",
+                             false);
+                        }
+                        event.stopPropagation();
+                    });
+                });
             });
-
-                       // total flows
-                       var flowCount = $table.find('tbody').find('tr').size();
-                       // prompt output
-                       var flowText = "flow";
-                       var verb = "is";
-                       if (flowCount != 1) {
-                               flowText += "s";
-                               verb = "are";
-                       }
-                       var out = "There "+verb+" "+flowCount+" "+flowText;
-                       $p = $(document.createElement('p'));
-                       $p.append(out);
-                       $dashlet.append($p);
-            // add table to dashlet
-            $dashlet.append($table);
+            
             // details callback
             if(callback != undefined) callback();
         });
@@ -363,54 +435,54 @@ one.f.flows = {
             }
         });
         if (one.f.flows.registry.privilege === 'WRITE') {
-               // remove button
-               var button = one.lib.dashlet.button.single("Remove Flow", one.f.flows.id.dashlet.remove, "btn-danger", "btn-mini");
-               var $button = one.lib.dashlet.button.button(button);
-               $button.click(function() {
-                   var $modal = one.f.flows.modal.dialog.initialize(id, node);
-                   $modal.modal();
-               });
-               // toggle button
-               var toggle;
-               if (flow['flow']['installInHw'] == 'true' && flow['flow']['status'] == 'Success') {
-                   toggle = one.lib.dashlet.button.single("Uninstall Flow", one.f.flows.id.dashlet.toggle, "btn-warning", "btn-mini");
-               } else {
-                   toggle = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.dashlet.toggle, "btn-success", "btn-mini");
-               }
-               var $toggle = one.lib.dashlet.button.button(toggle);
-               $toggle.click(function() {
-                   one.f.flows.modal.ajax.toggleflow(id, node, function(data) {
-                       if(data == "Success") {
-                           one.main.dashlet.right.bottom.empty();
-                           one.f.detail.dashlet(one.main.dashlet.right.bottom);
-                           one.main.dashlet.left.top.empty();
-                               one.f.flows.dashlet(one.main.dashlet.left.top, function() {
-                                  // checks are backwards due to stale registry
-                                  if(flow['flow']['installInHw'] == 'true') {
-                                      one.lib.alert('Uninstalled Flow');
-                                  } else {
-                                      one.lib.alert('Installed Flow');
-                                  }
-                                  one.f.flows.detail(id, node)
-                               });
-                       } else {
-                           one.lib.alert('Cannot toggle flow: '+data);
-                       }
-                   });
-               });
-
-               $detailDashlet.append($button).append($toggle);
+            // remove button
+            var button = one.lib.dashlet.button.single("Remove Flow", one.f.flows.id.dashlet.remove, "btn-danger", "btn-mini");
+            var $button = one.lib.dashlet.button.button(button);
+            $button.click(function() {
+                var $modal = one.f.flows.modal.dialog.initialize(id, node);
+                $modal.modal();
+            });
+            // toggle button
+            var toggle;
+            if (flow['flow']['installInHw'] == 'true' && flow['flow']['status'] == 'Success') {
+                toggle = one.lib.dashlet.button.single("Uninstall Flow", one.f.flows.id.dashlet.toggle, "btn-warning", "btn-mini");
+            } else {
+                toggle = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.dashlet.toggle, "btn-success", "btn-mini");
+            }
+            var $toggle = one.lib.dashlet.button.button(toggle);
+            $toggle.click(function() {
+                one.f.flows.modal.ajax.toggleflow(id, node, function(data) {
+                    if(data == "Success") {
+                        one.main.dashlet.right.bottom.empty();
+                        one.f.detail.dashlet(one.main.dashlet.right.bottom);
+                        one.main.dashlet.left.top.empty();
+                        one.f.flows.dashlet(one.main.dashlet.left.top, function() {
+                           // checks are backwards due to stale registry
+                           if(flow['flow']['installInHw'] == 'true') {
+                               one.lib.alert('Uninstalled Flow');
+                           } else {
+                               one.lib.alert('Installed Flow');
+                           }
+                           one.f.flows.detail(id, node)
+                        });
+                    } else {
+                        one.lib.alert('Cannot toggle flow: '+data);
+                    }
+                });
+            });
+
+            $detailDashlet.append($button).append($toggle);
         }
         // append details
         var body = one.f.detail.data.dashlet(flow);
         var $body = one.f.detail.body.dashlet(body);
         $detailDashlet.append($body);
-               var body = one.f.detail.data.description(flow);
-               var $body = one.f.detail.body.description(body);
-               $detailDashlet.append($body);
-               var body = one.f.detail.data.actions(flow);
-               var $body = one.f.detail.body.actions(body);
-               $detailDashlet.append($body);
+        var body = one.f.detail.data.description(flow);
+        var $body = one.f.detail.body.description(body);
+        $detailDashlet.append($body);
+        var body = one.f.detail.data.actions(flow);
+        var $body = one.f.detail.body.actions(body);
+        $detailDashlet.append($body);
     },
     modal : {
         dialog : {
@@ -492,8 +564,8 @@ one.f.flows = {
             result['ingressPort'] = $('#'+one.f.flows.id.modal.form.port, $modal).val();
             result['priority'] = $('#'+one.f.flows.id.modal.form.priority, $modal).val();
             result['hardTimeout'] = $('#'+one.f.flows.id.modal.form.hardTimeout, $modal).val();
-                       result['idleTimeout'] = $('#'+one.f.flows.id.modal.form.idleTimeout, $modal).val();
-                       result['cookie'] = $('#'+one.f.flows.id.modal.form.cookie, $modal).val();
+            result['idleTimeout'] = $('#'+one.f.flows.id.modal.form.idleTimeout, $modal).val();
+            result['cookie'] = $('#'+one.f.flows.id.modal.form.cookie, $modal).val();
             result['etherType'] = $('#'+one.f.flows.id.modal.form.etherType, $modal).val();
             result['vlanId'] = $('#'+one.f.flows.id.modal.form.vlanId, $modal).val();
             result['vlanPriority'] = $('#'+one.f.flows.id.modal.form.vlanPriority, $modal).val();
@@ -506,7 +578,7 @@ one.f.flows = {
             result['tpDst'] = $('#'+one.f.flows.id.modal.form.dstPort, $modal).val();
             result['protocol'] = $('#'+one.f.flows.id.modal.form.protocol, $modal).val();
 
-                       result['installInHw'] = install;
+            result['installInHw'] = install;
 
             var nodeId = $('#'+one.f.flows.id.modal.form.nodes, $modal).val();
 
@@ -517,31 +589,31 @@ one.f.flows = {
             var action = [];
             var $table = $('#'+one.f.flows.id.modal.action.table, $modal);
             $($table.find('tbody').find('tr')).each(function(index, value) {
-                               if (!$(this).find('td').hasClass('empty')) {
-                       action.push($(value).data('action'));
-                               }
+                if (!$(this).find('td').hasClass('empty')) {
+                    action.push($(value).data('action'));
+                }
             });
             result['actions'] = action;
 
             // frontend validation
-                       if (result['name'] == undefined) {
-                               alert('Need flow name');
-                               return;
-                       }
-                       if (nodeId == '') {
-                               alert('Select node');
-                               return;
-                       }
-                       if (action.length == 0) {
-                               alert('Please specify an action');
-                               return;
-                       }
-
-                       // package for ajax call
+            if (result['name'] == undefined) {
+                alert('Need flow name');
+                return;
+            }
+            if (nodeId == '') {
+                alert('Select node');
+                return;
+            }
+            if (action.length == 0) {
+                alert('Please specify an action');
+                return;
+            }
+
+            // package for ajax call
             var resource = {};
             resource['body'] = JSON.stringify(result);
             resource['action'] = 'add';
-                       resource['nodeId'] = nodeId;
+            resource['nodeId'] = nodeId;
 
             one.f.flows.modal.ajax.saveflow(resource, function(data) {
                 if (data == "Success") {
@@ -550,7 +622,7 @@ one.f.flows = {
                     one.main.dashlet.left.top.empty();
                     one.f.flows.dashlet(one.main.dashlet.left.top);
                 } else {
-                                       alert('Could not add flow: '+data);
+                    alert('Could not add flow: '+data);
                 }
             });
         },
@@ -570,18 +642,18 @@ one.f.flows = {
                 });
             },
             removeflow : function(id, node, callback) {
-               resource = {};
-               resource['action'] = 'remove';
+                resource = {};
+                resource['action'] = 'remove';
                 $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
                     callback(data);
                 });
             },
             toggleflow : function(id, node, callback) {
-               resource = {};
-               resource['action'] = 'toggle';
-               $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
-                       callback(data);
-               });
+                resource = {};
+                resource['action'] = 'toggle';
+                $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
+                    callback(data);
+                });
             }
         },
         data : {
@@ -595,184 +667,184 @@ one.f.flows = {
         },
         body : function(nodes, nodeports) {
             var $form = $(document.createElement('form'));
-                       var $fieldset = $(document.createElement('fieldset'));
-                       // flow description
-                       var $legend = one.lib.form.legend("Flow Description");
-                       $fieldset.append($legend);
-                       // name
-                       var $label = one.lib.form.label("Name");
-                       var $input = one.lib.form.input("Flow Name");
-                       $input.attr('id', one.f.flows.id.modal.form.name);
-                       $fieldset.append($label).append($input);
-                       // node
-                       var $label = one.lib.form.label("Node");
-                       var $select = one.lib.form.select.create(nodes);
-                       one.lib.form.select.prepend($select, { '' : 'Please Select a Node' });
-                       $select.val($select.find("option:first").val());
-                       $select.attr('id', one.f.flows.id.modal.form.nodes);
-
-                       // bind onchange
-                       $select.change(function() {
-                           // retrieve port value
-                           var node = $(this).find('option:selected').attr('value');
-                           var $ports = $('#'+one.f.flows.id.modal.form.port);
-                               if (node == '') {
-                                       one.lib.form.select.inject($ports, {});
-                                       return;
-                               }
-                           one.f.flows.registry['currentNode'] = node;
-                           var ports = nodeports[node]['ports'];
-                           one.lib.form.select.inject($ports, ports);
-                           one.lib.form.select.prepend($ports, { '' : 'Please Select a Port' });
-                           $ports.val($ports.find("option:first").val());
-                       });
+            var $fieldset = $(document.createElement('fieldset'));
+            // flow description
+            var $legend = one.lib.form.legend("Flow Description");
+            $fieldset.append($legend);
+            // name
+            var $label = one.lib.form.label("Name");
+            var $input = one.lib.form.input("Flow Name");
+            $input.attr('id', one.f.flows.id.modal.form.name);
+            $fieldset.append($label).append($input);
+            // node
+            var $label = one.lib.form.label("Node");
+            var $select = one.lib.form.select.create(nodes);
+            one.lib.form.select.prepend($select, { '' : 'Please Select a Node' });
+            $select.val($select.find("option:first").val());
+            $select.attr('id', one.f.flows.id.modal.form.nodes);
+
+            // bind onchange
+            $select.change(function() {
+                // retrieve port value
+                var node = $(this).find('option:selected').attr('value');
+                var $ports = $('#'+one.f.flows.id.modal.form.port);
+                if (node == '') {
+                    one.lib.form.select.inject($ports, {});
+                    return;
+                }
+                one.f.flows.registry['currentNode'] = node;
+                var ports = nodeports[node]['ports'];
+                one.lib.form.select.inject($ports, ports);
+                one.lib.form.select.prepend($ports, { '' : 'Please Select a Port' });
+                $ports.val($ports.find("option:first").val());
+            });
 
             $fieldset.append($label).append($select);
-                       // input port
-                       var $label = one.lib.form.label("Input Port");
-                       var $select = one.lib.form.select.create();
-                       $select.attr('id', one.f.flows.id.modal.form.port);
-                       $fieldset.append($label).append($select);
-                       // priority
-                       var $label = one.lib.form.label("Priority");
-                       var $input = one.lib.form.input("Priority");
-                       $input.attr('id', one.f.flows.id.modal.form.priority);
-                       $input.val('500');
-                       $fieldset.append($label).append($input);
-                       // hardTimeout
-                       var $label = one.lib.form.label("Hard Timeout");
-                       var $input = one.lib.form.input("Hard Timeout");
-                       $input.attr('id', one.f.flows.id.modal.form.hardTimeout);
-                       $fieldset.append($label).append($input);
-                       // idleTimeout
-                       var $label = one.lib.form.label("Idle Timeout");
-                       var $input = one.lib.form.input("Idle Timeout");
-                       $input.attr('id', one.f.flows.id.modal.form.idleTimeout);
-                       $fieldset.append($label).append($input);
-                       // cookie
-                       var $label = one.lib.form.label("Cookie");
-                       var $input = one.lib.form.input("Cookie");
-                       $input.attr('id', one.f.flows.id.modal.form.cookie);
-                       $fieldset.append($label).append($input);
-                       // layer 2
-                       var $legend = one.lib.form.legend("Layer 2");
-                       $fieldset.append($legend);
-                       // etherType
-                       var $label = one.lib.form.label("Ethernet Type");
-                       var $input = one.lib.form.input("Ethernet Type");
-                       $input.attr('id', one.f.flows.id.modal.form.etherType);
-                       $input.val('0x800');
-                       $fieldset.append($label).append($input);
-                       // vlanId
-                       var $label = one.lib.form.label("VLAN Identification Number");
-                       var $input = one.lib.form.input("VLAN Identification Number");
-                       $input.attr('id', one.f.flows.id.modal.form.vlanId);
-                       var $help = one.lib.form.help("Range: 0 - 4095");
-                       $fieldset.append($label).append($input).append($help);
-                       // vlanPriority
-                       var $label = one.lib.form.label("VLAN Priority");
-                       var $input = one.lib.form.input("VLAN Priority");
-                       $input.attr('id', one.f.flows.id.modal.form.vlanPriority);
-                       var $help = one.lib.form.help("Range: 0 - 7");
-                       $fieldset.append($label).append($input).append($help);
-                       // srcMac
-                       var $label = one.lib.form.label("Source MAC Address");
-                       var $input = one.lib.form.input("Source MAC Address");
-                       $input.attr('id', one.f.flows.id.modal.form.srcMac);
-                       var $help = one.lib.form.help("Example: 00:11:22:aa:bb:cc");
-                       $fieldset.append($label).append($input).append($help);
-                       // dstMac
-                       var $label = one.lib.form.label("Destination MAC Address");
-                       var $input = one.lib.form.input("Destination MAC Address");
-                       $input.attr('id', one.f.flows.id.modal.form.dstMac);
-                       var $help = one.lib.form.help("Example: 00:11:22:aa:bb:cc");
-                       $fieldset.append($label).append($input).append($help);
-                       // layer 3
-                       var $legend = one.lib.form.legend("Layer 3");
-                       $fieldset.append($legend);
-                       // srcIp
-                       var $label = one.lib.form.label("Source IP Address");
-                       var $input = one.lib.form.input("Source IP Address");
-                       $input.attr('id', one.f.flows.id.modal.form.srcIp);
-                       var $help = one.lib.form.help("Example: 127.0.0.1");
-                       $fieldset.append($label).append($input).append($help);
-                       // dstIp
-                       var $label = one.lib.form.label("Destination IP Address");
-                       var $input = one.lib.form.input("Destination IP Address");
-                       $input.attr('id', one.f.flows.id.modal.form.dstIp);
-                       var $help = one.lib.form.help("Example: 127.0.0.1");
-                       $fieldset.append($label).append($input).append($help);
-                       // tosBits
-                       var $label = one.lib.form.label("TOS Bits");
-                       var $input = one.lib.form.input("TOS Bits");
-                       $input.attr('id', one.f.flows.id.modal.form.tosBits);
-                       var $help = one.lib.form.help("Range: 0 - 63");
-                       $fieldset.append($label).append($input).append($help);
-                       // layer 4
-                       var $legend = one.lib.form.legend("Layer 4");
-                       $fieldset.append($legend);
-                       // srcPort
-                       var $label = one.lib.form.label("Source Port");
-                       var $input = one.lib.form.input("Source Port");
-                       $input.attr('id', one.f.flows.id.modal.form.srcPort);
-                       var $help = one.lib.form.help("Range: 0 - 65535");
-                       $fieldset.append($label).append($input).append($help);
-                       // dstPort
-                       var $label = one.lib.form.label("Destination Port");
-                       var $input = one.lib.form.input("Destination Port");
-                       $input.attr('id', one.f.flows.id.modal.form.dstPort);
-                       var $help = one.lib.form.help("Range: 0 - 65535");
-                       $fieldset.append($label).append($input).append($help);
-                       // protocol
-                       var $label = one.lib.form.label("Protocol");
-                       var $input = one.lib.form.input("Protocol");
-                       $input.attr('id', one.f.flows.id.modal.form.protocol);
-                       $fieldset.append($label).append($input);
-                       // actions
-                       var $legend = one.lib.form.label("Actions");
-                       $fieldset.append($legend);
-                       // actions table
-                       var tableAttributes = ["table-striped", "table-bordered", "table-condensed", "table-hover", "table-cursor"];
-                       var $table = one.lib.dashlet.table.table(tableAttributes);
-                       $table.attr('id', one.f.flows.id.modal.action.table);
-                       var tableHeaders = ["Action", "Data", "Type"];
-                   var $thead = one.lib.dashlet.table.header(tableHeaders);
-                       var $tbody = one.lib.dashlet.table.body("", tableHeaders);
-                       $table.append($thead).append($tbody);
-                       // actions
-                       var actions = {
-                           "" : "Please Select an Action",
-                           "drop" : "Drop",
-                           "loopback" : "Loopback",
-                           "flood" : "Flood",
-                           "softwarePath" : "Software Path",
-                           "hardwarePath" : "Hardware Path",
-                           "controller" : "Controller",
-                           "addOutputPorts" : "Add Output Ports",
-                           "setVlanId" : "Set VLAN ID",
-                           "setVlanPriority" : "Set VLAN Priority",
-                           "stripVlanHeader" : "Strip VLAN Header",
-                           "modifyDatalayerSourceAddress" : "Modify Datalayer Source Address",
-                           "modifyDatalayerDestinationAddress" : "Modify Datalayer Destination Address",
-                           "modifyNetworkSourceAddress" : "Modify Network Source Address",
-                           "modifyNetworkDestinationAddress" :"Modify Network Destination Address",
-                           "modifyTosBits" : "Modify TOS Bits",
-                           "modifyTransportSourcePort" : "Modify Transport Source Port",
-                           "modifyTransportDestinationPort" : "Modify Transport Destination Port"
-                       };
+            // input port
+            var $label = one.lib.form.label("Input Port");
+            var $select = one.lib.form.select.create();
+            $select.attr('id', one.f.flows.id.modal.form.port);
+            $fieldset.append($label).append($select);
+            // priority
+            var $label = one.lib.form.label("Priority");
+            var $input = one.lib.form.input("Priority");
+            $input.attr('id', one.f.flows.id.modal.form.priority);
+            $input.val('500');
+            $fieldset.append($label).append($input);
+            // hardTimeout
+            var $label = one.lib.form.label("Hard Timeout");
+            var $input = one.lib.form.input("Hard Timeout");
+            $input.attr('id', one.f.flows.id.modal.form.hardTimeout);
+            $fieldset.append($label).append($input);
+            // idleTimeout
+            var $label = one.lib.form.label("Idle Timeout");
+            var $input = one.lib.form.input("Idle Timeout");
+            $input.attr('id', one.f.flows.id.modal.form.idleTimeout);
+            $fieldset.append($label).append($input);
+            // cookie
+            var $label = one.lib.form.label("Cookie");
+            var $input = one.lib.form.input("Cookie");
+            $input.attr('id', one.f.flows.id.modal.form.cookie);
+            $fieldset.append($label).append($input);
+            // layer 2
+            var $legend = one.lib.form.legend("Layer 2");
+            $fieldset.append($legend);
+            // etherType
+            var $label = one.lib.form.label("Ethernet Type");
+            var $input = one.lib.form.input("Ethernet Type");
+            $input.attr('id', one.f.flows.id.modal.form.etherType);
+            $input.val('0x800');
+            $fieldset.append($label).append($input);
+            // vlanId
+            var $label = one.lib.form.label("VLAN Identification Number");
+            var $input = one.lib.form.input("VLAN Identification Number");
+            $input.attr('id', one.f.flows.id.modal.form.vlanId);
+            var $help = one.lib.form.help("Range: 0 - 4095");
+            $fieldset.append($label).append($input).append($help);
+            // vlanPriority
+            var $label = one.lib.form.label("VLAN Priority");
+            var $input = one.lib.form.input("VLAN Priority");
+            $input.attr('id', one.f.flows.id.modal.form.vlanPriority);
+            var $help = one.lib.form.help("Range: 0 - 7");
+            $fieldset.append($label).append($input).append($help);
+            // srcMac
+            var $label = one.lib.form.label("Source MAC Address");
+            var $input = one.lib.form.input("Source MAC Address");
+            $input.attr('id', one.f.flows.id.modal.form.srcMac);
+            var $help = one.lib.form.help("Example: 00:11:22:aa:bb:cc");
+            $fieldset.append($label).append($input).append($help);
+            // dstMac
+            var $label = one.lib.form.label("Destination MAC Address");
+            var $input = one.lib.form.input("Destination MAC Address");
+            $input.attr('id', one.f.flows.id.modal.form.dstMac);
+            var $help = one.lib.form.help("Example: 00:11:22:aa:bb:cc");
+            $fieldset.append($label).append($input).append($help);
+            // layer 3
+            var $legend = one.lib.form.legend("Layer 3");
+            $fieldset.append($legend);
+            // srcIp
+            var $label = one.lib.form.label("Source IP Address");
+            var $input = one.lib.form.input("Source IP Address");
+            $input.attr('id', one.f.flows.id.modal.form.srcIp);
+            var $help = one.lib.form.help("Example: 127.0.0.1");
+            $fieldset.append($label).append($input).append($help);
+            // dstIp
+            var $label = one.lib.form.label("Destination IP Address");
+            var $input = one.lib.form.input("Destination IP Address");
+            $input.attr('id', one.f.flows.id.modal.form.dstIp);
+            var $help = one.lib.form.help("Example: 127.0.0.1");
+            $fieldset.append($label).append($input).append($help);
+            // tosBits
+            var $label = one.lib.form.label("TOS Bits");
+            var $input = one.lib.form.input("TOS Bits");
+            $input.attr('id', one.f.flows.id.modal.form.tosBits);
+            var $help = one.lib.form.help("Range: 0 - 63");
+            $fieldset.append($label).append($input).append($help);
+            // layer 4
+            var $legend = one.lib.form.legend("Layer 4");
+            $fieldset.append($legend);
+            // srcPort
+            var $label = one.lib.form.label("Source Port");
+            var $input = one.lib.form.input("Source Port");
+            $input.attr('id', one.f.flows.id.modal.form.srcPort);
+            var $help = one.lib.form.help("Range: 0 - 65535");
+            $fieldset.append($label).append($input).append($help);
+            // dstPort
+            var $label = one.lib.form.label("Destination Port");
+            var $input = one.lib.form.input("Destination Port");
+            $input.attr('id', one.f.flows.id.modal.form.dstPort);
+            var $help = one.lib.form.help("Range: 0 - 65535");
+            $fieldset.append($label).append($input).append($help);
+            // protocol
+            var $label = one.lib.form.label("Protocol");
+            var $input = one.lib.form.input("Protocol");
+            $input.attr('id', one.f.flows.id.modal.form.protocol);
+            $fieldset.append($label).append($input);
+            // actions
+            var $legend = one.lib.form.label("Actions");
+            $fieldset.append($legend);
+            // actions table
+            var tableAttributes = ["table-striped", "table-bordered", "table-condensed", "table-hover", "table-cursor"];
+            var $table = one.lib.dashlet.table.table(tableAttributes);
+            $table.attr('id', one.f.flows.id.modal.action.table);
+            var tableHeaders = ["Action", "Data", "Type"];
+            var $thead = one.lib.dashlet.table.header(tableHeaders);
+            var $tbody = one.lib.dashlet.table.body("", tableHeaders);
+            $table.append($thead).append($tbody);
+            // actions
+            var actions = {
+                "" : "Please Select an Action",
+                "drop" : "Drop",
+                "loopback" : "Loopback",
+                "flood" : "Flood",
+                "softwarePath" : "Software Path",
+                "hardwarePath" : "Hardware Path",
+                "controller" : "Controller",
+                "addOutputPorts" : "Add Output Ports",
+                "setVlanId" : "Set VLAN ID",
+                "setVlanPriority" : "Set VLAN Priority",
+                "stripVlanHeader" : "Strip VLAN Header",
+                "modifyDatalayerSourceAddress" : "Modify Datalayer Source Address",
+                "modifyDatalayerDestinationAddress" : "Modify Datalayer Destination Address",
+                "modifyNetworkSourceAddress" : "Modify Network Source Address",
+                "modifyNetworkDestinationAddress" :"Modify Network Destination Address",
+                "modifyTosBits" : "Modify TOS Bits",
+                "modifyTransportSourcePort" : "Modify Transport Source Port",
+                "modifyTransportDestinationPort" : "Modify Transport Destination Port"
+            };
             var $select = one.lib.form.select.create(actions);
             // when selecting an action
             $select.change(function() {
                 var action = $(this).find('option:selected');
                 one.f.flows.modal.action.parse(action.attr('value'));
-                               $select[0].selectedIndex = 0;
+                $select[0].selectedIndex = 0;
             });
 
-                       $fieldset.append($select).append($table);
+            $fieldset.append($select).append($table);
 
-                       // return
-                       $form.append($fieldset);
-                       return $form;
+            // return
+            $form.append($fieldset);
+            return $form;
         },
         action : {
             parse : function(option) {
@@ -991,9 +1063,9 @@ one.f.flows = {
                     var $tr = one.f.flows.modal.action.table.add("Add Output Ports", ports);
                     $tr.attr('id', 'addOutputPorts');
                     $tr.data('action', 'OUTPUT='+pid);
-                                       $tr.click(function() {
-                                               one.f.flows.modal.action.add.modal.initialize(this);
-                                       });
+                    $tr.click(function() {
+                        one.f.flows.modal.action.add.modal.initialize(this);
+                    });
                     one.f.flows.modal.action.table.append($tr);
                     $modal.modal('hide');
                 },
@@ -1001,9 +1073,9 @@ one.f.flows = {
                     var $tr = one.f.flows.modal.action.table.add(name);
                     $tr.attr('id', action);
                     $tr.data('action', action);
-                                       $tr.click(function() {
-                                               one.f.flows.modal.action.add.modal.initialize(this);
-                                       });
+                    $tr.click(function() {
+                        one.f.flows.modal.action.add.modal.initialize(this);
+                    });
                     one.f.flows.modal.action.table.append($tr);
                 },
                 set : function(name, id, action, $modal) {
@@ -1012,64 +1084,64 @@ one.f.flows = {
                     var $tr = one.f.flows.modal.action.table.add(name, value);
                     $tr.attr('id', action);
                     $tr.data('action', action+'='+value);
-                                       $tr.click(function() {
-                                               one.f.flows.modal.action.add.modal.initialize(this);
-                                       });
+                    $tr.click(function() {
+                        one.f.flows.modal.action.add.modal.initialize(this);
+                    });
                     one.f.flows.modal.action.table.append($tr);
                     $modal.modal('hide');
                 },
-                               remove : function(that) {
-                                       $(that).remove();
-                                       var $table = $('#'+one.f.flows.id.modal.action.table);
-                                       if ($table.find('tbody').find('tr').size() == 0) {
-                                               var $tr = $(document.createElement('tr'));
-                                               var $td = $(document.createElement('td'));
-                                               $td.attr('colspan', '3');
-                                               $tr.addClass('empty');
-                                               $td.text('No data available');
-                                               $tr.append($td);
-                                               $table.find('tbody').append($tr);
-                                       }
-                               },
-                               modal : {
-                                       initialize : function(that) {
-                                               var h3 = "Remove Action";
-                                               var footer = one.f.flows.modal.action.add.modal.footer();
-                                               var $body = one.f.flows.modal.action.add.modal.body();
-                                               var $modal = one.lib.modal.spawn(one.f.flows.id.modal.action.modal.modal, h3, $body, footer);
-
-                                               // bind cancel button
-                                               $('#'+one.f.flows.id.modal.action.modal.cancel, $modal).click(function() {
-                                                       $modal.modal('hide');
-                                               });
-
-                                               // bind remove button
-                                               $('#'+one.f.flows.id.modal.action.modal.remove, $modal).click(function() {
-                                                       one.f.flows.modal.action.add.remove(that);
-                                                       $modal.modal('hide');
-                                               });
-
-                                               $modal.modal();
-                                       },
-                                       body : function() {
-                                               var $p = $(document.createElement('p'));
-                                               $p.append("Remove this action?");
-                                               return $p;
-                                       },
-                                       footer : function() {
-                                               var footer = [];
-
-                                               var removeButton = one.lib.dashlet.button.single("Remove Action", one.f.flows.id.modal.action.modal.remove, "btn-danger", "");
-                                               var $removeButton = one.lib.dashlet.button.button(removeButton);
-                                               footer.push($removeButton);
-
-                                               var cancelButton = one.lib.dashlet.button.single("Cancel", one.f.flows.id.modal.action.modal.cancel, "", "");
-                                               var $cancelButton = one.lib.dashlet.button.button(cancelButton);
-                                               footer.push($cancelButton);
-
-                                               return footer;
-                                       }
-                               }
+                remove : function(that) {
+                    $(that).remove();
+                    var $table = $('#'+one.f.flows.id.modal.action.table);
+                    if ($table.find('tbody').find('tr').size() == 0) {
+                        var $tr = $(document.createElement('tr'));
+                        var $td = $(document.createElement('td'));
+                        $td.attr('colspan', '3');
+                        $tr.addClass('empty');
+                        $td.text('No data available');
+                        $tr.append($td);
+                        $table.find('tbody').append($tr);
+                    }
+                },
+                modal : {
+                    initialize : function(that) {
+                        var h3 = "Remove Action";
+                        var footer = one.f.flows.modal.action.add.modal.footer();
+                        var $body = one.f.flows.modal.action.add.modal.body();
+                        var $modal = one.lib.modal.spawn(one.f.flows.id.modal.action.modal.modal, h3, $body, footer);
+
+                        // bind cancel button
+                        $('#'+one.f.flows.id.modal.action.modal.cancel, $modal).click(function() {
+                            $modal.modal('hide');
+                        });
+
+                        // bind remove button
+                        $('#'+one.f.flows.id.modal.action.modal.remove, $modal).click(function() {
+                            one.f.flows.modal.action.add.remove(that);
+                            $modal.modal('hide');
+                        });
+
+                        $modal.modal();
+                    },
+                    body : function() {
+                        var $p = $(document.createElement('p'));
+                        $p.append("Remove this action?");
+                        return $p;
+                    },
+                    footer : function() {
+                        var footer = [];
+
+                        var removeButton = one.lib.dashlet.button.single("Remove Action", one.f.flows.id.modal.action.modal.remove, "btn-danger", "");
+                        var $removeButton = one.lib.dashlet.button.button(removeButton);
+                        footer.push($removeButton);
+
+                        var cancelButton = one.lib.dashlet.button.single("Cancel", one.f.flows.id.modal.action.modal.cancel, "", "");
+                        var $cancelButton = one.lib.dashlet.button.button(cancelButton);
+                        footer.push($cancelButton);
+
+                        return footer;
+                    }
+                }
             },
             table : {
                 add : function(action, data, type) {
@@ -1143,9 +1215,9 @@ one.f.flows = {
         footer : function() {
             var footer = [];
 
-                       var installButton = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.modal.install, "btn-success", "");
-                       var $installButton = one.lib.dashlet.button.button(installButton);
-                       footer.push($installButton);
+            var installButton = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.modal.install, "btn-success", "");
+            var $installButton = one.lib.dashlet.button.button(installButton);
+            footer.push($installButton);
 
             var addButton = one.lib.dashlet.button.single("Save Flow", one.f.flows.id.modal.add, "btn-primary", "");
             var $addButton = one.lib.dashlet.button.button(addButton);
@@ -1163,26 +1235,64 @@ one.f.flows = {
             $.getJSON(one.f.address.root+one.f.address.flows.main, function(data) {
                 one.f.flows.registry['flows'] = data.flows;
                 one.f.flows.registry['privilege'] = data.privilege;
-                var body = one.f.flows.data.dashlet(data.flows);
-                var $body = one.f.flows.body.dashlet(body, callback);
-                callback($body);
+                callback(data);
             });
         }
     },
     data : {
+        flowsDataGrid: function(data) {
+            var source = new StaticDataSource({
+                    columns: [
+                        {
+                            property: 'selector',
+                            label: "<input type='checkbox' id='"+one.f.flows.id.dashlet.datagrid.selectAllFlows+"'/>",
+                            sortable: false
+                        },
+                        {
+                            property: 'name',
+                            label: 'Flow Name',
+                            sortable: true
+                        },
+                        {
+                            property: 'node',
+                            label: 'Node',
+                            sortable: true
+                        }
+                    ],
+                    data: data.flows,
+                    formatter: function(items) {
+                        $.each(items, function(index, item) {
+                                    var $checkbox = document.createElement("input");
+                            $checkbox.setAttribute("type", "checkbox");
+                            $checkbox.setAttribute("name", item.name);
+                            $checkbox.setAttribute("node", item.node);
+                            $checkbox.setAttribute('class','flowEntry')
+                            item.selector = $checkbox.outerHTML;
+                                  item["name"] = '<span data-installInHw=' + item["flow"]["installInHw"] + 
+                                ' data-flowstatus=' + item["flow"]["status"] + 
+                                ' data-nodeId=' + item["nodeId"] + '>' + item["name"] + '</span>';
+                        });
+
+                    },
+                    delay: 0
+                });
+            return source;
+        },
         dashlet : function(data) {
             var body = [];
             $(data).each(function(index, value) {
                 var tr = {};
                 var entry = [];
+
+                
                 entry.push(value['name']);
                 entry.push(value['node']);
                 if (value['flow']['installInHw'] == 'true' && value['flow']['status'] == 'Success')
-                       tr['type'] = ['success'];
+                    tr['type'] = ['success'];
                 else if (value['flow']['installInHw'] == 'false' && value['flow']['status'] == 'Success')
-                       tr['type'] = ['warning'];
+                    tr['type'] = ['warning'];
                 else 
-                       tr['type'] = ['warning'];
+                    tr['type'] = ['warning'];
                 tr['entry'] = entry;
                 tr['id'] = value['nodeId'];
 
@@ -1197,12 +1307,12 @@ one.f.flows = {
             var $table = one.lib.dashlet.table.table(attributes);
 
             var headers = ['Flow Name', 'Node'];
+                
             var $thead = one.lib.dashlet.table.header(headers);
             $table.append($thead);
 
             var $tbody = one.lib.dashlet.table.body(body);
             $table.append($tbody);
-
             return $table;
         }
     }
index a532560bcde4b3166cf42c7f7bc8e62fc83ef068..c7c3ef16c3fb037c55e0405ff0b46e5ef09c08fb 100644 (file)
@@ -16,6 +16,8 @@
 
 <!-- Bootstrap CSS - 1 -->
 <link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
+<link rel="stylesheet" type="text/css" href="/css/fuelux.min.css">
+<link rel="stylesheet" type="text/css" href="/css/opendaylight.css">
 
 <!-- Core CSS - 2 -->
 <link rel="stylesheet/less" type="text/css" href="/css/one.less">
@@ -38,7 +40,9 @@
 <script src="/js/jquery-1.9.1.min.js"></script>
 
 <!-- Bootstrap JS - 2 -->
-<script src="/js/bootstrap.min.js"></script>
+<script src="/js/underscore-min.js"></script>
+<script src="/js/fuelux/loader.min.js"></script>
+<script src="/js/datasource.js"></script>
 
 <!-- LESS - 3 -->
 <script type="text/javascript">
diff --git a/opendaylight/web/root/src/main/resources/css/fuelux-responsive.min.css b/opendaylight/web/root/src/main/resources/css/fuelux-responsive.min.css
new file mode 100755 (executable)
index 0000000..1dbe323
--- /dev/null
@@ -0,0 +1,9 @@
+/*!
+ * Bootstrap Responsive v2.3.2
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */.fuelux .clearfix{*zoom:1}.fuelux .clearfix:before,.fuelux .clearfix:after{display:table;line-height:0;content:""}.fuelux .clearfix:after{clear:both}.fuelux .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.fuelux .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.fuelux .hidden{display:none;visibility:hidden}.fuelux .visible-phone{display:none!important}.fuelux .visible-tablet{display:none!important}.fuelux .hidden-desktop{display:none!important}.fuelux .visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.fuelux .hidden-desktop{display:inherit!important}.fuelux .visible-desktop{display:none!important}.fuelux .visible-tablet{display:inherit!important}.fuelux .hidden-tablet{display:none!important}}@media(max-width:767px){.fuelux .hidden-desktop{display:inherit!important}.fuelux .visible-desktop{display:none!important}.fuelux .visible-phone{display:inherit!important}.fuelux .hidden-phone{display:none!important}}.fuelux .visible-print{display:none!important}@media print{.fuelux .visible-print{display:inherit!important}.fuelux .hidden-print{display:none!important}}@media(min-width:1200px){.fuelux .row{margin-left:-30px;*zoom:1}.fuelux .row:before,.fuelux .row:after{display:table;line-height:0;content:""}.fuelux .row:after{clear:both}.fuelux [class*="span"]{float:left;min-height:1px;margin-left:30px}.fuelux .container,.fuelux .navbar-static-top .container,.fuelux .navbar-fixed-top .container,.fuelux .navbar-fixed-bottom .container{width:1170px}.fuelux .span12{width:1170px}.fuelux .span11{width:1070px}.fuelux .span10{width:970px}.fuelux .span9{width:870px}.fuelux .span8{width:770px}.fuelux .span7{width:670px}.fuelux .span6{width:570px}.fuelux .span5{width:470px}.fuelux .span4{width:370px}.fuelux .span3{width:270px}.fuelux .span2{width:170px}.fuelux .span1{width:70px}.fuelux .offset12{margin-left:1230px}.fuelux .offset11{margin-left:1130px}.fuelux .offset10{margin-left:1030px}.fuelux .offset9{margin-left:930px}.fuelux .offset8{margin-left:830px}.fuelux .offset7{margin-left:730px}.fuelux .offset6{margin-left:630px}.fuelux .offset5{margin-left:530px}.fuelux .offset4{margin-left:430px}.fuelux .offset3{margin-left:330px}.fuelux .offset2{margin-left:230px}.fuelux .offset1{margin-left:130px}.fuelux .row-fluid{width:100%;*zoom:1}.fuelux .row-fluid:before,.fuelux .row-fluid:after{display:table;line-height:0;content:""}.fuelux .row-fluid:after{clear:both}.fuelux .row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.fuelux .row-fluid [class*="span"]:first-child{margin-left:0}.fuelux .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.fuelux .row-fluid .span12{width:100%;*width:99.94680851063829%}.fuelux .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.fuelux .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.fuelux .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.fuelux .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.fuelux .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.fuelux .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.fuelux .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.fuelux .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.fuelux .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.fuelux .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.fuelux .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.fuelux .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.fuelux .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.fuelux .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.fuelux .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.fuelux .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.fuelux .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.fuelux .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.fuelux .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.fuelux .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.fuelux .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.fuelux .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.fuelux .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.fuelux .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.fuelux .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.fuelux .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.fuelux .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.fuelux .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.fuelux .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.fuelux .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.fuelux .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.fuelux .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.fuelux .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.fuelux .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.fuelux .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}.fuelux input,.fuelux textarea,.fuelux .uneditable-input{margin-left:0}.fuelux .controls-row [class*="span"]+[class*="span"]{margin-left:30px}.fuelux input.span12,textarea.span12,.uneditable-input.span12{width:1156px}.fuelux input.span11,textarea.span11,.uneditable-input.span11{width:1056px}.fuelux input.span10,textarea.span10,.uneditable-input.span10{width:956px}.fuelux input.span9,textarea.span9,.uneditable-input.span9{width:856px}.fuelux input.span8,textarea.span8,.uneditable-input.span8{width:756px}.fuelux input.span7,textarea.span7,.uneditable-input.span7{width:656px}.fuelux input.span6,textarea.span6,.uneditable-input.span6{width:556px}.fuelux input.span5,textarea.span5,.uneditable-input.span5{width:456px}.fuelux input.span4,textarea.span4,.uneditable-input.span4{width:356px}.fuelux input.span3,textarea.span3,.uneditable-input.span3{width:256px}.fuelux input.span2,textarea.span2,.uneditable-input.span2{width:156px}.fuelux input.span1,textarea.span1,.uneditable-input.span1{width:56px}.fuelux .thumbnails{margin-left:-30px}.fuelux .thumbnails>li{margin-left:30px}.fuelux .row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.fuelux .row{margin-left:-20px;*zoom:1}.fuelux .row:before,.fuelux .row:after{display:table;line-height:0;content:""}.fuelux .row:after{clear:both}.fuelux [class*="span"]{float:left;min-height:1px;margin-left:20px}.fuelux .container,.fuelux .navbar-static-top .container,.fuelux .navbar-fixed-top .container,.fuelux .navbar-fixed-bottom .container{width:724px}.fuelux .span12{width:724px}.fuelux .span11{width:662px}.fuelux .span10{width:600px}.fuelux .span9{width:538px}.fuelux .span8{width:476px}.fuelux .span7{width:414px}.fuelux .span6{width:352px}.fuelux .span5{width:290px}.fuelux .span4{width:228px}.fuelux .span3{width:166px}.fuelux .span2{width:104px}.fuelux .span1{width:42px}.fuelux .offset12{margin-left:764px}.fuelux .offset11{margin-left:702px}.fuelux .offset10{margin-left:640px}.fuelux .offset9{margin-left:578px}.fuelux .offset8{margin-left:516px}.fuelux .offset7{margin-left:454px}.fuelux .offset6{margin-left:392px}.fuelux .offset5{margin-left:330px}.fuelux .offset4{margin-left:268px}.fuelux .offset3{margin-left:206px}.fuelux .offset2{margin-left:144px}.fuelux .offset1{margin-left:82px}.fuelux .row-fluid{width:100%;*zoom:1}.fuelux .row-fluid:before,.fuelux .row-fluid:after{display:table;line-height:0;content:""}.fuelux .row-fluid:after{clear:both}.fuelux .row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.fuelux .row-fluid [class*="span"]:first-child{margin-left:0}.fuelux .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.fuelux .row-fluid .span12{width:100%;*width:99.94680851063829%}.fuelux .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.fuelux .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.fuelux .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.fuelux .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.fuelux .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.fuelux .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.fuelux .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.fuelux .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.fuelux .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.fuelux .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.fuelux .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.fuelux .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.fuelux .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.fuelux .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.fuelux .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.fuelux .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.fuelux .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.fuelux .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.fuelux .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.fuelux .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.fuelux .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.fuelux .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.fuelux .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.fuelux .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.fuelux .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.fuelux .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.fuelux .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.fuelux .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.fuelux .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.fuelux .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.fuelux .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.fuelux .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.fuelux .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.fuelux .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.fuelux .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}.fuelux input,.fuelux textarea,.fuelux .uneditable-input{margin-left:0}.fuelux .controls-row [class*="span"]+[class*="span"]{margin-left:20px}.fuelux input.span12,textarea.span12,.uneditable-input.span12{width:710px}.fuelux input.span11,textarea.span11,.uneditable-input.span11{width:648px}.fuelux input.span10,textarea.span10,.uneditable-input.span10{width:586px}.fuelux input.span9,textarea.span9,.uneditable-input.span9{width:524px}.fuelux input.span8,textarea.span8,.uneditable-input.span8{width:462px}.fuelux input.span7,textarea.span7,.uneditable-input.span7{width:400px}.fuelux input.span6,textarea.span6,.uneditable-input.span6{width:338px}.fuelux input.span5,textarea.span5,.uneditable-input.span5{width:276px}.fuelux input.span4,textarea.span4,.uneditable-input.span4{width:214px}.fuelux input.span3,textarea.span3,.uneditable-input.span3{width:152px}.fuelux input.span2,textarea.span2,.uneditable-input.span2{width:90px}.fuelux input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){.fuelux body{padding-right:20px;padding-left:20px}.fuelux .navbar-fixed-top,.fuelux .navbar-fixed-bottom,.fuelux .navbar-static-top{margin-right:-20px;margin-left:-20px}.fuelux .container-fluid{padding:0}.fuelux .dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.fuelux .dl-horizontal dd{margin-left:0}.fuelux .container{width:auto}.fuelux .row-fluid{width:100%}.fuelux .row,.fuelux .thumbnails{margin-left:0}.fuelux .thumbnails>li{float:none;margin-left:0}.fuelux [class*="span"],.fuelux .uneditable-input[class*="span"],.fuelux .row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.fuelux .span12,.fuelux .row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.fuelux .row-fluid [class*="offset"]:first-child{margin-left:0}.fuelux .input-large,.fuelux .input-xlarge,.fuelux .input-xxlarge,.fuelux input[class*="span"],.fuelux select[class*="span"],.fuelux textarea[class*="span"],.fuelux .uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.fuelux .input-prepend input,.fuelux .input-append input,.fuelux .input-prepend input[class*="span"],.fuelux .input-append input[class*="span"]{display:inline-block;width:auto}.fuelux .controls-row [class*="span"]+[class*="span"]{margin-left:0}.fuelux .modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.fuelux .modal.fade{top:-100px}.fuelux .modal.fade.in{top:20px}}@media(max-width:480px){.fuelux .nav-collapse{-webkit-transform:translate3d(0,0,0)}.fuelux .page-header h1 small{display:block;line-height:20px}.fuelux input[type="checkbox"],.fuelux input[type="radio"]{border:1px solid #ccc}.fuelux .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.fuelux .form-horizontal .controls{margin-left:0}.fuelux .form-horizontal .control-list{padding-top:0}.fuelux .form-horizontal .form-actions{padding-right:10px;padding-left:10px}.fuelux .media .pull-left,.fuelux .media .pull-right{display:block;float:none;margin-bottom:10px}.fuelux .media-object{margin-right:0;margin-left:0}.fuelux .modal{top:10px;right:10px;left:10px}.fuelux .modal-header .close{padding:10px;margin:-10px}.fuelux .carousel-caption{position:static}}@media(max-width:979px){.fuelux body{padding-top:0}.fuelux .navbar-fixed-top,.fuelux .navbar-fixed-bottom{position:static}.fuelux .navbar-fixed-top{margin-bottom:20px}.fuelux .navbar-fixed-bottom{margin-top:20px}.fuelux .navbar-fixed-top .navbar-inner,.fuelux .navbar-fixed-bottom .navbar-inner{padding:5px}.fuelux .navbar .container{width:auto;padding:0}.fuelux .navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.fuelux .nav-collapse{clear:both}.fuelux .nav-collapse .nav{float:none;margin:0 0 10px}.fuelux .nav-collapse .nav>li{float:none}.fuelux .nav-collapse .nav>li>a{margin-bottom:2px}.fuelux .nav-collapse .nav>.divider-vertical{display:none}.fuelux .nav-collapse .nav .nav-header{color:#777;text-shadow:none}.fuelux .nav-collapse .nav>li>a,.fuelux .nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fuelux .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.fuelux .nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.fuelux .nav-collapse .nav>li>a:hover,.fuelux .nav-collapse .nav>li>a:focus,.fuelux .nav-collapse .dropdown-menu a:hover,.fuelux .nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.fuelux .navbar-inverse .nav-collapse .nav>li>a,.fuelux .navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.fuelux .navbar-inverse .nav-collapse .nav>li>a:hover,.fuelux .navbar-inverse .nav-collapse .nav>li>a:focus,.fuelux .navbar-inverse .nav-collapse .dropdown-menu a:hover,.fuelux .navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.fuelux .nav-collapse.in .btn-group{padding:0;margin-top:5px}.fuelux .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.fuelux .nav-collapse .open>.dropdown-menu{display:block}.fuelux .nav-collapse .dropdown-menu:before,.fuelux .nav-collapse .dropdown-menu:after{display:none}.fuelux .nav-collapse .dropdown-menu .divider{display:none}.fuelux .nav-collapse .nav>li>.dropdown-menu:before,.fuelux .nav-collapse .nav>li>.dropdown-menu:after{display:none}.fuelux .nav-collapse .navbar-form,.fuelux .nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.fuelux .navbar-inverse .nav-collapse .navbar-form,.fuelux .navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.fuelux .navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.fuelux .nav-collapse,.fuelux .nav-collapse.collapse{height:0;overflow:hidden}.fuelux .navbar .btn-navbar{display:block}.fuelux .navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.fuelux .nav-collapse.collapse{height:auto!important;overflow:visible!important}}
\ No newline at end of file
diff --git a/opendaylight/web/root/src/main/resources/css/fuelux.min.css b/opendaylight/web/root/src/main/resources/css/fuelux.min.css
new file mode 100755 (executable)
index 0000000..314f3dc
--- /dev/null
@@ -0,0 +1,9 @@
+/*!
+ * Bootstrap v2.3.2
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */.fuelux .clearfix{*zoom:1}.fuelux .clearfix:before,.fuelux .clearfix:after{display:table;line-height:0;content:""}.fuelux .clearfix:after{clear:both}.fuelux .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.fuelux .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.fuelux article,.fuelux aside,.fuelux details,.fuelux figcaption,.fuelux figure,.fuelux footer,.fuelux header,.fuelux hgroup,.fuelux nav,.fuelux section{display:block}.fuelux audio,.fuelux canvas,.fuelux video{display:inline-block;*display:inline;*zoom:1}.fuelux audio:not([controls]){display:none}.fuelux html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}.fuelux a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.fuelux a:hover,.fuelux a:active{outline:0}.fuelux sub,.fuelux sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}.fuelux sup{top:-0.5em}.fuelux sub{bottom:-0.25em}.fuelux img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}.fuelux #map_canvas img,.fuelux .google-maps img{max-width:none}.fuelux button,.fuelux input,.fuelux select,.fuelux textarea{margin:0;font-size:100%;vertical-align:middle}.fuelux button,.fuelux input{*overflow:visible;line-height:normal}.fuelux button::-moz-focus-inner,.fuelux input::-moz-focus-inner{padding:0;border:0}.fuelux button,.fuelux html input[type="button"],.fuelux input[type="reset"],.fuelux input[type="submit"]{cursor:pointer;-webkit-appearance:button}.fuelux label,.fuelux select,.fuelux button,.fuelux input[type="button"],.fuelux input[type="reset"],.fuelux input[type="submit"],.fuelux input[type="radio"],.fuelux input[type="checkbox"]{cursor:pointer}.fuelux input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}.fuelux input[type="search"]::-webkit-search-decoration,.fuelux input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}.fuelux textarea{overflow:auto;vertical-align:top}@media print{.fuelux *{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}.fuelux a,.fuelux a:visited{text-decoration:underline}.fuelux a[href]:after{content:" (" attr(href) ")"}.fuelux abbr[title]:after{content:" (" attr(title) ")"}.fuelux .ir a:after,.fuelux a[href^="javascript:"]:after,.fuelux a[href^="#"]:after{content:""}.fuelux pre,.fuelux blockquote{border:1px solid #999;page-break-inside:avoid}.fuelux thead{display:table-header-group}.fuelux tr,.fuelux img{page-break-inside:avoid}.fuelux img{max-width:100%!important}@page{margin:.5cm}.fuelux p,.fuelux h2,.fuelux h3{widows:3;orphans:3}.fuelux h2,.fuelux h3{page-break-after:avoid}}.fuelux body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}.fuelux a{color:#08c;text-decoration:none}.fuelux a:hover,.fuelux a:focus{color:#005580;text-decoration:underline}.fuelux .img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.fuelux .img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.fuelux .img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.fuelux .row{margin-left:-20px;*zoom:1}.fuelux .row:before,.fuelux .row:after{display:table;line-height:0;content:""}.fuelux .row:after{clear:both}.fuelux [class*="span"]{float:left;min-height:1px;margin-left:20px}.fuelux .container,.fuelux .navbar-static-top .container,.fuelux .navbar-fixed-top .container,.fuelux .navbar-fixed-bottom .container{width:940px}.fuelux .span12{width:940px}.fuelux .span11{width:860px}.fuelux .span10{width:780px}.fuelux .span9{width:700px}.fuelux .span8{width:620px}.fuelux .span7{width:540px}.fuelux .span6{width:460px}.fuelux .span5{width:380px}.fuelux .span4{width:300px}.fuelux .span3{width:220px}.fuelux .span2{width:140px}.fuelux .span1{width:60px}.fuelux .offset12{margin-left:980px}.fuelux .offset11{margin-left:900px}.fuelux .offset10{margin-left:820px}.fuelux .offset9{margin-left:740px}.fuelux .offset8{margin-left:660px}.fuelux .offset7{margin-left:580px}.fuelux .offset6{margin-left:500px}.fuelux .offset5{margin-left:420px}.fuelux .offset4{margin-left:340px}.fuelux .offset3{margin-left:260px}.fuelux .offset2{margin-left:180px}.fuelux .offset1{margin-left:100px}.fuelux .row-fluid{width:100%;*zoom:1}.fuelux .row-fluid:before,.fuelux .row-fluid:after{display:table;line-height:0;content:""}.fuelux .row-fluid:after{clear:both}.fuelux .row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.fuelux .row-fluid [class*="span"]:first-child{margin-left:0}.fuelux .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.fuelux .row-fluid .span12{width:100%;*width:99.94680851063829%}.fuelux .row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.fuelux .row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.fuelux .row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.fuelux .row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.fuelux .row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.fuelux .row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.fuelux .row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.fuelux .row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.fuelux .row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.fuelux .row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.fuelux .row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.fuelux .row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.fuelux .row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.fuelux .row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.fuelux .row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.fuelux .row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.fuelux .row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.fuelux .row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.fuelux .row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.fuelux .row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.fuelux .row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.fuelux .row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.fuelux .row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.fuelux .row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.fuelux .row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.fuelux .row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.fuelux .row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.fuelux .row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.fuelux .row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.fuelux .row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.fuelux .row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.fuelux .row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.fuelux .row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.fuelux .row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.fuelux .row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}.fuelux [class*="span"].hide,.fuelux .row-fluid [class*="span"].hide{display:none}.fuelux [class*="span"].pull-right,.fuelux .row-fluid [class*="span"].pull-right{float:right}.fuelux .container{margin-right:auto;margin-left:auto;*zoom:1}.fuelux .container:before,.fuelux .container:after{display:table;line-height:0;content:""}.fuelux .container:after{clear:both}.fuelux .container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.fuelux .container-fluid:before,.fuelux .container-fluid:after{display:table;line-height:0;content:""}.fuelux .container-fluid:after{clear:both}.fuelux p{margin:0 0 10px}.fuelux .lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}.fuelux small{font-size:85%}.fuelux strong{font-weight:bold}.fuelux em{font-style:italic}.fuelux cite{font-style:normal}.fuelux .muted{color:#999}.fuelux a.muted:hover,.fuelux a.muted:focus{color:#808080}.fuelux .text-warning{color:#c09853}.fuelux a.text-warning:hover,.fuelux a.text-warning:focus{color:#a47e3c}.fuelux .text-error{color:#b94a48}.fuelux a.text-error:hover,.fuelux a.text-error:focus{color:#953b39}.fuelux .text-info{color:#3a87ad}.fuelux a.text-info:hover,.fuelux a.text-info:focus{color:#2d6987}.fuelux .text-success{color:#468847}.fuelux a.text-success:hover,.fuelux a.text-success:focus{color:#356635}.fuelux .text-left{text-align:left}.fuelux .text-right{text-align:right}.fuelux .text-center{text-align:center}.fuelux h1,.fuelux h2,.fuelux h3,.fuelux h4,.fuelux h5,.fuelux h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}.fuelux h1 small,.fuelux h2 small,.fuelux h3 small,.fuelux h4 small,.fuelux h5 small,.fuelux h6 small{font-weight:normal;line-height:1;color:#999}.fuelux h1,.fuelux h2,.fuelux h3{line-height:40px}.fuelux h1{font-size:38.5px}.fuelux h2{font-size:31.5px}.fuelux h3{font-size:24.5px}.fuelux h4{font-size:17.5px}.fuelux h5{font-size:14px}.fuelux h6{font-size:11.9px}.fuelux h1 small{font-size:24.5px}.fuelux h2 small{font-size:17.5px}.fuelux h3 small{font-size:14px}.fuelux h4 small{font-size:14px}.fuelux .page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}.fuelux ul,.fuelux ol{padding:0;margin:0 0 10px 25px}.fuelux ul ul,.fuelux ul ol,.fuelux ol ol,.fuelux ol ul{margin-bottom:0}.fuelux li{line-height:20px}.fuelux ul.unstyled,.fuelux ol.unstyled{margin-left:0;list-style:none}.fuelux ul.inline,.fuelux ol.inline{margin-left:0;list-style:none}.fuelux ul.inline>li,.fuelux ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}.fuelux dl{margin-bottom:20px}.fuelux dt,.fuelux dd{line-height:20px}.fuelux dt{font-weight:bold}.fuelux dd{margin-left:10px}.fuelux .dl-horizontal{*zoom:1}.fuelux .dl-horizontal:before,.fuelux .dl-horizontal:after{display:table;line-height:0;content:""}.fuelux .dl-horizontal:after{clear:both}.fuelux .dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.fuelux .dl-horizontal dd{margin-left:180px}.fuelux hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}.fuelux abbr[title],.fuelux abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.fuelux abbr.initialism{font-size:90%;text-transform:uppercase}.fuelux blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}.fuelux blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}.fuelux blockquote small{display:block;line-height:20px;color:#999}.fuelux blockquote small:before{content:'\2014 \00A0'}.fuelux blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}.fuelux blockquote.pull-right p,.fuelux blockquote.pull-right small{text-align:right}.fuelux blockquote.pull-right small:before{content:''}.fuelux blockquote.pull-right small:after{content:'\00A0 \2014'}.fuelux q:before,.fuelux q:after,.fuelux blockquote:before,.fuelux blockquote:after{content:""}.fuelux address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}.fuelux code,.fuelux pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fuelux code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}.fuelux pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.fuelux pre.prettyprint{margin-bottom:20px}.fuelux pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.fuelux .pre-scrollable{max-height:340px;overflow-y:scroll}.fuelux form{margin:0 0 20px}.fuelux fieldset{padding:0;margin:0;border:0}.fuelux legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}.fuelux legend small{font-size:15px;color:#999}.fuelux label,.fuelux input,.fuelux button,.fuelux select,.fuelux textarea{font-size:14px;font-weight:normal;line-height:20px}.fuelux input,.fuelux button,.fuelux select,.fuelux textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.fuelux label{display:block;margin-bottom:5px}.fuelux select,.fuelux textarea,.fuelux input[type="text"],.fuelux input[type="password"],.fuelux input[type="datetime"],.fuelux input[type="datetime-local"],.fuelux input[type="date"],.fuelux input[type="month"],.fuelux input[type="time"],.fuelux input[type="week"],.fuelux input[type="number"],.fuelux input[type="email"],.fuelux input[type="url"],.fuelux input[type="search"],.fuelux input[type="tel"],.fuelux input[type="color"],.fuelux .uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.fuelux input,.fuelux textarea,.fuelux .uneditable-input{width:206px}.fuelux textarea{height:auto}.fuelux textarea,.fuelux input[type="text"],.fuelux input[type="password"],.fuelux input[type="datetime"],.fuelux input[type="datetime-local"],.fuelux input[type="date"],.fuelux input[type="month"],.fuelux input[type="time"],.fuelux input[type="week"],.fuelux input[type="number"],.fuelux input[type="email"],.fuelux input[type="url"],.fuelux input[type="search"],.fuelux input[type="tel"],.fuelux input[type="color"],.fuelux .uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}.fuelux textarea:focus,.fuelux input[type="text"]:focus,.fuelux input[type="password"]:focus,.fuelux input[type="datetime"]:focus,.fuelux input[type="datetime-local"]:focus,.fuelux input[type="date"]:focus,.fuelux input[type="month"]:focus,.fuelux input[type="time"]:focus,.fuelux input[type="week"]:focus,.fuelux input[type="number"]:focus,.fuelux input[type="email"]:focus,.fuelux input[type="url"]:focus,.fuelux input[type="search"]:focus,.fuelux input[type="tel"]:focus,.fuelux input[type="color"]:focus,.fuelux .uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}.fuelux input[type="radio"],.fuelux input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}.fuelux input[type="file"],.fuelux input[type="image"],.fuelux input[type="submit"],.fuelux input[type="reset"],.fuelux input[type="button"],.fuelux input[type="radio"],.fuelux input[type="checkbox"]{width:auto}.fuelux select,.fuelux input[type="file"]{height:30px;*margin-top:4px;line-height:30px}.fuelux select{width:220px;background-color:#fff;border:1px solid #ccc}.fuelux select[multiple],.fuelux select[size]{height:auto}.fuelux select:focus,.fuelux input[type="file"]:focus,.fuelux input[type="radio"]:focus,.fuelux input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.fuelux .uneditable-input,.fuelux .uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.fuelux .uneditable-input{overflow:hidden;white-space:nowrap}.fuelux .uneditable-textarea{width:auto;height:auto}.fuelux input:-moz-placeholder,.fuelux textarea:-moz-placeholder{color:#999}.fuelux input:-ms-input-placeholder,.fuelux textarea:-ms-input-placeholder{color:#999}.fuelux input::-webkit-input-placeholder,.fuelux textarea::-webkit-input-placeholder{color:#999}.fuelux .radio,.fuelux .checkbox{min-height:20px;padding-left:20px}.fuelux .radio input[type="radio"],.fuelux .checkbox input[type="checkbox"]{float:left;margin-left:-20px}.fuelux .controls>.radio:first-child,.fuelux .controls>.checkbox:first-child{padding-top:5px}.fuelux .radio.inline,.fuelux .checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.fuelux .radio.inline+.radio.inline,.fuelux .checkbox.inline+.checkbox.inline{margin-left:10px}.fuelux .input-mini{width:60px}.fuelux .input-small{width:90px}.fuelux .input-medium{width:150px}.fuelux .input-large{width:210px}.fuelux .input-xlarge{width:270px}.fuelux .input-xxlarge{width:530px}.fuelux input[class*="span"],.fuelux select[class*="span"],.fuelux textarea[class*="span"],.fuelux .uneditable-input[class*="span"],.fuelux .row-fluid input[class*="span"],.fuelux .row-fluid select[class*="span"],.fuelux .row-fluid textarea[class*="span"],.fuelux .row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.fuelux .input-append input[class*="span"],.fuelux .input-append .uneditable-input[class*="span"],.fuelux .input-prepend input[class*="span"],.fuelux .input-prepend .uneditable-input[class*="span"],.fuelux .row-fluid input[class*="span"],.fuelux .row-fluid select[class*="span"],.fuelux .row-fluid textarea[class*="span"],.fuelux .row-fluid .uneditable-input[class*="span"],.fuelux .row-fluid .input-prepend [class*="span"],.fuelux .row-fluid .input-append [class*="span"]{display:inline-block}.fuelux input,.fuelux textarea,.fuelux .uneditable-input{margin-left:0}.fuelux .controls-row [class*="span"]+[class*="span"]{margin-left:20px}.fuelux input.span12,textarea.span12,.uneditable-input.span12{width:926px}.fuelux input.span11,textarea.span11,.uneditable-input.span11{width:846px}.fuelux input.span10,textarea.span10,.uneditable-input.span10{width:766px}.fuelux input.span9,textarea.span9,.uneditable-input.span9{width:686px}.fuelux input.span8,textarea.span8,.uneditable-input.span8{width:606px}.fuelux input.span7,textarea.span7,.uneditable-input.span7{width:526px}.fuelux input.span6,textarea.span6,.uneditable-input.span6{width:446px}.fuelux input.span5,textarea.span5,.uneditable-input.span5{width:366px}.fuelux input.span4,textarea.span4,.uneditable-input.span4{width:286px}.fuelux input.span3,textarea.span3,.uneditable-input.span3{width:206px}.fuelux input.span2,textarea.span2,.uneditable-input.span2{width:126px}.fuelux input.span1,textarea.span1,.uneditable-input.span1{width:46px}.fuelux .controls-row{*zoom:1}.fuelux .controls-row:before,.fuelux .controls-row:after{display:table;line-height:0;content:""}.fuelux .controls-row:after{clear:both}.fuelux .controls-row [class*="span"],.fuelux .row-fluid .controls-row [class*="span"]{float:left}.fuelux .controls-row .checkbox[class*="span"],.fuelux .controls-row .radio[class*="span"]{padding-top:5px}.fuelux input[disabled],.fuelux select[disabled],.fuelux textarea[disabled],.fuelux input[readonly],.fuelux select[readonly],.fuelux textarea[readonly]{cursor:not-allowed;background-color:#eee}.fuelux input[type="radio"][disabled],.fuelux input[type="checkbox"][disabled],.fuelux input[type="radio"][readonly],.fuelux input[type="checkbox"][readonly]{background-color:transparent}.fuelux .control-group.warning .control-label,.fuelux .control-group.warning .help-block,.fuelux .control-group.warning .help-inline{color:#c09853}.fuelux .control-group.warning .checkbox,.fuelux .control-group.warning .radio,.fuelux .control-group.warning input,.fuelux .control-group.warning select,.fuelux .control-group.warning textarea{color:#c09853}.fuelux .control-group.warning input,.fuelux .control-group.warning select,.fuelux .control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.fuelux .control-group.warning input:focus,.fuelux .control-group.warning select:focus,.fuelux .control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.fuelux .control-group.warning .input-prepend .add-on,.fuelux .control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.fuelux .control-group.error .control-label,.fuelux .control-group.error .help-block,.fuelux .control-group.error .help-inline{color:#b94a48}.fuelux .control-group.error .checkbox,.fuelux .control-group.error .radio,.fuelux .control-group.error input,.fuelux .control-group.error select,.fuelux .control-group.error textarea{color:#b94a48}.fuelux .control-group.error input,.fuelux .control-group.error select,.fuelux .control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.fuelux .control-group.error input:focus,.fuelux .control-group.error select:focus,.fuelux .control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.fuelux .control-group.error .input-prepend .add-on,.fuelux .control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.fuelux .control-group.success .control-label,.fuelux .control-group.success .help-block,.fuelux .control-group.success .help-inline{color:#468847}.fuelux .control-group.success .checkbox,.fuelux .control-group.success .radio,.fuelux .control-group.success input,.fuelux .control-group.success select,.fuelux .control-group.success textarea{color:#468847}.fuelux .control-group.success input,.fuelux .control-group.success select,.fuelux .control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.fuelux .control-group.success input:focus,.fuelux .control-group.success select:focus,.fuelux .control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.fuelux .control-group.success .input-prepend .add-on,.fuelux .control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.fuelux .control-group.info .control-label,.fuelux .control-group.info .help-block,.fuelux .control-group.info .help-inline{color:#3a87ad}.fuelux .control-group.info .checkbox,.fuelux .control-group.info .radio,.fuelux .control-group.info input,.fuelux .control-group.info select,.fuelux .control-group.info textarea{color:#3a87ad}.fuelux .control-group.info input,.fuelux .control-group.info select,.fuelux .control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.fuelux .control-group.info input:focus,.fuelux .control-group.info select:focus,.fuelux .control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.fuelux .control-group.info .input-prepend .add-on,.fuelux .control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}.fuelux input:focus:invalid,.fuelux textarea:focus:invalid,.fuelux select:focus:invalid{color:#b94a48;border-color:#ee5f5b}.fuelux input:focus:invalid:focus,.fuelux textarea:focus:invalid:focus,.fuelux select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.fuelux .form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.fuelux .form-actions:before,.fuelux .form-actions:after{display:table;line-height:0;content:""}.fuelux .form-actions:after{clear:both}.fuelux .help-block,.fuelux .help-inline{color:#595959}.fuelux .help-block{display:block;margin-bottom:10px}.fuelux .help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.fuelux .input-append,.fuelux .input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.fuelux .input-append input,.fuelux .input-prepend input,.fuelux .input-append select,.fuelux .input-prepend select,.fuelux .input-append .uneditable-input,.fuelux .input-prepend .uneditable-input,.fuelux .input-append .dropdown-menu,.fuelux .input-prepend .dropdown-menu,.fuelux .input-append .popover,.fuelux .input-prepend .popover{font-size:14px}.fuelux .input-append input,.fuelux .input-prepend input,.fuelux .input-append select,.fuelux .input-prepend select,.fuelux .input-append .uneditable-input,.fuelux .input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.fuelux .input-append input:focus,.fuelux .input-prepend input:focus,.fuelux .input-append select:focus,.fuelux .input-prepend select:focus,.fuelux .input-append .uneditable-input:focus,.fuelux .input-prepend .uneditable-input:focus{z-index:2}.fuelux .input-append .add-on,.fuelux .input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.fuelux .input-append .add-on,.fuelux .input-prepend .add-on,.fuelux .input-append .btn,.fuelux .input-prepend .btn,.fuelux .input-append .btn-group>.dropdown-toggle,.fuelux .input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.fuelux .input-append .active,.fuelux .input-prepend .active{background-color:#a9dba9;border-color:#46a546}.fuelux .input-prepend .add-on,.fuelux .input-prepend .btn{margin-right:-1px}.fuelux .input-prepend .add-on:first-child,.fuelux .input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.fuelux .input-append input,.fuelux .input-append select,.fuelux .input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.fuelux .input-append input+.btn-group .btn:last-child,.fuelux .input-append select+.btn-group .btn:last-child,.fuelux .input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.fuelux .input-append .add-on,.fuelux .input-append .btn,.fuelux .input-append .btn-group{margin-left:-1px}.fuelux .input-append .add-on:last-child,.fuelux .input-append .btn:last-child,.fuelux .input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.fuelux .input-prepend.input-append input,.fuelux .input-prepend.input-append select,.fuelux .input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.fuelux .input-prepend.input-append input+.btn-group .btn,.fuelux .input-prepend.input-append select+.btn-group .btn,.fuelux .input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.fuelux .input-prepend.input-append .add-on:first-child,.fuelux .input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.fuelux .input-prepend.input-append .add-on:last-child,.fuelux .input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.fuelux .input-prepend.input-append .btn-group:first-child{margin-left:0}.fuelux input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.fuelux .form-search .input-append .search-query,.fuelux .form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.fuelux .form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.fuelux .form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.fuelux .form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.fuelux .form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.fuelux .form-search input,.fuelux .form-inline input,.fuelux .form-horizontal input,.fuelux .form-search textarea,.fuelux .form-inline textarea,.fuelux .form-horizontal textarea,.fuelux .form-search select,.fuelux .form-inline select,.fuelux .form-horizontal select,.fuelux .form-search .help-inline,.fuelux .form-inline .help-inline,.fuelux .form-horizontal .help-inline,.fuelux .form-search .uneditable-input,.fuelux .form-inline .uneditable-input,.fuelux .form-horizontal .uneditable-input,.fuelux .form-search .input-prepend,.fuelux .form-inline .input-prepend,.fuelux .form-horizontal .input-prepend,.fuelux .form-search .input-append,.fuelux .form-inline .input-append,.fuelux .form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.fuelux .form-search .hide,.fuelux .form-inline .hide,.fuelux .form-horizontal .hide{display:none}.fuelux .form-search label,.fuelux .form-inline label,.fuelux .form-search .btn-group,.fuelux .form-inline .btn-group{display:inline-block}.fuelux .form-search .input-append,.fuelux .form-inline .input-append,.fuelux .form-search .input-prepend,.fuelux .form-inline .input-prepend{margin-bottom:0}.fuelux .form-search .radio,.fuelux .form-search .checkbox,.fuelux .form-inline .radio,.fuelux .form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.fuelux .form-search .radio input[type="radio"],.fuelux .form-search .checkbox input[type="checkbox"],.fuelux .form-inline .radio input[type="radio"],.fuelux .form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.fuelux .control-group{margin-bottom:10px}.fuelux legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.fuelux .form-horizontal .control-group{margin-bottom:20px;*zoom:1}.fuelux .form-horizontal .control-group:before,.fuelux .form-horizontal .control-group:after{display:table;line-height:0;content:""}.fuelux .form-horizontal .control-group:after{clear:both}.fuelux .form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.fuelux .form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.fuelux .form-horizontal .controls:first-child{*padding-left:180px}.fuelux .form-horizontal .help-block{margin-bottom:0}.fuelux .form-horizontal input+.help-block,.fuelux .form-horizontal select+.help-block,.fuelux .form-horizontal textarea+.help-block,.fuelux .form-horizontal .uneditable-input+.help-block,.fuelux .form-horizontal .input-prepend+.help-block,.fuelux .form-horizontal .input-append+.help-block{margin-top:10px}.fuelux .form-horizontal .form-actions{padding-left:180px}.fuelux table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.fuelux .table{width:100%;margin-bottom:20px}.fuelux .table th,.fuelux .table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.fuelux .table th{font-weight:bold}.fuelux .table thead th{vertical-align:bottom}.fuelux .table caption+thead tr:first-child th,.fuelux .table caption+thead tr:first-child td,.fuelux .table colgroup+thead tr:first-child th,.fuelux .table colgroup+thead tr:first-child td,.fuelux .table thead:first-child tr:first-child th,.fuelux .table thead:first-child tr:first-child td{border-top:0}.fuelux .table tbody+tbody{border-top:2px solid #ddd}.fuelux .table .table{background-color:#fff}.fuelux .table-condensed th,.fuelux .table-condensed td{padding:4px 5px}.fuelux .table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.fuelux .table-bordered th,.fuelux .table-bordered td{border-left:1px solid #ddd}.fuelux .table-bordered caption+thead tr:first-child th,.fuelux .table-bordered caption+tbody tr:first-child th,.fuelux .table-bordered caption+tbody tr:first-child td,.fuelux .table-bordered colgroup+thead tr:first-child th,.fuelux .table-bordered colgroup+tbody tr:first-child th,.fuelux .table-bordered colgroup+tbody tr:first-child td,.fuelux .table-bordered thead:first-child tr:first-child th,.fuelux .table-bordered tbody:first-child tr:first-child th,.fuelux .table-bordered tbody:first-child tr:first-child td{border-top:0}.fuelux .table-bordered thead:first-child tr:first-child>th:first-child,.fuelux .table-bordered tbody:first-child tr:first-child>td:first-child,.fuelux .table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.fuelux .table-bordered thead:first-child tr:first-child>th:last-child,.fuelux .table-bordered tbody:first-child tr:first-child>td:last-child,.fuelux .table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.fuelux .table-bordered thead:last-child tr:last-child>th:first-child,.fuelux .table-bordered tbody:last-child tr:last-child>td:first-child,.fuelux .table-bordered tbody:last-child tr:last-child>th:first-child,.fuelux .table-bordered tfoot:last-child tr:last-child>td:first-child,.fuelux .table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.fuelux .table-bordered thead:last-child tr:last-child>th:last-child,.fuelux .table-bordered tbody:last-child tr:last-child>td:last-child,.fuelux .table-bordered tbody:last-child tr:last-child>th:last-child,.fuelux .table-bordered tfoot:last-child tr:last-child>td:last-child,.fuelux .table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.fuelux .table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.fuelux .table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.fuelux .table-bordered caption+thead tr:first-child th:first-child,.fuelux .table-bordered caption+tbody tr:first-child td:first-child,.fuelux .table-bordered colgroup+thead tr:first-child th:first-child,.fuelux .table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.fuelux .table-bordered caption+thead tr:first-child th:last-child,.fuelux .table-bordered caption+tbody tr:first-child td:last-child,.fuelux .table-bordered colgroup+thead tr:first-child th:last-child,.fuelux .table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.fuelux .table-striped tbody>tr:nth-child(odd)>td,.fuelux .table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.fuelux .table-hover tbody tr:hover>td,.fuelux .table-hover tbody tr:hover>th{background-color:#f5f5f5}.fuelux table td[class*="span"],.fuelux table th[class*="span"],.fuelux .row-fluid table td[class*="span"],.fuelux .row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.fuelux .table td.span1,.fuelux .table th.span1{float:none;width:44px;margin-left:0}.fuelux .table td.span2,.fuelux .table th.span2{float:none;width:124px;margin-left:0}.fuelux .table td.span3,.fuelux .table th.span3{float:none;width:204px;margin-left:0}.fuelux .table td.span4,.fuelux .table th.span4{float:none;width:284px;margin-left:0}.fuelux .table td.span5,.fuelux .table th.span5{float:none;width:364px;margin-left:0}.fuelux .table td.span6,.fuelux .table th.span6{float:none;width:444px;margin-left:0}.fuelux .table td.span7,.fuelux .table th.span7{float:none;width:524px;margin-left:0}.fuelux .table td.span8,.fuelux .table th.span8{float:none;width:604px;margin-left:0}.fuelux .table td.span9,.fuelux .table th.span9{float:none;width:684px;margin-left:0}.fuelux .table td.span10,.fuelux .table th.span10{float:none;width:764px;margin-left:0}.fuelux .table td.span11,.fuelux .table th.span11{float:none;width:844px;margin-left:0}.fuelux .table td.span12,.fuelux .table th.span12{float:none;width:924px;margin-left:0}.fuelux .table tbody tr.success>td{background-color:#dff0d8}.fuelux .table tbody tr.error>td{background-color:#f2dede}.fuelux .table tbody tr.warning>td{background-color:#fcf8e3}.fuelux .table tbody tr.info>td{background-color:#d9edf7}.fuelux .table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.fuelux .table-hover tbody tr.error:hover>td{background-color:#ebcccc}.fuelux .table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.fuelux .table-hover tbody tr.info:hover>td{background-color:#c4e3f3}.fuelux [class^="icon-"],.fuelux [class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.fuelux .icon-white,.fuelux .nav-pills>.active>a>[class^="icon-"],.fuelux .nav-pills>.active>a>[class*=" icon-"],.fuelux .nav-list>.active>a>[class^="icon-"],.fuelux .nav-list>.active>a>[class*=" icon-"],.fuelux .navbar-inverse .nav>.active>a>[class^="icon-"],.fuelux .navbar-inverse .nav>.active>a>[class*=" icon-"],.fuelux .dropdown-menu>li>a:hover>[class^="icon-"],.fuelux .dropdown-menu>li>a:focus>[class^="icon-"],.fuelux .dropdown-menu>li>a:hover>[class*=" icon-"],.fuelux .dropdown-menu>li>a:focus>[class*=" icon-"],.fuelux .dropdown-menu>.active>a>[class^="icon-"],.fuelux .dropdown-menu>.active>a>[class*=" icon-"],.fuelux .dropdown-submenu:hover>a>[class^="icon-"],.fuelux .dropdown-submenu:focus>a>[class^="icon-"],.fuelux .dropdown-submenu:hover>a>[class*=" icon-"],.fuelux .dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.fuelux .icon-glass{background-position:0 0}.fuelux .icon-music{background-position:-24px 0}.fuelux .icon-search{background-position:-48px 0}.fuelux .icon-envelope{background-position:-72px 0}.fuelux .icon-heart{background-position:-96px 0}.fuelux .icon-star{background-position:-120px 0}.fuelux .icon-star-empty{background-position:-144px 0}.fuelux .icon-user{background-position:-168px 0}.fuelux .icon-film{background-position:-192px 0}.fuelux .icon-th-large{background-position:-216px 0}.fuelux .icon-th{background-position:-240px 0}.fuelux .icon-th-list{background-position:-264px 0}.fuelux .icon-ok{background-position:-288px 0}.fuelux .icon-remove{background-position:-312px 0}.fuelux .icon-zoom-in{background-position:-336px 0}.fuelux .icon-zoom-out{background-position:-360px 0}.fuelux .icon-off{background-position:-384px 0}.fuelux .icon-signal{background-position:-408px 0}.fuelux .icon-cog{background-position:-432px 0}.fuelux .icon-trash{background-position:-456px 0}.fuelux .icon-home{background-position:0 -24px}.fuelux .icon-file{background-position:-24px -24px}.fuelux .icon-time{background-position:-48px -24px}.fuelux .icon-road{background-position:-72px -24px}.fuelux .icon-download-alt{background-position:-96px -24px}.fuelux .icon-download{background-position:-120px -24px}.fuelux .icon-upload{background-position:-144px -24px}.fuelux .icon-inbox{background-position:-168px -24px}.fuelux .icon-play-circle{background-position:-192px -24px}.fuelux .icon-repeat{background-position:-216px -24px}.fuelux .icon-refresh{background-position:-240px -24px}.fuelux .icon-list-alt{background-position:-264px -24px}.fuelux .icon-lock{background-position:-287px -24px}.fuelux .icon-flag{background-position:-312px -24px}.fuelux .icon-headphones{background-position:-336px -24px}.fuelux .icon-volume-off{background-position:-360px -24px}.fuelux .icon-volume-down{background-position:-384px -24px}.fuelux .icon-volume-up{background-position:-408px -24px}.fuelux .icon-qrcode{background-position:-432px -24px}.fuelux .icon-barcode{background-position:-456px -24px}.fuelux .icon-tag{background-position:0 -48px}.fuelux .icon-tags{background-position:-25px -48px}.fuelux .icon-book{background-position:-48px -48px}.fuelux .icon-bookmark{background-position:-72px -48px}.fuelux .icon-print{background-position:-96px -48px}.fuelux .icon-camera{background-position:-120px -48px}.fuelux .icon-font{background-position:-144px -48px}.fuelux .icon-bold{background-position:-167px -48px}.fuelux .icon-italic{background-position:-192px -48px}.fuelux .icon-text-height{background-position:-216px -48px}.fuelux .icon-text-width{background-position:-240px -48px}.fuelux .icon-align-left{background-position:-264px -48px}.fuelux .icon-align-center{background-position:-288px -48px}.fuelux .icon-align-right{background-position:-312px -48px}.fuelux .icon-align-justify{background-position:-336px -48px}.fuelux .icon-list{background-position:-360px -48px}.fuelux .icon-indent-left{background-position:-384px -48px}.fuelux .icon-indent-right{background-position:-408px -48px}.fuelux .icon-facetime-video{background-position:-432px -48px}.fuelux .icon-picture{background-position:-456px -48px}.fuelux .icon-pencil{background-position:0 -72px}.fuelux .icon-map-marker{background-position:-24px -72px}.fuelux .icon-adjust{background-position:-48px -72px}.fuelux .icon-tint{background-position:-72px -72px}.fuelux .icon-edit{background-position:-96px -72px}.fuelux .icon-share{background-position:-120px -72px}.fuelux .icon-check{background-position:-144px -72px}.fuelux .icon-move{background-position:-168px -72px}.fuelux .icon-step-backward{background-position:-192px -72px}.fuelux .icon-fast-backward{background-position:-216px -72px}.fuelux .icon-backward{background-position:-240px -72px}.fuelux .icon-play{background-position:-264px -72px}.fuelux .icon-pause{background-position:-288px -72px}.fuelux .icon-stop{background-position:-312px -72px}.fuelux .icon-forward{background-position:-336px -72px}.fuelux .icon-fast-forward{background-position:-360px -72px}.fuelux .icon-step-forward{background-position:-384px -72px}.fuelux .icon-eject{background-position:-408px -72px}.fuelux .icon-chevron-left{background-position:-432px -72px}.fuelux .icon-chevron-right{background-position:-456px -72px}.fuelux .icon-plus-sign{background-position:0 -96px}.fuelux .icon-minus-sign{background-position:-24px -96px}.fuelux .icon-remove-sign{background-position:-48px -96px}.fuelux .icon-ok-sign{background-position:-72px -96px}.fuelux .icon-question-sign{background-position:-96px -96px}.fuelux .icon-info-sign{background-position:-120px -96px}.fuelux .icon-screenshot{background-position:-144px -96px}.fuelux .icon-remove-circle{background-position:-168px -96px}.fuelux .icon-ok-circle{background-position:-192px -96px}.fuelux .icon-ban-circle{background-position:-216px -96px}.fuelux .icon-arrow-left{background-position:-240px -96px}.fuelux .icon-arrow-right{background-position:-264px -96px}.fuelux .icon-arrow-up{background-position:-289px -96px}.fuelux .icon-arrow-down{background-position:-312px -96px}.fuelux .icon-share-alt{background-position:-336px -96px}.fuelux .icon-resize-full{background-position:-360px -96px}.fuelux .icon-resize-small{background-position:-384px -96px}.fuelux .icon-plus{background-position:-408px -96px}.fuelux .icon-minus{background-position:-433px -96px}.fuelux .icon-asterisk{background-position:-456px -96px}.fuelux .icon-exclamation-sign{background-position:0 -120px}.fuelux .icon-gift{background-position:-24px -120px}.fuelux .icon-leaf{background-position:-48px -120px}.fuelux .icon-fire{background-position:-72px -120px}.fuelux .icon-eye-open{background-position:-96px -120px}.fuelux .icon-eye-close{background-position:-120px -120px}.fuelux .icon-warning-sign{background-position:-144px -120px}.fuelux .icon-plane{background-position:-168px -120px}.fuelux .icon-calendar{background-position:-192px -120px}.fuelux .icon-random{width:16px;background-position:-216px -120px}.fuelux .icon-comment{background-position:-240px -120px}.fuelux .icon-magnet{background-position:-264px -120px}.fuelux .icon-chevron-up{background-position:-288px -120px}.fuelux .icon-chevron-down{background-position:-313px -119px}.fuelux .icon-retweet{background-position:-336px -120px}.fuelux .icon-shopping-cart{background-position:-360px -120px}.fuelux .icon-folder-close{width:16px;background-position:-384px -120px}.fuelux .icon-folder-open{width:16px;background-position:-408px -120px}.fuelux .icon-resize-vertical{background-position:-432px -119px}.fuelux .icon-resize-horizontal{background-position:-456px -118px}.fuelux .icon-hdd{background-position:0 -144px}.fuelux .icon-bullhorn{background-position:-24px -144px}.fuelux .icon-bell{background-position:-48px -144px}.fuelux .icon-certificate{background-position:-72px -144px}.fuelux .icon-thumbs-up{background-position:-96px -144px}.fuelux .icon-thumbs-down{background-position:-120px -144px}.fuelux .icon-hand-right{background-position:-144px -144px}.fuelux .icon-hand-left{background-position:-168px -144px}.fuelux .icon-hand-up{background-position:-192px -144px}.fuelux .icon-hand-down{background-position:-216px -144px}.fuelux .icon-circle-arrow-right{background-position:-240px -144px}.fuelux .icon-circle-arrow-left{background-position:-264px -144px}.fuelux .icon-circle-arrow-up{background-position:-288px -144px}.fuelux .icon-circle-arrow-down{background-position:-312px -144px}.fuelux .icon-globe{background-position:-336px -144px}.fuelux .icon-wrench{background-position:-360px -144px}.fuelux .icon-tasks{background-position:-384px -144px}.fuelux .icon-filter{background-position:-408px -144px}.fuelux .icon-briefcase{background-position:-432px -144px}.fuelux .icon-fullscreen{background-position:-456px -144px}.fuelux .dropup,.fuelux .dropdown{position:relative}.fuelux .dropdown-toggle{*margin-bottom:-3px}.fuelux .dropdown-toggle:active,.fuelux .open .dropdown-toggle{outline:0}.fuelux .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.fuelux .dropdown .caret{margin-top:8px;margin-left:2px}.fuelux .dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.fuelux .dropdown-menu.pull-right{right:0;left:auto}.fuelux .dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.fuelux .dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.fuelux .dropdown-menu>li>a:hover,.fuelux .dropdown-menu>li>a:focus,.fuelux .dropdown-submenu:hover>a,.fuelux .dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.fuelux .dropdown-menu>.active>a,.fuelux .dropdown-menu>.active>a:hover,.fuelux .dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.fuelux .dropdown-menu>.disabled>a,.fuelux .dropdown-menu>.disabled>a:hover,.fuelux .dropdown-menu>.disabled>a:focus{color:#999}.fuelux .dropdown-menu>.disabled>a:hover,.fuelux .dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.fuelux .open{*z-index:1000}.fuelux .open>.dropdown-menu{display:block}.fuelux .dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.fuelux .pull-right>.dropdown-menu{right:0;left:auto}.fuelux .dropup .caret,.fuelux .navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.fuelux .dropup .dropdown-menu,.fuelux .navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.fuelux .dropdown-submenu{position:relative}.fuelux .dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.fuelux .dropdown-submenu:hover>.dropdown-menu{display:block}.fuelux .dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.fuelux .dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.fuelux .dropdown-submenu:hover>a:after{border-left-color:#fff}.fuelux .dropdown-submenu.pull-left{float:none}.fuelux .dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.fuelux .dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.fuelux .typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.fuelux .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.fuelux .well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.fuelux .well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.fuelux .well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fuelux .fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fuelux .fade.in{opacity:1}.fuelux .collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.fuelux .collapse.in{height:auto}.fuelux .close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.fuelux .close:hover,.fuelux .close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}.fuelux button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.fuelux .btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.fuelux .btn:hover,.fuelux .btn:focus,.fuelux .btn:active,.fuelux .btn.active,.fuelux .btn.disabled,.fuelux .btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.fuelux .btn:active,.fuelux .btn.active{background-color:#ccc \9}.fuelux .btn:first-child{*margin-left:0}.fuelux .btn:hover,.fuelux .btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.fuelux .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.fuelux .btn.active,.fuelux .btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.fuelux .btn.disabled,.fuelux .btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.fuelux .btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.fuelux .btn-large [class^="icon-"],.fuelux .btn-large [class*=" icon-"]{margin-top:4px}.fuelux .btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fuelux .btn-small [class^="icon-"],.fuelux .btn-small [class*=" icon-"]{margin-top:0}.fuelux .btn-mini [class^="icon-"],.fuelux .btn-mini [class*=" icon-"]{margin-top:-1px}.fuelux .btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fuelux .btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.fuelux .btn-block+.btn-block{margin-top:5px}.fuelux input[type="submit"].btn-block,.fuelux input[type="reset"].btn-block,.fuelux input[type="button"].btn-block{width:100%}.fuelux .btn-primary.active,.fuelux .btn-warning.active,.fuelux .btn-danger.active,.fuelux .btn-success.active,.fuelux .btn-info.active,.fuelux .btn-inverse.active{color:rgba(255,255,255,0.75)}.fuelux .btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-image:-moz-linear-gradient(top,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.fuelux .btn-primary:hover,.fuelux .btn-primary:focus,.fuelux .btn-primary:active,.fuelux .btn-primary.active,.fuelux .btn-primary.disabled,.fuelux .btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.fuelux .btn-primary:active,.fuelux .btn-primary.active{background-color:#039 \9}.fuelux .btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.fuelux .btn-warning:hover,.fuelux .btn-warning:focus,.fuelux .btn-warning:active,.fuelux .btn-warning.active,.fuelux .btn-warning.disabled,.fuelux .btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.fuelux .btn-warning:active,.fuelux .btn-warning.active{background-color:#c67605 \9}.fuelux .btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.fuelux .btn-danger:hover,.fuelux .btn-danger:focus,.fuelux .btn-danger:active,.fuelux .btn-danger.active,.fuelux .btn-danger.disabled,.fuelux .btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.fuelux .btn-danger:active,.fuelux .btn-danger.active{background-color:#942a25 \9}.fuelux .btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-image:-moz-linear-gradient(top,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.fuelux .btn-success:hover,.fuelux .btn-success:focus,.fuelux .btn-success:active,.fuelux .btn-success.active,.fuelux .btn-success.disabled,.fuelux .btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.fuelux .btn-success:active,.fuelux .btn-success.active{background-color:#408140 \9}.fuelux .btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.fuelux .btn-info:hover,.fuelux .btn-info:focus,.fuelux .btn-info:active,.fuelux .btn-info.active,.fuelux .btn-info.disabled,.fuelux .btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.fuelux .btn-info:active,.fuelux .btn-info.active{background-color:#24748c \9}.fuelux .btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-image:-moz-linear-gradient(top,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.fuelux .btn-inverse:hover,.fuelux .btn-inverse:focus,.fuelux .btn-inverse:active,.fuelux .btn-inverse.active,.fuelux .btn-inverse.disabled,.fuelux .btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.fuelux .btn-inverse:active,.fuelux .btn-inverse.active{background-color:#080808 \9}.fuelux button.btn,.fuelux input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}.fuelux button.btn::-moz-focus-inner,.fuelux input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}.fuelux button.btn.btn-large,.fuelux input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}.fuelux button.btn.btn-small,.fuelux input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}.fuelux button.btn.btn-mini,.fuelux input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.fuelux .btn-link,.fuelux .btn-link:active,.fuelux .btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.fuelux .btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.fuelux .btn-link:hover,.fuelux .btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.fuelux .btn-link[disabled]:hover,.fuelux .btn-link[disabled]:focus{color:#333;text-decoration:none}.fuelux .btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.fuelux .btn-group:first-child{*margin-left:0}.fuelux .btn-group+.btn-group{margin-left:5px}.fuelux .btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.fuelux .btn-toolbar>.btn+.btn,.fuelux .btn-toolbar>.btn-group+.btn,.fuelux .btn-toolbar>.btn+.btn-group{margin-left:5px}.fuelux .btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.fuelux .btn-group>.btn+.btn{margin-left:-1px}.fuelux .btn-group>.btn,.fuelux .btn-group>.dropdown-menu,.fuelux .btn-group>.popover{font-size:14px}.fuelux .btn-group>.btn-mini{font-size:10.5px}.fuelux .btn-group>.btn-small{font-size:11.9px}.fuelux .btn-group>.btn-large{font-size:17.5px}.fuelux .btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.fuelux .btn-group>.btn:last-child,.fuelux .btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.fuelux .btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.fuelux .btn-group>.btn.large:last-child,.fuelux .btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.fuelux .btn-group>.btn:hover,.fuelux .btn-group>.btn:focus,.fuelux .btn-group>.btn:active,.fuelux .btn-group>.btn.active{z-index:2}.fuelux .btn-group .dropdown-toggle:active,.fuelux .btn-group.open .dropdown-toggle{outline:0}.fuelux .btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.fuelux .btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.fuelux .btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.fuelux .btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.fuelux .btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.fuelux .btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.fuelux .btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.fuelux .btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.fuelux .btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.fuelux .btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.fuelux .btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.fuelux .btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.fuelux .btn .caret{margin-top:8px;margin-left:0}.fuelux .btn-large .caret{margin-top:6px}.fuelux .btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.fuelux .btn-mini .caret,.fuelux .btn-small .caret{margin-top:8px}.fuelux .dropup .btn-large .caret{border-bottom-width:5px}.fuelux .btn-primary .caret,.fuelux .btn-warning .caret,.fuelux .btn-danger .caret,.fuelux .btn-info .caret,.fuelux .btn-success .caret,.fuelux .btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.fuelux .btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.fuelux .btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.fuelux .btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.fuelux .btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.fuelux .btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.fuelux .btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.fuelux .btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.fuelux .alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.fuelux .alert,.fuelux .alert h4{color:#c09853}.fuelux .alert h4{margin:0}.fuelux .alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.fuelux .alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.fuelux .alert-success h4{color:#468847}.fuelux .alert-danger,.fuelux .alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.fuelux .alert-danger h4,.fuelux .alert-error h4{color:#b94a48}.fuelux .alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.fuelux .alert-info h4{color:#3a87ad}.fuelux .alert-block{padding-top:14px;padding-bottom:14px}.fuelux .alert-block>p,.fuelux .alert-block>ul{margin-bottom:0}.fuelux .alert-block p+p{margin-top:5px}.fuelux .nav{margin-bottom:20px;margin-left:0;list-style:none}.fuelux .nav>li>a{display:block}.fuelux .nav>li>a:hover,.fuelux .nav>li>a:focus{text-decoration:none;background-color:#eee}.fuelux .nav>li>a>img{max-width:none}.fuelux .nav>.pull-right{float:right}.fuelux .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.fuelux .nav li+.nav-header{margin-top:9px}.fuelux .nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.fuelux .nav-list>li>a,.fuelux .nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.fuelux .nav-list>li>a{padding:3px 15px}.fuelux .nav-list>.active>a,.fuelux .nav-list>.active>a:hover,.fuelux .nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.fuelux .nav-list [class^="icon-"],.fuelux .nav-list [class*=" icon-"]{margin-right:2px}.fuelux .nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.fuelux .nav-tabs,.fuelux .nav-pills{*zoom:1}.fuelux .nav-tabs:before,.fuelux .nav-pills:before,.fuelux .nav-tabs:after,.fuelux .nav-pills:after{display:table;line-height:0;content:""}.fuelux .nav-tabs:after,.fuelux .nav-pills:after{clear:both}.fuelux .nav-tabs>li,.fuelux .nav-pills>li{float:left}.fuelux .nav-tabs>li>a,.fuelux .nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.fuelux .nav-tabs{border-bottom:1px solid #ddd}.fuelux .nav-tabs>li{margin-bottom:-1px}.fuelux .nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.fuelux .nav-tabs>li>a:hover,.fuelux .nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.fuelux .nav-tabs>.active>a,.fuelux .nav-tabs>.active>a:hover,.fuelux .nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.fuelux .nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.fuelux .nav-pills>.active>a,.fuelux .nav-pills>.active>a:hover,.fuelux .nav-pills>.active>a:focus{color:#fff;background-color:#08c}.fuelux .nav-stacked>li{float:none}.fuelux .nav-stacked>li>a{margin-right:0}.fuelux .nav-tabs.nav-stacked{border-bottom:0}.fuelux .nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.fuelux .nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.fuelux .nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.fuelux .nav-tabs.nav-stacked>li>a:hover,.fuelux .nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.fuelux .nav-pills.nav-stacked>li>a{margin-bottom:3px}.fuelux .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.fuelux .nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.fuelux .nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.fuelux .nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.fuelux .nav .dropdown-toggle:hover .caret,.fuelux .nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.fuelux .nav-tabs .dropdown-toggle .caret{margin-top:8px}.fuelux .nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.fuelux .nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.fuelux .nav>.dropdown.active>a:hover,.fuelux .nav>.dropdown.active>a:focus{cursor:pointer}.fuelux .nav-tabs .open .dropdown-toggle,.fuelux .nav-pills .open .dropdown-toggle,.fuelux .nav>li.dropdown.open.active>a:hover,.fuelux .nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.fuelux .nav li.dropdown.open .caret,.fuelux .nav li.dropdown.open.active .caret,.fuelux .nav li.dropdown.open a:hover .caret,.fuelux .nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.fuelux .tabs-stacked .open>a:hover,.fuelux .tabs-stacked .open>a:focus{border-color:#999}.fuelux .tabbable{*zoom:1}.fuelux .tabbable:before,.fuelux .tabbable:after{display:table;line-height:0;content:""}.fuelux .tabbable:after{clear:both}.fuelux .tab-content{overflow:auto}.fuelux .tabs-below>.nav-tabs,.fuelux .tabs-right>.nav-tabs,.fuelux .tabs-left>.nav-tabs{border-bottom:0}.fuelux .tab-content>.tab-pane,.fuelux .pill-content>.pill-pane{display:none}.fuelux .tab-content>.active,.fuelux .pill-content>.active{display:block}.fuelux .tabs-below>.nav-tabs{border-top:1px solid #ddd}.fuelux .tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.fuelux .tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.fuelux .tabs-below>.nav-tabs>li>a:hover,.fuelux .tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.fuelux .tabs-below>.nav-tabs>.active>a,.fuelux .tabs-below>.nav-tabs>.active>a:hover,.fuelux .tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.fuelux .tabs-left>.nav-tabs>li,.fuelux .tabs-right>.nav-tabs>li{float:none}.fuelux .tabs-left>.nav-tabs>li>a,.fuelux .tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.fuelux .tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.fuelux .tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.fuelux .tabs-left>.nav-tabs>li>a:hover,.fuelux .tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.fuelux .tabs-left>.nav-tabs .active>a,.fuelux .tabs-left>.nav-tabs .active>a:hover,.fuelux .tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.fuelux .tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.fuelux .tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.fuelux .tabs-right>.nav-tabs>li>a:hover,.fuelux .tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.fuelux .tabs-right>.nav-tabs .active>a,.fuelux .tabs-right>.nav-tabs .active>a:hover,.fuelux .tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.fuelux .nav>.disabled>a{color:#999}.fuelux .nav>.disabled>a:hover,.fuelux .nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.fuelux .navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.fuelux .navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.fuelux .navbar-inner:before,.fuelux .navbar-inner:after{display:table;line-height:0;content:""}.fuelux .navbar-inner:after{clear:both}.fuelux .navbar .container{width:auto}.fuelux .nav-collapse.collapse{height:auto;overflow:visible}.fuelux .navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.fuelux .navbar .brand:hover,.fuelux .navbar .brand:focus{text-decoration:none}.fuelux .navbar-text{margin-bottom:0;line-height:40px;color:#777}.fuelux .navbar-link{color:#777}.fuelux .navbar-link:hover,.fuelux .navbar-link:focus{color:#333}.fuelux .navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.fuelux .navbar .btn,.fuelux .navbar .btn-group{margin-top:5px}.fuelux .navbar .btn-group .btn,.fuelux .navbar .input-prepend .btn,.fuelux .navbar .input-append .btn,.fuelux .navbar .input-prepend .btn-group,.fuelux .navbar .input-append .btn-group{margin-top:0}.fuelux .navbar-form{margin-bottom:0;*zoom:1}.fuelux .navbar-form:before,.fuelux .navbar-form:after{display:table;line-height:0;content:""}.fuelux .navbar-form:after{clear:both}.fuelux .navbar-form input,.fuelux .navbar-form select,.fuelux .navbar-form .radio,.fuelux .navbar-form .checkbox{margin-top:5px}.fuelux .navbar-form input,.fuelux .navbar-form select,.fuelux .navbar-form .btn{display:inline-block;margin-bottom:0}.fuelux .navbar-form input[type="image"],.fuelux .navbar-form input[type="checkbox"],.fuelux .navbar-form input[type="radio"]{margin-top:3px}.fuelux .navbar-form .input-append,.fuelux .navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.fuelux .navbar-form .input-append input,.fuelux .navbar-form .input-prepend input{margin-top:0}.fuelux .navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.fuelux .navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.fuelux .navbar-static-top{position:static;margin-bottom:0}.fuelux .navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.fuelux .navbar-fixed-top,.fuelux .navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.fuelux .navbar-fixed-top .navbar-inner,.fuelux .navbar-static-top .navbar-inner{border-width:0 0 1px}.fuelux .navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.fuelux .navbar-fixed-top .navbar-inner,.fuelux .navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.fuelux .navbar-static-top .container,.fuelux .navbar-fixed-top .container,.fuelux .navbar-fixed-bottom .container{width:940px}.fuelux .navbar-fixed-top{top:0}.fuelux .navbar-fixed-top .navbar-inner,.fuelux .navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.fuelux .navbar-fixed-bottom{bottom:0}.fuelux .navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.fuelux .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.fuelux .navbar .nav.pull-right{float:right;margin-right:0}.fuelux .navbar .nav>li{float:left}.fuelux .navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.fuelux .navbar .nav .dropdown-toggle .caret{margin-top:8px}.fuelux .navbar .nav>li>a:focus,.fuelux .navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.fuelux .navbar .nav>.active>a,.fuelux .navbar .nav>.active>a:hover,.fuelux .navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.fuelux .navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.fuelux .navbar .btn-navbar:hover,.fuelux .navbar .btn-navbar:focus,.fuelux .navbar .btn-navbar:active,.fuelux .navbar .btn-navbar.active,.fuelux .navbar .btn-navbar.disabled,.fuelux .navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.fuelux .navbar .btn-navbar:active,.fuelux .navbar .btn-navbar.active{background-color:#ccc \9}.fuelux .navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.fuelux .btn-navbar .icon-bar+.icon-bar{margin-top:3px}.fuelux .navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.fuelux .navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.fuelux .navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.fuelux .navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.fuelux .navbar .nav li.dropdown>a:hover .caret,.fuelux .navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.fuelux .navbar .nav li.dropdown.open>.dropdown-toggle,.fuelux .navbar .nav li.dropdown.active>.dropdown-toggle,.fuelux .navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.fuelux .navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.fuelux .navbar .nav li.dropdown.open>.dropdown-toggle .caret,.fuelux .navbar .nav li.dropdown.active>.dropdown-toggle .caret,.fuelux .navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.fuelux .navbar .pull-right>li>.dropdown-menu,.fuelux .navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.fuelux .navbar .pull-right>li>.dropdown-menu:before,.fuelux .navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.fuelux .navbar .pull-right>li>.dropdown-menu:after,.fuelux .navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.fuelux .navbar .pull-right>li>.dropdown-menu .dropdown-menu,.fuelux .navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.fuelux .navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.fuelux .navbar-inverse .brand,.fuelux .navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.fuelux .navbar-inverse .brand:hover,.fuelux .navbar-inverse .nav>li>a:hover,.fuelux .navbar-inverse .brand:focus,.fuelux .navbar-inverse .nav>li>a:focus{color:#fff}.fuelux .navbar-inverse .brand{color:#999}.fuelux .navbar-inverse .navbar-text{color:#999}.fuelux .navbar-inverse .nav>li>a:focus,.fuelux .navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.fuelux .navbar-inverse .nav .active>a,.fuelux .navbar-inverse .nav .active>a:hover,.fuelux .navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.fuelux .navbar-inverse .navbar-link{color:#999}.fuelux .navbar-inverse .navbar-link:hover,.fuelux .navbar-inverse .navbar-link:focus{color:#fff}.fuelux .navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.fuelux .navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.fuelux .navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.fuelux .navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.fuelux .navbar-inverse .nav li.dropdown>a:hover .caret,.fuelux .navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.fuelux .navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.fuelux .navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.fuelux .navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.fuelux .navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.fuelux .navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.fuelux .navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.fuelux .navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.fuelux .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.fuelux .navbar-inverse .navbar-search .search-query:focus,.fuelux .navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.fuelux .navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-image:-moz-linear-gradient(top,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.fuelux .navbar-inverse .btn-navbar:hover,.fuelux .navbar-inverse .btn-navbar:focus,.fuelux .navbar-inverse .btn-navbar:active,.fuelux .navbar-inverse .btn-navbar.active,.fuelux .navbar-inverse .btn-navbar.disabled,.fuelux .navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.fuelux .navbar-inverse .btn-navbar:active,.fuelux .navbar-inverse .btn-navbar.active{background-color:#000 \9}.fuelux .breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.fuelux .breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.fuelux .breadcrumb>li>.divider{padding:0 5px;color:#ccc}.fuelux .breadcrumb>.active{color:#999}.fuelux .pagination{margin:20px 0}.fuelux .pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.fuelux .pagination ul>li{display:inline}.fuelux .pagination ul>li>a,.fuelux .pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.fuelux .pagination ul>li>a:hover,.fuelux .pagination ul>li>a:focus,.fuelux .pagination ul>.active>a,.fuelux .pagination ul>.active>span{background-color:#f5f5f5}.fuelux .pagination ul>.active>a,.fuelux .pagination ul>.active>span{color:#999;cursor:default}.fuelux .pagination ul>.disabled>span,.fuelux .pagination ul>.disabled>a,.fuelux .pagination ul>.disabled>a:hover,.fuelux .pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.fuelux .pagination ul>li:first-child>a,.fuelux .pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.fuelux .pagination ul>li:last-child>a,.fuelux .pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.fuelux .pagination-centered{text-align:center}.fuelux .pagination-right{text-align:right}.fuelux .pagination-large ul>li>a,.fuelux .pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.fuelux .pagination-large ul>li:first-child>a,.fuelux .pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.fuelux .pagination-large ul>li:last-child>a,.fuelux .pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.fuelux .pagination-mini ul>li:first-child>a,.fuelux .pagination-small ul>li:first-child>a,.fuelux .pagination-mini ul>li:first-child>span,.fuelux .pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.fuelux .pagination-mini ul>li:last-child>a,.fuelux .pagination-small ul>li:last-child>a,.fuelux .pagination-mini ul>li:last-child>span,.fuelux .pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.fuelux .pagination-small ul>li>a,.fuelux .pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.fuelux .pagination-mini ul>li>a,.fuelux .pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.fuelux .pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.fuelux .pager:before,.fuelux .pager:after{display:table;line-height:0;content:""}.fuelux .pager:after{clear:both}.fuelux .pager li{display:inline}.fuelux .pager li>a,.fuelux .pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.fuelux .pager li>a:hover,.fuelux .pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.fuelux .pager .next>a,.fuelux .pager .next>span{float:right}.fuelux .pager .previous>a,.fuelux .pager .previous>span{float:left}.fuelux .pager .disabled>a,.fuelux .pager .disabled>a:hover,.fuelux .pager .disabled>a:focus,.fuelux .pager .disabled>span{color:#999;cursor:default;background-color:#fff}.fuelux .modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.fuelux .modal-backdrop.fade{opacity:0}.fuelux .modal-backdrop,.fuelux .modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.fuelux .modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.fuelux .modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.fuelux .modal.fade.in{top:10%}.fuelux .modal-header{padding:9px 15px;border-bottom:1px solid #eee}.fuelux .modal-header .close{margin-top:2px}.fuelux .modal-header h3{margin:0;line-height:30px}.fuelux .modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.fuelux .modal-form{margin-bottom:0}.fuelux .modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.fuelux .modal-footer:before,.fuelux .modal-footer:after{display:table;line-height:0;content:""}.fuelux .modal-footer:after{clear:both}.fuelux .modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.fuelux .modal-footer .btn-group .btn+.btn{margin-left:-1px}.fuelux .modal-footer .btn-block+.btn-block{margin-left:0}.fuelux .tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.fuelux .tooltip.in{opacity:.8;filter:alpha(opacity=80)}.fuelux .tooltip.top{padding:5px 0;margin-top:-3px}.fuelux .tooltip.right{padding:0 5px;margin-left:3px}.fuelux .tooltip.bottom{padding:5px 0;margin-top:3px}.fuelux .tooltip.left{padding:0 5px;margin-left:-3px}.fuelux .tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.fuelux .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.fuelux .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.fuelux .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.fuelux .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.fuelux .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.fuelux .popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.fuelux .popover.top{margin-top:-10px}.fuelux .popover.right{margin-left:10px}.fuelux .popover.bottom{margin-top:10px}.fuelux .popover.left{margin-left:-10px}.fuelux .popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.fuelux .popover-title:empty{display:none}.fuelux .popover-content{padding:9px 14px}.fuelux .popover .arrow,.fuelux .popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.fuelux .popover .arrow{border-width:11px}.fuelux .popover .arrow:after{border-width:10px;content:""}.fuelux .popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.fuelux .popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.fuelux .popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.fuelux .popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.fuelux .popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.fuelux .popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.fuelux .popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.fuelux .popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.fuelux .thumbnails{margin-left:-20px;list-style:none;*zoom:1}.fuelux .thumbnails:before,.fuelux .thumbnails:after{display:table;line-height:0;content:""}.fuelux .thumbnails:after{clear:both}.fuelux .row-fluid .thumbnails{margin-left:0}.fuelux .thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.fuelux .thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.fuelux a.thumbnail:hover,.fuelux a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.fuelux .thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.fuelux .thumbnail .caption{padding:9px;color:#555}.fuelux .media,.fuelux .media-body{overflow:hidden;*overflow:visible;zoom:1}.fuelux .media,.fuelux .media .media{margin-top:15px}.fuelux .media:first-child{margin-top:0}.fuelux .media-object{display:block}.fuelux .media-heading{margin:0 0 5px}.fuelux .media>.pull-left{margin-right:10px}.fuelux .media>.pull-right{margin-left:10px}.fuelux .media-list{margin-left:0;list-style:none}.fuelux .label,.fuelux .badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.fuelux .label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fuelux .badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.fuelux .label:empty,.fuelux .badge:empty{display:none}.fuelux a.label:hover,.fuelux a.label:focus,.fuelux a.badge:hover,.fuelux a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.fuelux .label-important,.fuelux .badge-important{background-color:#b94a48}.fuelux .label-important[href],.fuelux .badge-important[href]{background-color:#953b39}.fuelux .label-warning,.fuelux .badge-warning{background-color:#f89406}.fuelux .label-warning[href],.fuelux .badge-warning[href]{background-color:#c67605}.fuelux .label-success,.fuelux .badge-success{background-color:#468847}.fuelux .label-success[href],.fuelux .badge-success[href]{background-color:#356635}.fuelux .label-info,.fuelux .badge-info{background-color:#3a87ad}.fuelux .label-info[href],.fuelux .badge-info[href]{background-color:#2d6987}.fuelux .label-inverse,.fuelux .badge-inverse{background-color:#333}.fuelux .label-inverse[href],.fuelux .badge-inverse[href]{background-color:#1a1a1a}.fuelux .btn .label,.fuelux .btn .badge{position:relative;top:-1px}.fuelux .btn-mini .label,.fuelux .btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.fuelux .progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.fuelux .progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.fuelux .progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.fuelux .progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.fuelux .progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.fuelux .progress-danger .bar,.fuelux .progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.fuelux .progress-danger.progress-striped .bar,.fuelux .progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.fuelux .progress-success .bar,.fuelux .progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.fuelux .progress-success.progress-striped .bar,.fuelux .progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.fuelux .progress-info .bar,.fuelux .progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.fuelux .progress-info.progress-striped .bar,.fuelux .progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.fuelux .progress-warning .bar,.fuelux .progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.fuelux .progress-warning.progress-striped .bar,.fuelux .progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.fuelux .accordion{margin-bottom:20px}.fuelux .accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.fuelux .accordion-heading{border-bottom:0}.fuelux .accordion-heading .accordion-toggle{display:block;padding:8px 15px}.fuelux .accordion-toggle{cursor:pointer}.fuelux .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.fuelux .carousel{position:relative;margin-bottom:20px;line-height:1}.fuelux .carousel-inner{position:relative;width:100%;overflow:hidden}.fuelux .carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.fuelux .carousel-inner>.item>img,.fuelux .carousel-inner>.item>a>img{display:block;line-height:1}.fuelux .carousel-inner>.active,.fuelux .carousel-inner>.next,.fuelux .carousel-inner>.prev{display:block}.fuelux .carousel-inner>.active{left:0}.fuelux .carousel-inner>.next,.fuelux .carousel-inner>.prev{position:absolute;top:0;width:100%}.fuelux .carousel-inner>.next{left:100%}.fuelux .carousel-inner>.prev{left:-100%}.fuelux .carousel-inner>.next.left,.fuelux .carousel-inner>.prev.right{left:0}.fuelux .carousel-inner>.active.left{left:-100%}.fuelux .carousel-inner>.active.right{left:100%}.fuelux .carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.fuelux .carousel-control.right{right:15px;left:auto}.fuelux .carousel-control:hover,.fuelux .carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.fuelux .carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.fuelux .carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.fuelux .carousel-indicators .active{background-color:#fff}.fuelux .carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.fuelux .carousel-caption h4,.fuelux .carousel-caption p{line-height:20px;color:#fff}.fuelux .carousel-caption h4{margin:0 0 5px}.fuelux .carousel-caption p{margin-bottom:0}.fuelux .hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.fuelux .hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.fuelux .hero-unit li{line-height:30px}.fuelux .pull-right{float:right}.fuelux .pull-left{float:left}.fuelux .hide{display:none}.fuelux .show{display:block}.fuelux .invisible{visibility:hidden}.fuelux .affix{position:fixed}.fuelux .form-inline .checkbox-custom{padding-left:20px}.fuelux .form-inline .checkbox-custom .checkbox{padding-left:16px}.fuelux .checkbox-custom input[type=checkbox]{position:relative;top:-99999px}.fuelux .checkbox-custom i{width:16px;height:16px;padding-left:16px;margin-right:4px;margin-left:-20px;background-image:url(../img/form.png);background-position:0 1px;background-repeat:no-repeat}.fuelux .checkbox-custom i.checked{background-position:-48px 1px}.fuelux .checkbox-custom i.disabled{background-position:-64px 1px}.fuelux .checkbox-custom i.disabled.checked{background-position:-80px 1px}.fuelux .checkbox-custom:hover i{background-position:-16px 1px}.fuelux .checkbox-custom:hover i.checked{background-position:-32px 1px}.fuelux .checkbox-custom:hover i.disabled{background-position:-64px 1px}.fuelux .checkbox-custom:hover i.disabled.checked{background-position:-80px 1px}.fuelux .combobox{display:inline-block}.fuelux .combobox a{font-size:14px}.fuelux .combobox button.btn{border-radius:0 4px 4px 0}.fuelux .datagrid thead{background-color:#f9f9f9}.fuelux .datagrid thead .datagrid-header-title{float:left;margin-right:10px;font-size:14px;font-weight:normal;line-height:28px}.fuelux .datagrid thead .datagrid-header-left{float:left}.fuelux .datagrid thead .datagrid-header-right{float:right}.fuelux .datagrid thead .datagrid-header-right .search,.fuelux .datagrid thead .datagrid-header-left .search,.fuelux .datagrid thead .datagrid-header-right .filter,.fuelux .datagrid thead .datagrid-header-left .filter{margin-bottom:0;margin-left:8px}.fuelux .datagrid thead .datagrid-header-right .search .dropdown-menu,.fuelux .datagrid thead .datagrid-header-left .search .dropdown-menu,.fuelux .datagrid thead .datagrid-header-right .filter .dropdown-menu,.fuelux .datagrid thead .datagrid-header-left .filter .dropdown-menu{top:auto;left:auto}.fuelux .datagrid thead .sorted{padding-right:30px;color:#333;text-shadow:'none';background-color:#f1f1f1;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f9f9f9),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f9f9f9,#e5e5e5);background-image:-o-linear-gradient(top,#f9f9f9,#e5e5e5);background-image:-moz-linear-gradient(top,#f9f9f9,#e5e5e5);background-image:linear-gradient(to bottom,#f9f9f9,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bebebe;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fff9f9f9',endColorstr='#ffe5e5e5',GradientType=0)}.fuelux .datagrid thead .sorted i{float:right;margin-top:2px;margin-right:-22px}.fuelux .datagrid thead .sortable{cursor:pointer}.fuelux .datagrid thead .sortable:hover{color:#333;text-shadow:'none';background-color:#f1f1f1;background-image:-moz-linear-gradient(top,#f9f9f9,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f9f9f9),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f9f9f9,#e5e5e5);background-image:-o-linear-gradient(top,#f9f9f9,#e5e5e5);background-image:linear-gradient(to bottom,#f9f9f9,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bebebe;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fff9f9f9',endColorstr='#ffe5e5e5',GradientType=0)}.fuelux .datagrid tfoot{background-color:#f9f9f9}.fuelux .datagrid tfoot .datagrid-footer-left{float:left}.fuelux .datagrid tfoot .datagrid-footer-left .grid-controls{margin-top:7px}.fuelux .datagrid tfoot .datagrid-footer-left .grid-controls select{width:60px;margin:0 5px 1px}.fuelux .datagrid tfoot .datagrid-footer-left .grid-controls .grid-pagesize{display:inline-block;margin-bottom:5px;vertical-align:middle}.fuelux .datagrid tfoot .datagrid-footer-left .grid-controls .grid-pagesize .dropdown-menu{top:auto;left:auto}.fuelux .datagrid tfoot .datagrid-footer-left .grid-controls span{font-weight:normal}.fuelux .datagrid tfoot .datagrid-footer-right{float:right}.fuelux .datagrid tfoot .datagrid-footer-right .grid-pager>span{position:relative;top:8px;font-weight:normal}.fuelux .datagrid tfoot .datagrid-footer-right .grid-pager .dropdown-menu{min-width:50px}.fuelux .datagrid tfoot .datagrid-footer-right .grid-pager .combobox{position:relative;top:-2px;display:inline-block;margin-bottom:4px;vertical-align:baseline}.fuelux .datagrid tfoot .datagrid-footer-right .grid-pager>button{position:relative;top:7px}.fuelux .datagrid-stretch-header{margin-bottom:0;border-bottom:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0}.fuelux .datagrid-stretch-header thead:last-child tr:last-child>th:first-child,.fuelux .datagrid-stretch-header thead:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0}.fuelux .datagrid-stretch-wrapper{overflow:auto;border:1px solid #ddd}.fuelux .datagrid-stretch-wrapper .datagrid{margin-bottom:0;border:0;border-collapse:collapse;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.fuelux .datagrid-stretch-wrapper .datagrid td,.fuelux .datagrid-stretch-wrapper .datagrid th{border-bottom:1px solid #ddd}.fuelux .datagrid-stretch-wrapper .datagrid td:first-child,.fuelux .datagrid-stretch-wrapper .datagrid th:first-child{border-left:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.fuelux .datagrid-stretch-footer{border-top:0;-webkit-border-top-right-radius:0;border-top-right-radius:0;-webkit-border-top-left-radius:0;border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-topleft:0}.fuelux .datagrid-stretch-footer th{border-top:0}.fuelux .pillbox{padding:3px}.fuelux .pillbox ul{display:inline-block;margin:0}.fuelux .pillbox li{display:inline-block;float:left;padding:1px 4px 2px;margin:2px;font-size:11.844px;font-weight:bold;line-height:21px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);vertical-align:baseline;cursor:pointer;background-color:#999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fuelux .pillbox li:after{position:relative;top:-2px;float:right;padding-left:4px;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;content:" \00D7";opacity:.2;filter:alpha(opacity=20)}.fuelux .pillbox li:hover:after{opacity:.4;filter:alpha(opacity=40)}.fuelux .pillbox li.status-important{background-color:#b94a48}.fuelux .pillbox li.status-warning{background-color:#f89406}.fuelux .pillbox li.status-success{background-color:#468847}.fuelux .pillbox li.status-info{background-color:#3a87ad}.fuelux .radio-custom input[type=radio]{display:none}.fuelux .radio-custom i{width:16px;height:16px;padding-left:16px;margin-right:4px;margin-left:-20px;background-image:url(../img/form.png);background-position:0 -15px;background-repeat:no-repeat}.fuelux .radio-custom i.checked{background-position:-48px -15px}.fuelux .radio-custom i.disabled{background-position:-64px -15px}.fuelux .radio-custom i.disabled.checked{background-position:-80px -15px}.fuelux .radio-custom:hover i{background-position:-16px -15px}.fuelux .radio-custom:hover i.checked{background-position:-32px -15px}.fuelux .radio-custom:hover i.disabled{background-position:-64px -15px}.fuelux .radio-custom:hover i.disabled.checked{background-position:-80px -15px}.fuelux .spinner input{float:left;width:43px}.fuelux .spinner .btn{position:relative;width:20px;height:14px;padding-top:0;padding-right:9px;padding-left:9px}.fuelux .spinner .btn.disabled{cursor:not-allowed}.fuelux .spinner .spinner-buttons{position:relative;left:-22px;float:left;width:20px;height:28px}.fuelux .spinner .spinner-up{top:2px;padding:0 0 4px 1px}.fuelux .spinner .spinner-up i{position:relative;top:-4px}.fuelux .spinner .spinner-down{top:2px;height:13px;padding:0 0 4px 1px}.fuelux .spinner .spinner-down i{position:relative;top:-5px}.fuelux .search{display:inline-block}.fuelux .select .dropdown-label{display:inline-block;padding:0 10px 0 0;margin:0;font-weight:normal;color:#333;text-align:left}.fuelux #selectTextSize{position:absolute;top:0;display:inline-block;visibility:hidden}.fuelux .tree{position:relative;padding:10px 15px 0 15px;overflow-x:hidden;overflow-y:auto;border:1px solid #bbb;border-radius:4px 4px 4px 4px}.fuelux .tree .tree-folder{width:100%;min-height:20px;margin-top:1px;cursor:pointer}.fuelux .tree .tree-folder .tree-folder-header{position:relative;height:20px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.fuelux .tree .tree-folder .tree-folder-header:hover{background-color:#dfeef5}.fuelux .tree .tree-folder .tree-folder-header i{position:absolute;top:1px;left:5px;float:left}.fuelux .tree .tree-folder .tree-folder-header .tree-folder-name{padding-left:29px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fuelux .tree .tree-folder .tree-folder-content{margin-left:23px}.fuelux .tree .tree-item{position:relative;width:100%;height:20px;margin-top:1px;cursor:pointer;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.fuelux .tree .tree-item:hover{background-color:#dfeef5}.fuelux .tree .tree-item .tree-item-name{position:absolute;left:29px}.fuelux .tree .tree-item .tree-dot{position:absolute;top:8px;left:10px;display:block;width:4px;height:4px;background-color:#333;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.fuelux .tree .tree-item .icon-ok{position:absolute;top:1px;left:5px}.fuelux .tree .tree-selected{background-color:#b9dff1}.fuelux .tree .tree-selected:hover{background-color:#b9dff1}.fuelux .wizard{background-color:#f9f9f9;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.fuelux .wizard:before,.fuelux .wizard:after{display:table;line-height:0;content:""}.fuelux .wizard:after{clear:both}.fuelux .wizard ul{padding:0;margin:0;list-style:none outside none}.fuelux .wizard ul li{position:relative;float:left;height:46px;padding:0 20px 0 30px;margin:0;font-size:16px;line-height:46px;color:#999;cursor:default;background:#ededed}.fuelux .wizard ul li .chevron{position:absolute;top:0;right:-14px;display:block;border:24px solid transparent;border-right:0;border-left:14px solid #d4d4d4}.fuelux .wizard ul li .chevron:before{position:absolute;top:-24px;right:1px;display:block;border:24px solid transparent;border-right:0;border-left:14px solid #ededed;content:""}.fuelux .wizard ul li.complete{color:#468847;background:#f3f4f5}.fuelux .wizard ul li.complete:hover{cursor:pointer;background:#e7eff8}.fuelux .wizard ul li.complete:hover .chevron:before{border-left:14px solid #e7eff8}.fuelux .wizard ul li.complete .chevron:before{border-left:14px solid #f3f4f5}.fuelux .wizard ul li.active{color:#3a87ad;background:#f1f6fc}.fuelux .wizard ul li.active .chevron:before{border-left:14px solid #f1f6fc}.fuelux .wizard ul li .badge{margin-right:8px}.fuelux .wizard ul li:nth-child(1){z-index:10;padding-left:20px;border-radius:4px 0 0 4px}.fuelux .wizard ul li:nth-child(2){z-index:9}.fuelux .wizard ul li:nth-child(3){z-index:8}.fuelux .wizard ul li:nth-child(4){z-index:7}.fuelux .wizard ul li:nth-child(5){z-index:6}.fuelux .wizard ul li:nth-child(6){z-index:5}.fuelux .wizard ul li:nth-child(7){z-index:4}.fuelux .wizard ul li:nth-child(8){z-index:3}.fuelux .wizard ul li:nth-child(9){z-index:2}.fuelux .wizard ul li:nth-child(10){z-index:1}.fuelux .wizard .actions{float:right;padding-right:15px;line-height:44px;vertical-align:middle}.fuelux .wizard .actions a{margin-right:8px;font-size:12px;line-height:45px}.fuelux .wizard .actions .btn-prev i{margin-right:5px}.fuelux .wizard .actions .btn-next i{margin-left:5px}.fuelux .step-content .step-pane{display:none}.fuelux .step-content .active{display:block}.fuelux .step-content .active .btn-group .active{display:inline-block}
\ No newline at end of file
diff --git a/opendaylight/web/root/src/main/resources/css/opendaylight.css b/opendaylight/web/root/src/main/resources/css/opendaylight.css
new file mode 100644 (file)
index 0000000..9a988b0
--- /dev/null
@@ -0,0 +1,80 @@
+.fuelux [class^="icon-"],
+.fuelux [class*=" icon-"] {
+  display: inline-block;
+  width: 14px;
+  height: 14px;
+  margin-top: 1px;
+  *margin-right: .3em;
+  line-height: 14px;
+  vertical-align: text-top;
+  background-position: 14px 14px;
+  background-repeat: no-repeat;
+}
+
+.fuelux .icon-white,
+.fuelux .nav-pills > .active > a > [class^="icon-"],
+.fuelux .nav-pills > .active > a > [class*=" icon-"],
+.fuelux .nav-list > .active > a > [class^="icon-"],
+.fuelux .nav-list > .active > a > [class*=" icon-"],
+.fuelux .navbar-inverse .nav > .active > a > [class^="icon-"],
+.fuelux .navbar-inverse .nav > .active > a > [class*=" icon-"],
+.fuelux .dropdown-menu > li > a:hover > [class^="icon-"],
+.fuelux .dropdown-menu > li > a:focus > [class^="icon-"],
+.fuelux .dropdown-menu > li > a:hover > [class*=" icon-"],
+.fuelux .dropdown-menu > li > a:focus > [class*=" icon-"],
+.fuelux .dropdown-menu > .active > a > [class^="icon-"],
+.fuelux .dropdown-menu > .active > a > [class*=" icon-"],
+.fuelux .dropdown-submenu:hover > a > [class^="icon-"],
+.fuelux .dropdown-submenu:focus > a > [class^="icon-"],
+.fuelux .dropdown-submenu:hover > a > [class*=" icon-"],
+.fuelux .dropdown-submenu:focus > a > [class*=" icon-"] {
+}
+
+.fuelux .icon-search {
+  background:url('../img/search.png') 0 0 no-repeat;
+  height: 16px;
+  line-height: 16px;
+  width: 16px;
+}
+.fuelux .icon-remove {
+  background:url('../img/searchremove.png') 0 0 no-repeat;
+  height: 16px;
+  line-height: 16px;
+  width: 16px;
+}
+
+.fuelux .icon-chevron-up {
+  background:url('../img/sort_up.png') 0 0 no-repeat;
+  height: 16px;
+  line-height: 16px;
+  width: 16px;
+}
+
+.fuelux .icon-chevron-down {
+  background:url('../img/sort_down.png') 0 0 no-repeat;
+  height: 16px;
+  line-height: 16px;
+  width: 16px;
+}
+
+.fuelux .icon-chevron-left {
+  background:url('../img/nextpageleft.png') 0 0 no-repeat;
+  height: 16px;
+  line-height: 16px;
+  width: 16px;
+}
+
+.fuelux .icon-chevron-right {
+  background:url('../img/nextpageright.png') 0 0 no-repeat;
+  height: 16px;
+  line-height: 16px;
+  width: 16px;
+}
+
+.fuelux .icon-chevron-right {
+  background:url('../img/nextpageright.png') 0 0 no-repeat;
+  height: 16px;
+  line-height: 16px;
+  width: 16px;
+}
+
diff --git a/opendaylight/web/root/src/main/resources/img/form.png b/opendaylight/web/root/src/main/resources/img/form.png
new file mode 100755 (executable)
index 0000000..ce846da
Binary files /dev/null and b/opendaylight/web/root/src/main/resources/img/form.png differ
diff --git a/opendaylight/web/root/src/main/resources/img/nextpageleft.png b/opendaylight/web/root/src/main/resources/img/nextpageleft.png
new file mode 100644 (file)
index 0000000..62126b1
Binary files /dev/null and b/opendaylight/web/root/src/main/resources/img/nextpageleft.png differ
diff --git a/opendaylight/web/root/src/main/resources/img/nextpageright.png b/opendaylight/web/root/src/main/resources/img/nextpageright.png
new file mode 100644 (file)
index 0000000..2a71a14
Binary files /dev/null and b/opendaylight/web/root/src/main/resources/img/nextpageright.png differ
diff --git a/opendaylight/web/root/src/main/resources/img/search.png b/opendaylight/web/root/src/main/resources/img/search.png
new file mode 100644 (file)
index 0000000..b8742d2
Binary files /dev/null and b/opendaylight/web/root/src/main/resources/img/search.png differ
diff --git a/opendaylight/web/root/src/main/resources/img/searchremove.png b/opendaylight/web/root/src/main/resources/img/searchremove.png
new file mode 100644 (file)
index 0000000..3809f51
Binary files /dev/null and b/opendaylight/web/root/src/main/resources/img/searchremove.png differ
diff --git a/opendaylight/web/root/src/main/resources/img/sort_down.png b/opendaylight/web/root/src/main/resources/img/sort_down.png
new file mode 100644 (file)
index 0000000..708e44e
Binary files /dev/null and b/opendaylight/web/root/src/main/resources/img/sort_down.png differ
diff --git a/opendaylight/web/root/src/main/resources/img/sort_up.png b/opendaylight/web/root/src/main/resources/img/sort_up.png
new file mode 100644 (file)
index 0000000..0b5c041
Binary files /dev/null and b/opendaylight/web/root/src/main/resources/img/sort_up.png differ
diff --git a/opendaylight/web/root/src/main/resources/js/datasource.js b/opendaylight/web/root/src/main/resources/js/datasource.js
new file mode 100755 (executable)
index 0000000..8226df0
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Fuel UX Data components - static data source
+ * https://github.com/ExactTarget/fuelux-data
+ *
+ * Copyright (c) 2012 ExactTarget
+ * Licensed under the MIT license.
+ */
+
+(function (root, factory) {
+       if (typeof define === 'function' && define.amd) {
+               define(['underscore'], factory);
+       } else {
+               root.StaticDataSource = factory();
+       }
+}(this, function () {
+
+       var StaticDataSource = function (options) {
+               this._formatter = options.formatter;
+               this._columns = options.columns;
+               this._delay = options.delay || 0;
+               this._data = options.data;
+       };
+
+       StaticDataSource.prototype = {
+
+               columns: function () {
+                       return this._columns;
+               },
+
+               data: function (options, callback) {
+                       var self = this;
+
+                       setTimeout(function () {
+                               var data = $.extend(true, [], self._data);
+
+                               // SEARCHING
+                               if (options.search) {
+                                       data = _.filter(data, function (item) {
+                                               var match = false;
+
+                                               _.each(item, function (prop) {
+                                                       if (_.isString(prop) || _.isFinite(prop)) {
+                                                               if (prop.toString().toLowerCase().indexOf(options.search.toLowerCase()) !== -1) match = true;
+                                                       }
+                                               });
+
+                                               return match;
+                                       });
+                               }
+
+                               // FILTERING
+                               if (options.filter) {
+                                       data = _.filter(data, function (item) {
+                                               switch(options.filter.value) {
+                                                       case 'lt5m':
+                                                               if(item.population < 5000000) return true;
+                                                               break;
+                                                       case 'gte5m':
+                                                               if(item.population >= 5000000) return true;
+                                                               break;
+                                                       default:
+                                                               return true;
+                                                               break;
+                                               }
+                                       });
+                               }
+
+                               var count = data.length;
+
+                               // SORTING
+                               if (options.sortProperty) {
+                                       data = _.sortBy(data, options.sortProperty);
+                                       if (options.sortDirection === 'desc') data.reverse();
+                               }
+
+                               // PAGING
+                               var startIndex = options.pageIndex * options.pageSize;
+                               var endIndex = startIndex + options.pageSize;
+                               var end = (endIndex > count) ? count : endIndex;
+                               var pages = Math.ceil(count / options.pageSize);
+                               var page = options.pageIndex + 1;
+                               var start = startIndex + 1;
+
+                               data = data.slice(startIndex, endIndex);
+
+                               if (self._formatter) self._formatter(data);
+
+                               callback({ data: data, start: start, end: end, count: count, pages: pages, page: page });
+
+                       }, this._delay)
+               }
+       };
+
+       return StaticDataSource;
+}));
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/COPYING b/opendaylight/web/root/src/main/resources/js/fuelux/COPYING
new file mode 100644 (file)
index 0000000..9b8ce79
--- /dev/null
@@ -0,0 +1,33 @@
+Copyright (C) 2012, ExactTarget, Inc.
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in the
+Software without restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+====================================================================
+
+The above license does not apply to the following bundled components:
+
+Â¥      jQuery located at lib/jquery.js
+Â¥      Bootstrap Apache 2.0 Located under lib/bootstrap
+Â¥      RequireJS located at lib/require.js
+Â¥      QUnit located under lib/qunit
+Â¥      Grunt located under node-modules/grunt
+Â¥      Grunt-contrib located under node-modules/grunt-contrib
+Â¥      Grunt-recess located under node-modules/grunt-recess
+
+Licensing information regarding the above packages can be found in the THIRD-PARTY file.
\ No newline at end of file
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/all.min.js b/opendaylight/web/root/src/main/resources/js/fuelux/all.min.js
new file mode 100755 (executable)
index 0000000..2f9e721
--- /dev/null
@@ -0,0 +1,4 @@
+/*! Fuel UX - v2.3.1 - 2013-08-02
+* https://github.com/ExactTarget/fuelux
+* Copyright (c) 2013 ExactTarget; Licensed MIT */
+(function(){(function(a){var b;define("bootstrap/bootstrap-transition",["jquery"],function(){return function(){!function(a){a(function(){a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery)}.call(a),b})})(this),function(a){var b;define("bootstrap/bootstrap-affix",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b,c){this.options=a.extend({},a.fn.affix.defaults,c),this.$window=a(window).on("scroll.affix.data-api",a.proxy(this.checkPosition,this)).on("click.affix.data-api",a.proxy(function(){setTimeout(a.proxy(this.checkPosition,this),1)},this)),this.$element=a(b),this.checkPosition()};b.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var b=a(document).height(),c=this.$window.scrollTop(),d=this.$element.offset(),e=this.options.offset,f=e.bottom,g=e.top,h="affix affix-top affix-bottom",i;typeof e!="object"&&(f=g=e),typeof g=="function"&&(g=e.top()),typeof f=="function"&&(f=e.bottom()),i=this.unpin!=null&&c+this.unpin<=d.top?!1:f!=null&&d.top+this.$element.height()>=b-f?"bottom":g!=null&&c<=g?"top":!1;if(this.affixed===i)return;this.affixed=i,this.unpin=i=="bottom"?d.top-c:null,this.$element.removeClass(h).addClass("affix"+(i?"-"+i:""))};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("affix"),f=typeof c=="object"&&c;e||d.data("affix",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.defaults={offset:0},a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(window.jQuery)}.call(a),b})}(this),function(a){var b;define("bootstrap/bootstrap-alert",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.alert.data-api",b,c.prototype.close)}(window.jQuery)}.call(a),b})}(this),function(a){var b;define("bootstrap/bootstrap-button",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a=a+"Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})}(window.jQuery)}.call(a),b})}(this),function(a){var b;define("bootstrap/bootstrap-carousel",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.options.pause=="hover"&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.prototype={cycle:function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(b){var c=this.getActiveIndex(),d=this;if(b>this.$items.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){d.to(b)}):c==b?this.pause().cycle():this.slide(b>c?"next":"prev",a(this.$items[b]))},pause:function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this,j;this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h](),j=a.Event("slide",{relatedTarget:e[0],direction:g});if(e.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")}));if(a.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(j);if(j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})}else{this.$element.trigger(j);if(j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=a.extend({},a.fn.carousel.defaults,typeof c=="object"&&c),g=typeof c=="string"?c:f.slide;e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.defaults={interval:5e3,pause:"hover"},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),c.data()),g;e.carousel(f),(g=c.attr("data-slide-to"))&&e.data("carousel").pause().to(g).cycle(),b.preventDefault()})}(window.jQuery)}.call(a),b})}(this),function(a){var b;define("bootstrap/bootstrap-collapse",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b,c,d,e;if(this.transitioning||this.$element.hasClass("in"))return;b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find("> .accordion-group > .in");if(d&&d.length){e=d.data("collapse");if(e&&e.transitioning)return;d.collapse("hide"),e||d.data("collapse",null)}this.$element[b](0),this.transition("addClass",a.Event("show"),"shown"),a.support.transition&&this.$element[b](this.$element[0][c])},hide:function(){var b;if(this.transitioning||!this.$element.hasClass("in"))return;b=this.dimension(),this.reset(this.$element[b]()),this.transition("removeClass",a.Event("hide"),"hidden"),this.$element[b](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a!==null?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c.type=="show"&&e.reset(),e.transitioning=0,e.$element.trigger(d)};this.$element.trigger(c);if(c.isDefaultPrevented())return;this.transitioning=1,this.$element[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=a.extend({},a.fn.collapse.defaults,d.data(),typeof c=="object"&&c);e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();c[a(e).hasClass("in")?"addClass":"removeClass"]("collapsed"),a(e).collapse(f)})}(window.jQuery)}.call(a),b})}(this),function(a){var b;define("bootstrap/bootstrap-dropdown",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){function d(){a(".dropdown-backdrop").remove(),a(b).each(function(){e(a(this)).removeClass("open")})}function e(b){var c=b.attr("data-target"),d;c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,"")),d=c&&a(c);if(!d||!d.length)d=b.parent();return d}var b="[data-toggle=dropdown]",c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),f,g;if(c.is(".disabled, :disabled"))return;return f=e(c),g=f.hasClass("open"),d(),g||("ontouchstart"in document.documentElement&&a('<div class="dropdown-backdrop"/>').insertBefore(a(this)).on("click",d),f.toggleClass("open")),c.focus(),!1},keydown:function(c){var d,f,g,h,i,j;if(!/(38|40|27)/.test(c.keyCode))return;d=a(this),c.preventDefault(),c.stopPropagation();if(d.is(".disabled, :disabled"))return;h=e(d),i=h.hasClass("open");if(!i||i&&c.keyCode==27)return c.which==27&&h.find(b).focus(),d.click();f=a("[role=menu] li:not(.divider):visible a",h);if(!f.length)return;j=f.index(f.filter(":focus")),c.keyCode==38&&j>0&&j--,c.keyCode==40&&j<f.length-1&&j++,~j||(j=0),f.eq(j).focus()}};var f=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=f,this},a(document).on("click.dropdown.data-api",d).on("click.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle).on("keydown.dropdown.data-api",b+", [role=menu]",c.prototype.keydown)}(window.jQuery)}.call(a),b})}(this),function(a){var b;define("bootstrap/bootstrap-modal",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in").attr("aria-hidden",!1),b.enforceFocus(),c?b.$element.one(a.support.transition.end,function(){b.$element.focus().trigger("shown")}):b.$element.focus().trigger("shown")})},hide:function(b){b&&b.preventDefault();var c=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,this.escape(),a(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),a.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var b=this;a(document).on("focusin.modal",function(a){b.$element[0]!==a.target&&!b.$element.has(a.target).length&&b.$element.focus()})},escape:function(){var a=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(b){b.which==27&&a.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),b.hideModal()},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),b.hideModal()})},hideModal:function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?a.proxy(this.$element[0].focus,this.$element[0]):a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!b)return;e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b):b()):b&&b()}};var c=a.fn.modal;a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=a.extend({},a.fn.modal.defaults,d.data(),typeof c=="object"&&c);e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():f.show&&e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f).one("hide",function(){c.focus()})})}(window.jQuery)}.call(a),b})}(this),function(a){var b;define("bootstrap/bootstrap-tooltip",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(a,b){this.init("tooltip",a,b)};b.prototype={constructor:b,init:function(b,c,d){var e,f,g,h,i;this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.enabled=!0,g=this.options.trigger.split(" ");for(i=g.length;i--;)h=g[i],h=="click"?this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this)):h!="manual"&&(e=h=="hover"?"mouseenter":"focus",f=h=="hover"?"mouseleave":"blur",this.$element.on(e+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(f+"."+this.type,this.options.selector,a.proxy(this.leave,this)));this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(b){return b=a.extend({},a.fn[this.type].defaults,this.$element.data(),b),b.delay&&typeof b.delay=="number"&&(b.delay={show:b.delay,hide:b.delay}),b},enter:function(b){var c=a.fn[this.type].defaults,d={},e;this._options&&a.each(this._options,function(a,b){c[a]!=b&&(d[a]=b)}),e=a(b.currentTarget)[this.type](d).data(this.type);if(!e.options.delay||!e.options.delay.show)return e.show();clearTimeout(this.timeout),e.hoverState="in",this.timeout=setTimeout(function(){e.hoverState=="in"&&e.show()},e.options.delay.show)},leave:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!c.options.delay||!c.options.delay.hide)return c.hide();c.hoverState="out",this.timeout=setTimeout(function(){c.hoverState=="out"&&c.hide()},c.options.delay.hide)},show:function(){var b,c,d,e,f,g,h=a.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(h);if(h.isDefaultPrevented())return;b=this.tip(),this.setContent(),this.options.animation&&b.addClass("fade"),f=typeof this.options.placement=="function"?this.options.placement.call(this,b[0],this.$element[0]):this.options.placement,b.detach().css({top:0,left:0,display:"block"}),this.options.container?b.appendTo(this.options.container):b.insertAfter(this.$element),c=this.getPosition(),d=b[0].offsetWidth,e=b[0].offsetHeight;switch(f){case"bottom":g={top:c.top+c.height,left:c.left+c.width/2-d/2};break;case"top":g={top:c.top-e,left:c.left+c.width/2-d/2};break;case"left":g={top:c.top+c.height/2-e/2,left:c.left-d};break;case"right":g={top:c.top+c.height/2-e/2,left:c.left+c.width}}this.applyPlacement(g,f),this.$element.trigger("shown")}},applyPlacement:function(a,b){var c=this.tip(),d=c[0].offsetWidth,e=c[0].offsetHeight,f,g,h,i;c.offset(a).addClass(b).addClass("in"),f=c[0].offsetWidth,g=c[0].offsetHeight,b=="top"&&g!=e&&(a.top=a.top+e-g,i=!0),b=="bottom"||b=="top"?(h=0,a.left<0&&(h=a.left*-2,a.left=0,c.offset(a),f=c[0].offsetWidth,g=c[0].offsetHeight),this.replaceArrow(h-d+f,f,"left")):this.replaceArrow(g-e,g,"top"),i&&c.offset(a)},replaceArrow:function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},setContent:function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},hide:function(){function e(){var b=setTimeout(function(){c.off(a.support.transition.end).detach()},500);c.one(a.support.transition.end,function(){clearTimeout(b),c.detach()})}var b=this,c=this.tip(),d=a.Event("hide");this.$element.trigger(d);if(d.isDefaultPrevented())return;return c.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?e():c.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var a=this.$element;(a.attr("title")||typeof a.attr("data-original-title")!="string")&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var b=this.$element[0];return a.extend({},typeof b.getBoundingClientRect=="function"?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},getTitle:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||(typeof c.title=="function"?c.title.call(b[0]):c.title),a},tip:function(){return this.$tip=this.$tip||a(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(b){var c=b?a(b.currentTarget)[this.type](this._options).data(this.type):this;c.tip().hasClass("in")?c.hide():c.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("tooltip"),f=typeof c=="object"&&c;e||d.data("tooltip",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(window.jQuery)}.call(a),b})}(this),function(a){var b;define("bootstrap/bootstrap-popover",["bootstrap/bootstrap-transition","bootstrap/bootstrap-tooltip"],function(){return function(){!function(a){var b=function(a,b){this.init("popover",a,b)};b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype,{constructor:b,setContent:function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var a,b=this.$element,c=this.options;return a=(typeof c.content=="function"?c.content.call(b[0]):c.content)||b.attr("data-content"),a},tip:function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("popover"),f=typeof c=="object"&&c;e||d.data("popover",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.defaults=a.extend({},a.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(window.jQuery)}.call(a),b})}(this),function(a){var b;define("bootstrap/bootstrap-scrollspy",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){function b(b,c){var d=a.proxy(this.process,this),e=a(b).is("body")?a(window):a(b),f;this.options=a.extend({},a.fn.scrollspy.defaults,c),this.$scrollElement=e.on("scroll.scroll-spy.data-api",d),this.selector=(this.options.target||(f=a(b).attr("href"))&&f.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=a("body"),this.refresh(),this.process()}b.prototype={constructor:b,refresh:function(){var b=this,c;this.offsets=a([]),this.targets=a([]),c=this.$body.find(this.selector).map(function(){var c=a(this),d=c.data("target")||c.attr("href"),e=/^#\w/.test(d)&&a(d);return e&&e.length&&[[e.position().top+(!a.isWindow(b.$scrollElement.get(0))&&b.$scrollElement.scrollTop()),d]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},process:function(){var a=this.$scrollElement.scrollTop()+this.options.offset,b=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,c=b-this.$scrollElement.height(),d=this.offsets,e=this.targets,f=this.activeTarget,g;if(a>=c)return f!=(g=e.last()[0])&&this.activate(g);for(g=d.length;g--;)f!=e[g]&&a>=d[g]&&(!d[g+1]||a<=d[g+1])&&this.activate(e[g])},activate:function(b){var c,d;this.activeTarget=b,a(this.selector).parent(".active").removeClass("active"),d=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',c=a(d).parent("li").addClass("active"),c.parent(".dropdown-menu").length&&(c=c.closest("li.dropdown").addClass("active")),c.trigger("activate")}};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("scrollspy"),f=typeof c=="object"&&c;e||d.data("scrollspy",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.defaults={offset:10},a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery)}.call(a),b})}(this),function(a){var b;define("bootstrap/bootstrap-tab",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b){this.element=a(b)};b.prototype={constructor:b,show:function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target"),e,f,g;d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,""));if(b.parent("li").hasClass("active"))return;e=c.find(".active:last a")[0],g=a.Event("show",{relatedTarget:e}),b.trigger(g);if(g.isDefaultPrevented())return;f=a(d),this.activate(b.parent("li"),c),this.activate(f,f.parent(),function(){b.trigger({type:"shown",relatedTarget:e})})},activate:function(b,c,d){function g(){e.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),f?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var e=c.find("> .active"),f=d&&a.support.transition&&e.hasClass("fade");f?e.one(a.support.transition.end,g):g(),e.removeClass("in")}};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("tab");e||d.data("tab",e=new b(this)),typeof c=="string"&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(window.jQuery)}.call(a),b})}(this),function(a){var b;define("bootstrap/bootstrap-typeahead",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=a(this.options.menu),this.shown=!1,this.listen()};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(a)).change(),this.hide()},updater:function(a){return a},show:function(){var b=a.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:b.top+b.height,left:b.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){var c;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(c=a.isFunction(this.source)?this.source(this.query,a.proxy(this.process,this)):this.source,c?this.process(c):this)},process:function(b){var c=this;return b=a.grep(b,function(a){return c.matcher(a)}),b=this.sorter(b),b.length?this.render(b.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(a){return~a.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){var b=[],c=[],d=[],e;while(e=a.shift())e.toLowerCase().indexOf(this.query.toLowerCase())?~e.indexOf(this.query)?c.push(e):d.push(e):b.push(e);return b.concat(c,d)},highlighter:function(a){var b=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return a.replace(new RegExp("("+b+")","ig"),function(a,b){return"<strong>"+b+"</strong>"})},render:function(b){var c=this;return b=a(b).map(function(b,d){return b=a(c.options.item).attr("data-value",d),b.find("a").html(c.highlighter(d)),b[0]}),b.first().addClass("active"),this.$menu.html(b),this},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("focus",a.proxy(this.focus,this)).on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",a.proxy(this.keydown,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this)).on("mouseleave","li",a.proxy(this.mouseleave,this))},eventSupported:function(a){var b=a in this.$element;return b||(this.$element.setAttribute(a,"return;"),b=typeof this.$element[a]=="function"),b},move:function(a){if(!this.shown)return;switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:a.preventDefault(),this.prev();break;case 40:a.preventDefault(),this.next()}a.stopPropagation()},keydown:function(b){this.suppressKeyPressRepeat=~a.inArray(b.keyCode,[40,38,9,13,27]),this.move(b)},keypress:function(a){if(this.suppressKeyPressRepeat)return;this.move(a)},keyup:function(a){switch(a.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}a.stopPropagation(),a.preventDefault()},focus:function(a){this.focused=!0},blur:function(a){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(a){a.stopPropagation(),a.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(b){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")},mouseleave:function(a){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var c=a.fn.typeahead;a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f=typeof c=="object"&&c;e||d.data("typeahead",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},a.fn.typeahead.Constructor=b,a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this},a(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;c.typeahead(c.data())})}(window.jQuery)}.call(a),b})}(this),define("fuelux/checkbox",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.checkbox.defaults,c),this.$label=this.$element.parent(),this.$icon=this.$label.find("i"),this.$chk=this.$label.find("input[type=checkbox]"),this.setState(this.$chk),this.$chk.on("change",b.proxy(this.itemchecked,this))};c.prototype={constructor:c,setState:function(a){var b=a.is(":checked"),c=a.is(":disabled");this.$icon.removeClass("checked").removeClass("disabled"),b===!0&&this.$icon.addClass("checked"),c===!0&&this.$icon.addClass("disabled")},enable:function(){this.$chk.attr("disabled",!1),this.$icon.removeClass("disabled")},disable:function(){this.$chk.attr("disabled",!0),this.$icon.addClass("disabled")},toggle:function(){this.$chk.click()},itemchecked:function(a){var c=b(a.target);this.setState(c)}},b.fn.checkbox=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("checkbox"),h=typeof a=="object"&&a;g||f.data("checkbox",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.checkbox.defaults={},b.fn.checkbox.Constructor=c,b(function(){b(window).on("load",function(){b(".checkbox-custom > input[type=checkbox]").each(function(){var a=b(this);if(a.data("checkbox"))return;a.checkbox(a.data())})})})}),define("fuelux/util",["require","jquery"],function(a){function c(a,c){return(a.textContent||a.innerText||b(a).text()||"").toLowerCase()===(c||"").toLowerCase()}var b=a("jquery");b.expr[":"].fuelTextExactCI=b.expr.createPseudo?b.expr.createPseudo(function(a){return function(b){return c(b,a)}}):function(a,b,d){return c(a,d[3])}}),define("fuelux/combobox",["require","jquery","./util"],function(a){var b=a("jquery");a("./util");var c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.combobox.defaults,c),this.$element.on("click","a",b.proxy(this.itemclicked,this)),this.$element.on("change","input",b.proxy(this.inputchanged,this)),this.$input=this.$element.find("input"),this.$button=this.$element.find(".btn"),this.setDefaultSelection()};c.prototype={constructor:c,selectedItem:function(){var a=this.$selectedItem,c={};if(a){var d=this.$selectedItem.text();c=b.extend({text:d},this.$selectedItem.data())}else c={text:this.$input.val()};return c},selectByText:function(a){var b="li:fuelTextExactCI("+a+")";this.selectBySelector(b)},selectByValue:function(a){var b='li[data-value="'+a+'"]';this.selectBySelector(b)},selectByIndex:function(a){var b="li:eq("+a+")";this.selectBySelector(b)},selectBySelector:function(a){var b=this.$element.find(a);typeof b[0]!="undefined"?(this.$selectedItem=b,this.$input.val(this.$selectedItem.text())):this.$selectedItem=null},setDefaultSelection:function(){var a="li[data-selected=true]:first",b=this.$element.find(a);b.length>0&&(this.selectBySelector(a),b.removeData("selected"),b.removeAttr("data-selected"))},enable:function(){this.$input.removeAttr("disabled"),this.$button.removeClass("disabled")},disable:function(){this.$input.attr("disabled",!0),this.$button.addClass("disabled")},itemclicked:function(a){this.$selectedItem=b(a.target).parent(),this.$input.val(this.$selectedItem.text()).trigger("change",{synthetic:!0});var c=this.selectedItem();this.$element.trigger("changed",c),a.preventDefault()},inputchanged:function(a,c){if(c&&c.synthetic)return;var d=b(a.target).val();this.selectByText(d);var e=this.selectedItem();e.text.length===0&&(e={text:d}),this.$element.trigger("changed",e)}},b.fn.combobox=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("combobox"),h=typeof a=="object"&&a;g||f.data("combobox",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.combobox.defaults={},b.fn.combobox.Constructor=c,b(function(){b(window).on("load",function(){b(".combobox").each(function(){var a=b(this);if(a.data("combobox"))return;a.combobox(a.data())})}),b("body").on("mousedown.combobox.data-api",".combobox",function(a){var c=b(this);if(c.data("combobox"))return;c.combobox(c.data())})})}),define("fuelux/datagrid",["require","jquery"],function(a){var b=a("jquery"),c=22,d=function(a,c){this.$element=b(a),this.$thead=this.$element.find("thead"),this.$tfoot=this.$element.find("tfoot"),this.$footer=this.$element.find("tfoot th"),this.$footerchildren=this.$footer.children().show().css("visibility","hidden"),this.$topheader=this.$element.find("thead th"),this.$searchcontrol=this.$element.find(".datagrid-search"),this.$filtercontrol=this.$element.find(".filter"),this.$pagesize=this.$element.find(".grid-pagesize"),this.$pageinput=this.$element.find(".grid-pager input"),this.$pagedropdown=this.$element.find(".grid-pager .dropdown-menu"),this.$prevpagebtn=this.$element.find(".grid-prevpage"),this.$nextpagebtn=this.$element.find(".grid-nextpage"),this.$pageslabel=this.$element.find(".grid-pages"),this.$countlabel=this.$element.find(".grid-count"),this.$startlabel=this.$element.find(".grid-start"),this.$endlabel=this.$element.find(".grid-end"),this.$tbody=b("<tbody>").insertAfter(this.$thead),this.$colheader=b("<tr>").appendTo(this.$thead),this.options=b.extend(!0,{},b.fn.datagrid.defaults,c),this.$pagesize.hasClass("select")?this.options.dataOptions.pageSize=parseInt(this.$pagesize.select("selectedItem").value,10):this.options.dataOptions.pageSize=parseInt(this.$pagesize.val(),10),this.$searchcontrol.length<=0&&(this.$searchcontrol=this.$element.find(".search")),this.columns=this.options.dataSource.columns(),this.$nextpagebtn.on("click",b.proxy(this.next,this)),this.$prevpagebtn.on("click",b.proxy(this.previous,this)),this.$searchcontrol.on("searched cleared",b.proxy(this.searchChanged,this)),this.$filtercontrol.on("changed",b.proxy(this.filterChanged,this)),this.$colheader.on("click","th",b.proxy(this.headerClicked,this)),this.$pagesize.hasClass("select")?this.$pagesize.on("changed",b.proxy(this.pagesizeChanged,this)):this.$pagesize.on("change",b.proxy(this.pagesizeChanged,this)),this.$pageinput.on("change",b.proxy(this.pageChanged,this)),this.renderColumns(),this.options.stretchHeight&&this.initStretchHeight(),this.renderData()};d.prototype={constructor:d,renderColumns:function(){var a=this;this.$footer.attr("colspan",this.columns.length),this.$topheader.attr("colspan",this.columns.length);var c="";b.each(this.columns,function(a,b){c+='<th data-property="'+b.property+'"',b.sortable&&(c+=' class="sortable"'),c+=">"+b.label+"</th>"}),a.$colheader.append(c)},updateColumns:function(a,b){this._updateColumns(this.$colheader,a,b),this.$sizingHeader&&this._updateColumns(this.$sizingHeader,this.$sizingHeader.find("th").eq(a.index()),b)},_updateColumns:function(a,c,d){var e=d==="asc"?"icon-chevron-up":"icon-chevron-down";a.find("i.datagrid-sort").remove(),a.find("th").removeClass("sorted"),b("<i>").addClass(e+" datagrid-sort").appendTo(c),c.addClass("sorted")},updatePageDropdown:function(a){var b="";for(var c=1;c<=a.pages;c++)b+="<li><a>"+c+"</a></li>";this.$pagedropdown.html(b)},updatePageButtons:function(a){a.page===1?this.$prevpagebtn.attr("disabled","disabled"):this.$prevpagebtn.removeAttr("disabled"),a.page===a.pages?this.$nextpagebtn.attr("disabled","disabled"):this.$nextpagebtn.removeAttr("disabled")},renderData:function(){var a=this;this.$tbody.html(this.placeholderRowHTML(this.options.loadingHTML)),this.options.dataSource.data(this.options.dataOptions,function(c){var d=c.count===1?a.options.itemText:a.options.itemsText,e="";a.$footerchildren.css("visibility",function(){return c.count>0?"visible":"hidden"}),a.$pageinput.val(c.page),a.$pageslabel.text(c.pages),a.$countlabel.text(c.count+" "+d),a.$startlabel.text(c.start),a.$endlabel.text(c.end),a.updatePageDropdown(c),a.updatePageButtons(c),b.each(c.data,function(c,d){e+="<tr>",b.each(a.columns,function(a,b){e+="<td>"+d[b.property]+"</td>"}),e+="</tr>"}),e||(e=a.placeholderRowHTML("0 "+a.options.itemsText)),a.$tbody.html(e),a.stretchHeight(),a.$element.trigger("loaded")})},placeholderRowHTML:function(a){return'<tr><td style="text-align:center;padding:20px;border-bottom:none;" colspan="'+this.columns.length+'">'+a+"</td></tr>"},headerClicked:function(a){var c=b(a.target);if(!c.hasClass("sortable"))return;var d=this.options.dataOptions.sortDirection,e=this.options.dataOptions.sortProperty,f=c.data("property");e===f?this.options.dataOptions.sortDirection=d==="asc"?"desc":"asc":(this.options.dataOptions.sortDirection="asc",this.options.dataOptions.sortProperty=f),this.options.dataOptions.pageIndex=0,this.updateColumns(c,this.options.dataOptions.sortDirection),this.renderData()},pagesizeChanged:function(a,c){c?this.options.dataOptions.pageSize=parseInt(c.value,10):this.options.dataOptions.pageSize=parseInt(b(a.target).val(),10),this.options.dataOptions.pageIndex=0,this.renderData()},pageChanged:function(a){var c=parseInt(b(a.target).val(),10);c=isNaN(c)?1:c;var d=this.$pageslabel.text();this.options.dataOptions.pageIndex=c>d?d-1:c-1,this.renderData()},searchChanged:function(a,b){this.options.dataOptions.search=b,this.options.dataOptions.pageIndex=0,this.renderData()},filterChanged:function(a,b){this.options.dataOptions.filter=b,this.options.dataOptions.pageIndex=0,this.renderData()},previous:function(){this.$nextpagebtn.attr("disabled","disabled"),this.$prevpagebtn.attr("disabled","disabled"),this.options.dataOptions.pageIndex--,this.renderData()},next:function(){this.$nextpagebtn.attr("disabled","disabled"),this.$prevpagebtn.attr("disabled","disabled"),this.options.dataOptions.pageIndex++,this.renderData()},reload:function(){this.options.dataOptions.pageIndex=0,this.renderData()},initStretchHeight:function(){this.$gridContainer=this.$element.parent(),this.$element.wrap('<div class="datagrid-stretch-wrapper">'),this.$stretchWrapper=this.$element.parent(),this.$headerTable=b("<table>").attr("class",this.$element.attr("class")),this.$footerTable=this.$headerTable.clone(),this.$headerTable.prependTo(this.$gridContainer).addClass("datagrid-stretch-header"),this.$thead.detach().appendTo(this.$headerTable),this.$sizingHeader=this.$thead.clone(),this.$sizingHeader.find("tr:first").remove(),this.$footerTable.appendTo(this.$gridContainer).addClass("datagrid-stretch-footer"),this.$tfoot.detach().appendTo(this.$footerTable)},stretchHeight:function(){if(!this.$gridContainer)return;this.setColumnWidths();var a=this.$gridContainer.height(),b=this.$headerTable.outerHeight(),c=this.$footerTable.outerHeight(),d=b+c;this.$stretchWrapper.height(a-d)},setColumnWidths:function(){function e(e,f){if(e===d-1)return;var g=b(f),h=a.eq(e),i=h.width();h.hasClass("sorted")&&g.prop("tagName")==="TD"&&(i=i+c),g.width(i)}if(!this.$sizingHeader)return;this.$element.prepend(this.$sizingHeader);var a=this.$sizingHeader.find("th"),d=a.length;this.$colheader.find("th").each(e),this.$tbody.find("tr:first > td").each(e),this.$sizingHeader.detach()}},b.fn.datagrid=function(a){return this.each(function(){var c=b(this),e=c.data("datagrid"),f=typeof a=="object"&&a;e||c.data("datagrid",e=new d(this,f)),typeof a=="string"&&e[a]()})},b.fn.datagrid.defaults={dataOptions:{pageIndex:0,pageSize:10},loadingHTML:'<div class="progress progress-striped active" style="width:50%;margin:auto;"><div class="bar" style="width:100%;"></div></div>',itemsText:"items",itemText:"item"},b.fn.datagrid.Constructor=d}),define("fuelux/pillbox",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.pillbox.defaults,c),this.$element.on("click","li",b.proxy(this.itemclicked,this))};c.prototype={constructor:c,items:function(){return this.$element.find("li").map(function(){var a=b(this);return b.extend({text:a.text()},a.data())}).get()},itemclicked:function(a){b(a.currentTarget).remove(),a.preventDefault()}},b.fn.pillbox=function(a){var d,e=this.each(function(){var e=b(this),f=e.data("pillbox"),g=typeof a=="object"&&a;f||e.data("pillbox",f=new c(this,g)),typeof a=="string"&&(d=f[a]())});return d===undefined?e:d},b.fn.pillbox.defaults={},b.fn.pillbox.Constructor=c,b(function(){b("body").on("mousedown.pillbox.data-api",".pillbox",function(a){var c=b(this);if(c.data("pillbox"))return;c.pillbox(c.data())})})}),define("fuelux/radio",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.radio.defaults,c),this.$label=this.$element.parent(),this.$icon=this.$label.find("i"),this.$radio=this.$label.find("input[type=radio]"),this.groupName=this.$radio.attr("name"),this.setState(this.$radio),this.$radio.on("change",b.proxy(this.itemchecked,this))};c.prototype={constructor:c,setState:function(a,b){var c=a.is(":checked"),d=a.is(":disabled");c===!0&&this.$icon.addClass("checked"),d===!0&&this.$icon.addClass("disabled")},resetGroup:function(){b("input[name="+this.groupName+"]").next().removeClass("checked")},enable:function(){this.$radio.attr("disabled",!1),this.$icon.removeClass("disabled")},disable:function(){this.$radio.attr("disabled",!0),this.$icon.addClass("disabled")},itemchecked:function(a){var c=b(a.target);this.resetGroup(),this.setState(c)}},b.fn.radio=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("radio"),h=typeof a=="object"&&a;g||f.data("radio",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.radio.defaults={},b.fn.radio.Constructor=c,b(function(){b(window).on("load",function(){b(".radio-custom > input[type=radio]").each(function(){var a=b(this);if(a.data("radio"))return;a.radio(a.data())})})})}),define("fuelux/search",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.search.defaults,c),this.$button=this.$element.find("button").on("click",b.proxy(this.buttonclicked,this)),this.$input=this.$element.find("input").on("keydown",b.proxy(this.keypress,this)).on("keyup",b.proxy(this.keypressed,this)),this.$icon=this.$element.find("i"),this.activeSearch=""};c.prototype={constructor:c,search:function(a){this.$icon.attr("class","icon-remove"),this.activeSearch=a,this.$element.trigger("searched",a)},clear:function(){this.$icon.attr("class","icon-search"),this.activeSearch="",this.$input.val(""),this.$element.trigger("cleared")},action:function(){var a=this.$input.val(),b=a===""||a===this.activeSearch;this.activeSearch&&b?this.clear():a&&this.search(a)},buttonclicked:function(a){a.preventDefault();if(b(a.currentTarget).is(".disabled, :disabled"))return;this.action()},keypress:function(a){a.which===13&&a.preventDefault()},keypressed:function(a){var b,c;a.which===13?(a.preventDefault(),this.action()):(b=this.$input.val(),c=b&&b===this.activeSearch,this.$icon.attr("class",c?"icon-remove":"icon-search"))},disable:function(){this.$input.attr("disabled","disabled"),this.$button.addClass("disabled")},enable:function(){this.$input.removeAttr("disabled"),this.$button.removeClass("disabled")}},b.fn.search=function(a){return this.each(function(){var d=b(this),e=d.data("search"),f=typeof a=="object"&&a;e||d.data("search",e=new c(this,f)),typeof a=="string"&&e[a]()})},b.fn.search.defaults={},b.fn.search.Constructor=c,b(function(){b("body").on("mousedown.search.data-api",".search",function(){var a=b(this);if(a.data("search"))return;a.search(a.data())})})}),define("fuelux/spinner",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.spinner.defaults,c),this.$input=this.$element.find(".spinner-input"),this.$element.on("keyup",this.$input,b.proxy(this.change,this)),this.options.hold?(this.$element.on("mousedown",".spinner-up",b.proxy(function(){this.startSpin(!0)},this)),this.$element.on("mouseup",".spinner-up, .spinner-down",b.proxy(this.stopSpin,this)),this.$element.on("mouseout",".spinner-up, .spinner-down",b.proxy(this.stopSpin,this)),this.$element.on("mousedown",".spinner-down",b.proxy(function(){this.startSpin(!1)},this))):(this.$element.on("click",".spinner-up",b.proxy(function(){this.step(!0)},this)),this.$element.on("click",".spinner-down",b.proxy(function(){this.step(!1)},this))),this.switches={count:1,enabled:!0},this.options.speed==="medium"?this.switches.speed=300:this.options.speed==="fast"?this.switches.speed=100:this.switches.speed=500,this.lastValue=null,this.render(),this.options.disabled&&this.disable()};c.prototype={constructor:c,render:function(){this.$input.val(this.options.value),this.$input.attr("maxlength",(this.options.max+"").split("").length)},change:function(){var a=this.$input.val();a/1?this.options.value=a/1:(a=a.replace(/[^0-9]/g,""),this.$input.val(a),this.options.value=a/1),this.triggerChangedEvent()},stopSpin:function(){clearTimeout(this.switches.timeout),this.switches.count=1,this.triggerChangedEvent()},triggerChangedEvent:function(){var a=this.value();if(a===this.lastValue)return;this.lastValue=a,this.$element.trigger("changed",a),this.$element.trigger("change")},startSpin:function(a){if(!this.options.disabled){var c=this.switches.count;c===1?(this.step(a),c=1):c<3?c=1.5:c<8?c=2.5:c=4,this.switches.timeout=setTimeout(b.proxy(function(){this.iterator(a)},this),this.switches.speed/c),this.switches.count++}},iterator:function(a){this.step(a),this.startSpin(a)},step:function(a){var b=this.options.value,c=a?this.options.max:this.options.min;if(a?b<c:b>c){var d=b+(a?1:-1)*this.options.step;(a?d>c:d<c)?this.value(c):this.value(d)}},value:function(a){return!isNaN(parseFloat(a))&&isFinite(a)?(a=parseFloat(a),this.options.value=a,this.$input.val(a),this):this.options.value},disable:function(){this.options.disabled=!0,this.$input.attr("disabled",""),this.$element.find("button").addClass("disabled")},enable:function(){this.options.disabled=!1,this.$input.removeAttr("disabled"),this.$element.find("button").removeClass("disabled")}},b.fn.spinner=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("spinner"),h=typeof a=="object"&&a;g||f.data("spinner",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.spinner.defaults={value:1,min:1,max:999,step:1,hold:!0,speed:"medium",disabled:!1},b.fn.spinner.Constructor=c,b(function(){b("body").on("mousedown.spinner.data-api",".spinner",function(a){var c=b(this);if(c.data("spinner"))return;c.spinner(c.data())})})}),define("fuelux/select",["require","jquery","./util"],function(a){var b=a("jquery");a("./util");var c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.select.defaults,c),this.$element.on("click","a",b.proxy(this.itemclicked,this)),this.$button=this.$element.find(".btn"),this.$label=this.$element.find(".dropdown-label"),this.setDefaultSelection(),c.resize==="auto"&&this.resize()};c.prototype={constructor:c,itemclicked:function(a){this.$selectedItem=b(a.target).parent(),this.$label.text(this.$selectedItem.text());var c=this.selectedItem();this.$element.trigger("changed",c),a.preventDefault()},resize:function(){var a=b("#selectTextSize")[0];a||b("<div/>").attr({id:"selectTextSize"}).appendTo("body");var c=0,d=0;this.$element.find("a").each(function(){var a=b(this),e=a.text(),f=b("#selectTextSize");f.text(e),d=f.outerWidth(),d>c&&(c=d)}),this.$label.width(c)},selectedItem:function(){var a=this.$selectedItem.text();return b.extend({text:a},this.$selectedItem.data())},selectByText:function(a){var b="li a:fuelTextExactCI("+a+")";this.selectBySelector(b)},selectByValue:function(a){var b='li[data-value="'+a+'"]';this.selectBySelector(b)},selectByIndex:function(a){var b="li:eq("+a+")";this.selectBySelector(b)},selectBySelector:function(a){var b=this.$element.find(a);this.$selectedItem=b,this.$label.text(this.$selectedItem.text())},setDefaultSelection:function(){var a="li[data-selected=true]:first",b=this.$element.find(a);b.length===0?this.selectByIndex(0):(this.selectBySelector(a),b.removeData("selected"),b.removeAttr("data-selected"))},enable:function(){this.$button.removeClass("disabled")},disable:function(){this.$button.addClass("disabled")}},b.fn.select=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("select"),h=typeof a=="object"&&a;g||f.data("select",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.select.defaults={},b.fn.select.Constructor=c,b(function(){b(window).on("load",function(){b(".select").each(function(){var a=b(this);if(a.data("select"))return;a.select(a.data())})}),b("body").on("mousedown.select.data-api",".select",function(a){var c=b(this);if(c.data("select"))return;c.select(c.data())})})}),define("fuelux/tree",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.tree.defaults,c),this.$element.on("click",".tree-item",b.proxy(function(a){this.selectItem(a.currentTarget)},this)),this.$element.on("click",".tree-folder-header",b.proxy(function(a){this.selectFolder(a.currentTarget)},this)),this.render()};c.prototype={constructor:c,render:function(){this.populate(this.$element)},populate:function(a){var c=this,d=a.parent().find(".tree-loader:eq(0)");d.show(),this.options.dataSource.data(a.data(),function(e){d.hide(),b.each(e.data,function(b,d){var e;d.type==="folder"?(e=c.$element.find(".tree-folder:eq(0)").clone().show(),e.find(".tree-folder-name").html(d.name),e.find(".tree-loader").html(c.options.loadingHTML),e.find(".tree-folder-header").data(d)):d.type==="item"&&(e=c.$element.find(".tree-item:eq(0)").clone().show(),e.find(".tree-item-name").html(d.name),e.data(d)),a.hasClass("tree-folder-header")?a.parent().find(".tree-folder-content:eq(0)").append(e):a.append(e)}),c.$element.trigger("loaded")})},selectItem:function(a){var c=b(a),d=this.$element.find(".tree-selected"),e=[];this.options.multiSelect?b.each(d,function(a,d){var f=b(d);f[0]!==c[0]&&e.push(b(d).data())}):d[0]!==c[0]&&(d.removeClass("tree-selected").find("i").removeClass("icon-ok").addClass("tree-dot"),e.push(c.data())),c.hasClass("tree-selected")?(c.removeClass("tree-selected"),c.find("i").removeClass("icon-ok").addClass("tree-dot")):(c.addClass("tree-selected"),c.find("i").removeClass("tree-dot").addClass("icon-ok"),this.options.multiSelect&&e.push(c.data())),e.length&&this.$element.trigger("selected",{info:e})},selectFolder:function(a){var c=b(a),d=c.parent();c.find(".icon-folder-close").length?(d.find(".tree-folder-content").children().length?d.find(".tree-folder-content:eq(0)").show():this.populate(c),d.find(".icon-folder-close:eq(0)").removeClass("icon-folder-close").addClass("icon-folder-open"),this.$element.trigger("opened",c.data())):(this.options.cacheItems?d.find(".tree-folder-content:eq(0)").hide():d.find(".tree-folder-content:eq(0)").empty(),d.find(".icon-folder-open:eq(0)").removeClass("icon-folder-open").addClass("icon-folder-close"),this.$element.trigger("closed",c.data()))},selectedItems:function(){var a=this.$element.find(".tree-selected"),c=[];return b.each(a,function(a,d){c.push(b(d).data())}),c}},b.fn.tree=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("tree"),h=typeof a=="object"&&a;g||f.data("tree",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.tree.defaults={multiSelect:!1,loadingHTML:"<div>Loading...</div>",cacheItems:!0},b.fn.tree.Constructor=c}),define("fuelux/wizard",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){var d;this.$element=b(a),this.options=b.extend({},b.fn.wizard.defaults,c),this.currentStep=1,this.numSteps=this.$element.find("li").length,this.$prevBtn=this.$element.find("button.btn-prev"),this.$nextBtn=this.$element.find("button.btn-next"),d=this.$nextBtn.children().detach(),this.nextText=b.trim(this.$nextBtn.text()),this.$nextBtn.append(d),this.$prevBtn.on("click",b.proxy(this.previous,this)),this.$nextBtn.on("click",b.proxy(this.next,this)),this.$element.on("click","li.complete",b.proxy(this.stepclicked,this))};c.prototype={constructor:c,setState:function(){var a=this.currentStep>1,c=this.currentStep===1,d=this.currentStep===this.numSteps;this.$prevBtn.attr("disabled",c===!0||a===!1);var e=this.$nextBtn.data();if(e&&e.last){this.lastText=e.last;if(typeof this.lastText!="undefined"){var f=d!==!0?this.nextText:this.lastText,g=this.$nextBtn.children().detach();this.$nextBtn.text(f).append(g)}}var h=this.$element.find("li");h.removeClass("active").removeClass("complete"),h.find("span.badge").removeClass("badge-info").removeClass("badge-success");var i="li:lt("+(this.currentStep-1)+")",j=this.$element.find(i);j.addClass("complete"),j.find("span.badge").addClass("badge-success");var k="li:eq("+(this.currentStep-1)+")",l=this.$element.find(k);l.addClass("active"),l.find("span.badge").addClass("badge-info");var m=l.data().target;b(".step-pane").removeClass("active"),b(m).addClass("active"),this.$element.trigger("changed")},stepclicked:function(a){var c=b(a.currentTarget),d=b(".steps li").index(c),e=b.Event("stepclick");this.$element.trigger(e,{step:d+1});if(e.isDefaultPrevented())return;this.currentStep=d+1,this.setState()},previous:function(){var a=this.currentStep>1;if(a){var c=b.Event("change");this.$element.trigger(c,{step:this.currentStep,direction:"previous"});if(c.isDefaultPrevented())return;this.currentStep-=1,this.setState()}},next:function(){var a=this.currentStep+1<=this.numSteps,c=this.currentStep===this.numSteps;if(a){var d=b.Event("change");this.$element.trigger(d,{step:this.currentStep,direction:"next"});if(d.isDefaultPrevented())return;this.currentStep+=1,this.setState()}else c&&this.$element.trigger("finished")},selectedItem:function(a){return{step:this.currentStep}}},b.fn.wizard=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("wizard"),h=typeof a=="object"&&a;g||f.data("wizard",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.wizard.defaults={},b.fn.wizard.Constructor=c,b(function(){b("body").on("mousedown.wizard.data-api",".wizard",function(){var a=b(this);if(a.data("wizard"))return;a.wizard(a.data())})})}),define("fuelux/all",["require","jquery","bootstrap/bootstrap-affix","bootstrap/bootstrap-alert","bootstrap/bootstrap-button","bootstrap/bootstrap-carousel","bootstrap/bootstrap-collapse","bootstrap/bootstrap-dropdown","bootstrap/bootstrap-modal","bootstrap/bootstrap-popover","bootstrap/bootstrap-scrollspy","bootstrap/bootstrap-tab","bootstrap/bootstrap-tooltip","bootstrap/bootstrap-transition","bootstrap/bootstrap-typeahead","fuelux/checkbox","fuelux/combobox","fuelux/datagrid","fuelux/pillbox","fuelux/radio","fuelux/search","fuelux/spinner","fuelux/select","fuelux/tree","fuelux/wizard"],function(a){a("jquery"),a("bootstrap/bootstrap-affix"),a("bootstrap/bootstrap-alert"),a("bootstrap/bootstrap-button"),a("bootstrap/bootstrap-carousel"),a("bootstrap/bootstrap-collapse"),a("bootstrap/bootstrap-dropdown"),a("bootstrap/bootstrap-modal"),a("bootstrap/bootstrap-popover"),a("bootstrap/bootstrap-scrollspy"),a("bootstrap/bootstrap-tab"),a("bootstrap/bootstrap-tooltip"),a("bootstrap/bootstrap-transition"),a("bootstrap/bootstrap-typeahead"),a("fuelux/checkbox"),a("fuelux/combobox"),a("fuelux/datagrid"),a("fuelux/pillbox"),a("fuelux/radio"),a("fuelux/search"),a("fuelux/spinner"),a("fuelux/select"),a("fuelux/tree"),a("fuelux/wizard")})})();
\ No newline at end of file
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/checkbox.js b/opendaylight/web/root/src/main/resources/js/fuelux/checkbox.js
new file mode 100755 (executable)
index 0000000..639300e
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Fuel UX Checkbox
+ * https://github.com/ExactTarget/fuelux
+ *
+ * Copyright (c) 2012 ExactTarget
+ * Licensed under the MIT license.
+ */
+
+define(['require','jquery'],function (require) {
+
+       var $ = require('jquery');
+
+
+       // CHECKBOX CONSTRUCTOR AND PROTOTYPE
+
+       var Checkbox = function (element, options) {
+
+               this.$element = $(element);
+               this.options = $.extend({}, $.fn.checkbox.defaults, options);
+
+               // cache elements
+               this.$label = this.$element.parent();
+               this.$icon = this.$label.find('i');
+               this.$chk = this.$label.find('input[type=checkbox]');
+
+               // set default state
+               this.setState(this.$chk);
+
+               // handle events
+               this.$chk.on('change', $.proxy(this.itemchecked, this));
+       };
+
+       Checkbox.prototype = {
+
+               constructor: Checkbox,
+
+               setState: function ($chk) {
+                       var checked = $chk.is(':checked');
+                       var disabled = $chk.is(':disabled');
+
+                       // reset classes
+                       this.$icon.removeClass('checked').removeClass('disabled');
+
+                       // set state of checkbox
+                       if (checked === true) {
+                               this.$icon.addClass('checked');
+                       }
+                       if (disabled === true) {
+                               this.$icon.addClass('disabled');
+                       }
+               },
+
+               enable: function () {
+                       this.$chk.attr('disabled', false);
+                       this.$icon.removeClass('disabled');
+               },
+
+               disable: function () {
+                       this.$chk.attr('disabled', true);
+                       this.$icon.addClass('disabled');
+               },
+
+               toggle: function () {
+                       this.$chk.click();
+               },
+
+               itemchecked: function (e) {
+                       var chk = $(e.target);
+                       this.setState(chk);
+               }
+       };
+
+
+       // CHECKBOX PLUGIN DEFINITION
+
+       $.fn.checkbox = function (option, value) {
+               var methodReturn;
+
+               var $set = this.each(function () {
+                       var $this = $(this);
+                       var data = $this.data('checkbox');
+                       var options = typeof option === 'object' && option;
+
+                       if (!data) $this.data('checkbox', (data = new Checkbox(this, options)));
+                       if (typeof option === 'string') methodReturn = data[option](value);
+               });
+
+               return (methodReturn === undefined) ? $set : methodReturn;
+       };
+
+       $.fn.checkbox.defaults = {};
+
+       $.fn.checkbox.Constructor = Checkbox;
+
+
+       // CHECKBOX DATA-API
+
+       $(function () {
+               $(window).on('load', function () {
+                       //$('i.checkbox').each(function () {
+                       $('.checkbox-custom > input[type=checkbox]').each(function () {
+                               var $this = $(this);
+                               if ($this.data('checkbox')) return;
+                               $this.checkbox($this.data());
+                       });
+               });
+       });
+
+});
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/combobox.js b/opendaylight/web/root/src/main/resources/js/fuelux/combobox.js
new file mode 100755 (executable)
index 0000000..1d0a132
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Fuel UX Combobox
+ * https://github.com/ExactTarget/fuelux
+ *
+ * Copyright (c) 2012 ExactTarget
+ * Licensed under the MIT license.
+ */
+
+define(['require','jquery','./util'],function (require) {
+
+       var $ = require('jquery');
+       require('./util');
+
+       // COMBOBOX CONSTRUCTOR AND PROTOTYPE
+
+       var Combobox = function (element, options) {
+               this.$element = $(element);
+               this.options = $.extend({}, $.fn.combobox.defaults, options);
+               this.$element.on('click', 'a', $.proxy(this.itemclicked, this));
+               this.$element.on('change', 'input', $.proxy(this.inputchanged, this));
+               this.$input = this.$element.find('input');
+               this.$button = this.$element.find('.btn');
+
+               // set default selection
+               this.setDefaultSelection();
+       };
+
+       Combobox.prototype = {
+
+               constructor: Combobox,
+
+               selectedItem: function () {
+                       var item = this.$selectedItem;
+                       var data = {};
+
+                       if (item) {
+                               var txt = this.$selectedItem.text();
+                               data = $.extend({ text: txt }, this.$selectedItem.data());
+                       }
+                       else {
+                               data = { text: this.$input.val()};
+                       }
+
+                       return data;
+               },
+
+               selectByText: function (text) {
+                       var selector = 'li:fuelTextExactCI(' + text + ')';
+                       this.selectBySelector(selector);
+               },
+
+               selectByValue: function (value) {
+                       var selector = 'li[data-value="' + value + '"]';
+                       this.selectBySelector(selector);
+               },
+
+               selectByIndex: function (index) {
+                       // zero-based index
+                       var selector = 'li:eq(' + index + ')';
+                       this.selectBySelector(selector);
+               },
+
+               selectBySelector: function (selector) {
+                       var $item = this.$element.find(selector);
+
+                       if (typeof $item[0] !== 'undefined') {
+                               this.$selectedItem = $item;
+                               this.$input.val(this.$selectedItem.text());
+                       }
+                       else {
+                               this.$selectedItem = null;
+                       }
+               },
+
+               setDefaultSelection: function () {
+                       var selector = 'li[data-selected=true]:first';
+                       var item = this.$element.find(selector);
+
+                       if (item.length > 0) {
+                               // select by data-attribute
+                               this.selectBySelector(selector);
+                               item.removeData('selected');
+                               item.removeAttr('data-selected');
+                       }
+               },
+
+               enable: function () {
+                       this.$input.removeAttr('disabled');
+                       this.$button.removeClass('disabled');
+               },
+
+               disable: function () {
+                       this.$input.attr('disabled', true);
+                       this.$button.addClass('disabled');
+               },
+
+               itemclicked: function (e) {
+                       this.$selectedItem = $(e.target).parent();
+
+                       // set input text and trigger input change event marked as synthetic
+                       this.$input.val(this.$selectedItem.text()).trigger('change', { synthetic: true });
+
+                       // pass object including text and any data-attributes
+                       // to onchange event
+                       var data = this.selectedItem();
+
+                       // trigger changed event
+                       this.$element.trigger('changed', data);
+
+                       e.preventDefault();
+               },
+
+               inputchanged: function (e, extra) {
+
+                       // skip processing for internally-generated synthetic event
+                       // to avoid double processing
+                       if (extra && extra.synthetic) return;
+
+                       var val = $(e.target).val();
+                       this.selectByText(val);
+
+                       // find match based on input
+                       // if no match, pass the input value
+                       var data = this.selectedItem();
+                       if (data.text.length === 0) {
+                               data = { text: val };
+                       }
+
+                       // trigger changed event
+                       this.$element.trigger('changed', data);
+
+               }
+
+       };
+
+
+       // COMBOBOX PLUGIN DEFINITION
+
+       $.fn.combobox = function (option, value) {
+               var methodReturn;
+
+               var $set = this.each(function () {
+                       var $this = $(this);
+                       var data = $this.data('combobox');
+                       var options = typeof option === 'object' && option;
+
+                       if (!data) $this.data('combobox', (data = new Combobox(this, options)));
+                       if (typeof option === 'string') methodReturn = data[option](value);
+               });
+
+               return (methodReturn === undefined) ? $set : methodReturn;
+       };
+
+       $.fn.combobox.defaults = {};
+
+       $.fn.combobox.Constructor = Combobox;
+
+
+       // COMBOBOX DATA-API
+
+       $(function () {
+
+               $(window).on('load', function () {
+                       $('.combobox').each(function () {
+                               var $this = $(this);
+                               if ($this.data('combobox')) return;
+                               $this.combobox($this.data());
+                       });
+               });
+
+               $('body').on('mousedown.combobox.data-api', '.combobox', function (e) {
+                       var $this = $(this);
+                       if ($this.data('combobox')) return;
+                       $this.combobox($this.data());
+               });
+       });
+
+});
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/datagrid.js b/opendaylight/web/root/src/main/resources/js/fuelux/datagrid.js
new file mode 100755 (executable)
index 0000000..e051928
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Fuel UX Datagrid
+ * https://github.com/ExactTarget/fuelux
+ *
+ * Copyright (c) 2012 ExactTarget
+ * Licensed under the MIT license.
+ */
+
+define(['require','jquery'],function(require) {
+
+       var $ = require('jquery');
+
+       // Relates to thead .sorted styles in datagrid.less
+       var SORTED_HEADER_OFFSET = 22;
+
+
+       // DATAGRID CONSTRUCTOR AND PROTOTYPE
+
+       var Datagrid = function (element, options) {
+               this.$element = $(element);
+               this.$thead = this.$element.find('thead');
+               this.$tfoot = this.$element.find('tfoot');
+               this.$footer = this.$element.find('tfoot th');
+               this.$footerchildren = this.$footer.children().show().css('visibility', 'hidden');
+               this.$topheader = this.$element.find('thead th');
+               this.$searchcontrol = this.$element.find('.datagrid-search');
+               this.$filtercontrol = this.$element.find('.filter');
+               this.$pagesize = this.$element.find('.grid-pagesize');
+               this.$pageinput = this.$element.find('.grid-pager input');
+               this.$pagedropdown = this.$element.find('.grid-pager .dropdown-menu');
+               this.$prevpagebtn = this.$element.find('.grid-prevpage');
+               this.$nextpagebtn = this.$element.find('.grid-nextpage');
+               this.$pageslabel = this.$element.find('.grid-pages');
+               this.$countlabel = this.$element.find('.grid-count');
+               this.$startlabel = this.$element.find('.grid-start');
+               this.$endlabel = this.$element.find('.grid-end');
+
+               this.$tbody = $('<tbody>').insertAfter(this.$thead);
+               this.$colheader = $('<tr>').appendTo(this.$thead);
+
+               this.options = $.extend(true, {}, $.fn.datagrid.defaults, options);
+
+               // Shim until v3 -- account for FuelUX select or native select for page size:
+               if (this.$pagesize.hasClass('select')) {
+                       this.options.dataOptions.pageSize = parseInt(this.$pagesize.select('selectedItem').value, 10);
+               } else {
+                       this.options.dataOptions.pageSize = parseInt(this.$pagesize.val(), 10);
+               }
+
+               // Shim until v3 -- account for older search class:
+               if (this.$searchcontrol.length <= 0) {
+                       this.$searchcontrol = this.$element.find('.search');
+               }
+
+               this.columns = this.options.dataSource.columns();
+
+               this.$nextpagebtn.on('click', $.proxy(this.next, this));
+               this.$prevpagebtn.on('click', $.proxy(this.previous, this));
+               this.$searchcontrol.on('searched cleared', $.proxy(this.searchChanged, this));
+               this.$filtercontrol.on('changed', $.proxy(this.filterChanged, this));
+               this.$colheader.on('click', 'th', $.proxy(this.headerClicked, this));
+
+               if(this.$pagesize.hasClass('select')) {
+                       this.$pagesize.on('changed', $.proxy(this.pagesizeChanged, this));
+               } else {
+                       this.$pagesize.on('change', $.proxy(this.pagesizeChanged, this));
+               }
+
+               this.$pageinput.on('change', $.proxy(this.pageChanged, this));
+
+               this.renderColumns();
+
+               if (this.options.stretchHeight) this.initStretchHeight();
+
+               this.renderData();
+       };
+
+       Datagrid.prototype = {
+
+               constructor: Datagrid,
+
+               renderColumns: function () {
+                       var self = this;
+
+                       this.$footer.attr('colspan', this.columns.length);
+                       this.$topheader.attr('colspan', this.columns.length);
+
+                       var colHTML = '';
+
+                       $.each(this.columns, function (index, column) {
+                               colHTML += '<th data-property="' + column.property + '"';
+                               if (column.sortable) colHTML += ' class="sortable"';
+                               colHTML += '>' + column.label + '</th>';
+                       });
+
+                       self.$colheader.append(colHTML);
+               },
+
+               updateColumns: function ($target, direction) {
+                       this._updateColumns(this.$colheader, $target, direction);
+
+                       if (this.$sizingHeader) {
+                               this._updateColumns(this.$sizingHeader, this.$sizingHeader.find('th').eq($target.index()), direction);
+                       }
+               },
+
+               _updateColumns: function ($header, $target, direction) {
+                       var className = (direction === 'asc') ? 'icon-chevron-up' : 'icon-chevron-down';
+                       $header.find('i.datagrid-sort').remove();
+                       $header.find('th').removeClass('sorted');
+                       $('<i>').addClass(className + ' datagrid-sort').appendTo($target);
+                       $target.addClass('sorted');
+               },
+
+               updatePageDropdown: function (data) {
+                       var pageHTML = '';
+
+                       for (var i = 1; i <= data.pages; i++) {
+                               pageHTML += '<li><a>' + i + '</a></li>';
+                       }
+
+                       this.$pagedropdown.html(pageHTML);
+               },
+
+               updatePageButtons: function (data) {
+                       if (data.page === 1) {
+                               this.$prevpagebtn.attr('disabled', 'disabled');
+                       } else {
+                               this.$prevpagebtn.removeAttr('disabled');
+                       }
+
+                       if (data.page === data.pages) {
+                               this.$nextpagebtn.attr('disabled', 'disabled');
+                       } else {
+                               this.$nextpagebtn.removeAttr('disabled');
+                       }
+               },
+
+               renderData: function () {
+                       var self = this;
+
+                       this.$tbody.html(this.placeholderRowHTML(this.options.loadingHTML));
+
+                       this.options.dataSource.data(this.options.dataOptions, function (data) {
+                               var itemdesc = (data.count === 1) ? self.options.itemText : self.options.itemsText;
+                               var rowHTML = '';
+
+                               self.$footerchildren.css('visibility', function () {
+                                       return (data.count > 0) ? 'visible' : 'hidden';
+                               });
+
+                               self.$pageinput.val(data.page);
+                               self.$pageslabel.text(data.pages);
+                               self.$countlabel.text(data.count + ' ' + itemdesc);
+                               self.$startlabel.text(data.start);
+                               self.$endlabel.text(data.end);
+
+                               self.updatePageDropdown(data);
+                               self.updatePageButtons(data);
+
+                               $.each(data.data, function (index, row) {
+                                       rowHTML += '<tr>';
+                                       $.each(self.columns, function (index, column) {
+                                               rowHTML += '<td>' + row[column.property] + '</td>';
+                                       });
+                                       rowHTML += '</tr>';
+                               });
+
+                               if (!rowHTML) rowHTML = self.placeholderRowHTML('0 ' + self.options.itemsText);
+
+                               self.$tbody.html(rowHTML);
+                               self.stretchHeight();
+
+                               self.$element.trigger('loaded');
+                       });
+
+               },
+
+               placeholderRowHTML: function (content) {
+                       return '<tr><td style="text-align:center;padding:20px;border-bottom:none;" colspan="' +
+                               this.columns.length + '">' + content + '</td></tr>';
+               },
+
+               headerClicked: function (e) {
+                       var $target = $(e.target);
+                       if (!$target.hasClass('sortable')) return;
+
+                       var direction = this.options.dataOptions.sortDirection;
+                       var sort = this.options.dataOptions.sortProperty;
+                       var property = $target.data('property');
+
+                       if (sort === property) {
+                               this.options.dataOptions.sortDirection = (direction === 'asc') ? 'desc' : 'asc';
+                       } else {
+                               this.options.dataOptions.sortDirection = 'asc';
+                               this.options.dataOptions.sortProperty = property;
+                       }
+
+                       this.options.dataOptions.pageIndex = 0;
+                       this.updateColumns($target, this.options.dataOptions.sortDirection);
+                       this.renderData();
+               },
+
+               pagesizeChanged: function (e, pageSize) {
+                       if(pageSize) {
+                               this.options.dataOptions.pageSize = parseInt(pageSize.value, 10);
+                       } else {
+                               this.options.dataOptions.pageSize = parseInt($(e.target).val(), 10);
+                       }
+
+                       this.options.dataOptions.pageIndex = 0;
+                       this.renderData();
+               },
+
+               pageChanged: function (e) {
+                       var pageRequested = parseInt($(e.target).val(), 10);
+                       pageRequested = (isNaN(pageRequested)) ? 1 : pageRequested;
+                       var maxPages = this.$pageslabel.text();
+               
+                       this.options.dataOptions.pageIndex = 
+                               (pageRequested > maxPages) ? maxPages - 1 : pageRequested - 1;
+
+                       this.renderData();
+               },
+
+               searchChanged: function (e, search) {
+                       this.options.dataOptions.search = search;
+                       this.options.dataOptions.pageIndex = 0;
+                       this.renderData();
+               },
+
+               filterChanged: function (e, filter) {
+                       this.options.dataOptions.filter = filter;
+                       this.options.dataOptions.pageIndex = 0;
+                       this.renderData();
+               },
+
+               previous: function () {
+                       this.$nextpagebtn.attr('disabled', 'disabled');
+                       this.$prevpagebtn.attr('disabled', 'disabled');
+                       this.options.dataOptions.pageIndex--;
+                       this.renderData();
+               },
+
+               next: function () {
+                       this.$nextpagebtn.attr('disabled', 'disabled');
+                       this.$prevpagebtn.attr('disabled', 'disabled');
+                       this.options.dataOptions.pageIndex++;
+                       this.renderData();
+               },
+
+               reload: function () {
+                       this.options.dataOptions.pageIndex = 0;
+                       this.renderData();
+               },
+
+               initStretchHeight: function () {
+                       this.$gridContainer = this.$element.parent();
+
+                       this.$element.wrap('<div class="datagrid-stretch-wrapper">');
+                       this.$stretchWrapper = this.$element.parent();
+
+                       this.$headerTable = $('<table>').attr('class', this.$element.attr('class'));
+                       this.$footerTable = this.$headerTable.clone();
+
+                       this.$headerTable.prependTo(this.$gridContainer).addClass('datagrid-stretch-header');
+                       this.$thead.detach().appendTo(this.$headerTable);
+
+                       this.$sizingHeader = this.$thead.clone();
+                       this.$sizingHeader.find('tr:first').remove();
+
+                       this.$footerTable.appendTo(this.$gridContainer).addClass('datagrid-stretch-footer');
+                       this.$tfoot.detach().appendTo(this.$footerTable);
+               },
+
+               stretchHeight: function () {
+                       if (!this.$gridContainer) return;
+
+                       this.setColumnWidths();
+
+                       var targetHeight = this.$gridContainer.height();
+                       var headerHeight = this.$headerTable.outerHeight();
+                       var footerHeight = this.$footerTable.outerHeight();
+                       var overhead = headerHeight + footerHeight;
+
+                       this.$stretchWrapper.height(targetHeight - overhead);
+               },
+
+               setColumnWidths: function () {
+                       if (!this.$sizingHeader) return;
+
+                       this.$element.prepend(this.$sizingHeader);
+
+                       var $sizingCells = this.$sizingHeader.find('th');
+                       var columnCount = $sizingCells.length;
+
+                       function matchSizingCellWidth(i, el) {
+                               if (i === columnCount - 1) return;
+
+                               var $el = $(el);
+                               var $sourceCell = $sizingCells.eq(i);
+                               var width = $sourceCell.width();
+
+                               // TD needs extra width to match sorted column header
+                               if ($sourceCell.hasClass('sorted') && $el.prop('tagName') === 'TD') width = width + SORTED_HEADER_OFFSET;
+
+                               $el.width(width);
+                       }
+
+                       this.$colheader.find('th').each(matchSizingCellWidth);
+                       this.$tbody.find('tr:first > td').each(matchSizingCellWidth);
+
+                       this.$sizingHeader.detach();
+               }
+       };
+
+
+       // DATAGRID PLUGIN DEFINITION
+
+       $.fn.datagrid = function (option) {
+               return this.each(function () {
+                       var $this = $(this);
+                       var data = $this.data('datagrid');
+                       var options = typeof option === 'object' && option;
+
+                       if (!data) $this.data('datagrid', (data = new Datagrid(this, options)));
+                       if (typeof option === 'string') data[option]();
+               });
+       };
+
+       $.fn.datagrid.defaults = {
+               dataOptions: { pageIndex: 0, pageSize: 10 },
+               loadingHTML: '<div class="progress progress-striped active" style="width:50%;margin:auto;"><div class="bar" style="width:100%;"></div></div>',
+               itemsText: 'items',
+               itemText: 'item'
+       };
+
+       $.fn.datagrid.Constructor = Datagrid;
+
+});
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/loader.min.js b/opendaylight/web/root/src/main/resources/js/fuelux/loader.min.js
new file mode 100755 (executable)
index 0000000..fe68290
--- /dev/null
@@ -0,0 +1,4 @@
+/*! Fuel UX - v2.3.1 - 2013-08-02
+* https://github.com/ExactTarget/fuelux
+* Copyright (c) 2013 ExactTarget; Licensed MIT */
+(function(){var a,b,c;(function(d){function l(a,b){var c,d,e,f,g,h,j,k,l,m,n=b&&b.split("/"),o=i.map,p=o&&o["*"]||{};if(a&&a.charAt(0)==="."&&b){n=n.slice(0,n.length-1),a=n.concat(a.split("/"));for(k=0;k<a.length;k+=1){m=a[k];if(m===".")a.splice(k,1),k-=1;else if(m==="..")if(k!==1||a[2]!==".."&&a[0]!=="..")k>0&&(a.splice(k-1,2),k-=2);else break}a=a.join("/")}if((n||p)&&o){c=a.split("/");for(k=c.length;k>0;k-=1){d=c.slice(0,k).join("/");if(n)for(l=n.length;l>0;l-=1){e=o[n.slice(0,l).join("/")];if(e){e=e[d];if(e){f=e,g=k;break}}}if(f)break;!h&&p&&p[d]&&(h=p[d],j=k)}!f&&h&&(f=h,g=j),f&&(c.splice(0,g,f),a=c.join("/"))}return a}function m(a,b){return function(){return f.apply(d,k.call(arguments,0).concat([a,b]))}}function n(a){return function(b){return l(b,a)}}function o(a){return function(b){g[a]=b}}function p(a){if(h.hasOwnProperty(a)){var b=h[a];delete h[a],j[a]=!0,e.apply(d,b)}if(!g.hasOwnProperty(a))throw new Error("No "+a);return g[a]}function q(a,b){var c,d,e=a.indexOf("!");return e!==-1?(c=l(a.slice(0,e),b),a=a.slice(e+1),d=p(c),d&&d.normalize?a=d.normalize(a,n(b)):a=l(a,b)):a=l(a,b),{f:c?c+"!"+a:a,n:a,p:d}}function r(a){return function(){return i&&i.config&&i.config[a]||{}}}var e,f,g={},h={},i={},j={},k=[].slice;e=function(a,b,c,e){var f,i,k,l,n,s=[],t;e=e||a;if(typeof c=="function"){b=!b.length&&c.length?["require","exports","module"]:b;for(n=0;n<b.length;n+=1){l=q(b[n],e),i=l.f;if(i==="require")s[n]=m(a);else if(i==="exports")s[n]=g[a]={},t=!0;else if(i==="module")f=s[n]={id:a,uri:"",exports:g[a],config:r(a)};else if(g.hasOwnProperty(i)||h.hasOwnProperty(i))s[n]=p(i);else if(l.p)l.p.load(l.n,m(e,!0),o(i),{}),s[n]=g[i];else if(!j[i])throw new Error(a+" missing "+i)}k=c.apply(g[a],s);if(a)if(f&&f.exports!==d&&f.exports!==g[a])g[a]=f.exports;else if(k!==d||!t)g[a]=k}else a&&(g[a]=c)},a=b=f=function(a,b,c,g,h){return typeof a=="string"?p(q(a,b).f):(a.splice||(i=a,b.splice?(a=b,b=c,c=null):a=d),b=b||function(){},typeof c=="function"&&(c=g,g=h),g?e(d,a,b,c):setTimeout(function(){e(d,a,b,c)},15),f)},f.config=function(a){return i=a,f},c=function(a,b,c){b.splice||(c=b,b=[]),h[a]=[a,b,c]},c.amd={jQuery:!0}})(),c("almond",function(){}),function(a){var b;c("bootstrap/bootstrap-transition",["jquery"],function(){return function(){!function(a){a(function(){a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery)}.call(a),b})}(this),function(a){var b;c("bootstrap/bootstrap-affix",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b,c){this.options=a.extend({},a.fn.affix.defaults,c),this.$window=a(window).on("scroll.affix.data-api",a.proxy(this.checkPosition,this)).on("click.affix.data-api",a.proxy(function(){setTimeout(a.proxy(this.checkPosition,this),1)},this)),this.$element=a(b),this.checkPosition()};b.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var b=a(document).height(),c=this.$window.scrollTop(),d=this.$element.offset(),e=this.options.offset,f=e.bottom,g=e.top,h="affix affix-top affix-bottom",i;typeof e!="object"&&(f=g=e),typeof g=="function"&&(g=e.top()),typeof f=="function"&&(f=e.bottom()),i=this.unpin!=null&&c+this.unpin<=d.top?!1:f!=null&&d.top+this.$element.height()>=b-f?"bottom":g!=null&&c<=g?"top":!1;if(this.affixed===i)return;this.affixed=i,this.unpin=i=="bottom"?d.top-c:null,this.$element.removeClass(h).addClass("affix"+(i?"-"+i:""))};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("affix"),f=typeof c=="object"&&c;e||d.data("affix",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.defaults={offset:0},a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(window.jQuery)}.call(a),b})}(this),function(a){var b;c("bootstrap/bootstrap-alert",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.alert.data-api",b,c.prototype.close)}(window.jQuery)}.call(a),b})}(this),function(a){var b;c("bootstrap/bootstrap-button",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a=a+"Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})}(window.jQuery)}.call(a),b})}(this),function(a){var b;c("bootstrap/bootstrap-carousel",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.options.pause=="hover"&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.prototype={cycle:function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(b){var c=this.getActiveIndex(),d=this;if(b>this.$items.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){d.to(b)}):c==b?this.pause().cycle():this.slide(b>c?"next":"prev",a(this.$items[b]))},pause:function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this,j;this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h](),j=a.Event("slide",{relatedTarget:e[0],direction:g});if(e.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")}));if(a.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(j);if(j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})}else{this.$element.trigger(j);if(j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=a.extend({},a.fn.carousel.defaults,typeof c=="object"&&c),g=typeof c=="string"?c:f.slide;e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.defaults={interval:5e3,pause:"hover"},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),c.data()),g;e.carousel(f),(g=c.attr("data-slide-to"))&&e.data("carousel").pause().to(g).cycle(),b.preventDefault()})}(window.jQuery)}.call(a),b})}(this),function(a){var b;c("bootstrap/bootstrap-collapse",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b,c,d,e;if(this.transitioning||this.$element.hasClass("in"))return;b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find("> .accordion-group > .in");if(d&&d.length){e=d.data("collapse");if(e&&e.transitioning)return;d.collapse("hide"),e||d.data("collapse",null)}this.$element[b](0),this.transition("addClass",a.Event("show"),"shown"),a.support.transition&&this.$element[b](this.$element[0][c])},hide:function(){var b;if(this.transitioning||!this.$element.hasClass("in"))return;b=this.dimension(),this.reset(this.$element[b]()),this.transition("removeClass",a.Event("hide"),"hidden"),this.$element[b](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a!==null?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c.type=="show"&&e.reset(),e.transitioning=0,e.$element.trigger(d)};this.$element.trigger(c);if(c.isDefaultPrevented())return;this.transitioning=1,this.$element[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=a.extend({},a.fn.collapse.defaults,d.data(),typeof c=="object"&&c);e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();c[a(e).hasClass("in")?"addClass":"removeClass"]("collapsed"),a(e).collapse(f)})}(window.jQuery)}.call(a),b})}(this),function(a){var b;c("bootstrap/bootstrap-dropdown",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){function d(){a(".dropdown-backdrop").remove(),a(b).each(function(){e(a(this)).removeClass("open")})}function e(b){var c=b.attr("data-target"),d;c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,"")),d=c&&a(c);if(!d||!d.length)d=b.parent();return d}var b="[data-toggle=dropdown]",c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),f,g;if(c.is(".disabled, :disabled"))return;return f=e(c),g=f.hasClass("open"),d(),g||("ontouchstart"in document.documentElement&&a('<div class="dropdown-backdrop"/>').insertBefore(a(this)).on("click",d),f.toggleClass("open")),c.focus(),!1},keydown:function(c){var d,f,g,h,i,j;if(!/(38|40|27)/.test(c.keyCode))return;d=a(this),c.preventDefault(),c.stopPropagation();if(d.is(".disabled, :disabled"))return;h=e(d),i=h.hasClass("open");if(!i||i&&c.keyCode==27)return c.which==27&&h.find(b).focus(),d.click();f=a("[role=menu] li:not(.divider):visible a",h);if(!f.length)return;j=f.index(f.filter(":focus")),c.keyCode==38&&j>0&&j--,c.keyCode==40&&j<f.length-1&&j++,~j||(j=0),f.eq(j).focus()}};var f=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=f,this},a(document).on("click.dropdown.data-api",d).on("click.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle).on("keydown.dropdown.data-api",b+", [role=menu]",c.prototype.keydown)}(window.jQuery)}.call(a),b})}(this),function(a){var b;c("bootstrap/bootstrap-modal",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in").attr("aria-hidden",!1),b.enforceFocus(),c?b.$element.one(a.support.transition.end,function(){b.$element.focus().trigger("shown")}):b.$element.focus().trigger("shown")})},hide:function(b){b&&b.preventDefault();var c=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,this.escape(),a(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),a.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var b=this;a(document).on("focusin.modal",function(a){b.$element[0]!==a.target&&!b.$element.has(a.target).length&&b.$element.focus()})},escape:function(){var a=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(b){b.which==27&&a.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),b.hideModal()},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),b.hideModal()})},hideModal:function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?a.proxy(this.$element[0].focus,this.$element[0]):a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!b)return;e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b):b()):b&&b()}};var c=a.fn.modal;a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=a.extend({},a.fn.modal.defaults,d.data(),typeof c=="object"&&c);e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():f.show&&e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f).one("hide",function(){c.focus()})})}(window.jQuery)}.call(a),b})}(this),function(a){var b;c("bootstrap/bootstrap-tooltip",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(a,b){this.init("tooltip",a,b)};b.prototype={constructor:b,init:function(b,c,d){var e,f,g,h,i;this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.enabled=!0,g=this.options.trigger.split(" ");for(i=g.length;i--;)h=g[i],h=="click"?this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this)):h!="manual"&&(e=h=="hover"?"mouseenter":"focus",f=h=="hover"?"mouseleave":"blur",this.$element.on(e+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(f+"."+this.type,this.options.selector,a.proxy(this.leave,this)));this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(b){return b=a.extend({},a.fn[this.type].defaults,this.$element.data(),b),b.delay&&typeof b.delay=="number"&&(b.delay={show:b.delay,hide:b.delay}),b},enter:function(b){var c=a.fn[this.type].defaults,d={},e;this._options&&a.each(this._options,function(a,b){c[a]!=b&&(d[a]=b)}),e=a(b.currentTarget)[this.type](d).data(this.type);if(!e.options.delay||!e.options.delay.show)return e.show();clearTimeout(this.timeout),e.hoverState="in",this.timeout=setTimeout(function(){e.hoverState=="in"&&e.show()},e.options.delay.show)},leave:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!c.options.delay||!c.options.delay.hide)return c.hide();c.hoverState="out",this.timeout=setTimeout(function(){c.hoverState=="out"&&c.hide()},c.options.delay.hide)},show:function(){var b,c,d,e,f,g,h=a.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(h);if(h.isDefaultPrevented())return;b=this.tip(),this.setContent(),this.options.animation&&b.addClass("fade"),f=typeof this.options.placement=="function"?this.options.placement.call(this,b[0],this.$element[0]):this.options.placement,b.detach().css({top:0,left:0,display:"block"}),this.options.container?b.appendTo(this.options.container):b.insertAfter(this.$element),c=this.getPosition(),d=b[0].offsetWidth,e=b[0].offsetHeight;switch(f){case"bottom":g={top:c.top+c.height,left:c.left+c.width/2-d/2};break;case"top":g={top:c.top-e,left:c.left+c.width/2-d/2};break;case"left":g={top:c.top+c.height/2-e/2,left:c.left-d};break;case"right":g={top:c.top+c.height/2-e/2,left:c.left+c.width}}this.applyPlacement(g,f),this.$element.trigger("shown")}},applyPlacement:function(a,b){var c=this.tip(),d=c[0].offsetWidth,e=c[0].offsetHeight,f,g,h,i;c.offset(a).addClass(b).addClass("in"),f=c[0].offsetWidth,g=c[0].offsetHeight,b=="top"&&g!=e&&(a.top=a.top+e-g,i=!0),b=="bottom"||b=="top"?(h=0,a.left<0&&(h=a.left*-2,a.left=0,c.offset(a),f=c[0].offsetWidth,g=c[0].offsetHeight),this.replaceArrow(h-d+f,f,"left")):this.replaceArrow(g-e,g,"top"),i&&c.offset(a)},replaceArrow:function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},setContent:function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},hide:function(){function e(){var b=setTimeout(function(){c.off(a.support.transition.end).detach()},500);c.one(a.support.transition.end,function(){clearTimeout(b),c.detach()})}var b=this,c=this.tip(),d=a.Event("hide");this.$element.trigger(d);if(d.isDefaultPrevented())return;return c.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?e():c.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var a=this.$element;(a.attr("title")||typeof a.attr("data-original-title")!="string")&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var b=this.$element[0];return a.extend({},typeof b.getBoundingClientRect=="function"?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},getTitle:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||(typeof c.title=="function"?c.title.call(b[0]):c.title),a},tip:function(){return this.$tip=this.$tip||a(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(b){var c=b?a(b.currentTarget)[this.type](this._options).data(this.type):this;c.tip().hasClass("in")?c.hide():c.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("tooltip"),f=typeof c=="object"&&c;e||d.data("tooltip",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(window.jQuery)}.call(a),b})}(this),function(a){var b;c("bootstrap/bootstrap-popover",["bootstrap/bootstrap-transition","bootstrap/bootstrap-tooltip"],function(){return function(){!function(a){var b=function(a,b){this.init("popover",a,b)};b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype,{constructor:b,setContent:function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var a,b=this.$element,c=this.options;return a=(typeof c.content=="function"?c.content.call(b[0]):c.content)||b.attr("data-content"),a},tip:function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("popover"),f=typeof c=="object"&&c;e||d.data("popover",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.defaults=a.extend({},a.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(window.jQuery)}.call(a),b})}(this),function(a){var b;c("bootstrap/bootstrap-scrollspy",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){function b(b,c){var d=a.proxy(this.process,this),e=a(b).is("body")?a(window):a(b),f;this.options=a.extend({},a.fn.scrollspy.defaults,c),this.$scrollElement=e.on("scroll.scroll-spy.data-api",d),this.selector=(this.options.target||(f=a(b).attr("href"))&&f.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=a("body"),this.refresh(),this.process()}b.prototype={constructor:b,refresh:function(){var b=this,c;this.offsets=a([]),this.targets=a([]),c=this.$body.find(this.selector).map(function(){var c=a(this),d=c.data("target")||c.attr("href"),e=/^#\w/.test(d)&&a(d);return e&&e.length&&[[e.position().top+(!a.isWindow(b.$scrollElement.get(0))&&b.$scrollElement.scrollTop()),d]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},process:function(){var a=this.$scrollElement.scrollTop()+this.options.offset,b=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,c=b-this.$scrollElement.height(),d=this.offsets,e=this.targets,f=this.activeTarget,g;if(a>=c)return f!=(g=e.last()[0])&&this.activate(g);for(g=d.length;g--;)f!=e[g]&&a>=d[g]&&(!d[g+1]||a<=d[g+1])&&this.activate(e[g])},activate:function(b){var c,d;this.activeTarget=b,a(this.selector).parent(".active").removeClass("active"),d=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',c=a(d).parent("li").addClass("active"),c.parent(".dropdown-menu").length&&(c=c.closest("li.dropdown").addClass("active")),c.trigger("activate")}};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("scrollspy"),f=typeof c=="object"&&c;e||d.data("scrollspy",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.defaults={offset:10},a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery)}.call(a),b})}(this),function(a){var b;c("bootstrap/bootstrap-tab",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b){this.element=a(b)};b.prototype={constructor:b,show:function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target"),e,f,g;d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,""));if(b.parent("li").hasClass("active"))return;e=c.find(".active:last a")[0],g=a.Event("show",{relatedTarget:e}),b.trigger(g);if(g.isDefaultPrevented())return;f=a(d),this.activate(b.parent("li"),c),this.activate(f,f.parent(),function(){b.trigger({type:"shown",relatedTarget:e})})},activate:function(b,c,d){function g(){e.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),f?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var e=c.find("> .active"),f=d&&a.support.transition&&e.hasClass("fade");f?e.one(a.support.transition.end,g):g(),e.removeClass("in")}};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("tab");e||d.data("tab",e=new b(this)),typeof c=="string"&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(window.jQuery)}.call(a),b})}(this),function(a){var b;c("bootstrap/bootstrap-typeahead",["bootstrap/bootstrap-transition"],function(){return function(){!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=a(this.options.menu),this.shown=!1,this.listen()};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(a)).change(),this.hide()},updater:function(a){return a},show:function(){var b=a.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:b.top+b.height,left:b.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){var c;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(c=a.isFunction(this.source)?this.source(this.query,a.proxy(this.process,this)):this.source,c?this.process(c):this)},process:function(b){var c=this;return b=a.grep(b,function(a){return c.matcher(a)}),b=this.sorter(b),b.length?this.render(b.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(a){return~a.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){var b=[],c=[],d=[],e;while(e=a.shift())e.toLowerCase().indexOf(this.query.toLowerCase())?~e.indexOf(this.query)?c.push(e):d.push(e):b.push(e);return b.concat(c,d)},highlighter:function(a){var b=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return a.replace(new RegExp("("+b+")","ig"),function(a,b){return"<strong>"+b+"</strong>"})},render:function(b){var c=this;return b=a(b).map(function(b,d){return b=a(c.options.item).attr("data-value",d),b.find("a").html(c.highlighter(d)),b[0]}),b.first().addClass("active"),this.$menu.html(b),this},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("focus",a.proxy(this.focus,this)).on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",a.proxy(this.keydown,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this)).on("mouseleave","li",a.proxy(this.mouseleave,this))},eventSupported:function(a){var b=a in this.$element;return b||(this.$element.setAttribute(a,"return;"),b=typeof this.$element[a]=="function"),b},move:function(a){if(!this.shown)return;switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:a.preventDefault(),this.prev();break;case 40:a.preventDefault(),this.next()}a.stopPropagation()},keydown:function(b){this.suppressKeyPressRepeat=~a.inArray(b.keyCode,[40,38,9,13,27]),this.move(b)},keypress:function(a){if(this.suppressKeyPressRepeat)return;this.move(a)},keyup:function(a){switch(a.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}a.stopPropagation(),a.preventDefault()},focus:function(a){this.focused=!0},blur:function(a){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(a){a.stopPropagation(),a.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(b){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")},mouseleave:function(a){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var c=a.fn.typeahead;a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f=typeof c=="object"&&c;e||d.data("typeahead",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},a.fn.typeahead.Constructor=b,a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this},a(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;c.typeahead(c.data())})}(window.jQuery)}.call(a),b})}(this),c("fuelux/checkbox",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.checkbox.defaults,c),this.$label=this.$element.parent(),this.$icon=this.$label.find("i"),this.$chk=this.$label.find("input[type=checkbox]"),this.setState(this.$chk),this.$chk.on("change",b.proxy(this.itemchecked,this))};c.prototype={constructor:c,setState:function(a){var b=a.is(":checked"),c=a.is(":disabled");this.$icon.removeClass("checked").removeClass("disabled"),b===!0&&this.$icon.addClass("checked"),c===!0&&this.$icon.addClass("disabled")},enable:function(){this.$chk.attr("disabled",!1),this.$icon.removeClass("disabled")},disable:function(){this.$chk.attr("disabled",!0),this.$icon.addClass("disabled")},toggle:function(){this.$chk.click()},itemchecked:function(a){var c=b(a.target);this.setState(c)}},b.fn.checkbox=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("checkbox"),h=typeof a=="object"&&a;g||f.data("checkbox",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.checkbox.defaults={},b.fn.checkbox.Constructor=c,b(function(){b(window).on("load",function(){b(".checkbox-custom > input[type=checkbox]").each(function(){var a=b(this);if(a.data("checkbox"))return;a.checkbox(a.data())})})})}),c("fuelux/util",["require","jquery"],function(a){function c(a,c){return(a.textContent||a.innerText||b(a).text()||"").toLowerCase()===(c||"").toLowerCase()}var b=a("jquery");b.expr[":"].fuelTextExactCI=b.expr.createPseudo?b.expr.createPseudo(function(a){return function(b){return c(b,a)}}):function(a,b,d){return c(a,d[3])}}),c("fuelux/combobox",["require","jquery","./util"],function(a){var b=a("jquery");a("./util");var c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.combobox.defaults,c),this.$element.on("click","a",b.proxy(this.itemclicked,this)),this.$element.on("change","input",b.proxy(this.inputchanged,this)),this.$input=this.$element.find("input"),this.$button=this.$element.find(".btn"),this.setDefaultSelection()};c.prototype={constructor:c,selectedItem:function(){var a=this.$selectedItem,c={};if(a){var d=this.$selectedItem.text();c=b.extend({text:d},this.$selectedItem.data())}else c={text:this.$input.val()};return c},selectByText:function(a){var b="li:fuelTextExactCI("+a+")";this.selectBySelector(b)},selectByValue:function(a){var b='li[data-value="'+a+'"]';this.selectBySelector(b)},selectByIndex:function(a){var b="li:eq("+a+")";this.selectBySelector(b)},selectBySelector:function(a){var b=this.$element.find(a);typeof b[0]!="undefined"?(this.$selectedItem=b,this.$input.val(this.$selectedItem.text())):this.$selectedItem=null},setDefaultSelection:function(){var a="li[data-selected=true]:first",b=this.$element.find(a);b.length>0&&(this.selectBySelector(a),b.removeData("selected"),b.removeAttr("data-selected"))},enable:function(){this.$input.removeAttr("disabled"),this.$button.removeClass("disabled")},disable:function(){this.$input.attr("disabled",!0),this.$button.addClass("disabled")},itemclicked:function(a){this.$selectedItem=b(a.target).parent(),this.$input.val(this.$selectedItem.text()).trigger("change",{synthetic:!0});var c=this.selectedItem();this.$element.trigger("changed",c),a.preventDefault()},inputchanged:function(a,c){if(c&&c.synthetic)return;var d=b(a.target).val();this.selectByText(d);var e=this.selectedItem();e.text.length===0&&(e={text:d}),this.$element.trigger("changed",e)}},b.fn.combobox=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("combobox"),h=typeof a=="object"&&a;g||f.data("combobox",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.combobox.defaults={},b.fn.combobox.Constructor=c,b(function(){b(window).on("load",function(){b(".combobox").each(function(){var a=b(this);if(a.data("combobox"))return;a.combobox(a.data())})}),b("body").on("mousedown.combobox.data-api",".combobox",function(a){var c=b(this);if(c.data("combobox"))return;c.combobox(c.data())})})}),c("fuelux/datagrid",["require","jquery"],function(a){var b=a("jquery"),c=22,d=function(a,c){this.$element=b(a),this.$thead=this.$element.find("thead"),this.$tfoot=this.$element.find("tfoot"),this.$footer=this.$element.find("tfoot th"),this.$footerchildren=this.$footer.children().show().css("visibility","hidden"),this.$topheader=this.$element.find("thead th"),this.$searchcontrol=this.$element.find(".datagrid-search"),this.$filtercontrol=this.$element.find(".filter"),this.$pagesize=this.$element.find(".grid-pagesize"),this.$pageinput=this.$element.find(".grid-pager input"),this.$pagedropdown=this.$element.find(".grid-pager .dropdown-menu"),this.$prevpagebtn=this.$element.find(".grid-prevpage"),this.$nextpagebtn=this.$element.find(".grid-nextpage"),this.$pageslabel=this.$element.find(".grid-pages"),this.$countlabel=this.$element.find(".grid-count"),this.$startlabel=this.$element.find(".grid-start"),this.$endlabel=this.$element.find(".grid-end"),this.$tbody=b("<tbody>").insertAfter(this.$thead),this.$colheader=b("<tr>").appendTo(this.$thead),this.options=b.extend(!0,{},b.fn.datagrid.defaults,c),this.$pagesize.hasClass("select")?this.options.dataOptions.pageSize=parseInt(this.$pagesize.select("selectedItem").value,10):this.options.dataOptions.pageSize=parseInt(this.$pagesize.val(),10),this.$searchcontrol.length<=0&&(this.$searchcontrol=this.$element.find(".search")),this.columns=this.options.dataSource.columns(),this.$nextpagebtn.on("click",b.proxy(this.next,this)),this.$prevpagebtn.on("click",b.proxy(this.previous,this)),this.$searchcontrol.on("searched cleared",b.proxy(this.searchChanged,this)),this.$filtercontrol.on("changed",b.proxy(this.filterChanged,this)),this.$colheader.on("click","th",b.proxy(this.headerClicked,this)),this.$pagesize.hasClass("select")?this.$pagesize.on("changed",b.proxy(this.pagesizeChanged,this)):this.$pagesize.on("change",b.proxy(this.pagesizeChanged,this)),this.$pageinput.on("change",b.proxy(this.pageChanged,this)),this.renderColumns(),this.options.stretchHeight&&this.initStretchHeight(),this.renderData()};d.prototype={constructor:d,renderColumns:function(){var a=this;this.$footer.attr("colspan",this.columns.length),this.$topheader.attr("colspan",this.columns.length);var c="";b.each(this.columns,function(a,b){c+='<th data-property="'+b.property+'"',b.sortable&&(c+=' class="sortable"'),c+=">"+b.label+"</th>"}),a.$colheader.append(c)},updateColumns:function(a,b){this._updateColumns(this.$colheader,a,b),this.$sizingHeader&&this._updateColumns(this.$sizingHeader,this.$sizingHeader.find("th").eq(a.index()),b)},_updateColumns:function(a,c,d){var e=d==="asc"?"icon-chevron-up":"icon-chevron-down";a.find("i.datagrid-sort").remove(),a.find("th").removeClass("sorted"),b("<i>").addClass(e+" datagrid-sort").appendTo(c),c.addClass("sorted")},updatePageDropdown:function(a){var b="";for(var c=1;c<=a.pages;c++)b+="<li><a>"+c+"</a></li>";this.$pagedropdown.html(b)},updatePageButtons:function(a){a.page===1?this.$prevpagebtn.attr("disabled","disabled"):this.$prevpagebtn.removeAttr("disabled"),a.page===a.pages?this.$nextpagebtn.attr("disabled","disabled"):this.$nextpagebtn.removeAttr("disabled")},renderData:function(){var a=this;this.$tbody.html(this.placeholderRowHTML(this.options.loadingHTML)),this.options.dataSource.data(this.options.dataOptions,function(c){var d=c.count===1?a.options.itemText:a.options.itemsText,e="";a.$footerchildren.css("visibility",function(){return c.count>0?"visible":"hidden"}),a.$pageinput.val(c.page),a.$pageslabel.text(c.pages),a.$countlabel.text(c.count+" "+d),a.$startlabel.text(c.start),a.$endlabel.text(c.end),a.updatePageDropdown(c),a.updatePageButtons(c),b.each(c.data,function(c,d){e+="<tr>",b.each(a.columns,function(a,b){e+="<td>"+d[b.property]+"</td>"}),e+="</tr>"}),e||(e=a.placeholderRowHTML("0 "+a.options.itemsText)),a.$tbody.html(e),a.stretchHeight(),a.$element.trigger("loaded")})},placeholderRowHTML:function(a){return'<tr><td style="text-align:center;padding:20px;border-bottom:none;" colspan="'+this.columns.length+'">'+a+"</td></tr>"},headerClicked:function(a){var c=b(a.target);if(!c.hasClass("sortable"))return;var d=this.options.dataOptions.sortDirection,e=this.options.dataOptions.sortProperty,f=c.data("property");e===f?this.options.dataOptions.sortDirection=d==="asc"?"desc":"asc":(this.options.dataOptions.sortDirection="asc",this.options.dataOptions.sortProperty=f),this.options.dataOptions.pageIndex=0,this.updateColumns(c,this.options.dataOptions.sortDirection),this.renderData()},pagesizeChanged:function(a,c){c?this.options.dataOptions.pageSize=parseInt(c.value,10):this.options.dataOptions.pageSize=parseInt(b(a.target).val(),10),this.options.dataOptions.pageIndex=0,this.renderData()},pageChanged:function(a){var c=parseInt(b(a.target).val(),10);c=isNaN(c)?1:c;var d=this.$pageslabel.text();this.options.dataOptions.pageIndex=c>d?d-1:c-1,this.renderData()},searchChanged:function(a,b){this.options.dataOptions.search=b,this.options.dataOptions.pageIndex=0,this.renderData()},filterChanged:function(a,b){this.options.dataOptions.filter=b,this.options.dataOptions.pageIndex=0,this.renderData()},previous:function(){this.$nextpagebtn.attr("disabled","disabled"),this.$prevpagebtn.attr("disabled","disabled"),this.options.dataOptions.pageIndex--,this.renderData()},next:function(){this.$nextpagebtn.attr("disabled","disabled"),this.$prevpagebtn.attr("disabled","disabled"),this.options.dataOptions.pageIndex++,this.renderData()},reload:function(){this.options.dataOptions.pageIndex=0,this.renderData()},initStretchHeight:function(){this.$gridContainer=this.$element.parent(),this.$element.wrap('<div class="datagrid-stretch-wrapper">'),this.$stretchWrapper=this.$element.parent(),this.$headerTable=b("<table>").attr("class",this.$element.attr("class")),this.$footerTable=this.$headerTable.clone(),this.$headerTable.prependTo(this.$gridContainer).addClass("datagrid-stretch-header"),this.$thead.detach().appendTo(this.$headerTable),this.$sizingHeader=this.$thead.clone(),this.$sizingHeader.find("tr:first").remove(),this.$footerTable.appendTo(this.$gridContainer).addClass("datagrid-stretch-footer"),this.$tfoot.detach().appendTo(this.$footerTable)},stretchHeight:function(){if(!this.$gridContainer)return;this.setColumnWidths();var a=this.$gridContainer.height(),b=this.$headerTable.outerHeight(),c=this.$footerTable.outerHeight(),d=b+c;this.$stretchWrapper.height(a-d)},setColumnWidths:function(){function e(e,f){if(e===d-1)return;var g=b(f),h=a.eq(e),i=h.width();h.hasClass("sorted")&&g.prop("tagName")==="TD"&&(i=i+c),g.width(i)}if(!this.$sizingHeader)return;this.$element.prepend(this.$sizingHeader);var a=this.$sizingHeader.find("th"),d=a.length;this.$colheader.find("th").each(e),this.$tbody.find("tr:first > td").each(e),this.$sizingHeader.detach()}},b.fn.datagrid=function(a){return this.each(function(){var c=b(this),e=c.data("datagrid"),f=typeof a=="object"&&a;e||c.data("datagrid",e=new d(this,f)),typeof a=="string"&&e[a]()})},b.fn.datagrid.defaults={dataOptions:{pageIndex:0,pageSize:10},loadingHTML:'<div class="progress progress-striped active" style="width:50%;margin:auto;"><div class="bar" style="width:100%;"></div></div>',itemsText:"items",itemText:"item"},b.fn.datagrid.Constructor=d}),c("fuelux/pillbox",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.pillbox.defaults,c),this.$element.on("click","li",b.proxy(this.itemclicked,this))};c.prototype={constructor:c,items:function(){return this.$element.find("li").map(function(){var a=b(this);return b.extend({text:a.text()},a.data())}).get()},itemclicked:function(a){b(a.currentTarget).remove(),a.preventDefault()}},b.fn.pillbox=function(a){var d,e=this.each(function(){var e=b(this),f=e.data("pillbox"),g=typeof a=="object"&&a;f||e.data("pillbox",f=new c(this,g)),typeof a=="string"&&(d=f[a]())});return d===undefined?e:d},b.fn.pillbox.defaults={},b.fn.pillbox.Constructor=c,b(function(){b("body").on("mousedown.pillbox.data-api",".pillbox",function(a){var c=b(this);if(c.data("pillbox"))return;c.pillbox(c.data())})})}),c("fuelux/radio",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.radio.defaults,c),this.$label=this.$element.parent(),this.$icon=this.$label.find("i"),this.$radio=this.$label.find("input[type=radio]"),this.groupName=this.$radio.attr("name"),this.setState(this.$radio),this.$radio.on("change",b.proxy(this.itemchecked,this))};c.prototype={constructor:c,setState:function(a,b){var c=a.is(":checked"),d=a.is(":disabled");c===!0&&this.$icon.addClass("checked"),d===!0&&this.$icon.addClass("disabled")},resetGroup:function(){b("input[name="+this.groupName+"]").next().removeClass("checked")},enable:function(){this.$radio.attr("disabled",!1),this.$icon.removeClass("disabled")},disable:function(){this.$radio.attr("disabled",!0),this.$icon.addClass("disabled")},itemchecked:function(a){var c=b(a.target);this.resetGroup(),this.setState(c)}},b.fn.radio=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("radio"),h=typeof a=="object"&&a;g||f.data("radio",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.radio.defaults={},b.fn.radio.Constructor=c,b(function(){b(window).on("load",function(){b(".radio-custom > input[type=radio]").each(function(){var a=b(this);if(a.data("radio"))return;a.radio(a.data())})})})}),c("fuelux/search",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.search.defaults,c),this.$button=this.$element.find("button").on("click",b.proxy(this.buttonclicked,this)),this.$input=this.$element.find("input").on("keydown",b.proxy(this.keypress,this)).on("keyup",b.proxy(this.keypressed,this)),this.$icon=this.$element.find("i"),this.activeSearch=""};c.prototype={constructor:c,search:function(a){this.$icon.attr("class","icon-remove"),this.activeSearch=a,this.$element.trigger("searched",a)},clear:function(){this.$icon.attr("class","icon-search"),this.activeSearch="",this.$input.val(""),this.$element.trigger("cleared")},action:function(){var a=this.$input.val(),b=a===""||a===this.activeSearch;this.activeSearch&&b?this.clear():a&&this.search(a)},buttonclicked:function(a){a.preventDefault();if(b(a.currentTarget).is(".disabled, :disabled"))return;this.action()},keypress:function(a){a.which===13&&a.preventDefault()},keypressed:function(a){var b,c;a.which===13?(a.preventDefault(),this.action()):(b=this.$input.val(),c=b&&b===this.activeSearch,this.$icon.attr("class",c?"icon-remove":"icon-search"))},disable:function(){this.$input.attr("disabled","disabled"),this.$button.addClass("disabled")},enable:function(){this.$input.removeAttr("disabled"),this.$button.removeClass("disabled")}},b.fn.search=function(a){return this.each(function(){var d=b(this),e=d.data("search"),f=typeof a=="object"&&a;e||d.data("search",e=new c(this,f)),typeof a=="string"&&e[a]()})},b.fn.search.defaults={},b.fn.search.Constructor=c,b(function(){b("body").on("mousedown.search.data-api",".search",function(){var a=b(this);if(a.data("search"))return;a.search(a.data())})})}),c("fuelux/spinner",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.spinner.defaults,c),this.$input=this.$element.find(".spinner-input"),this.$element.on("keyup",this.$input,b.proxy(this.change,this)),this.options.hold?(this.$element.on("mousedown",".spinner-up",b.proxy(function(){this.startSpin(!0)},this)),this.$element.on("mouseup",".spinner-up, .spinner-down",b.proxy(this.stopSpin,this)),this.$element.on("mouseout",".spinner-up, .spinner-down",b.proxy(this.stopSpin,this)),this.$element.on("mousedown",".spinner-down",b.proxy(function(){this.startSpin(!1)},this))):(this.$element.on("click",".spinner-up",b.proxy(function(){this.step(!0)},this)),this.$element.on("click",".spinner-down",b.proxy(function(){this.step(!1)},this))),this.switches={count:1,enabled:!0},this.options.speed==="medium"?this.switches.speed=300:this.options.speed==="fast"?this.switches.speed=100:this.switches.speed=500,this.lastValue=null,this.render(),this.options.disabled&&this.disable()};c.prototype={constructor:c,render:function(){this.$input.val(this.options.value),this.$input.attr("maxlength",(this.options.max+"").split("").length)},change:function(){var a=this.$input.val();a/1?this.options.value=a/1:(a=a.replace(/[^0-9]/g,""),this.$input.val(a),this.options.value=a/1),this.triggerChangedEvent()},stopSpin:function(){clearTimeout(this.switches.timeout),this.switches.count=1,this.triggerChangedEvent()},triggerChangedEvent:function(){var a=this.value();if(a===this.lastValue)return;this.lastValue=a,this.$element.trigger("changed",a),this.$element.trigger("change")},startSpin:function(a){if(!this.options.disabled){var c=this.switches.count;c===1?(this.step(a),c=1):c<3?c=1.5:c<8?c=2.5:c=4,this.switches.timeout=setTimeout(b.proxy(function(){this.iterator(a)},this),this.switches.speed/c),this.switches.count++}},iterator:function(a){this.step(a),this.startSpin(a)},step:function(a){var b=this.options.value,c=a?this.options.max:this.options.min;if(a?b<c:b>c){var d=b+(a?1:-1)*this.options.step;(a?d>c:d<c)?this.value(c):this.value(d)}},value:function(a){return!isNaN(parseFloat(a))&&isFinite(a)?(a=parseFloat(a),this.options.value=a,this.$input.val(a),this):this.options.value},disable:function(){this.options.disabled=!0,this.$input.attr("disabled",""),this.$element.find("button").addClass("disabled")},enable:function(){this.options.disabled=!1,this.$input.removeAttr("disabled"),this.$element.find("button").removeClass("disabled")}},b.fn.spinner=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("spinner"),h=typeof a=="object"&&a;g||f.data("spinner",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.spinner.defaults={value:1,min:1,max:999,step:1,hold:!0,speed:"medium",disabled:!1},b.fn.spinner.Constructor=c,b(function(){b("body").on("mousedown.spinner.data-api",".spinner",function(a){var c=b(this);if(c.data("spinner"))return;c.spinner(c.data())})})}),c("fuelux/select",["require","jquery","./util"],function(a){var b=a("jquery");a("./util");var c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.select.defaults,c),this.$element.on("click","a",b.proxy(this.itemclicked,this)),this.$button=this.$element.find(".btn"),this.$label=this.$element.find(".dropdown-label"),this.setDefaultSelection(),c.resize==="auto"&&this.resize()};c.prototype={constructor:c,itemclicked:function(a){this.$selectedItem=b(a.target).parent(),this.$label.text(this.$selectedItem.text());var c=this.selectedItem();this.$element.trigger("changed",c),a.preventDefault()},resize:function(){var a=b("#selectTextSize")[0];a||b("<div/>").attr({id:"selectTextSize"}).appendTo("body");var c=0,d=0;this.$element.find("a").each(function(){var a=b(this),e=a.text(),f=b("#selectTextSize");f.text(e),d=f.outerWidth(),d>c&&(c=d)}),this.$label.width(c)},selectedItem:function(){var a=this.$selectedItem.text();return b.extend({text:a},this.$selectedItem.data())},selectByText:function(a){var b="li a:fuelTextExactCI("+a+")";this.selectBySelector(b)},selectByValue:function(a){var b='li[data-value="'+a+'"]';this.selectBySelector(b)},selectByIndex:function(a){var b="li:eq("+a+")";this.selectBySelector(b)},selectBySelector:function(a){var b=this.$element.find(a);this.$selectedItem=b,this.$label.text(this.$selectedItem.text())},setDefaultSelection:function(){var a="li[data-selected=true]:first",b=this.$element.find(a);b.length===0?this.selectByIndex(0):(this.selectBySelector(a),b.removeData("selected"),b.removeAttr("data-selected"))},enable:function(){this.$button.removeClass("disabled")},disable:function(){this.$button.addClass("disabled")}},b.fn.select=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("select"),h=typeof a=="object"&&a;g||f.data("select",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.select.defaults={},b.fn.select.Constructor=c,b(function(){b(window).on("load",function(){b(".select").each(function(){var a=b(this);if(a.data("select"))return;a.select(a.data())})}),b("body").on("mousedown.select.data-api",".select",function(a){var c=b(this);if(c.data("select"))return;c.select(c.data())})})}),c("fuelux/tree",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){this.$element=b(a),this.options=b.extend({},b.fn.tree.defaults,c),this.$element.on("click",".tree-item",b.proxy(function(a){this.selectItem(a.currentTarget)},this)),this.$element.on("click",".tree-folder-header",b.proxy(function(a){this.selectFolder(a.currentTarget)},this)),this.render()};c.prototype={constructor:c,render:function(){this.populate(this.$element)},populate:function(a){var c=this,d=a.parent().find(".tree-loader:eq(0)");d.show(),this.options.dataSource.data(a.data(),function(e){d.hide(),b.each(e.data,function(b,d){var e;d.type==="folder"?(e=c.$element.find(".tree-folder:eq(0)").clone().show(),e.find(".tree-folder-name").html(d.name),e.find(".tree-loader").html(c.options.loadingHTML),e.find(".tree-folder-header").data(d)):d.type==="item"&&(e=c.$element.find(".tree-item:eq(0)").clone().show(),e.find(".tree-item-name").html(d.name),e.data(d)),a.hasClass("tree-folder-header")?a.parent().find(".tree-folder-content:eq(0)").append(e):a.append(e)}),c.$element.trigger("loaded")})},selectItem:function(a){var c=b(a),d=this.$element.find(".tree-selected"),e=[];this.options.multiSelect?b.each(d,function(a,d){var f=b(d);f[0]!==c[0]&&e.push(b(d).data())}):d[0]!==c[0]&&(d.removeClass("tree-selected").find("i").removeClass("icon-ok").addClass("tree-dot"),e.push(c.data())),c.hasClass("tree-selected")?(c.removeClass("tree-selected"),c.find("i").removeClass("icon-ok").addClass("tree-dot")):(c.addClass("tree-selected"),c.find("i").removeClass("tree-dot").addClass("icon-ok"),this.options.multiSelect&&e.push(c.data())),e.length&&this.$element.trigger("selected",{info:e})},selectFolder:function(a){var c=b(a),d=c.parent();c.find(".icon-folder-close").length?(d.find(".tree-folder-content").children().length?d.find(".tree-folder-content:eq(0)").show():this.populate(c),d.find(".icon-folder-close:eq(0)").removeClass("icon-folder-close").addClass("icon-folder-open"),this.$element.trigger("opened",c.data())):(this.options.cacheItems?d.find(".tree-folder-content:eq(0)").hide():d.find(".tree-folder-content:eq(0)").empty(),d.find(".icon-folder-open:eq(0)").removeClass("icon-folder-open").addClass("icon-folder-close"),this.$element.trigger("closed",c.data()))},selectedItems:function(){var a=this.$element.find(".tree-selected"),c=[];return b.each(a,function(a,d){c.push(b(d).data())}),c}},b.fn.tree=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("tree"),h=typeof a=="object"&&a;g||f.data("tree",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.tree.defaults={multiSelect:!1,loadingHTML:"<div>Loading...</div>",cacheItems:!0},b.fn.tree.Constructor=c}),c("fuelux/wizard",["require","jquery"],function(a){var b=a("jquery"),c=function(a,c){var d;this.$element=b(a),this.options=b.extend({},b.fn.wizard.defaults,c),this.currentStep=1,this.numSteps=this.$element.find("li").length,this.$prevBtn=this.$element.find("button.btn-prev"),this.$nextBtn=this.$element.find("button.btn-next"),d=this.$nextBtn.children().detach(),this.nextText=b.trim(this.$nextBtn.text()),this.$nextBtn.append(d),this.$prevBtn.on("click",b.proxy(this.previous,this)),this.$nextBtn.on("click",b.proxy(this.next,this)),this.$element.on("click","li.complete",b.proxy(this.stepclicked,this))};c.prototype={constructor:c,setState:function(){var a=this.currentStep>1,c=this.currentStep===1,d=this.currentStep===this.numSteps;this.$prevBtn.attr("disabled",c===!0||a===!1);var e=this.$nextBtn.data();if(e&&e.last){this.lastText=e.last;if(typeof this.lastText!="undefined"){var f=d!==!0?this.nextText:this.lastText,g=this.$nextBtn.children().detach();this.$nextBtn.text(f).append(g)}}var h=this.$element.find("li");h.removeClass("active").removeClass("complete"),h.find("span.badge").removeClass("badge-info").removeClass("badge-success");var i="li:lt("+(this.currentStep-1)+")",j=this.$element.find(i);j.addClass("complete"),j.find("span.badge").addClass("badge-success");var k="li:eq("+(this.currentStep-1)+")",l=this.$element.find(k);l.addClass("active"),l.find("span.badge").addClass("badge-info");var m=l.data().target;b(".step-pane").removeClass("active"),b(m).addClass("active"),this.$element.trigger("changed")},stepclicked:function(a){var c=b(a.currentTarget),d=b(".steps li").index(c),e=b.Event("stepclick");this.$element.trigger(e,{step:d+1});if(e.isDefaultPrevented())return;this.currentStep=d+1,this.setState()},previous:function(){var a=this.currentStep>1;if(a){var c=b.Event("change");this.$element.trigger(c,{step:this.currentStep,direction:"previous"});if(c.isDefaultPrevented())return;this.currentStep-=1,this.setState()}},next:function(){var a=this.currentStep+1<=this.numSteps,c=this.currentStep===this.numSteps;if(a){var d=b.Event("change");this.$element.trigger(d,{step:this.currentStep,direction:"next"});if(d.isDefaultPrevented())return;this.currentStep+=1,this.setState()}else c&&this.$element.trigger("finished")},selectedItem:function(a){return{step:this.currentStep}}},b.fn.wizard=function(a,d){var e,f=this.each(function(){var f=b(this),g=f.data("wizard"),h=typeof a=="object"&&a;g||f.data("wizard",g=new c(this,h)),typeof a=="string"&&(e=g[a](d))});return e===undefined?f:e},b.fn.wizard.defaults={},b.fn.wizard.Constructor=c,b(function(){b("body").on("mousedown.wizard.data-api",".wizard",function(){var a=b(this);if(a.data("wizard"))return;a.wizard(a.data())})})}),c("fuelux/all",["require","jquery","bootstrap/bootstrap-affix","bootstrap/bootstrap-alert","bootstrap/bootstrap-button","bootstrap/bootstrap-carousel","bootstrap/bootstrap-collapse","bootstrap/bootstrap-dropdown","bootstrap/bootstrap-modal","bootstrap/bootstrap-popover","bootstrap/bootstrap-scrollspy","bootstrap/bootstrap-tab","bootstrap/bootstrap-tooltip","bootstrap/bootstrap-transition","bootstrap/bootstrap-typeahead","fuelux/checkbox","fuelux/combobox","fuelux/datagrid","fuelux/pillbox","fuelux/radio","fuelux/search","fuelux/spinner","fuelux/select","fuelux/tree","fuelux/wizard"],function(a){a("jquery"),a("bootstrap/bootstrap-affix"),a("bootstrap/bootstrap-alert"),a("bootstrap/bootstrap-button"),a("bootstrap/bootstrap-carousel"),a("bootstrap/bootstrap-collapse"),a("bootstrap/bootstrap-dropdown"),a("bootstrap/bootstrap-modal"),a("bootstrap/bootstrap-popover"),a("bootstrap/bootstrap-scrollspy"),a("bootstrap/bootstrap-tab"),a("bootstrap/bootstrap-tooltip"),a("bootstrap/bootstrap-transition"),a("bootstrap/bootstrap-typeahead"),a("fuelux/checkbox"),a("fuelux/combobox"),a("fuelux/datagrid"),a("fuelux/pillbox"),a("fuelux/radio"),a("fuelux/search"),a("fuelux/spinner"),a("fuelux/select"),a("fuelux/tree"),a("fuelux/wizard")}),c("jquery",[],function(){return jQuery}),c("fuelux/loader",["fuelux/all"],function(){}),b("fuelux/loader")})();
\ No newline at end of file
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/pillbox.js b/opendaylight/web/root/src/main/resources/js/fuelux/pillbox.js
new file mode 100755 (executable)
index 0000000..d61f60b
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Fuel UX Pillbox
+ * https://github.com/ExactTarget/fuelux
+ *
+ * Copyright (c) 2012 ExactTarget
+ * Licensed under the MIT license.
+ */
+
+define(['require','jquery'],function(require) {
+       
+       var $ = require('jquery');
+
+
+       // PILLBOX CONSTRUCTOR AND PROTOTYPE
+
+       var Pillbox = function (element, options) {
+               this.$element = $(element);
+               this.options = $.extend({}, $.fn.pillbox.defaults, options);
+               this.$element.on('click', 'li', $.proxy(this.itemclicked, this));
+       };
+
+       Pillbox.prototype = {
+               constructor: Pillbox,
+
+               items: function() {
+                       return this.$element.find('li').map(function() {
+                               var $this = $(this);
+                               return $.extend({ text: $this.text() }, $this.data());
+                       }).get();
+               },
+
+               itemclicked: function (e) {
+                       $(e.currentTarget).remove();
+                       e.preventDefault();
+               }
+       };
+
+
+       // PILLBOX PLUGIN DEFINITION
+
+       $.fn.pillbox = function (option) {
+               var methodReturn;
+
+               var $set = this.each(function () {
+                       var $this = $(this);
+                       var data = $this.data('pillbox');
+                       var options = typeof option === 'object' && option;
+
+                       if (!data) $this.data('pillbox', (data = new Pillbox(this, options)));
+                       if (typeof option === 'string') methodReturn = data[option]();
+               });
+
+               return (methodReturn === undefined) ? $set : methodReturn;
+       };
+
+       $.fn.pillbox.defaults = {};
+
+       $.fn.pillbox.Constructor = Pillbox;
+
+
+       // PILLBOX DATA-API
+
+       $(function () {
+               $('body').on('mousedown.pillbox.data-api', '.pillbox', function (e) {
+                       var $this = $(this);
+                       if ($this.data('pillbox')) return;
+                       $this.pillbox($this.data());
+               });
+       });
+       
+});
+
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/radio.js b/opendaylight/web/root/src/main/resources/js/fuelux/radio.js
new file mode 100755 (executable)
index 0000000..a09c07f
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Fuel UX Radio
+ * https://github.com/ExactTarget/fuelux
+ *
+ * Copyright (c) 2012 ExactTarget
+ * Licensed under the MIT license.
+ */
+
+define(['require','jquery'],function (require) {
+
+       var $ = require('jquery');
+
+
+       // RADIO CONSTRUCTOR AND PROTOTYPE
+
+       var Radio = function (element, options) {
+               this.$element = $(element);
+               this.options = $.extend({}, $.fn.radio.defaults, options);
+
+               // cache elements
+               this.$label = this.$element.parent();
+               this.$icon = this.$label.find('i');
+               this.$radio = this.$label.find('input[type=radio]');
+               this.groupName = this.$radio.attr('name');
+
+               // set default state
+               this.setState(this.$radio);
+
+               // handle events
+               this.$radio.on('change', $.proxy(this.itemchecked, this));
+       };
+
+       Radio.prototype = {
+
+               constructor: Radio,
+
+               setState: function ($radio, resetGroupState) {
+                       var checked = $radio.is(':checked');
+                       var disabled = $radio.is(':disabled');
+
+                       // set state of radio
+                       if (checked === true) {
+                               this.$icon.addClass('checked');
+                       }
+                       if (disabled === true) {
+                               this.$icon.addClass('disabled');
+                       }
+               },
+
+               resetGroup: function () {
+                       // reset all radio buttons in group
+                       $('input[name=' + this.groupName + ']').next().removeClass('checked');
+               },
+
+               enable: function () {
+                       this.$radio.attr('disabled', false);
+                       this.$icon.removeClass('disabled');
+               },
+
+               disable: function () {
+                       this.$radio.attr('disabled', true);
+                       this.$icon.addClass('disabled');
+               },
+
+               itemchecked: function (e) {
+                       var radio = $(e.target);
+
+                       this.resetGroup();
+                       this.setState(radio);
+               }
+       };
+
+
+       // RADIO PLUGIN DEFINITION
+
+       $.fn.radio = function (option, value) {
+               var methodReturn;
+
+               var $set = this.each(function () {
+                       var $this = $(this);
+                       var data = $this.data('radio');
+                       var options = typeof option === 'object' && option;
+
+                       if (!data) $this.data('radio', (data = new Radio(this, options)));
+                       if (typeof option === 'string') methodReturn = data[option](value);
+               });
+
+               return (methodReturn === undefined) ? $set : methodReturn;
+       };
+
+       $.fn.radio.defaults = {};
+
+       $.fn.radio.Constructor = Radio;
+
+
+       // RADIO DATA-API
+
+       $(function () {
+               $(window).on('load', function () {
+                       //$('i.radio').each(function () {
+                       $('.radio-custom > input[type=radio]').each(function () {
+                               var $this = $(this);
+                               if ($this.data('radio')) return;
+                               $this.radio($this.data());
+                       });
+               });
+       });
+
+});
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/search.js b/opendaylight/web/root/src/main/resources/js/fuelux/search.js
new file mode 100755 (executable)
index 0000000..7f6a27b
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Fuel UX Search
+ * https://github.com/ExactTarget/fuelux
+ *
+ * Copyright (c) 2012 ExactTarget
+ * Licensed under the MIT license.
+ */
+
+define(['require','jquery'],function(require) {
+
+       var $ = require('jquery');
+
+
+       // SEARCH CONSTRUCTOR AND PROTOTYPE
+
+       var Search = function (element, options) {
+               this.$element = $(element);
+               this.options = $.extend({}, $.fn.search.defaults, options);
+
+               this.$button = this.$element.find('button')
+                       .on('click', $.proxy(this.buttonclicked, this));
+
+               this.$input = this.$element.find('input')
+                       .on('keydown', $.proxy(this.keypress, this))
+                       .on('keyup', $.proxy(this.keypressed, this));
+
+               this.$icon = this.$element.find('i');
+               this.activeSearch = '';
+       };
+
+       Search.prototype = {
+
+               constructor: Search,
+
+               search: function (searchText) {
+                       this.$icon.attr('class', 'icon-remove');
+                       this.activeSearch = searchText;
+                       this.$element.trigger('searched', searchText);
+               },
+
+               clear: function () {
+                       this.$icon.attr('class', 'icon-search');
+                       this.activeSearch = '';
+                       this.$input.val('');
+                       this.$element.trigger('cleared');
+               },
+
+               action: function () {
+                       var val = this.$input.val();
+                       var inputEmptyOrUnchanged = val === '' || val === this.activeSearch;
+
+                       if (this.activeSearch && inputEmptyOrUnchanged) {
+                               this.clear();
+                       } else if (val) {
+                               this.search(val);
+                       }
+               },
+
+               buttonclicked: function (e) {
+                       e.preventDefault();
+                       if ($(e.currentTarget).is('.disabled, :disabled')) return;
+                       this.action();
+               },
+
+               keypress: function (e) {
+                       if (e.which === 13) {
+                               e.preventDefault();
+                       }
+               },
+
+               keypressed: function (e) {
+                       var val, inputPresentAndUnchanged;
+
+                       if (e.which === 13) {
+                               e.preventDefault();
+                               this.action();
+                       } else {
+                               val = this.$input.val();
+                               inputPresentAndUnchanged = val && (val === this.activeSearch);
+                               this.$icon.attr('class', inputPresentAndUnchanged ? 'icon-remove' : 'icon-search');
+                       }
+               },
+
+               disable: function () {
+                       this.$input.attr('disabled', 'disabled');
+                       this.$button.addClass('disabled');
+               },
+
+               enable: function () {
+                       this.$input.removeAttr('disabled');
+                       this.$button.removeClass('disabled');
+               }
+
+       };
+
+
+       // SEARCH PLUGIN DEFINITION
+
+       $.fn.search = function (option) {
+               return this.each(function () {
+                       var $this = $(this);
+                       var data = $this.data('search');
+                       var options = typeof option === 'object' && option;
+
+                       if (!data) $this.data('search', (data = new Search(this, options)));
+                       if (typeof option === 'string') data[option]();
+               });
+       };
+
+       $.fn.search.defaults = {};
+
+       $.fn.search.Constructor = Search;
+
+
+       // SEARCH DATA-API
+
+       $(function () {
+               $('body').on('mousedown.search.data-api', '.search', function () {
+                       var $this = $(this);
+                       if ($this.data('search')) return;
+                       $this.search($this.data());
+               });
+       });
+
+});
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/select.js b/opendaylight/web/root/src/main/resources/js/fuelux/select.js
new file mode 100755 (executable)
index 0000000..38e6a60
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Fuel UX Select
+ * https://github.com/ExactTarget/fuelux
+ *
+ * Copyright (c) 2012 ExactTarget
+ * Licensed under the MIT license.
+ */
+
+define(['require','jquery','./util'],function(require) {
+
+    var $ = require('jquery');
+       require('./util');
+
+    // SELECT CONSTRUCTOR AND PROTOTYPE
+
+    var Select = function (element, options) {
+        this.$element = $(element);
+        this.options = $.extend({}, $.fn.select.defaults, options);
+        this.$element.on('click', 'a', $.proxy(this.itemclicked, this));
+        this.$button = this.$element.find('.btn');
+        this.$label = this.$element.find('.dropdown-label');
+        this.setDefaultSelection();
+
+        if (options.resize === 'auto') {
+            this.resize();
+        }
+    };
+
+    Select.prototype = {
+
+        constructor: Select,
+
+        itemclicked: function (e) {
+            this.$selectedItem = $(e.target).parent();
+            this.$label.text(this.$selectedItem.text());
+
+            // pass object including text and any data-attributes
+            // to onchange event
+            var data = this.selectedItem();
+
+            // trigger changed event
+            this.$element.trigger('changed', data);
+
+            e.preventDefault();
+        },
+
+        resize: function() {
+            var el = $('#selectTextSize')[0];
+
+            // create element if it doesn't exist
+            // used to calculate the length of the longest string
+            if(!el) {
+                $('<div/>').attr({id:'selectTextSize'}).appendTo('body');
+            }
+
+            var width = 0;
+            var newWidth = 0;
+
+            // iterate through each item to find longest string
+            this.$element.find('a').each(function () {
+                var $this = $(this);
+                var txt = $this.text();
+                var $txtSize = $('#selectTextSize');
+                $txtSize.text(txt);
+                newWidth = $txtSize.outerWidth();
+                if(newWidth > width) {
+                    width = newWidth;
+                }
+            });
+
+            this.$label.width(width);
+        },
+
+        selectedItem: function() {
+            var txt = this.$selectedItem.text();
+            return $.extend({ text: txt }, this.$selectedItem.data());
+        },
+
+        selectByText: function(text) {
+            var selector = 'li a:fuelTextExactCI(' + text + ')';
+            this.selectBySelector(selector);
+        },
+
+        selectByValue: function(value) {
+            var selector = 'li[data-value="' + value + '"]';
+            this.selectBySelector(selector);
+        },
+
+        selectByIndex: function(index) {
+            // zero-based index
+            var selector = 'li:eq(' + index + ')';
+            this.selectBySelector(selector);
+        },
+
+        selectBySelector: function(selector) {
+            var item = this.$element.find(selector);
+
+            this.$selectedItem = item;
+            this.$label.text(this.$selectedItem.text());
+        },
+
+        setDefaultSelection: function() {
+            var selector = 'li[data-selected=true]:first';
+            var item = this.$element.find(selector);
+            if(item.length === 0) {
+                // select first item
+                this.selectByIndex(0);
+            }
+            else {
+                // select by data-attribute
+                this.selectBySelector(selector);
+                item.removeData('selected');
+                item.removeAttr('data-selected');
+            }
+        },
+
+        enable: function() {
+            this.$button.removeClass('disabled');
+        },
+
+        disable: function() {
+            this.$button.addClass('disabled');
+        }
+
+    };
+
+
+    // SELECT PLUGIN DEFINITION
+
+    $.fn.select = function (option,value) {
+        var methodReturn;
+
+        var $set = this.each(function () {
+            var $this = $(this);
+            var data = $this.data('select');
+            var options = typeof option === 'object' && option;
+
+            if (!data) $this.data('select', (data = new Select(this, options)));
+            if (typeof option === 'string') methodReturn = data[option](value);
+        });
+
+        return (methodReturn === undefined) ? $set : methodReturn;
+    };
+
+    $.fn.select.defaults = {};
+
+    $.fn.select.Constructor = Select;
+
+
+    // SELECT DATA-API
+
+    $(function () {
+
+        $(window).on('load', function () {
+            $('.select').each(function () {
+                var $this = $(this);
+                if ($this.data('select')) return;
+                $this.select($this.data());
+            });
+        });
+
+        $('body').on('mousedown.select.data-api', '.select', function (e) {
+            var $this = $(this);
+            if ($this.data('select')) return;
+            $this.select($this.data());
+        });
+    });
+
+});
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/spinner.js b/opendaylight/web/root/src/main/resources/js/fuelux/spinner.js
new file mode 100755 (executable)
index 0000000..97720ee
--- /dev/null
@@ -0,0 +1,201 @@
+/*\r
+ * Fuel UX Spinner\r
+ * https://github.com/ExactTarget/fuelux\r
+ *\r
+ * Copyright (c) 2012 ExactTarget\r
+ * Licensed under the MIT license.\r
+ */\r
+\r
+define(['require','jquery'],function(require) {\r
+\r
+       var $ = require('jquery');\r
+\r
+\r
+       // SPINNER CONSTRUCTOR AND PROTOTYPE\r
+\r
+       var Spinner = function (element, options) {\r
+               this.$element = $(element);\r
+               this.options = $.extend({}, $.fn.spinner.defaults, options);\r
+               this.$input = this.$element.find('.spinner-input');\r
+               this.$element.on('keyup', this.$input, $.proxy(this.change, this));\r
+\r
+               if (this.options.hold) {\r
+                       this.$element.on('mousedown', '.spinner-up', $.proxy(function() { this.startSpin(true); } , this));\r
+                       this.$element.on('mouseup', '.spinner-up, .spinner-down', $.proxy(this.stopSpin, this));\r
+                       this.$element.on('mouseout', '.spinner-up, .spinner-down', $.proxy(this.stopSpin, this));\r
+                       this.$element.on('mousedown', '.spinner-down', $.proxy(function() {this.startSpin(false);} , this));\r
+               } else {\r
+                       this.$element.on('click', '.spinner-up', $.proxy(function() { this.step(true); } , this));\r
+                       this.$element.on('click', '.spinner-down', $.proxy(function() { this.step(false); }, this));\r
+               }\r
+\r
+               this.switches = {\r
+                       count: 1,\r
+                       enabled: true\r
+               };\r
+\r
+               if (this.options.speed === 'medium') {\r
+                       this.switches.speed = 300;\r
+               } else if (this.options.speed === 'fast') {\r
+                       this.switches.speed = 100;\r
+               } else {\r
+                       this.switches.speed = 500;\r
+               }\r
+\r
+               this.lastValue = null;\r
+\r
+               this.render();\r
+\r
+               if (this.options.disabled) {\r
+                       this.disable();\r
+               }\r
+       };\r
+\r
+       Spinner.prototype = {\r
+               constructor: Spinner,\r
+\r
+               render: function () {\r
+                       this.$input.val(this.options.value);\r
+                       this.$input.attr('maxlength',(this.options.max + '').split('').length);\r
+               },\r
+\r
+               change: function () {\r
+                       var newVal = this.$input.val();\r
+\r
+                       if(newVal/1){\r
+                               this.options.value = newVal/1;\r
+                       }else{\r
+                               newVal = newVal.replace(/[^0-9]/g,'');\r
+                               this.$input.val(newVal);\r
+                               this.options.value = newVal/1;\r
+                       }\r
+\r
+                       this.triggerChangedEvent();\r
+               },\r
+\r
+               stopSpin: function () {\r
+                       clearTimeout(this.switches.timeout);\r
+                       this.switches.count = 1;\r
+                       this.triggerChangedEvent();\r
+               },\r
+\r
+               triggerChangedEvent: function () {\r
+                       var currentValue = this.value();\r
+                       if (currentValue === this.lastValue) return;\r
+\r
+                       this.lastValue = currentValue;\r
+\r
+                       // Primary changed event\r
+                       this.$element.trigger('changed', currentValue);\r
+\r
+                       // Undocumented, kept for backward compatibility\r
+                       this.$element.trigger('change');\r
+               },\r
+\r
+               startSpin: function (type) {\r
+\r
+                       if (!this.options.disabled) {\r
+                               var divisor = this.switches.count;\r
+\r
+                               if (divisor === 1) {\r
+                                       this.step(type);\r
+                                       divisor = 1;\r
+                               } else if (divisor < 3){\r
+                                       divisor = 1.5;\r
+                               } else if (divisor < 8){\r
+                                       divisor = 2.5;\r
+                               } else {\r
+                                       divisor = 4;\r
+                               }\r
+\r
+                               this.switches.timeout = setTimeout($.proxy(function() {this.iterator(type);} ,this),this.switches.speed/divisor);\r
+                               this.switches.count++;\r
+                       }\r
+               },\r
+\r
+               iterator: function (type) {\r
+                       this.step(type);\r
+                       this.startSpin(type);\r
+               },\r
+\r
+               step: function (dir) {\r
+                       var curValue = this.options.value;\r
+                       var limValue = dir ? this.options.max : this.options.min;\r
+\r
+                       if ((dir ? curValue < limValue : curValue > limValue)) {\r
+                               var newVal = curValue + (dir ? 1 : -1) * this.options.step;\r
+\r
+                               if (dir ? newVal > limValue : newVal < limValue) {\r
+                                       this.value(limValue);\r
+                               } else {\r
+                                       this.value(newVal);\r
+                               }\r
+                       }\r
+               },\r
+\r
+               value: function (value) {\r
+                       if (!isNaN(parseFloat(value)) && isFinite(value)) {\r
+                               value = parseFloat(value);\r
+                               this.options.value = value;\r
+                               this.$input.val(value);\r
+                               return this;\r
+                       } else {\r
+                               return this.options.value;\r
+                       }\r
+               },\r
+\r
+               disable: function () {\r
+                       this.options.disabled = true;\r
+                       this.$input.attr('disabled','');\r
+                       this.$element.find('button').addClass('disabled');\r
+               },\r
+\r
+               enable: function () {\r
+                       this.options.disabled = false;\r
+                       this.$input.removeAttr("disabled");\r
+                       this.$element.find('button').removeClass('disabled');\r
+               }\r
+       };\r
+\r
+\r
+       // SPINNER PLUGIN DEFINITION\r
+\r
+       $.fn.spinner = function (option,value) {\r
+               var methodReturn;\r
+\r
+               var $set = this.each(function () {\r
+                       var $this = $(this);\r
+                       var data = $this.data('spinner');\r
+                       var options = typeof option === 'object' && option;\r
+\r
+                       if (!data) $this.data('spinner', (data = new Spinner(this, options)));\r
+                       if (typeof option === 'string') methodReturn = data[option](value);\r
+               });\r
+\r
+               return (methodReturn === undefined) ? $set : methodReturn;\r
+       };\r
+\r
+       $.fn.spinner.defaults = {\r
+               value: 1,\r
+               min: 1,\r
+               max: 999,\r
+               step: 1,\r
+               hold: true,\r
+               speed: 'medium',\r
+               disabled: false\r
+       };\r
+\r
+       $.fn.spinner.Constructor = Spinner;\r
+\r
+\r
+       // SPINNER DATA-API\r
+\r
+       $(function () {\r
+               $('body').on('mousedown.spinner.data-api', '.spinner', function (e) {\r
+                       var $this = $(this);\r
+                       if ($this.data('spinner')) return;\r
+                       $this.spinner($this.data());\r
+               });\r
+       });\r
+\r
+});\r
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/tree.js b/opendaylight/web/root/src/main/resources/js/fuelux/tree.js
new file mode 100755 (executable)
index 0000000..b243719
--- /dev/null
@@ -0,0 +1,169 @@
+/*\r
+ * Fuel UX Tree\r
+ * https://github.com/ExactTarget/fuelux\r
+ *\r
+ * Copyright (c) 2012 ExactTarget\r
+ * Licensed under the MIT license.\r
+ */\r
+\r
+define(['require','jquery'],function(require) {\r
+\r
+       var $ = require('jquery');\r
+\r
+\r
+       // TREE CONSTRUCTOR AND PROTOTYPE\r
+\r
+       var Tree = function (element, options) {\r
+               this.$element = $(element);\r
+               this.options = $.extend({}, $.fn.tree.defaults, options);\r
+\r
+               this.$element.on('click', '.tree-item', $.proxy( function(ev) { this.selectItem(ev.currentTarget); } ,this));\r
+               this.$element.on('click', '.tree-folder-header', $.proxy( function(ev) { this.selectFolder(ev.currentTarget); }, this));\r
+\r
+               this.render();\r
+       };\r
+\r
+       Tree.prototype = {\r
+               constructor: Tree,\r
+\r
+               render: function () {\r
+                       this.populate(this.$element);\r
+               },\r
+\r
+               populate: function ($el) {\r
+                       var self = this;\r
+                       var loader = $el.parent().find('.tree-loader:eq(0)');\r
+\r
+                       loader.show();\r
+                       this.options.dataSource.data($el.data(), function (items) {\r
+                               loader.hide();\r
+\r
+                               $.each( items.data, function(index, value) {\r
+                                       var $entity;\r
+\r
+                                       if(value.type === "folder") {\r
+                                               $entity = self.$element.find('.tree-folder:eq(0)').clone().show();\r
+                                               $entity.find('.tree-folder-name').html(value.name);\r
+                                               $entity.find('.tree-loader').html(self.options.loadingHTML);\r
+                                               $entity.find('.tree-folder-header').data(value);\r
+                                       } else if (value.type === "item") {\r
+                                               $entity = self.$element.find('.tree-item:eq(0)').clone().show();\r
+                                               $entity.find('.tree-item-name').html(value.name);\r
+                                               $entity.data(value);\r
+                                       }\r
+\r
+                                       if($el.hasClass('tree-folder-header')) {\r
+                                               $el.parent().find('.tree-folder-content:eq(0)').append($entity);\r
+                                       } else {\r
+                                               $el.append($entity);\r
+                                       }\r
+                               });\r
+\r
+                               self.$element.trigger('loaded');\r
+                       });\r
+               },\r
+\r
+               selectItem: function (el) {\r
+                       var $el = $(el);\r
+                       var $all = this.$element.find('.tree-selected');\r
+                       var data = [];\r
+\r
+                       if (this.options.multiSelect) {\r
+                               $.each($all, function(index, value) {\r
+                                       var $val = $(value);\r
+                                       if($val[0] !== $el[0]) {\r
+                                               data.push( $(value).data() );\r
+                                       }\r
+                               });\r
+                       } else if ($all[0] !== $el[0]) {\r
+                               $all.removeClass('tree-selected')\r
+                                       .find('i').removeClass('icon-ok').addClass('tree-dot');\r
+                               data.push($el.data());\r
+                       }\r
+\r
+                       if($el.hasClass('tree-selected')) {\r
+                               $el.removeClass('tree-selected');\r
+                               $el.find('i').removeClass('icon-ok').addClass('tree-dot');\r
+                       } else {\r
+                               $el.addClass ('tree-selected');\r
+                               $el.find('i').removeClass('tree-dot').addClass('icon-ok');\r
+                               if (this.options.multiSelect) {\r
+                                       data.push( $el.data() );\r
+                               }\r
+                       }\r
+\r
+                       if(data.length) {\r
+                               this.$element.trigger('selected', {info: data});\r
+                       }\r
+\r
+               },\r
+\r
+               selectFolder: function (el) {\r
+                       var $el = $(el);\r
+                       var $par = $el.parent();\r
+\r
+                       if($el.find('.icon-folder-close').length) {\r
+                               if ($par.find('.tree-folder-content').children().length) {\r
+                                       $par.find('.tree-folder-content:eq(0)').show();\r
+                               } else {\r
+                                       this.populate( $el );\r
+                               }\r
+\r
+                               $par.find('.icon-folder-close:eq(0)')\r
+                                       .removeClass('icon-folder-close')\r
+                                       .addClass('icon-folder-open');\r
+\r
+                               this.$element.trigger('opened', $el.data());\r
+                       } else {\r
+                               if(this.options.cacheItems) {\r
+                                       $par.find('.tree-folder-content:eq(0)').hide();\r
+                               } else {\r
+                                       $par.find('.tree-folder-content:eq(0)').empty();\r
+                               }\r
+\r
+                               $par.find('.icon-folder-open:eq(0)')\r
+                                       .removeClass('icon-folder-open')\r
+                                       .addClass('icon-folder-close');\r
+\r
+                               this.$element.trigger('closed', $el.data());\r
+                       }\r
+               },\r
+\r
+               selectedItems: function () {\r
+                       var $sel = this.$element.find('.tree-selected');\r
+                       var data = [];\r
+\r
+                       $.each($sel, function (index, value) {\r
+                               data.push($(value).data());\r
+                       });\r
+                       return data;\r
+               }\r
+       };\r
+\r
+\r
+       // TREE PLUGIN DEFINITION\r
+\r
+       $.fn.tree = function (option, value) {\r
+               var methodReturn;\r
+\r
+               var $set = this.each(function () {\r
+                       var $this = $(this);\r
+                       var data = $this.data('tree');\r
+                       var options = typeof option === 'object' && option;\r
+\r
+                       if (!data) $this.data('tree', (data = new Tree(this, options)));\r
+                       if (typeof option === 'string') methodReturn = data[option](value);\r
+               });\r
+\r
+               return (methodReturn === undefined) ? $set : methodReturn;\r
+       };\r
+\r
+       $.fn.tree.defaults = {\r
+               multiSelect: false,\r
+               loadingHTML: '<div>Loading...</div>',\r
+               cacheItems: true\r
+       };\r
+\r
+       $.fn.tree.Constructor = Tree;\r
+\r
+});\r
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/util.js b/opendaylight/web/root/src/main/resources/js/fuelux/util.js
new file mode 100755 (executable)
index 0000000..469e9db
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Fuel UX Utilities
+ * https://github.com/ExactTarget/fuelux
+ *
+ * Copyright (c) 2012 ExactTarget
+ * Licensed under the MIT license.
+ */
+
+define(['require','jquery'],function (require) {
+
+       var $ = require('jquery');
+
+       // custom case-insensitive match expression
+       function fuelTextExactCI(elem, text) {
+               return (elem.textContent || elem.innerText || $(elem).text() || '').toLowerCase() === (text || '').toLowerCase();
+       }
+
+       $.expr[':'].fuelTextExactCI = $.expr.createPseudo ?
+               $.expr.createPseudo(function (text) {
+                       return function (elem) {
+                               return fuelTextExactCI(elem, text);
+                       };
+               }) :
+               function (elem, i, match) {
+                       return fuelTextExactCI(elem, match[3]);
+               };
+
+});
\ No newline at end of file
diff --git a/opendaylight/web/root/src/main/resources/js/fuelux/wizard.js b/opendaylight/web/root/src/main/resources/js/fuelux/wizard.js
new file mode 100755 (executable)
index 0000000..31b9d80
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Fuel UX Wizard
+ * https://github.com/ExactTarget/fuelux
+ *
+ * Copyright (c) 2012 ExactTarget
+ * Licensed under the MIT license.
+ */
+
+define(['require','jquery'],function (require) {
+
+       var $ = require('jquery');
+
+
+       // WIZARD CONSTRUCTOR AND PROTOTYPE
+
+       var Wizard = function (element, options) {
+               var kids;
+
+               this.$element = $(element);
+               this.options = $.extend({}, $.fn.wizard.defaults, options);
+               this.currentStep = 1;
+               this.numSteps = this.$element.find('li').length;
+               this.$prevBtn = this.$element.find('button.btn-prev');
+               this.$nextBtn = this.$element.find('button.btn-next');
+
+               kids = this.$nextBtn.children().detach();
+               this.nextText = $.trim(this.$nextBtn.text());
+               this.$nextBtn.append(kids);
+
+               // handle events
+               this.$prevBtn.on('click', $.proxy(this.previous, this));
+               this.$nextBtn.on('click', $.proxy(this.next, this));
+               this.$element.on('click', 'li.complete', $.proxy(this.stepclicked, this));
+       };
+
+       Wizard.prototype = {
+
+               constructor: Wizard,
+
+               setState: function () {
+                       var canMovePrev = (this.currentStep > 1);
+                       var firstStep = (this.currentStep === 1);
+                       var lastStep = (this.currentStep === this.numSteps);
+
+                       // disable buttons based on current step
+                       this.$prevBtn.attr('disabled', (firstStep === true || canMovePrev === false));
+
+                       // change button text of last step, if specified
+                       var data = this.$nextBtn.data();
+                       if (data && data.last) {
+                               this.lastText = data.last;
+                               if (typeof this.lastText !== 'undefined') {
+                                       // replace text
+                                       var text = (lastStep !== true) ? this.nextText : this.lastText;
+                                       var kids = this.$nextBtn.children().detach();
+                                       this.$nextBtn.text(text).append(kids);
+                               }
+                       }
+
+                       // reset classes for all steps
+                       var $steps = this.$element.find('li');
+                       $steps.removeClass('active').removeClass('complete');
+                       $steps.find('span.badge').removeClass('badge-info').removeClass('badge-success');
+
+                       // set class for all previous steps
+                       var prevSelector = 'li:lt(' + (this.currentStep - 1) + ')';
+                       var $prevSteps = this.$element.find(prevSelector);
+                       $prevSteps.addClass('complete');
+                       $prevSteps.find('span.badge').addClass('badge-success');
+
+                       // set class for current step
+                       var currentSelector = 'li:eq(' + (this.currentStep - 1) + ')';
+                       var $currentStep = this.$element.find(currentSelector);
+                       $currentStep.addClass('active');
+                       $currentStep.find('span.badge').addClass('badge-info');
+
+                       // set display of target element
+                       var target = $currentStep.data().target;
+                       $('.step-pane').removeClass('active');
+                       $(target).addClass('active');
+
+                       this.$element.trigger('changed');
+               },
+
+               stepclicked: function (e) {
+                       var li = $(e.currentTarget);
+
+                       var index = $('.steps li').index(li);
+
+                       var evt = $.Event('stepclick');
+                       this.$element.trigger(evt, {step: index + 1});
+                       if (evt.isDefaultPrevented()) return;
+
+                       this.currentStep = (index + 1);
+                       this.setState();
+               },
+
+               previous: function () {
+                       var canMovePrev = (this.currentStep > 1);
+                       if (canMovePrev) {
+                               var e = $.Event('change');
+                               this.$element.trigger(e, {step: this.currentStep, direction: 'previous'});
+                               if (e.isDefaultPrevented()) return;
+
+                               this.currentStep -= 1;
+                               this.setState();
+                       }
+               },
+
+               next: function () {
+                       var canMoveNext = (this.currentStep + 1 <= this.numSteps);
+                       var lastStep = (this.currentStep === this.numSteps);
+
+                       if (canMoveNext) {
+                               var e = $.Event('change');
+                               this.$element.trigger(e, {step: this.currentStep, direction: 'next'});
+
+                               if (e.isDefaultPrevented()) return;
+
+                               this.currentStep += 1;
+                               this.setState();
+                       }
+                       else if (lastStep) {
+                               this.$element.trigger('finished');
+                       }
+               },
+
+               selectedItem: function (val) {
+                       return {
+                               step: this.currentStep
+                       };
+               }
+       };
+
+
+       // WIZARD PLUGIN DEFINITION
+
+       $.fn.wizard = function (option, value) {
+               var methodReturn;
+
+               var $set = this.each(function () {
+                       var $this = $(this);
+                       var data = $this.data('wizard');
+                       var options = typeof option === 'object' && option;
+
+                       if (!data) $this.data('wizard', (data = new Wizard(this, options)));
+                       if (typeof option === 'string') methodReturn = data[option](value);
+               });
+
+               return (methodReturn === undefined) ? $set : methodReturn;
+       };
+
+       $.fn.wizard.defaults = {};
+
+       $.fn.wizard.Constructor = Wizard;
+
+
+       // WIZARD DATA-API
+
+       $(function () {
+               $('body').on('mousedown.wizard.data-api', '.wizard', function () {
+                       var $this = $(this);
+                       if ($this.data('wizard')) return;
+                       $this.wizard($this.data());
+               });
+       });
+
+});
index 6b73668ab885d3c351e2bfcf15622710555381d8..90fd49772a71f0027811817cd3a07671db19f0d1 100644 (file)
@@ -67,6 +67,68 @@ one.lib.dashlet = {
             return $buttonGroup;
         }
     },
+    datagrid: {
+        /*
+         * The init function returns HTML markup for the datagrid per the options provided. Each consumer 
+         * of the datagrid must first call init and then provide the datasource for the grid.   
+         * id: this is the id of the table
+         * options: {
+         * searchable: true/false,
+         * pagination: turned off for now,
+         * flexibleRowsPerPage: turned off
+         * }
+         * classes : String containing bootstrap related classes. For ex: "table-striped table-condensed"
+         * The classes "table", "table-bordered" and "datagrid" will be added by default
+         */
+        init: function(id, options, classes) {
+            var $fuelGridContainerDiv = $(document.createElement("div"));
+            $fuelGridContainerDiv.addClass("fuelux");
+            $table = $(document.createElement("table"));
+            $table.attr("id", id);
+            $table.addClass("table table-bordered datagrid");
+            $table.addClass(classes);
+            // create datagrid header
+            $thead = $(document.createElement("thead"));
+            $headertr = $(document.createElement("tr"));
+            $headerth = $(document.createElement("th"));
+            // create datagrid footer
+            $tfoot = $(document.createElement("tfoot"));
+            $footertr = $(document.createElement("tr"));
+            $footerth = $(document.createElement("th"));
+            if(options.searchable == true) {
+                $headerth.append(one.lib.dashlet.datagrid._searchable());
+            }
+            if(options.flexibleRowsPerPage == true) {
+                $footerth.append(one.lib.dashlet.datagrid._rowsPerPage(options.popout));
+            }
+            if(options.pagination == true) {
+                $footerth.append(one.lib.dashlet.datagrid._pagination());
+            }
+            $headertr.append($headerth);
+            $thead.append($headertr);
+            $footertr.append($footerth);
+            $tfoot.append($footertr);
+            $table.append($thead).append($tfoot);
+            $fuelGridContainerDiv.append($table);
+            return $fuelGridContainerDiv;
+        },
+        _searchable: function() {
+            var searchHTML = "<div class='datagrid-header-left'><div class='input-append search datagrid-search'> <input type='text' class='input-medium' placeholder='Search'><button type='button' class='btn'><i class='icon-search'></i></button></div></div>";
+            return searchHTML;
+        },
+        _pagination: function() {
+            var html = '<div class="datagrid-footer-right" style="display:none;"><div class="grid-pager"><button type="button" class="btn grid-prevpage"><i class="icon-chevron-left"></i></button><span>Page</span> <div style="display:inline-block;"><input type="text" name="pagenumber" style="width:25px;margin-bottom:-10px;vertical-align:middle;margin-right:5px;"></div><span>of <span class="grid-pages"></span></span><button type="button" class="btn grid-nextpage"><i class="icon-chevron-right"></i></button></div></div>';
+            return html;
+        },
+        _rowsPerPage: function(popout) {
+            if(popout) {
+                var html = '<div class="datagrid-footer-left" style="display:none;"><div class="grid-controls"><span><span class="grid-start"></span>-<span class="grid-end"></span> of <span class="grid-count"></span></span><div class="select grid-pagesize" data-resize="auto" style="visibility:hidden;"><button type="button" data-toggle="dropdown" class="btn dropdown-toggle"><span class="dropdown-label"></span><span class="caret"></span></button><ul class="dropdown-menu"><li data-value="10" data-selected="true"><a href="#">5</a></li><li data-value="10"><a href="#">10</a></li><li data-value="20"><a href="#">20</a></li><li data-value="50"><a href="#">50</a></li><li data-value="100"><a href="#">100</a></li></ul></div><span style="display:none;">Per Page</span></div></div>';
+            } else {
+                var html = '<div class="datagrid-footer-left" style="display:none;"><div class="grid-controls"><span><span class="grid-start"></span>-<span class="grid-end"></span> of <span class="grid-count"></span></span><div class="select grid-pagesize" data-resize="auto" style="visibility:hidden;"><button type="button" data-toggle="dropdown" class="btn dropdown-toggle"><span class="dropdown-label"></span><span class="caret"></span></button><ul class="dropdown-menu"><li data-value="5" data-selected="true"><a href="#">5</a></li><li data-value="10"><a href="#">10</a></li><li data-value="20"><a href="#">20</a></li><li data-value="50"><a href="#">50</a></li><li data-value="100"><a href="#">100</a></li></ul></div><span style="display:none;">Per Page</span></div></div>';
+            }
+            return html;
+        }
+    },
     table : {
         table : function(classes, id) {
             var $table = $(document.createElement('table'));
diff --git a/opendaylight/web/root/src/main/resources/js/underscore-min.js b/opendaylight/web/root/src/main/resources/js/underscore-min.js
new file mode 100644 (file)
index 0000000..459f691
--- /dev/null
@@ -0,0 +1,32 @@
+// Underscore.js 1.3.3
+// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
+// Underscore is freely distributable under the MIT license.
+// Portions of Underscore are inspired or borrowed from Prototype,
+// Oliver Steele's Functional, and John Resig's Micro-Templating.
+// For all details and documentation:
+// http://documentcloud.github.com/underscore
+(function(){function r(a,c,d){if(a===c)return 0!==a||1/a==1/c;if(null==a||null==c)return a===c;a._chain&&(a=a._wrapped);c._chain&&(c=c._wrapped);if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return!1;switch(e){case "[object String]":return a==""+c;case "[object Number]":return a!=+a?c!=+c:0==a?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
+c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if("object"!=typeof a||"object"!=typeof c)return!1;for(var f=d.length;f--;)if(d[f]==a)return!0;d.push(a);var f=0,g=!0;if("[object Array]"==e){if(f=a.length,g=f==c.length)for(;f--&&(g=f in a==f in c&&r(a[f],c[f],d)););}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return!1;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,h)&&!f--)break;
+g=!f}}d.pop();return g}var s=this,I=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,J=k.unshift,l=p.toString,K=p.hasOwnProperty,y=k.forEach,z=k.map,A=k.reduce,B=k.reduceRight,C=k.filter,D=k.every,E=k.some,q=k.indexOf,F=k.lastIndexOf,p=Array.isArray,L=Object.keys,t=Function.prototype.bind,b=function(a){return new m(a)};"undefined"!==typeof exports?("undefined"!==typeof module&&module.exports&&(exports=module.exports=b),exports._=b):s._=b;b.VERSION="1.3.3";var j=b.each=b.forEach=function(a,
+c,d){if(a!=null)if(y&&a.forEach===y)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===o)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===o)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.map===z)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(A&&
+a.reduce===A){e&&(c=b.bind(c,e));return f?a.reduce(c,d):a.reduce(c)}j(a,function(a,b,i){if(f)d=c.call(e,d,a,b,i);else{d=a;f=true}});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(B&&a.reduceRight===B){e&&(c=b.bind(c,e));return f?a.reduceRight(c,d):a.reduceRight(c)}var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=function(a,
+c,b){var e;G(a,function(a,g,h){if(c.call(b,a,g,h)){e=a;return true}});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(C&&a.filter===C)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(D&&a.every===D)return a.every(c,b);j(a,function(a,g,h){if(!(e=e&&c.call(b,
+a,g,h)))return o});return!!e};var G=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(E&&a.some===E)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;if(q&&a.indexOf===q)return a.indexOf(c)!=-1;return b=G(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
+function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&
+(e={value:a,computed:b})});return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){d=Math.floor(Math.random()*(f+1));b[f]=b[d];b[d]=a});return b};b.sortBy=function(a,c,d){var e=b.isFunction(c)?c:function(a){return a[c]};return b.pluck(b.map(a,function(a,b,c){return{value:a,criteria:e.call(d,a,b,c)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c===void 0?1:d===void 0?-1:c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};
+j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:b.isArray(a)||b.isArguments(a)?i.call(a):a.toArray&&b.isFunction(a.toArray)?a.toArray():b.values(a)};b.size=function(a){return b.isArray(a)?a.length:b.keys(a).length};b.first=b.head=b.take=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,
+0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,
+e=[];a.length<3&&(c=true);b.reduce(d,function(d,g,h){if(c?b.last(d)!==g||!d.length:!b.include(d,g)){d.push(g);e.push(a[h])}return d},[]);return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1),true);return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=
+i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,d){if(a==null)return-1;var e;if(d){d=b.sortedIndex(a,c);return a[d]===c?d:-1}if(q&&a.indexOf===q)return a.indexOf(c);d=0;for(e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(F&&a.lastIndexOf===F)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){if(arguments.length<=
+1){b=a||0;a=0}for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;){g[f++]=a;a=a+d}return g};var H=function(){};b.bind=function(a,c){var d,e;if(a.bind===t&&t)return t.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));H.prototype=a.prototype;var b=new H,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=
+i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(null,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i,j=b.debounce(function(){h=
+g=false},c);return function(){d=this;e=arguments;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);j()},c));g?h=true:i=a.apply(d,e);j();g=true;return i}};b.debounce=function(a,b,d){var e;return function(){var f=this,g=arguments;d&&!e&&a.apply(f,g);clearTimeout(e);e=setTimeout(function(){e=null;d||a.apply(f,g)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));
+return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=L||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&
+c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.pick=function(a){var c={};j(b.flatten(i.call(arguments,1)),function(b){b in a&&(c[b]=a[b])});return c};b.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=
+function(a){if(a==null)return true;if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=function(a){return l.call(a)=="[object Arguments]"};b.isArguments(arguments)||(b.isArguments=function(a){return!(!a||!b.has(a,"callee"))});b.isFunction=function(a){return l.call(a)=="[object Function]"};
+b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isFinite=function(a){return b.isNumber(a)&&isFinite(a)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,
+b){return K.call(a,b)};b.noConflict=function(){s._=I;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.result=function(a,c){if(a==null)return null;var d=a[c];return b.isFunction(d)?d.call(a):d};b.mixin=function(a){j(b.functions(a),function(c){M(c,b[c]=a[c])})};var N=0;b.uniqueId=
+function(a){var b=N++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var u=/.^/,n={"\\":"\\","'":"'",r:"\r",n:"\n",t:"\t",u2028:"\u2028",u2029:"\u2029"},v;for(v in n)n[n[v]]=v;var O=/\\|'|\r|\n|\t|\u2028|\u2029/g,P=/\\(\\|'|r|n|t|u2028|u2029)/g,w=function(a){return a.replace(P,function(a,b){return n[b]})};b.template=function(a,c,d){d=b.defaults(d||{},b.templateSettings);a="__p+='"+a.replace(O,function(a){return"\\"+n[a]}).replace(d.escape||
+u,function(a,b){return"'+\n_.escape("+w(b)+")+\n'"}).replace(d.interpolate||u,function(a,b){return"'+\n("+w(b)+")+\n'"}).replace(d.evaluate||u,function(a,b){return"';\n"+w(b)+"\n;__p+='"})+"';\n";d.variable||(a="with(obj||{}){\n"+a+"}\n");var a="var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n"+a+"return __p;\n",e=new Function(d.variable||"obj","_",a);if(c)return e(c,b);c=function(a){return e.call(this,a,b)};c.source="function("+(d.variable||"obj")+"){\n"+a+"}";return c};
+b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var x=function(a,c){return c?b(a).chain():a},M=function(a,c){m.prototype[a]=function(){var a=i.call(arguments);J.call(a,this._wrapped);return x(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return x(d,
+this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return x(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
\ No newline at end of file
index 337d721696b8003713fe3805563c091760d1852b..71ba687f2d4b16e22c43de7586f6d75c7119b7ac 100644 (file)
@@ -208,7 +208,7 @@ public class Troubleshoot implements IDaylightWeb {
                 List<NodeConnectorStatistics> statistics = statisticsManager
                         .getNodeConnectorStatistics(node);
                 for (NodeConnectorStatistics stats : statistics) {
-                    cells.add(this.convertPortsStatistics(stats));
+                    cells.add(this.convertPortsStatistics(stats, containerName));
                 }
             }
         }
@@ -220,11 +220,19 @@ public class Troubleshoot implements IDaylightWeb {
     }
 
     private Map<String, String> convertPortsStatistics(
-            NodeConnectorStatistics ncStats) {
+            NodeConnectorStatistics ncStats, String containerName) {
         Map<String, String> row = new HashMap<String, String>();
 
+        ISwitchManager switchManager = (ISwitchManager) ServiceHelper
+                .getInstance(ISwitchManager.class, containerName, this);
+        NodeConnector nodeConnector = ncStats.getNodeConnector();
+        Description description = (Description) switchManager.getNodeProp(nodeConnector.getNode(), Description.propertyName);
+        String desc = (description == null) ? "" : description.getValue();
+        String nodeName = desc.equalsIgnoreCase("none") ? nodeConnector.getNode().getNodeIDString() : desc;
+        String nodeConnectorDisplayName = nodeConnector.getType() + "|" + nodeConnector.getID() + "@" + nodeName;
         row.put("nodeConnector",
-                String.valueOf(ncStats.getNodeConnector().toString()));
+                String.valueOf(nodeConnectorDisplayName));
+
         row.put("rxPkts", String.valueOf(ncStats.getReceivePacketCount()));
         row.put("txPkts", String.valueOf(ncStats.getTransmitPacketCount()));
         row.put("rxBytes", String.valueOf(ncStats.getReceiveByteCount()));
index 87e07f57df22d48ddff3ceb2908a4fc8a4d39d9b..3f0dc9e81231b50dc098011f20dd53f11ffdcfeb 100644 (file)
@@ -1,4 +1,3 @@
-
 /* 
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved. 
  * 
@@ -18,12 +17,12 @@ one.f.dashlet = {
         name : 'Existing Nodes'
     },
     uptime: {
-       id: 'uptime',
-       name: 'Uptime'
+        id: 'uptime',
+        name: 'Uptime'
     },
     flowsOrPorts: {
-       id: "flowsOrPorts",
-       name: "Statistics"
+        id: "flowsOrPorts",
+        name: "Statistics"
     }
 };
 
@@ -63,234 +62,484 @@ $(one.f.menu.right.bottom).each(function(index, value) {
 
 /**Troubleshoot modules*/
 one.f.troubleshooting = {
-       rootUrl: "/controller/web/troubleshoot",
-       rightBottomDashlet: { 
-               get: function() {
-                       var $rightBottomDashlet = $("#right-bottom").find(".dashlet");
-                       return $rightBottomDashlet;
-               },
-               setDashletHeader: function(label) {
-                       $("#right-bottom li a")[0].innerHTML = label; 
-               }
-       },
-       createTable: function(columnNames, body) {
-               var tableAttributes = ["table-striped", "table-bordered", "table-condensed"];
-               var $table = one.lib.dashlet.table.table(tableAttributes);
-               var tableHeaders = columnNames;
-               var $thead = one.lib.dashlet.table.header(tableHeaders);
-               var $tbody = one.lib.dashlet.table.body(body, tableHeaders);
-               $table.append($thead)
-                       .append($tbody);
-               return $table;
-       }
+    rootUrl: "/controller/web/troubleshoot",
+    rightBottomDashlet: { 
+        get: function() {
+            var $rightBottomDashlet = $("#right-bottom").find(".dashlet");
+            return $rightBottomDashlet;
+        },
+        setDashletHeader: function(label) {
+            $("#right-bottom li a")[0].innerHTML = label; 
+        }
+    },
+    createTable: function(columnNames, body) {
+        var tableAttributes = ["table-striped", "table-bordered", "table-condensed"];
+        var $table = one.lib.dashlet.table.table(tableAttributes);
+        var tableHeaders = columnNames;
+        var $thead = one.lib.dashlet.table.header(tableHeaders);
+        var $tbody = one.lib.dashlet.table.body(body, tableHeaders);
+        $table.append($thead)
+            .append($tbody);
+        return $table;
+    }
 };
 
 one.f.troubleshooting.existingNodes = {
-               id: {
-                       popout: "one_f_troubleshooting_existingNodes_id_popout",
-                       modal: "one_f_troubleshooting_existingNodes_id_modal"
-               },
-               // TODO: Make these values configurable.
-               autoRefreshInterval: {
-                       flows: 10000,
-                       ports: 10000,
-                       refreshRateInterval: 5000
-               },
-               load: {
-                       main: function($dashlet) {
-                               one.lib.dashlet.empty($dashlet);
-                               $dashlet.append(one.lib.dashlet.header(one.f.dashlet.existingNodes.name));
-                               
-                               // TODO(l): Add a generic auto expand function to one.lib and replace custom height setting.
-                               //$('#left-top').height('100%');
-                               one.f.troubleshooting.existingNodes.ajax(one.f.troubleshooting.rootUrl + "/existingNodes" , function(content) {
-                                       var body = one.f.troubleshooting.existingNodes.data.existingNodes(content);
-                                       var $table = one.f.troubleshooting.createTable(content.columnNames, body);
-                                       $dashlet.append($table);
-                               });
-                       },
-                       flows: function(nodeId) {
-                               try {
-                                       clearTimeout(one.f.troubleshooting.existingNodes.registry.refreshTimer);
-                                       $.getJSON(one.main.constants.address.prefix + "/troubleshoot/flowStats?nodeId=" + nodeId, function(content) {
-                                               var body = one.f.troubleshooting.existingNodes.data.flows(content);
-                                               var $table = one.f.troubleshooting.createTable(content.columnNames, body);
-                                               $rightBottomDashlet = one.f.troubleshooting.rightBottomDashlet.get();
-                                               one.f.troubleshooting.rightBottomDashlet.setDashletHeader("Flows");
-                                               one.lib.dashlet.empty($rightBottomDashlet);
-                                               $rightBottomDashlet.append(one.lib.dashlet.header("Flow Details"));
-                                               $rightBottomDashlet.append($table);
-                                               var numberOfFlows = content.nodeData.length;
-                                               var refreshRate = one.f.troubleshooting.existingNodes.autoRefreshInterval.flows;
-                                               if (numberOfFlows > 0) {
-                                                       refreshRate += Math.floor(numberOfFlows / 500) *
-                                                               one.f.troubleshooting.existingNodes.autoRefreshInterval.refreshRateInterval;
-                                               }
-                                               one.f.troubleshooting.existingNodes.registry.refreshTimer = setTimeout(
-                                                               one.f.troubleshooting.existingNodes.load.flows,
-                                                               refreshRate, nodeId);
-                                       });
-                               } catch(e) {}
-                       },
-                       ports: function(nodeId) {
-                               try {
-                                       clearTimeout(one.f.troubleshooting.existingNodes.registry.refreshTimer);
-                                       $.getJSON(one.main.constants.address.prefix + "/troubleshoot/portStats?nodeId=" + nodeId, function(content) {
-                                               var body = one.f.troubleshooting.existingNodes.data.ports(content);
-                                               var $table = one.f.troubleshooting.createTable(content.columnNames, body);
-                                               $rightBottomDashlet = one.f.troubleshooting.rightBottomDashlet.get();
-                                               one.f.troubleshooting.rightBottomDashlet.setDashletHeader("Ports");
-                                               one.lib.dashlet.empty($rightBottomDashlet);
-                                               $rightBottomDashlet.append(one.lib.dashlet.header("Port Details"));
-                                               $rightBottomDashlet.append($table);
-                                               var numberOfPorts = content.nodeData.length;
-                                               var refreshRate = one.f.troubleshooting.existingNodes.autoRefreshInterval.ports;
-                                               if (numberOfPorts > 0) {
-                                                       refreshRate += Math.floor(numberOfPorts / 500) *
-                                                               one.f.troubleshooting.existingNodes.autoRefreshInterval.refreshRateInterval;
-                                               }
-                                               one.f.troubleshooting.existingNodes.registry.refreshTimer = setTimeout(
-                                                               one.f.troubleshooting.existingNodes.load.ports,
-                                                               refreshRate, nodeId);
-                                       });
-                               } catch(e) {}
-                       } 
-               },
-               ajax : function(url, callback) {
-                       $.getJSON(url, function(data) {
-                               callback(data);
-                       });
-               },
-               registry: {},
-               modal : {
-               },
-               data : {
-                       existingNodes : function(data) {
-                               var result = [];
-                               $.each(data.nodeData, function(key, value) {
-                                       var tr = {};
-                                       var entry = [];
-                                       entry.push(value["nodeName"]);
-                                       entry.push(value["nodeId"]);
-                                       var nodeIdvalue = value["nodeId"];
-                                       entry.push("<a href=\"javascript:one.f.troubleshooting.existingNodes.load.flows('" + value["nodeId"] + "');\">Flows</a>" + 
-                                                       " <a href=\"javascript:one.f.troubleshooting.existingNodes.load.ports('" + value["nodeId"] + "');\">Ports</a>");
-                                       tr.entry = entry;
-                                       result.push(tr);
-                               });
-                               return result;
-                       },
-                       ports: function(data) {
-                               var result = [];
-                               $.each(data.nodeData, function(key, value) {
-                                       var tr = {};
-                                       var entry = [];
-                                       entry.push(value["nodeConnector"]);
-                                       entry.push(value["rxPkts"]);
-                                       entry.push(value["txPkts"]);
-                                       entry.push(value["rxBytes"]);
-                                       entry.push(value["txBytes"]);
-                                       entry.push(value["rxDrops"]);
-                                       entry.push(value["txDrops"]);
-                                       entry.push(value["rxErrors"]);
-                                       entry.push(value["txErrors"]);
-                                       entry.push(value["rxFrameErrors"]);
-                                       entry.push(value["rxOverRunErrors"]);
-                                       entry.push(value["rxCRCErrors"]);
-                                       entry.push(value["collisions"]);
-                                       tr.entry = entry;
-                                       result.push(tr);
-                               });
-                               return result;
-                       },
-                       flows: function(data) {
-                               var result = [];
-                               $.each(data.nodeData, function(key, value) {
-                                       var tr = {};
-                                       var entry = [];
-                                       entry.push(value["nodeName"]);
-                                       entry.push(value["inPort"]);
-                                       entry.push(value["dlSrc"]);
-                                       entry.push(value["dlDst"]);
-                                       entry.push(value["dlType"]);
-                                       entry.push(value["dlVlan"]);
-                                       entry.push(value["nwSrc"]);
-                                       entry.push(value["nwDst"]);
-                                       entry.push(value["nwProto"]);
-                                       entry.push(value["tpSrc"]);
-                                       entry.push(value["tpDst"]);
-                                       entry.push(value["actions"]);
-                                       entry.push(value["byteCount"]);
-                                       entry.push(value["packetCount"]);
-                                       entry.push(value["durationSeconds"]);
-                                       entry.push(value["idleTimeout"]);
-                                       entry.push(value["outPorts"]);
-                                       entry.push(value["outVlanId"]);
-                                       entry.push(value["priority"]);
-                                       tr.entry = entry;
-                                       result.push(tr);
-                               });
-                               return result;
-                       }
-               }
+        id: {
+            popout: "one_f_troubleshooting_existingNodes_id_popout",
+            modal: "one_f_troubleshooting_existingNodes_id_modal",
+            existingNodesDataGrid: "one_f_troubleshooting_existingNodes_id_datagrid",
+            portsDataGrid: "one_f_troubleshooting_existingNodes_id_portsDataGrid",
+            flowsDataGrid: "one_f_troubleshooting_existingNodes_id_flowsDataGrid"
+        },
+        // TODO: Make these values configurable.
+        autoRefreshInterval: {
+            flows: 10000,
+            ports: 10000,
+            refreshRateInterval: 5000
+        },
+        load: {
+            main: function($dashlet) {
+                one.lib.dashlet.empty($dashlet);
+                $dashlet.append(one.lib.dashlet.header(one.f.dashlet.existingNodes.name));
+                // TODO(l): Add a generic auto expand function to one.lib and replace custom height setting.
+                //$('#left-top').height('100%');
+                one.f.troubleshooting.existingNodes.ajax(one.f.troubleshooting.rootUrl + "/existingNodes" , function(content) {
+                    var $gridHTML = one.lib.dashlet.datagrid.init(one.f.troubleshooting.existingNodes.id.existingNodesDataGrid, {
+                        searchable: true,
+                        filterable: false,
+                        pagination: true,
+                        flexibleRowsPerPage: true
+                        }, "table-striped table-condensed");
+                    $dashlet.append($gridHTML);
+                    var dataSource = one.f.troubleshooting.existingNodes.data.existingNodesGrid(content);
+                    $("#" + one.f.troubleshooting.existingNodes.id.existingNodesDataGrid).datagrid({dataSource: dataSource});
+
+                });
+            },
+            flows: function(nodeId) {
+                try {
+                    clearTimeout(one.f.troubleshooting.existingNodes.registry.refreshTimer);
+                    $.getJSON(one.main.constants.address.prefix + "/troubleshoot/flowStats?nodeId=" + nodeId, function(content) {
+                        $rightBottomDashlet = one.f.troubleshooting.rightBottomDashlet.get();
+                        one.f.troubleshooting.rightBottomDashlet.setDashletHeader("Flows");
+                        one.lib.dashlet.empty($rightBottomDashlet);
+                        $rightBottomDashlet.append(one.lib.dashlet.header("Flow Details"));
+
+                        var $gridHTML = one.lib.dashlet.datagrid.init(one.f.troubleshooting.existingNodes.id.flowsDataGrid, {
+                            searchable: true,
+                            filterable: false,
+                            pagination: true,
+                            flexibleRowsPerPage: true
+                            }, "table-striped table-condensed");
+                        $rightBottomDashlet.append($gridHTML);
+                        var dataSource = one.f.troubleshooting.existingNodes.data.flowsGrid(content);
+                        $("#" + one.f.troubleshooting.existingNodes.id.flowsDataGrid).datagrid({dataSource: dataSource});
+
+                        var numberOfFlows = content.nodeData.length;
+                        var refreshRate = one.f.troubleshooting.existingNodes.autoRefreshInterval.flows;
+                        if (numberOfFlows > 0) {
+                            refreshRate += Math.floor(numberOfFlows / 500) *
+                                one.f.troubleshooting.existingNodes.autoRefreshInterval.refreshRateInterval;
+                        }
+                        one.f.troubleshooting.existingNodes.registry.refreshTimer = setTimeout(
+                                one.f.troubleshooting.existingNodes.load.flows,
+                                refreshRate, nodeId);
+                    });
+                } catch(e) {}
+            },
+            ports: function(nodeId) {
+                try {
+                    clearTimeout(one.f.troubleshooting.existingNodes.registry.refreshTimer);
+                    $.getJSON(one.main.constants.address.prefix + "/troubleshoot/portStats?nodeId=" + nodeId, function(content) {
+                        $rightBottomDashlet = one.f.troubleshooting.rightBottomDashlet.get();
+                        one.f.troubleshooting.rightBottomDashlet.setDashletHeader("Ports");
+                        one.lib.dashlet.empty($rightBottomDashlet);
+                        $rightBottomDashlet.append(one.lib.dashlet.header("Port Details"));
+
+                        var $gridHTML = one.lib.dashlet.datagrid.init(one.f.troubleshooting.existingNodes.id.portsDataGrid, {
+                            searchable: true,
+                            filterable: false,
+                            pagination: true,
+                            flexibleRowsPerPage: true
+                            }, "table-striped table-condensed");
+                        $rightBottomDashlet.append($gridHTML);
+                        var dataSource = one.f.troubleshooting.existingNodes.data.portsGrid(content);
+                        $("#" + one.f.troubleshooting.existingNodes.id.portsDataGrid).datagrid({dataSource: dataSource});
+
+                        var numberOfPorts = content.nodeData.length;
+                        var refreshRate = one.f.troubleshooting.existingNodes.autoRefreshInterval.ports;
+                        if (numberOfPorts > 0) {
+                            refreshRate += Math.floor(numberOfPorts / 500) *
+                                one.f.troubleshooting.existingNodes.autoRefreshInterval.refreshRateInterval;
+                        }
+                        one.f.troubleshooting.existingNodes.registry.refreshTimer = setTimeout(
+                                one.f.troubleshooting.existingNodes.load.ports,
+                                refreshRate, nodeId);
+                    });
+                } catch(e) {}
+            } 
+        },
+        ajax : function(url, callback) {
+            $.getJSON(url, function(data) {
+                callback(data);
+            });
+        },
+        registry: {},
+        modal : {
+        },
+        data : {
+            existingNodesGrid: function(data) {
+                var source = new StaticDataSource({
+                    columns: [
+                        {
+                            property: 'nodeName',
+                            label: 'Name',
+                            sortable: true
+                        },
+                        {
+                            property: 'nodeId',
+                            label: 'Static Route',
+                            sortable: true
+                        },
+                        {
+                            property: 'statistics',
+                            label: 'Statistics',
+                            sortable: true
+                        }
+                    ],
+                    data: data.nodeData,
+                    formatter: function(items) {
+                        $.each(items, function(index, item) {
+                            item["statistics"] = "<a href=\"javascript:one.f.troubleshooting.existingNodes.load.flows('" + item["nodeId"] + "');\">Flows</a>" + 
+                            " <a href=\"javascript:one.f.troubleshooting.existingNodes.load.ports('" + item["nodeId"] + "');\">Ports</a>";
+                        });
+
+                    },
+                    delay: 0
+                });
+                return source;
+            },
+            portsGrid: function(data) {
+                var source = new StaticDataSource({
+                    columns: [
+                        {
+                            property: 'nodeConnector',
+                            label: 'Node Connector',
+                            sortable: true
+                        },
+                        {
+                            property: 'rxPkts',
+                            label: 'Rx Pkts',
+                            sortable: true
+                        },
+                        {
+                            property: 'txPkts',
+                            label: 'Tx Pkts',
+                            sortable: true
+                        },
+                        {
+                            property: 'rxBytes',
+                            label: 'Rx Bytes',
+                            sortable: true
+                        },
+                        {
+                            property: 'txBytes',
+                            label: 'Tx Bytes',
+                            sortable: true
+                        },
+                        {
+                            property: 'rxDrops',
+                            label: 'Rx Drops',
+                            sortable: true
+                        },
+                        {
+                            property: 'txDrops',
+                            label: 'Tx Drops',
+                            sortable: true
+                        },
+                        {
+                            property: 'rxErrors',
+                            label: 'Rx Errs',
+                            sortable: true
+                        },
+                        {
+                            property: 'txErrors',
+                            label: 'Tx Errs',
+                            sortable: true
+                        },
+                        {
+                            property: 'rxFrameErrors',
+                            label: 'Rx Frame Errs',
+                            sortable: true
+                        },
+                        {
+                            property: 'rxOverRunErrors',
+                            label: 'Rx OverRun Errs',
+                            sortable: true
+                        },
+                        {
+                            property: 'rxCRCErrors',
+                            label: 'Rx CRC Errs',
+                            sortable: true
+                        },
+                        {
+                            property: 'collisions',
+                            label: 'Collisions',
+                            sortable: true
+                        }
+                    ],
+                    data: data.nodeData,
+                    delay: 200
+                });
+                return source;
+            },
+            ports: function(data) {
+                var result = [];
+                $.each(data.nodeData, function(key, value) {
+                    var tr = {};
+                    var entry = [];
+                    entry.push(value["nodeConnector"]);
+                    entry.push(value["rxPkts"]);
+                    entry.push(value["txPkts"]);
+                    entry.push(value["rxBytes"]);
+                    entry.push(value["txBytes"]);
+                    entry.push(value["rxDrops"]);
+                    entry.push(value["txDrops"]);
+                    entry.push(value["rxErrors"]);
+                    entry.push(value["txErrors"]);
+                    entry.push(value["rxFrameErrors"]);
+                    entry.push(value["rxOverRunErrors"]);
+                    entry.push(value["rxCRCErrors"]);
+                    entry.push(value["collisions"]);
+                    tr.entry = entry;
+                    result.push(tr);
+                });
+                return result;
+            },
+            flowsGrid: function(data) {
+                var source = new StaticDataSource({
+                    columns: [
+                        {
+                            property: 'nodeName',
+                            label: 'Node',
+                            sortable: true
+                        },
+                        {
+                            property: 'inPort',
+                            label: 'In Port',
+                            sortable: true
+                        },
+                        {
+                            property: 'dlSrc',
+                            label: 'DL Src',
+                            sortable: true
+                        },
+                        {
+                            property: 'dlDst',
+                            label: 'DL Dst',
+                            sortable: true
+                        },
+                        {
+                            property: 'dlType',
+                            label: 'DL Type',
+                            sortable: true
+                        },
+                        {
+                            property: 'dlVlan',
+                            label: 'DL Vlan',
+                            sortable: true
+                        },
+                        {
+                            property: 'nwSrc',
+                            label: 'NW Src',
+                            sortable: true
+                        },
+                        {
+                            property: 'nwDst',
+                            label: 'NW Dst',
+                            sortable: true
+                        },
+                        {
+                            property: 'nwProto',
+                            label: 'NW Proto',
+                            sortable: true
+                        },
+                        {
+                            property: 'tpSrc',
+                            label: 'TP Src',
+                            sortable: true
+                        },
+                        {
+                            property: 'tpDst',
+                            label: 'TP Dst',
+                            sortable: true
+                        },
+                        {
+                            property: 'actions',
+                            label: 'Actions',
+                            sortable: true
+                        },
+                        {
+                            property: 'byteCount',
+                            label: 'Byte Count',
+                            sortable: true
+                        },
+                        {
+                            property: 'packetCount',
+                            label: 'Packet Count',
+                            sortable: true
+                        },
+                        {
+                            property: 'durationSeconds',
+                            label: 'Duration Seconds',
+                            sortable: true
+                        },
+                        {
+                            property: 'idleTimeout',
+                            label: 'Idle Timeout',
+                            sortable: true
+                        },
+                        {
+                            property: 'outPorts',
+                            label: 'Out Ports',
+                            sortable: true
+                        },
+                        {
+                            property: 'outVlanId',
+                            label: 'Out VlanId',
+                            sortable: true
+                        },
+                        {
+                            property: 'priority',
+                            label: 'Priority',
+                            sortable: true
+                        }
+                    ],
+                    data: data.nodeData,
+                    delay: 0
+                });
+                return source;
+            },
+            flows: function(data) {
+                var result = [];
+                $.each(data.nodeData, function(key, value) {
+                    var tr = {};
+                    var entry = [];
+                    entry.push(value["nodeName"]);
+                    entry.push(value["inPort"]);
+                    entry.push(value["dlSrc"]);
+                    entry.push(value["dlDst"]);
+                    entry.push(value["dlType"]);
+                    entry.push(value["dlVlan"]);
+                    entry.push(value["nwSrc"]);
+                    entry.push(value["nwDst"]);
+                    entry.push(value["nwProto"]);
+                    entry.push(value["tpSrc"]);
+                    entry.push(value["tpDst"]);
+                    entry.push(value["actions"]);
+                    entry.push(value["byteCount"]);
+                    entry.push(value["packetCount"]);
+                    entry.push(value["durationSeconds"]);
+                    entry.push(value["idleTimeout"]);
+                    entry.push(value["outPorts"]);
+                    entry.push(value["outVlanId"]);
+                    entry.push(value["priority"]);
+                    tr.entry = entry;
+                    result.push(tr);
+                });
+                return result;
+            }
+        }
 };
 
 one.f.troubleshooting.uptime = {
-       id: {
-               popout: "one_f_troubleshooting_existingNodes_id_popout",
-               modal: "one_f_troubleshooting_existingNodes_id_modal"
-       },
+    id: {
+        popout: "one_f_troubleshooting_uptime_id_popout",
+        modal: "one_f_troubleshooting_uptime_id_modal",
+        datagrid: "one_f_troubleshooting_uptime_id_datagrid"
+    },
 
-       dashlet: function($dashlet) {
-                       one.lib.dashlet.empty($dashlet);
-                       $dashlet.append(one.lib.dashlet.header(one.f.dashlet.uptime.name));
-                       var url = one.f.troubleshooting.rootUrl + "/uptime";
-                       one.f.troubleshooting.uptime.ajax.main(url , {} ,function(content) {
-                               var body = one.f.troubleshooting.uptime.data.uptime(content);
-                               var $table = one.f.troubleshooting.createTable(content.columnNames, body);
-                               $dashlet.append($table);
-                       });
-       },
-       
-       ajax : {
-               main : function(url, requestData, callback) {
-                       $.getJSON(url, requestData, function(data) {
-                               callback(data);
-                       });
-               }
-       },
-       
-       data: {
-               uptime: function(data) {
-                       var result = [];
-                       $.each(data.nodeData, function(key, value) {
-                               var tr = {};
-                               var entry = [];
-                               entry.push(value["nodeName"]);
-                               entry.push(value["nodeId"]);
-                               entry.push(value["connectedSince"]);
-                               tr.entry = entry;
-                               result.push(tr);
-                       });
-                       return result;
-               }
-       },
+    dashlet: function($dashlet) {
+            one.lib.dashlet.empty($dashlet);
+            $dashlet.append(one.lib.dashlet.header(one.f.dashlet.uptime.name));
+            var url = one.f.troubleshooting.rootUrl + "/uptime";
+            one.f.troubleshooting.uptime.ajax.main(url , {} ,function(content) {
+                var $gridHTML = one.lib.dashlet.datagrid.init(one.f.troubleshooting.uptime.id.datagrid, {
+                    searchable: true,
+                    filterable: false,
+                    pagination: true,
+                    flexibleRowsPerPage: true
+                    }, "table-striped table-condensed");
+                $dashlet.append($gridHTML);
+                var dataSource = one.f.troubleshooting.uptime.data.uptimeDataGrid(content);
+                $("#" + one.f.troubleshooting.uptime.id.datagrid).datagrid({dataSource: dataSource});
+            });
+    },
+    
+    ajax : {
+        main : function(url, requestData, callback) {
+            $.getJSON(url, requestData, function(data) {
+                callback(data);
+            });
+        }
+    },
+    
+    data: {
+        uptimeDataGrid: function(data) {
+            var source = new StaticDataSource({
+                columns: [
+                    {
+                        property: 'nodeName',
+                        label: 'Node',
+                        sortable: true
+                    },
+                    {
+                        property: 'nodeId',
+                        label: 'Node ID',
+                        sortable: true
+                    },
+                    {
+                        property: 'connectedSince',
+                        label: 'Statistics',
+                        sortable: true
+                    }
+                ],
+                data: data.nodeData,
+                delay: 0
+            });
+            return source;
+        },
+        uptime: function(data) {
+            var result = [];
+            $.each(data.nodeData, function(key, value) {
+                var tr = {};
+                var entry = [];
+                entry.push(value["nodeName"]);
+                entry.push(value["nodeId"]);
+                entry.push(value["connectedSince"]);
+                tr.entry = entry;
+                result.push(tr);
+            });
+            return result;
+        }
+    },
 };
 
 one.f.troubleshooting.statistics = {
-       dashlet : function($dashlet) {
+    dashlet : function($dashlet) {
         var $h4 = one.lib.dashlet.header("Statistics");
         $dashlet.append($h4);
-               // empty
-               var $none = $(document.createElement('div'));
-               $none.addClass('none');
-               var $p = $(document.createElement('p'));
-               $p.text('Please select a Flow or Ports statistics');
-               $p.addClass('text-center').addClass('text-info');
-               
-               $dashlet.append($none)
-                       .append($p);
-       }
+        // empty
+        var $none = $(document.createElement('div'));
+        $none.addClass('none');
+        var $p = $(document.createElement('p'));
+        $p.text('Please select a Flow or Ports statistics');
+        $p.addClass('text-center').addClass('text-info');
+        
+        $dashlet.append($none)
+            .append($p);
+    }
 };
 
 // bind dashlet nav
@@ -308,14 +557,14 @@ $('.dash .nav a', '#main').click(function() {
     var menu = one.f.dashlet;
     switch (id) {
         case menu.existingNodes.id:
-               one.f.troubleshooting.existingNodes.load.main($dashlet);
+            one.f.troubleshooting.existingNodes.load.main($dashlet);
             break;
         case menu.uptime.id:
-               one.f.troubleshooting.uptime.dashlet($dashlet);
-                       break;
-               case menu.flowsOrPorts.id:
-                       one.f.troubleshooting.statistics.dashlet($dashlet);
-                       break;
+            one.f.troubleshooting.uptime.dashlet($dashlet);
+            break;
+        case menu.flowsOrPorts.id:
+            one.f.troubleshooting.statistics.dashlet($dashlet);
+            break;
     };
 });