blob: c17683cbb5f091d014bf5ba1e735d5d19e92b4ab [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.rest.resources;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Sets;
import org.onosproject.net.DeviceId;
import org.onosproject.net.region.Region;
import org.onosproject.net.region.RegionAdminService;
import org.onosproject.net.region.RegionId;
import org.onosproject.net.region.RegionService;
import org.onosproject.rest.AbstractWebResource;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Set;
import static org.onlab.util.Tools.nullIsNotFound;
/**
* Manages region and device membership.
*/
@Path("regions")
public class RegionsWebResource extends AbstractWebResource {
private final RegionService regionService = get(RegionService.class);
private final RegionAdminService regionAdminService = get(RegionAdminService.class);
private static final String REGION_NOT_FOUND = "Region is not found for ";
private static final String REGION_INVALID = "Invalid regionId in region update request";
private static final String DEVICE_IDS_INVALID = "Invalid device identifiers";
/**
* Returns set of all regions.
*
* @return 200 OK with set of all regions
* @onos.rsModel Regions
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getRegions() {
final Iterable<Region> regions = regionService.getRegions();
return ok(encodeArray(Region.class, "regions", regions)).build();
}
/**
* Returns the region with the specified identifier.
*
* @param regionId region identifier
* @return 200 OK with a region, 404 not found
* @onos.rsModel Region
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{regionId}")
public Response getRegionById(@PathParam("regionId") String regionId) {
final RegionId rid = RegionId.regionId(regionId);
final Region region = nullIsNotFound(regionService.getRegion(rid),
REGION_NOT_FOUND + rid.toString());
return ok(codec(Region.class).encode(region, this)).build();
}
/**
* Returns the set of devices that belong to the specified region.
*
* @param regionId region identifier
* @return 200 OK with set of devices that belong to the specified region
* @onos.rsModel RegionDeviceIds
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{regionId}/devices")
public Response getRegionDevices(@PathParam("regionId") String regionId) {
final RegionId rid = RegionId.regionId(regionId);
final Iterable<DeviceId> deviceIds = regionService.getRegionDevices(rid);
final ObjectNode root = mapper().createObjectNode();
final ArrayNode deviceIdsNode = root.putArray("deviceIds");
deviceIds.forEach(did -> deviceIdsNode.add(did.toString()));
return ok(root).build();
}
/**
* Creates a new region using the supplied JSON input stream.
*
* @param stream region JSON stream
* @return status of the request - CREATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid
* @onos.rsModel RegionPost
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createRegion(InputStream stream) {
URI location;
try {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
final Region region = codec(Region.class).decode(jsonTree, this);
final Region resultRegion = regionAdminService.createRegion(region.id(),
region.name(), region.type(), region.masters());
location = new URI(resultRegion.id().id());
} catch (IOException | URISyntaxException e) {
throw new IllegalArgumentException(e);
}
return Response.created(location).build();
}
/**
* Updates the specified region using the supplied JSON input stream.
*
* @param regionId region identifier
* @param stream region JSON stream
* @return status of the request - UPDATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid
* @onos.rsModel RegionPost
*/
@PUT
@Path("{regionId}")
@Consumes(MediaType.APPLICATION_JSON)
public Response updateRegion(@PathParam("regionId") String regionId,
InputStream stream) {
try {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
JsonNode specifiedRegionId = jsonTree.get("id");
if (specifiedRegionId != null &&
!specifiedRegionId.asText().equals(regionId)) {
throw new IllegalArgumentException(REGION_INVALID);
}
final Region region = codec(Region.class).decode(jsonTree, this);
regionAdminService.updateRegion(region.id(),
region.name(), region.type(), region.masters());
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
return Response.ok().build();
}
/**
* Removes the specified region using the given region identifier.
*
* @param regionId region identifier
* @return 204 NO CONTENT
*/
@DELETE
@Path("{regionId}")
public Response removeRegion(@PathParam("regionId") String regionId) {
final RegionId rid = RegionId.regionId(regionId);
regionAdminService.removeRegion(rid);
return Response.noContent().build();
}
/**
* Adds the specified collection of devices to the region.
*
* @param regionId region identifier
* @param stream deviceIds JSON stream
* @return status of the request - CREATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid
* @onos.rsModel RegionDeviceIds
*/
@POST
@Path("{regionId}/devices")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response addDevices(@PathParam("regionId") String regionId,
InputStream stream) {
final RegionId rid = RegionId.regionId(regionId);
URI location;
try {
regionAdminService.addDevices(rid, extractDeviceIds(stream));
location = new URI(rid.id());
} catch (IOException | URISyntaxException e) {
throw new IllegalArgumentException(e);
}
return Response.created(location).build();
}
/**
* Removes the specified collection of devices from the region.
*
* @param regionId region identifier
* @param stream deviceIds JSON stream
* @return 204 NO CONTENT
* @onos.rsModel RegionDeviceIds
*/
@DELETE
@Path("{regionId}/devices")
@Consumes(MediaType.APPLICATION_JSON)
public Response removeDevices(@PathParam("regionId") String regionId,
InputStream stream) {
final RegionId rid = RegionId.regionId(regionId);
try {
regionAdminService.removeDevices(rid, extractDeviceIds(stream));
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
return Response.noContent().build();
}
/**
* Extracts device ids from a given JSON string.
*
* @param stream deviceIds JSON stream
* @return a set of device identifiers
* @throws IOException
*/
private Set<DeviceId> extractDeviceIds(InputStream stream) throws IOException {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
JsonNode deviceIdsJson = jsonTree.get("deviceIds");
if (deviceIdsJson == null || deviceIdsJson.size() == 0) {
throw new IllegalArgumentException(DEVICE_IDS_INVALID);
}
Set<DeviceId> deviceIds = Sets.newHashSet();
deviceIdsJson.forEach(did -> deviceIds.add(DeviceId.deviceId(did.asText())));
return deviceIds;
}
}