--- /dev/null
+/*
+ * 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.statistics.northbound;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.ext.ContextResolver;
+
+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.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.query.QueryContext;
+import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
+import org.opendaylight.controller.sal.authorization.Privilege;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.reader.FlowOnNode;
+import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
+import org.opendaylight.controller.switchmanager.ISwitchManager;
+
+/**
+ * Northbound APIs that returns various Statistics exposed by the Southbound
+ * protocol plugins such as Openflow.
+ *
+ * <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.
+ *
+ */
+@Path("/")
+public class StatisticsNorthbound {
+
+ private String username;
+ private QueryContext queryContext;
+
+ @Context
+ public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
+ if (queryCtxResolver != null) {
+ queryContext = queryCtxResolver.getContext(QueryContext.class);
+ }
+ }
+ @Context
+ public void setSecurityContext(SecurityContext context) {
+ if (context != null && context.getUserPrincipal() != null) username = context.getUserPrincipal().getName();
+ }
+
+ protected String getUserName() {
+ return username;
+ }
+
+ private IStatisticsManager getStatisticsService(String containerName) {
+ IContainerManager containerManager = (IContainerManager) ServiceHelper
+ .getGlobalInstance(IContainerManager.class, this);
+ if (containerManager == null) {
+ throw new ServiceUnavailableException("Container "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ boolean found = false;
+ List<String> containerNames = containerManager.getContainerNames();
+ for (String cName : containerNames) {
+ if (cName.trim().equalsIgnoreCase(containerName.trim())) {
+ found = true;
+ }
+ }
+
+ if (found == false) {
+ throw new ResourceNotFoundException(containerName + " "
+ + RestMessages.NOCONTAINER.toString());
+ }
+
+ IStatisticsManager statsManager = (IStatisticsManager) ServiceHelper
+ .getInstance(IStatisticsManager.class, containerName, this);
+
+ if (statsManager == null) {
+ throw new ServiceUnavailableException("Statistics "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ return statsManager;
+ }
+
+ /**
+ * Returns a list of all Flow Statistics from all the Nodes.
+ *
+ * @param containerName
+ * 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:
+ * http://localhost:8080/controller/nb/v2/statistics/default/flow
+ *
+ * Response body in JSON:
+ * {
+ * "flowStatistics": [
+ * {
+ * "node": {
+ * "id":"00:00:00:00:00:00:00:02",
+ * "type":"OF"
+ * },
+ * "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": {
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:02",
+ * "type":"OF"
+ * },
+ * "id":"3",
+ * "type":"OF"
+ * }
+ * },
+ * "priority": "1",
+ * "idleTimeout": "0",
+ * "hardTimeout": "0",
+ * "id": "0"
+ * },
+ * "tableId": "0",
+ * "durationSeconds": "1828",
+ * "durationNanoseconds": "397000000",
+ * "packetCount": "0",
+ * "byteCount": "0"
+ * }
+ * ]
+ * },
+ * { flow statistics of another node
+ * ............
+ * ................
+ * ......................
+ * }
+ *
+ * ]
+ * }
+ *
+ * Response body in XML:
+ * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+ * <list>
+ * <flowStatistics>
+ * <node>
+ * <id>00:00:00:00:00:00:00:02</id>
+ * <type>OF</type>
+ * </node>
+ * <flowStatistic>
+ * <flow>
+ * <match>
+ * <matchField>
+ * <type>DL_TYPE</type>
+ * <value>2048</value>
+ * </matchField>
+ * <matchField>
+ * <mask>255.255.255.255</mask>
+ * <type>NW_DST</type>
+ * <value>1.1.1.2</value>
+ * </matchField>
+ * </match>
+ * <actions
+ * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="output">
+ * <port>
+ * <node>
+ * <id>00:00:00:00:00:00:00:02</id>
+ * <type>OF</type>
+ * </node>
+ * <id>3</id>
+ * <type>OF</type>
+ * </port>
+ * </actions>
+ * <priority>1</priority>
+ * <idleTimeout>0</idleTimeout>
+ * <hardTimeout>0</hardTimeout>
+ * <id>0</id>
+ * </flow>
+ * <tableId>0</tableId>
+ * <durationSeconds>337</durationSeconds>
+ * <durationNanoseconds>149000000</durationNanoseconds>
+ * <packetCount>0</packetCount>
+ * <byteCount>0</byteCount>
+ * </flowStatistic>
+ * </flowStatistics>
+ * <flowStatistics>
+ * flow statistics for another node
+ * ..........
+ * ................
+ * .....................
+ * </flowStatistics>
+ * </list>
+ * </pre>
+ */
+
+ @Path("/{containerName}/flow")
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @TypeHint(AllFlowStatistics.class)
+ @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 AllFlowStatistics getFlowStatistics(
+ @PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
+ if (!NorthboundUtils.isAuthorized(
+ getUserName(), containerName, Privilege.READ, this)) {
+ throw new UnauthorizedException(
+ "User is not authorized to perform this operation on container "
+ + containerName);
+ }
+ IStatisticsManager statisticsManager = getStatisticsService(containerName);
+ if (statisticsManager == null) {
+ throw new ServiceUnavailableException("Statistics "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ ISwitchManager switchManager = (ISwitchManager) ServiceHelper
+ .getInstance(ISwitchManager.class, containerName, this);
+ if (switchManager == null) {
+ throw new ServiceUnavailableException("Switch manager "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ List<FlowStatistics> statistics = new ArrayList<FlowStatistics>();
+ for (Node node : switchManager.getNodes()) {
+ List<FlowOnNode> flowStats = new ArrayList<FlowOnNode>();
+
+ List<FlowOnNode> flows = statisticsManager.getFlows(node);
+ for (FlowOnNode flowOnSwitch : flows) {
+ flowStats.add(flowOnSwitch);
+ }
+ FlowStatistics stat = new FlowStatistics(node, flowStats);
+ statistics.add(stat);
+ }
+ AllFlowStatistics result = new AllFlowStatistics(statistics);
+ if (queryString != null) {
+ queryContext.createQuery(queryString, AllFlowStatistics.class)
+ .filter(result, FlowStatistics.class);
+ }
+ return result;
+ }
+
+ /**
+ * Returns a list of Flow Statistics for a given Node.
+ *
+ * @param containerName
+ * Name of the Container. The Container name for the base
+ * controller is "default".
+ * @param nodeType
+ * 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. *
+ *
+ * <pre>
+ *
+ * Example:
+ *
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/statistics/default/flow/node/OF/00:00:00:00:00:00:00:01
+ *
+ * Response body in JSON:
+ * {
+ * "node": {
+ * "id":"00:00:00:00:00:00:00:01",
+ * "type":"OF"
+ * },
+ * "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":{
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:01",
+ * "type":"OF"
+ * },
+ * "id":"5",
+ * "type":"OF"
+ * }
+ * }
+ * ],
+ * "priority": "1",
+ * "idleTimeout": "0",
+ * "hardTimeout": "0",
+ * "id": "0"
+ * },
+ * "tableId": "0",
+ * "durationSeconds": "2089",
+ * "durationNanoseconds": "538000000",
+ * "packetCount": "0",
+ * "byteCount": "0"
+ * }
+ * ]
+ * }
+ *
+ * Response body in XML:
+ * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+ * <nodeFlowStatistics>
+ * <node>
+ * <id>00:00:00:00:00:00:00:02</id>
+ * <type>OF</type>
+ * </node>
+ * <flowStatistic>
+ * <flow>
+ * <match>
+ * <matchField>
+ * <type>DL_TYPE</type>
+ * <value>2048</value>
+ * </matchField>
+ * <matchField>
+ * <mask>255.255.255.255</mask>
+ * <type>NW_DST</type>
+ * <value>1.1.1.2</value>
+ * </matchField>
+ * </match>
+ * <actions
+ * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="output">
+ * <port>
+ * <node>
+ * <id>00:00:00:00:00:00:00:02</id>
+ * <type>OF</type>
+ * </node>
+ * <id>3</id>
+ * <type>OF</type>
+ * </port>
+ * </actions>
+ * <priority>1</priority>
+ * <idleTimeout>0</idleTimeout>
+ * <hardTimeout>0</hardTimeout>
+ * <id>0</id>
+ * </flow>
+ * <tableId>0</tableId>
+ * <durationSeconds>337</durationSeconds>
+ * <durationNanoseconds>149000000</durationNanoseconds>
+ * <packetCount>0</packetCount>
+ * <byteCount>0</byteCount>
+ * </flowStatistic>
+ * <flowStatistic>
+ * <flow>
+ * <match>
+ * <matchField>
+ * <type>DL_TYPE</type>
+ * <value>2048</value>
+ * </matchField>
+ * <matchField>
+ * <mask>255.255.255.255</mask>
+ * <type>NW_DST</type>
+ * <value>1.1.1.1</value>
+ * </matchField>
+ * </match>
+ * <actions
+ * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="output">
+ * <port>
+ * <node>
+ * <id>00:00:00:00:00:00:00:02</id>
+ * <type>OF</type>
+ * </node>
+ * <id>3</id>
+ * <type>OF</type>
+ * </port>
+ * </actions>
+ * <priority>1</priority>
+ * <idleTimeout>0</idleTimeout>
+ * <hardTimeout>0</hardTimeout>
+ * <id>0</id>
+ * </flow>
+ * <tableId>0</tableId>
+ * <durationSeconds>337</durationSeconds>
+ * <durationNanoseconds>208000000</durationNanoseconds>
+ * <packetCount>0</packetCount>
+ * <byteCount>0</byteCount>
+ * </flowStatistic>
+ * </nodeFlowStatistics>
+ * </pre>
+ */
+ @Path("/{containerName}/flow/node/{nodeType}/{nodeId}")
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @TypeHint(FlowStatistics.class)
+ @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 FlowStatistics getFlowStatistics(
+ @PathParam("containerName") String containerName,
+ @PathParam("nodeType") String nodeType,
+ @PathParam("nodeId") String nodeId) {
+ 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 "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ ISwitchManager switchManager = (ISwitchManager) ServiceHelper
+ .getInstance(ISwitchManager.class, containerName, this);
+ if (switchManager == null) {
+ throw new ServiceUnavailableException("Switch manager "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ Node node = handleNodeAvailability(containerName, nodeType, nodeId);
+ return new FlowStatistics(node, statisticsManager.getFlows(node));
+ }
+
+ /**
+ * Returns a list of all the Port Statistics across all the NodeConnectors
+ * on all the Nodes.
+ *
+ * @param containerName
+ * Name of the Container. The Container name for the base
+ * controller is "default".
+ * @return List of all the Port Statistics across all the NodeConnectors on
+ * all the Nodes.
+ *
+ * <pre>
+ *
+ * Example:
+ *
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/statistics/default/port
+ *
+ * Response body in JSON:
+ * {
+ * "portStatistics": [
+ * {
+ * "node": {
+ * "id":"00:00:00:00:00:00:00:02",
+ * "type":"OF"
+ * },
+ * "portStatistic": [
+ * {
+ * "nodeConnector":{
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:02",
+ * "type":"OF"
+ * },
+ * "id":"3",
+ * "type":"OF"
+ * },
+ * "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": {
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:02",
+ * "type":"OF"
+ * },
+ * "id":"2",
+ * "type":"OF"
+ * },
+ * "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": {
+ * "id":"00:00:00:00:00:00:00:03",
+ * "type":"OF"
+ * },
+ * "portStatistic": [
+ * ..................
+ * .......................
+ * ..........................
+ * ]
+ * }
+ * ]
+ * }
+ *
+ * Response body in XML:
+ * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+ * <list>
+ * <portStatistics>
+ * <node>
+ * <id>00:00:00:00:00:00:00:02</id>
+ * <type>OF</type>
+ * </node>
+ * <portStatistic>
+ * <nodeConnector>
+ * <node>
+ * <id>00:00:00:00:00:00:00:02</id>
+ * <type>OF</type>
+ * </node>
+ * <id>3</id>
+ * <type>OF</type>
+ * </nodeConnector>
+ * <receivePackets>181</receivePackets>
+ * <transmitPackets>172</transmitPackets>
+ * <receiveBytes>12670</receiveBytes>
+ * <transmitBytes>12040</transmitBytes>
+ * <receiveDrops>0</receiveDrops>
+ * <transmitDrops>0</transmitDrops>
+ * <receiveErrors>0</receiveErrors>
+ * <transmitErrors>0</transmitErrors>
+ * <receiveFrameError>0</receiveFrameError>
+ * <receiveOverRunError>0</receiveOverRunError>
+ * <receiveCrcError>0</receiveCrcError>
+ * <collisionCount>0</collisionCount>
+ * </portStatistic>
+ * <portStatistic>
+ * <nodeConnector>
+ * <node>
+ * <id>00:00:00:00:00:00:00:02</id>
+ * <type>OF</type>
+ * </node>
+ * <id>2</id>
+ * <type>OF</type>
+ * </nodeConnector>
+ * <receivePackets>173</receivePackets>
+ * <transmitPackets>180</transmitPackets>
+ * <receiveBytes>12110</receiveBytes>
+ * <transmitBytes>12600</transmitBytes>
+ * <receiveDrops>0</receiveDrops>
+ * <transmitDrops>0</transmitDrops>
+ * <receiveErrors>0</receiveErrors>
+ * <transmitErrors>0</transmitErrors>
+ * <receiveFrameError>0</receiveFrameError>
+ * <receiveOverRunError>0</receiveOverRunError>
+ * <receiveCrcError>0</receiveCrcError>
+ * <collisionCount>0</collisionCount>
+ * </portStatistic>
+ * </portStatistics>
+ * </list>
+ * </pre>
+ */
+
+ @Path("/{containerName}/port")
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @TypeHint(AllPortStatistics.class)
+ @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 AllPortStatistics getPortStatistics(
+ @PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
+
+ if (!NorthboundUtils.isAuthorized(
+ getUserName(), containerName, Privilege.READ, this)) {
+ throw new UnauthorizedException(
+ "User is not authorized to perform this operation on container "
+ + containerName);
+ }
+ IStatisticsManager statisticsManager = getStatisticsService(containerName);
+ if (statisticsManager == null) {
+ throw new ServiceUnavailableException("Statistics "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ ISwitchManager switchManager = (ISwitchManager) ServiceHelper
+ .getInstance(ISwitchManager.class, containerName, this);
+ if (switchManager == null) {
+ throw new ServiceUnavailableException("Switch manager "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ List<PortStatistics> statistics = new ArrayList<PortStatistics>();
+ for (Node node : switchManager.getNodes()) {
+ List<NodeConnectorStatistics> stat = statisticsManager
+ .getNodeConnectorStatistics(node);
+ PortStatistics portStat = new PortStatistics(node, stat);
+ statistics.add(portStat);
+ }
+
+ AllPortStatistics result = new AllPortStatistics(statistics);
+ if (queryString != null) {
+ queryContext.createQuery(queryString, AllPortStatistics.class)
+ .filter(result, PortStatistics.class);
+ }
+ return result;
+ }
+
+ /**
+ * Returns a list of all the Port Statistics across all the NodeConnectors
+ * in a given Node.
+ *
+ * @param containerName
+ * Name of the Container. The Container name for the base
+ * controller is "default".
+ * @param nodeType
+ * Node Type as specifid in {@link org.opendaylight.controller.sal.core.Node} class
+ * @param Node
+ * 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://localhost:8080/controller/nb/v2/statistics/default/port/node/OF/00:00:00:00:00:00:00:01
+ *
+ * Response body in JSON:
+ * {
+ * "node": {
+ * "id":"00:00:00:00:00:00:00:01",
+ * "type":"OF"
+ * },
+ * "portStatistic": [
+ * {
+ * "nodeConnector": {
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:01",
+ * "type":"OF"
+ * },
+ * "id":"3",
+ * "type":"OF"
+ * },
+ * "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": {
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:01",
+ * "type":"OF"
+ * },
+ * "id":"2",
+ * "type":"OF"
+ * },
+ * "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 body in XML:
+ * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+ * <nodePortStatistics>
+ * <node>
+ * <id>00:00:00:00:00:00:00:01</id>
+ * <type>OF</type>
+ * </node>
+ * <portStatistic>
+ * <nodeConnector>
+ * <node>
+ * <id>00:00:00:00:00:00:00:01</id>
+ * <type>OF</type>
+ * </node>
+ * <id>2</id>
+ * <type>OF</type>
+ * </nodeConnector>
+ * <receivePackets>180</receivePackets>
+ * <transmitPackets>2594</transmitPackets>
+ * <receiveBytes>12600</receiveBytes>
+ * <transmitBytes>249396</transmitBytes>
+ * <receiveDrops>0</receiveDrops>
+ * <transmitDrops>0</transmitDrops>
+ * <receiveErrors>0</receiveErrors>
+ * <transmitErrors>0</transmitErrors>
+ * <receiveFrameError>0</receiveFrameError>
+ * <receiveOverRunError>0</receiveOverRunError>
+ * <receiveCrcError>0</receiveCrcError>
+ * <collisionCount>0</collisionCount>
+ * </portStatistic>
+ * <portStatistic>
+ * <nodeConnector>
+ * <node>
+ * <id>00:00:00:00:00:00:00:01</id>
+ * <type>OF</type>
+ * </node>
+ * <id>5</id>
+ * <type>OF</type>
+ * </nodeConnector>
+ * <receivePackets>2542</receivePackets>
+ * <transmitPackets>2719</transmitPackets>
+ * <receiveBytes>243012</receiveBytes>
+ * <transmitBytes>255374</transmitBytes>
+ * <receiveDrops>0</receiveDrops>
+ * <transmitDrops>0</transmitDrops>
+ * <receiveErrors>0</receiveErrors>
+ * <transmitErrors>0</transmitErrors>
+ * <receiveFrameError>0</receiveFrameError>
+ * <receiveOverRunError>0</receiveOverRunError>
+ * <receiveCrcError>0</receiveCrcError>
+ * <collisionCount>0</collisionCount>
+ * </portStatistic>
+ * </nodePortStatistics>
+ * </pre>
+ */
+ @Path("/{containerName}/port/node/{nodeType}/{nodeId}")
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @TypeHint(PortStatistics.class)
+ @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 PortStatistics getPortStatistics(
+ @PathParam("containerName") String containerName,
+ @PathParam("nodeType") String nodeType,
+ @PathParam("nodeId") String nodeId) {
+
+ 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 "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ ISwitchManager switchManager = (ISwitchManager) ServiceHelper
+ .getInstance(ISwitchManager.class, containerName, this);
+ if (switchManager == null) {
+ throw new ServiceUnavailableException("Switch manager "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ Node node = handleNodeAvailability(containerName, nodeType, nodeId);
+ return new PortStatistics(node,
+ statisticsManager.getNodeConnectorStatistics(node));
+ }
+
+ /**
+ * Returns a list of all the Table Statistics on all Nodes.
+ *
+ * @param containerName
+ * Name of the Container. The Container name for the base
+ * controller is "default".
+ *
+ * @return Returns a list of all the Table Statistics in a given Node.
+ *
+ * <pre>
+ *
+ * Example:
+ *
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/statistics/default/table
+ *
+ * Response body in JSON:
+ * {
+ * "tableStatistics": [
+ * {
+ * "node": {
+ * "id":"00:00:00:00:00:00:00:02",
+ * "type":"OF"
+ * },
+ * "tableStatistic": [
+ * {
+ * "nodeTable": {
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:02",
+ * "type":"OF"
+ * },
+ * "id":"0"
+ * },
+ * "activeCount": "11",
+ * "lookupCount": "816",
+ * "matchedCount": "220",
+ * "maximumEntries": "1000"
+ * },
+ * {
+ * ...another table
+ * .....
+ * ........
+ * }
+ *
+ * ]
+ * }
+ * ]
+ * }
+ *
+ * Response body in XML:
+ * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+ * <list>
+ * <tableStatistics>
+ * <node>
+ * <id>00:00:00:00:00:00:00:01</id>
+ * <type>OF</type>
+ * </node>
+ * <tableStatistic>
+ * <nodeTable>
+ * <node>
+ * <id>00:00:00:00:00:00:00:01</id>
+ * <type>OF</type>
+ * </node>
+ * <id>0</id>
+ * </nodeTable>
+ * <activeCount>12</activeCount>
+ * <lookupCount>10935</lookupCount>
+ * <matchedCount>10084</matchedCount>
+ * <maximumEntries>1000</maximumEntries>
+ * </tableStatistic>
+ * <tableStatistic>
+ * <nodeTable>
+ * <node>
+ * <id>00:00:00:00:00:00:00:01</id>
+ * <type>OF</type>
+ * </node>
+ * <id>1</id>
+ * </nodeTable>
+ * <activeCount>0</activeCount>
+ * <lookupCount>0</lookupCount>
+ * <matchedCount>0</matchedCount>
+ * <maximumEntries>0</maximumEntries>
+ * </tableStatistic>
+ * <tableStatistic>
+ * <nodeTable>
+ * <node>
+ * <id>00:00:00:00:00:00:00:01</id>
+ * <type>OF</type>
+ * </node>
+ * <id>2</id>
+ * </nodeTable>
+ * <activeCount>0</activeCount>
+ * <lookupCount>0</lookupCount>
+ * <matchedCount>0</matchedCount>
+ * <maximumEntries>0</maximumEntries>
+ * </tableStatistic>
+ * </tableStatistics>
+ * <tableStatistics>
+ * ...
+ * ......
+ * ........
+ * </tableStatistics>
+ * </list>
+ *
+ * </pre>
+ */
+ @Path("/{containerName}/table")
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @TypeHint(AllTableStatistics.class)
+ @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 AllTableStatistics getTableStatistics(
+ @PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
+
+ 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 manager"
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ ISwitchManager switchManager = (ISwitchManager) ServiceHelper
+ .getInstance(ISwitchManager.class, containerName, this);
+ if (switchManager == null) {
+ throw new ServiceUnavailableException("Switch manager "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ List<TableStatistics> statistics = new ArrayList<TableStatistics>();
+ for (Node node : switchManager.getNodes()) {
+ List<NodeTableStatistics> stat = statisticsManager
+ .getNodeTableStatistics(node);
+ TableStatistics tableStat = new TableStatistics(node, stat);
+ statistics.add(tableStat);
+ }
+ AllTableStatistics allstats = new AllTableStatistics(statistics);
+ if (queryString != null) {
+ queryContext.createQuery(queryString, AllTableStatistics.class)
+ .filter(allstats, TableStatistics.class);
+ }
+ return allstats;
+ }
+
+ /**
+ * 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 specified in {@link org.opendaylight.controller.sal.core.Node} class (e.g. OF for Openflow)
+ * @param Node
+ * Identifier (e.g. MAC address)
+ * @return Returns a list of all the Table Statistics in a given Node.
+ *
+ * <pre>
+ *
+ * Example:
+ *
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/statistics/default/table/node/OF/00:00:00:00:00:00:00:01
+ *
+ * Response body in JSON:
+ * {
+ * "node": {
+ * "id":"00:00:00:00:00:00:00:01",
+ * "type":"OF"
+ * },
+ * "tableStatistic": [
+ * {
+ * "nodeTable": {
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:01",
+ * "type":"OF"
+ * },
+ * "id":"0"
+ * },
+ * "activeCount": "12",
+ * "lookupCount": "11382",
+ * "matchedCount": "10524",
+ * "maximumEntries": "1000"
+ * },
+ * {
+ * "nodeTable": {
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:01",
+ * "type":"OF"
+ * },
+ * "id":"1"
+ * },
+ * "activeCount": "0",
+ * "lookupCount": "0",
+ * "matchedCount": "0",
+ * "maximumEntries": "0"
+ * }
+ * ]
+ * }
+ *
+ * Response body in XML:
+ * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+ * <nodeTableStatistics>
+ * <node>
+ * <id>00:00:00:00:00:00:00:01</id>
+ * <type>OF</type>
+ * </node>
+ * <tableStatistic>
+ * <nodeTable>
+ * <node>
+ * <id>00:00:00:00:00:00:00:01</id>
+ * <type>OF</type>
+ * </node>
+ * <id>0</id>
+ * </nodeTable>
+ * <activeCount>12</activeCount>
+ * <lookupCount>10935</lookupCount>
+ * <matchedCount>10084</matchedCount>
+ * <maximumEntries>1000</maximumEntries>
+ * </tableStatistic>
+ * <tableStatistic>
+ * <nodeTable>
+ * <node>
+ * <id>00:00:00:00:00:00:00:01</id>
+ * <type>OF</type>
+ * </node>
+ * <id>1</id>
+ * </nodeTable>
+ * <activeCount>0</activeCount>
+ * <lookupCount>0</lookupCount>
+ * <matchedCount>0</matchedCount>
+ * <maximumEntries>0</maximumEntries>
+ * </tableStatistic>
+ * <tableStatistic>
+ * <nodeTable>
+ * <node>
+ * <id>00:00:00:00:00:00:00:01</id>
+ * <type>OF</type>
+ * </node>
+ * <id>2</id>
+ * </nodeTable>
+ * <activeCount>0</activeCount>
+ * <lookupCount>0</lookupCount>
+ * <matchedCount>0</matchedCount>
+ * <maximumEntries>0</maximumEntries>
+ * </tableStatistic>
+ * </nodeTableStatistics>
+ *
+ * </pre>
+ */
+ @Path("/{containerName}/table/node/{nodeType}/{nodeId}")
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @TypeHint(TableStatistics.class)
+ @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 TableStatistics getTableStatistics(
+ @PathParam("containerName") String containerName,
+ @PathParam("nodeType") String nodeType,
+ @PathParam("nodeId") String nodeId) {
+
+ 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 "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ ISwitchManager switchManager = (ISwitchManager) ServiceHelper
+ .getInstance(ISwitchManager.class, containerName, this);
+ if (switchManager == null) {
+ throw new ServiceUnavailableException("Switch manager "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ Node node = handleNodeAvailability(containerName, nodeType, nodeId);
+ return new TableStatistics(node,
+ statisticsManager.getNodeTableStatistics(node));
+ }
+
+ private void handleDefaultDisabled(String containerName) {
+ IContainerManager containerManager = (IContainerManager) ServiceHelper
+ .getGlobalInstance(IContainerManager.class, this);
+ if (containerManager == null) {
+ throw new InternalServerErrorException(
+ RestMessages.INTERNALERROR.toString());
+ }
+ if (containerName.equals(GlobalConstants.DEFAULT.toString())
+ && containerManager.hasNonDefaultContainer()) {
+ throw new ResourceConflictException(
+ RestMessages.DEFAULTDISABLED.toString());
+ }
+ }
+
+ private Node handleNodeAvailability(String containerName, String nodeType,
+ String nodeId) {
+
+ Node node = Node.fromString(nodeType, nodeId);
+ if (node == null) {
+ throw new ResourceNotFoundException(nodeId + " : "
+ + RestMessages.NONODE.toString());
+ }
+
+ ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
+ ISwitchManager.class, containerName, this);
+
+ if (sm == null) {
+ throw new ServiceUnavailableException("Switch Manager "
+ + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ if (!sm.getNodes().contains(node)) {
+ throw new ResourceNotFoundException(node.toString() + " : "
+ + RestMessages.NONODE.toString());
+ }
+ return node;
+ }
+
+}