aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/web/api
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/web/api')
-rw-r--r--framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java24
-rw-r--r--framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java158
-rw-r--r--framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/PathsWebResource.java64
-rw-r--r--framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java61
4 files changed, 191 insertions, 116 deletions
diff --git a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java
index 325e191b..0e88e34e 100644
--- a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java
+++ b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java
@@ -66,9 +66,9 @@ public class FlowsWebResource extends AbstractWebResource {
public Response getFlows() {
final Iterable<Device> devices = get(DeviceService.class).getDevices();
for (final Device device : devices) {
- final Iterable<FlowEntry> deviceEntries = service.getFlowEntries(device.id());
- if (deviceEntries != null) {
- for (final FlowEntry entry : deviceEntries) {
+ final Iterable<FlowEntry> flowEntries = service.getFlowEntries(device.id());
+ if (flowEntries != null) {
+ for (final FlowEntry entry : flowEntries) {
flowsNode.add(codec(FlowEntry.class).encode(entry, this));
}
}
@@ -88,13 +88,13 @@ public class FlowsWebResource extends AbstractWebResource {
@Produces(MediaType.APPLICATION_JSON)
@Path("{deviceId}")
public Response getFlowByDeviceId(@PathParam("deviceId") String deviceId) {
- final Iterable<FlowEntry> deviceEntries =
+ final Iterable<FlowEntry> flowEntries =
service.getFlowEntries(DeviceId.deviceId(deviceId));
- if (!deviceEntries.iterator().hasNext()) {
+ if (!flowEntries.iterator().hasNext()) {
throw new ItemNotFoundException(DEVICE_NOT_FOUND);
}
- for (final FlowEntry entry : deviceEntries) {
+ for (final FlowEntry entry : flowEntries) {
flowsNode.add(codec(FlowEntry.class).encode(entry, this));
}
return ok(root).build();
@@ -113,13 +113,13 @@ public class FlowsWebResource extends AbstractWebResource {
@Path("{deviceId}/{flowId}")
public Response getFlowByDeviceIdAndFlowId(@PathParam("deviceId") String deviceId,
@PathParam("flowId") long flowId) {
- final Iterable<FlowEntry> deviceEntries =
+ final Iterable<FlowEntry> flowEntries =
service.getFlowEntries(DeviceId.deviceId(deviceId));
- if (!deviceEntries.iterator().hasNext()) {
+ if (!flowEntries.iterator().hasNext()) {
throw new ItemNotFoundException(DEVICE_NOT_FOUND);
}
- for (final FlowEntry entry : deviceEntries) {
+ for (final FlowEntry entry : flowEntries) {
if (entry.id().value() == flowId) {
flowsNode.add(codec(FlowEntry.class).encode(entry, this));
}
@@ -175,14 +175,14 @@ public class FlowsWebResource extends AbstractWebResource {
@Path("{deviceId}/{flowId}")
public void deleteFlowByDeviceIdAndFlowId(@PathParam("deviceId") String deviceId,
@PathParam("flowId") long flowId) {
- final Iterable<FlowEntry> deviceEntries =
+ final Iterable<FlowEntry> flowEntries =
service.getFlowEntries(DeviceId.deviceId(deviceId));
- if (!deviceEntries.iterator().hasNext()) {
+ if (!flowEntries.iterator().hasNext()) {
throw new ItemNotFoundException(DEVICE_NOT_FOUND);
}
- StreamSupport.stream(deviceEntries.spliterator(), false)
+ StreamSupport.stream(flowEntries.spliterator(), false)
.filter(entry -> entry.id().value() == flowId)
.forEach(service::removeFlowRules);
}
diff --git a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java
index 9e2b6273..808fcc16 100644
--- a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java
+++ b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java
@@ -49,73 +49,77 @@ public class NetworkConfigWebResource extends AbstractWebResource {
public Response download() {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = mapper().createObjectNode();
- service.getSubjectClasses().forEach(sc ->
- produceJson(service, newObject(root, service.getSubjectFactory(sc).subjectKey()), sc));
+ service.getSubjectClasses().forEach(sc -> {
+ SubjectFactory subjectFactory = service.getSubjectFactory(sc);
+ produceJson(service, newObject(root, subjectFactory.subjectClassKey()),
+ subjectFactory, sc);
+ });
return ok(root).build();
}
/**
* Get all network configuration for a subject class.
*
- * @param subjectKey subject class key
+ * @param subjectClassKey subject class key
* @return network configuration JSON
*/
@GET
- @Path("{subjectKey}")
+ @Path("{subjectClassKey}")
@Produces(MediaType.APPLICATION_JSON)
@SuppressWarnings("unchecked")
- public Response download(@PathParam("subjectKey") String subjectKey) {
+ public Response download(@PathParam("subjectClassKey") String subjectClassKey) {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = mapper().createObjectNode();
- produceJson(service, root, service.getSubjectFactory(subjectKey).subjectClass());
+ SubjectFactory subjectFactory = service.getSubjectFactory(subjectClassKey);
+ produceJson(service, root, subjectFactory, subjectFactory.subjectClass());
return ok(root).build();
}
/**
- * Get all network configuration for a subject.
+ * Get all network configuration for a subjectKey.
*
- * @param subjectKey subject class key
- * @param subject subject key
+ * @param subjectClassKey subjectKey class key
+ * @param subjectKey subjectKey key
* @return network configuration JSON
*/
@GET
- @Path("{subjectKey}/{subject}")
+ @Path("{subjectClassKey}/{subjectKey}")
@Produces(MediaType.APPLICATION_JSON)
@SuppressWarnings("unchecked")
- public Response download(@PathParam("subjectKey") String subjectKey,
- @PathParam("subject") String subject) {
+ public Response download(@PathParam("subjectClassKey") String subjectClassKey,
+ @PathParam("subjectKey") String subjectKey) {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = mapper().createObjectNode();
- produceSubjectJson(service, root,
- service.getSubjectFactory(subjectKey).createSubject(subject));
+ SubjectFactory subjectFactory = service.getSubjectFactory(subjectClassKey);
+ produceSubjectJson(service, root, subjectFactory.createSubject(subjectKey));
return ok(root).build();
}
/**
- * Get specific network configuration for a subject.
+ * Get specific network configuration for a subjectKey.
*
- * @param subjectKey subject class key
- * @param subject subject key
- * @param configKey configuration class key
+ * @param subjectClassKey subjectKey class key
+ * @param subjectKey subjectKey key
+ * @param configKey configuration class key
* @return network configuration JSON
*/
@GET
- @Path("{subjectKey}/{subject}/{configKey}")
+ @Path("{subjectClassKey}/{subjectKey}/{configKey}")
@Produces(MediaType.APPLICATION_JSON)
@SuppressWarnings("unchecked")
- public Response download(@PathParam("subjectKey") String subjectKey,
- @PathParam("subject") String subject,
+ public Response download(@PathParam("subjectClassKey") String subjectClassKey,
+ @PathParam("subjectKey") String subjectKey,
@PathParam("configKey") String configKey) {
NetworkConfigService service = get(NetworkConfigService.class);
- return ok(service.getConfig(service.getSubjectFactory(subjectKey).createSubject(subject),
- service.getConfigClass(subjectKey, configKey)).node()).build();
+ return ok(service.getConfig(service.getSubjectFactory(subjectClassKey).createSubject(subjectKey),
+ service.getConfigClass(subjectClassKey, configKey)).node()).build();
}
@SuppressWarnings("unchecked")
private void produceJson(NetworkConfigService service, ObjectNode node,
- Class subjectClass) {
+ SubjectFactory subjectFactory, Class subjectClass) {
service.getSubjects(subjectClass).forEach(s ->
- produceSubjectJson(service, newObject(node, s.toString()), s));
+ produceSubjectJson(service, newObject(node, subjectFactory.subjectKey(s)), s));
}
private void produceSubjectJson(NetworkConfigService service, ObjectNode node,
@@ -128,8 +132,8 @@ public class NetworkConfigWebResource extends AbstractWebResource {
* Upload bulk network configuration.
*
* @param request network configuration JSON rooted at the top node
- * @throws IOException if unable to parse the request
* @return empty response
+ * @throws IOException if unable to parse the request
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@@ -146,78 +150,78 @@ public class NetworkConfigWebResource extends AbstractWebResource {
/**
* Upload multiple network configurations for a subject class.
*
- * @param subjectKey subject class key
- * @param request network configuration JSON rooted at the top node
+ * @param subjectClassKey subject class key
+ * @param request network configuration JSON rooted at the top node
* @return empty response
* @throws IOException if unable to parse the request
*/
@POST
- @Path("{subjectKey}")
+ @Path("{subjectClassKey}")
@Consumes(MediaType.APPLICATION_JSON)
@SuppressWarnings("unchecked")
- public Response upload(@PathParam("subjectKey") String subjectKey,
+ public Response upload(@PathParam("subjectClassKey") String subjectClassKey,
InputStream request) throws IOException {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = (ObjectNode) mapper().readTree(request);
- consumeJson(service, root, service.getSubjectFactory(subjectKey));
+ consumeJson(service, root, service.getSubjectFactory(subjectClassKey));
return Response.ok().build();
}
/**
- * Upload mutliple network configurations for a subject.
+ * Upload mutliple network configurations for a subjectKey.
*
- * @param subjectKey subject class key
- * @param subject subject key
- * @param request network configuration JSON rooted at the top node
+ * @param subjectClassKey subjectKey class key
+ * @param subjectKey subjectKey key
+ * @param request network configuration JSON rooted at the top node
* @return empty response
* @throws IOException if unable to parse the request
*/
@POST
- @Path("{subjectKey}/{subject}")
+ @Path("{subjectClassKey}/{subjectKey}")
@Consumes(MediaType.APPLICATION_JSON)
@SuppressWarnings("unchecked")
- public Response upload(@PathParam("subjectKey") String subjectKey,
- @PathParam("subject") String subject,
+ public Response upload(@PathParam("subjectClassKey") String subjectClassKey,
+ @PathParam("subjectKey") String subjectKey,
InputStream request) throws IOException {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = (ObjectNode) mapper().readTree(request);
consumeSubjectJson(service, root,
- service.getSubjectFactory(subjectKey).createSubject(subject),
- subjectKey);
+ service.getSubjectFactory(subjectClassKey).createSubject(subjectKey),
+ subjectClassKey);
return Response.ok().build();
}
/**
- * Upload specific network configuration for a subject.
+ * Upload specific network configuration for a subjectKey.
*
- * @param subjectKey subject class key
- * @param subject subject key
- * @param configKey configuration class key
- * @param request network configuration JSON rooted at the top node
+ * @param subjectClassKey subjectKey class key
+ * @param subjectKey subjectKey key
+ * @param configKey configuration class key
+ * @param request network configuration JSON rooted at the top node
* @return empty response
* @throws IOException if unable to parse the request
*/
@POST
- @Path("{subjectKey}/{subject}/{configKey}")
+ @Path("{subjectClassKey}/{subjectKey}/{configKey}")
@Consumes(MediaType.APPLICATION_JSON)
@SuppressWarnings("unchecked")
- public Response upload(@PathParam("subjectKey") String subjectKey,
- @PathParam("subject") String subject,
+ public Response upload(@PathParam("subjectClassKey") String subjectClassKey,
+ @PathParam("subjectKey") String subjectKey,
@PathParam("configKey") String configKey,
InputStream request) throws IOException {
NetworkConfigService service = get(NetworkConfigService.class);
ObjectNode root = (ObjectNode) mapper().readTree(request);
- service.applyConfig(service.getSubjectFactory(subjectKey).createSubject(subject),
- service.getConfigClass(subjectKey, configKey), root);
+ service.applyConfig(service.getSubjectFactory(subjectClassKey).createSubject(subjectKey),
+ service.getConfigClass(subjectClassKey, configKey), root);
return Response.ok().build();
}
private void consumeJson(NetworkConfigService service, ObjectNode classNode,
SubjectFactory subjectFactory) {
classNode.fieldNames().forEachRemaining(s ->
- consumeSubjectJson(service, (ObjectNode) classNode.path(s),
- subjectFactory.createSubject(s),
- subjectFactory.subjectKey()));
+ consumeSubjectJson(service, (ObjectNode) classNode.path(s),
+ subjectFactory.createSubject(s),
+ subjectFactory.subjectClassKey()));
}
private void consumeSubjectJson(NetworkConfigService service,
@@ -225,7 +229,7 @@ public class NetworkConfigWebResource extends AbstractWebResource {
String subjectKey) {
subjectNode.fieldNames().forEachRemaining(c ->
service.applyConfig(subject, service.getConfigClass(subjectKey, c),
- (ObjectNode) subjectNode.path(c)));
+ subjectNode.path(c)));
}
@@ -241,64 +245,62 @@ public class NetworkConfigWebResource extends AbstractWebResource {
service.getSubjectClasses()
.forEach(subjectClass -> service.getSubjects(subjectClass)
.forEach(subject -> service.getConfigs(subject)
- .forEach(config -> service
- .removeConfig(subject, config.getClass()))));
+ .forEach(config -> service.removeConfig(subject, config.getClass()))));
return Response.ok().build();
}
/**
* Clear all network configurations for a subject class.
*
- * @param subjectKey subject class key
+ * @param subjectClassKey subject class key
* @return empty response
*/
@DELETE
- @Path("{subjectKey}")
+ @Path("{subjectClassKey}")
@SuppressWarnings("unchecked")
- public Response delete(@PathParam("subjectKey") String subjectKey) {
+ public Response delete(@PathParam("subjectClassKey") String subjectClassKey) {
NetworkConfigService service = get(NetworkConfigService.class);
- service.getSubjects(service.getSubjectFactory(subjectKey).getClass())
+ service.getSubjects(service.getSubjectFactory(subjectClassKey).getClass())
.forEach(subject -> service.getConfigs(subject)
- .forEach(config -> service
- .removeConfig(subject, config.getClass())));
+ .forEach(config -> service.removeConfig(subject, config.getClass())));
return Response.ok().build();
}
/**
- * Clear all network configurations for a subject.
+ * Clear all network configurations for a subjectKey.
*
- * @param subjectKey subject class key
- * @param subject subject key
+ * @param subjectClassKey subjectKey class key
+ * @param subjectKey subjectKey key
* @return empty response
*/
@DELETE
- @Path("{subjectKey}/{subject}")
+ @Path("{subjectClassKey}/{subjectKey}")
@SuppressWarnings("unchecked")
- public Response delete(@PathParam("subjectKey") String subjectKey,
- @PathParam("subject") String subject) {
+ public Response delete(@PathParam("subjectClassKey") String subjectClassKey,
+ @PathParam("subjectKey") String subjectKey) {
NetworkConfigService service = get(NetworkConfigService.class);
- Object s = service.getSubjectFactory(subjectKey).createSubject(subject);
+ Object s = service.getSubjectFactory(subjectClassKey).createSubject(subjectKey);
service.getConfigs(s).forEach(c -> service.removeConfig(s, c.getClass()));
return Response.ok().build();
}
/**
- * Clear specific network configuration for a subject.
+ * Clear specific network configuration for a subjectKey.
*
- * @param subjectKey subject class key
- * @param subject subject key
- * @param configKey configuration class key
+ * @param subjectClassKey subjectKey class key
+ * @param subjectKey subjectKey key
+ * @param configKey configuration class key
* @return empty response
*/
@DELETE
- @Path("{subjectKey}/{subject}/{configKey}")
+ @Path("{subjectClassKey}/{subjectKey}/{configKey}")
@SuppressWarnings("unchecked")
- public Response delete(@PathParam("subjectKey") String subjectKey,
- @PathParam("subject") String subject,
+ public Response delete(@PathParam("subjectClassKey") String subjectClassKey,
+ @PathParam("subjectKey") String subjectKey,
@PathParam("configKey") String configKey) {
NetworkConfigService service = get(NetworkConfigService.class);
- service.removeConfig(service.getSubjectFactory(subjectKey).createSubject(subject),
- service.getConfigClass(subjectKey, configKey));
+ service.removeConfig(service.getSubjectFactory(subjectClassKey).createSubject(subjectKey),
+ service.getConfigClass(subjectClassKey, configKey));
return Response.ok().build();
}
diff --git a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/PathsWebResource.java b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/PathsWebResource.java
index baa1b1e6..9714690c 100644
--- a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/PathsWebResource.java
+++ b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/PathsWebResource.java
@@ -15,7 +15,11 @@
*/
package org.onosproject.rest.resources;
-import java.util.Set;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.ElementId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.topology.PathService;
+import org.onosproject.rest.AbstractWebResource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@@ -23,14 +27,7 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.ElementId;
-import org.onosproject.net.HostId;
-import org.onosproject.net.topology.PathService;
-
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import org.onosproject.rest.AbstractWebResource;
+import java.util.Set;
/**
* Compute paths in the network graph.
@@ -50,6 +47,17 @@ public class PathsWebResource extends AbstractWebResource {
}
/**
+ * Returns either host id or device id, depending on the ID format.
+ *
+ * @param id host or device id string
+ * @return element id
+ */
+ private ElementId elementId(String id) {
+ ElementId elementId = isHostId(id);
+ return elementId != null ? elementId : DeviceId.deviceId(id);
+ }
+
+ /**
* Get all shortest paths between any two hosts or devices.
* Returns array of all shortest paths between any two elements.
*
@@ -63,23 +71,27 @@ public class PathsWebResource extends AbstractWebResource {
public Response getPath(@PathParam("src") String src,
@PathParam("dst") String dst) {
PathService pathService = get(PathService.class);
-
- ElementId srcElement = isHostId(src);
- ElementId dstElement = isHostId(dst);
-
- if (srcElement == null) {
- // Doesn't look like a host, assume it is a device
- srcElement = DeviceId.deviceId(src);
- }
-
- if (dstElement == null) {
- // Doesn't look like a host, assume it is a device
- dstElement = DeviceId.deviceId(dst);
- }
-
- Set<org.onosproject.net.Path> paths = pathService.getPaths(srcElement, dstElement);
- ObjectNode root = encodeArray(org.onosproject.net.Path.class, "paths", paths);
- return ok(root).build();
+ Set<org.onosproject.net.Path> paths =
+ pathService.getPaths(elementId(src), elementId(dst));
+ return ok(encodeArray(org.onosproject.net.Path.class, "paths", paths)).build();
}
+ /**
+ * Get all shortest disjoint paths between any two hosts or devices.
+ * Returns array of all shortest disjoint paths between any two elements.
+ *
+ * @param src source identifier
+ * @param dst destination identifier
+ * @return path data
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("{src}/{dst}/disjoint")
+ public Response getDisjointPath(@PathParam("src") String src,
+ @PathParam("dst") String dst) {
+ PathService pathService = get(PathService.class);
+ Set<org.onosproject.net.DisjointPath> paths =
+ pathService.getDisjointPaths(elementId(src), elementId(dst));
+ return ok(encodeArray(org.onosproject.net.DisjointPath.class, "paths", paths)).build();
+ }
}
diff --git a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java
index 2ffa2295..c91cb6d0 100644
--- a/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java
+++ b/framework/src/onos/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java
@@ -21,6 +21,7 @@ import java.util.stream.StreamSupport;
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;
@@ -31,7 +32,12 @@ import javax.ws.rs.core.UriInfo;
import org.onosproject.codec.JsonCodec;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TableStatisticsEntry;
import org.onosproject.net.link.LinkService;
import org.onosproject.net.statistic.Load;
import org.onosproject.net.statistic.StatisticService;
@@ -92,4 +98,59 @@ public class StatisticsWebResource extends AbstractWebResource {
result.set("loads", loads);
return ok(result).build();
}
+
+ /**
+ * Get table statistics for all tables of all devices.
+ *
+ * @return JSON encoded array of table statistics
+ */
+ @GET
+ @Path("flows/tables")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getTableStatistics() {
+ final FlowRuleService service = get(FlowRuleService.class);
+ final Iterable<Device> devices = get(DeviceService.class).getDevices();
+ final ObjectNode root = mapper().createObjectNode();
+ final ArrayNode rootArrayNode = root.putArray("device-table-statistics");
+ for (final Device device : devices) {
+ final ObjectNode deviceStatsNode = mapper().createObjectNode();
+ deviceStatsNode.put("device", device.id().toString());
+ final ArrayNode statisticsNode = deviceStatsNode.putArray("table-statistics");
+ final Iterable<TableStatisticsEntry> tableStatsEntries = service.getFlowTableStatistics(device.id());
+ if (tableStatsEntries != null) {
+ for (final TableStatisticsEntry entry : tableStatsEntries) {
+ statisticsNode.add(codec(TableStatisticsEntry.class).encode(entry, this));
+ }
+ }
+ rootArrayNode.add(deviceStatsNode);
+ }
+
+ return ok(root).build();
+ }
+
+ /**
+ * Get table statistics for all tables of a specified device.
+ *
+ * @param deviceId device ID
+ * @return JSON encoded array of table statistics
+ */
+ @GET
+ @Path("flows/tables/{deviceId}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getTableStatisticsByDeviceId(@PathParam("deviceId") String deviceId) {
+ final FlowRuleService service = get(FlowRuleService.class);
+ final Iterable<TableStatisticsEntry> tableStatisticsEntries =
+ service.getFlowTableStatistics(DeviceId.deviceId(deviceId));
+ final ObjectNode root = mapper().createObjectNode();
+ final ArrayNode rootArrayNode = root.putArray("table-statistics");
+
+ final ObjectNode deviceStatsNode = mapper().createObjectNode();
+ deviceStatsNode.put("device", deviceId);
+ final ArrayNode statisticsNode = deviceStatsNode.putArray("table-statistics");
+ for (final TableStatisticsEntry entry : tableStatisticsEntries) {
+ statisticsNode.add(codec(TableStatisticsEntry.class).encode(entry, this));
+ }
+ rootArrayNode.add(deviceStatsNode);
+ return ok(root).build();
+ }
}