blob: 04fb8ad76baafe521383a03f138c0a87691a3bf7 [file] [log] [blame]
Jian Li0c451802016-02-24 22:39:25 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Jian Li0c451802016-02-24 22:39:25 +09003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.rest.resources;
17
18import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import com.google.common.collect.Sets;
22import org.onosproject.net.DeviceId;
23import org.onosproject.net.region.Region;
24import org.onosproject.net.region.RegionAdminService;
25import org.onosproject.net.region.RegionId;
26import org.onosproject.net.region.RegionService;
27import org.onosproject.rest.AbstractWebResource;
28
29import javax.ws.rs.Consumes;
30import javax.ws.rs.DELETE;
31import javax.ws.rs.GET;
32import javax.ws.rs.POST;
33import javax.ws.rs.PUT;
34import javax.ws.rs.Path;
35import javax.ws.rs.PathParam;
36import javax.ws.rs.Produces;
37import javax.ws.rs.core.MediaType;
38import javax.ws.rs.core.Response;
39import java.io.IOException;
40import java.io.InputStream;
41import java.net.URI;
42import java.net.URISyntaxException;
43import java.util.Set;
44
45import static org.onlab.util.Tools.nullIsNotFound;
Ray Milkeyb784adb2018-04-02 15:33:07 -070046import static org.onlab.util.Tools.readTreeFromStream;
Jian Li0c451802016-02-24 22:39:25 +090047
48/**
49 * Manages region and device membership.
50 */
51@Path("regions")
52public class RegionsWebResource extends AbstractWebResource {
53 private final RegionService regionService = get(RegionService.class);
54 private final RegionAdminService regionAdminService = get(RegionAdminService.class);
55
56 private static final String REGION_NOT_FOUND = "Region is not found for ";
57 private static final String REGION_INVALID = "Invalid regionId in region update request";
58 private static final String DEVICE_IDS_INVALID = "Invalid device identifiers";
59
60 /**
61 * Returns set of all regions.
62 *
Jian Licc730a62016-05-10 16:36:16 -070063 * @return 200 OK with set of all regions
Jian Li0c451802016-02-24 22:39:25 +090064 * @onos.rsModel Regions
65 */
66 @GET
67 @Produces(MediaType.APPLICATION_JSON)
68 public Response getRegions() {
69 final Iterable<Region> regions = regionService.getRegions();
70 return ok(encodeArray(Region.class, "regions", regions)).build();
71 }
72
73 /**
74 * Returns the region with the specified identifier.
75 *
76 * @param regionId region identifier
Jian Licc730a62016-05-10 16:36:16 -070077 * @return 200 OK with a region, 404 not found
Jian Li0c451802016-02-24 22:39:25 +090078 * @onos.rsModel Region
79 */
80 @GET
81 @Produces(MediaType.APPLICATION_JSON)
82 @Path("{regionId}")
83 public Response getRegionById(@PathParam("regionId") String regionId) {
84 final RegionId rid = RegionId.regionId(regionId);
85 final Region region = nullIsNotFound(regionService.getRegion(rid),
86 REGION_NOT_FOUND + rid.toString());
87 return ok(codec(Region.class).encode(region, this)).build();
88 }
89
90 /**
91 * Returns the set of devices that belong to the specified region.
92 *
93 * @param regionId region identifier
Jian Licc730a62016-05-10 16:36:16 -070094 * @return 200 OK with set of devices that belong to the specified region
Jian Li0c451802016-02-24 22:39:25 +090095 * @onos.rsModel RegionDeviceIds
96 */
97 @GET
98 @Produces(MediaType.APPLICATION_JSON)
99 @Path("{regionId}/devices")
100 public Response getRegionDevices(@PathParam("regionId") String regionId) {
101 final RegionId rid = RegionId.regionId(regionId);
102 final Iterable<DeviceId> deviceIds = regionService.getRegionDevices(rid);
103 final ObjectNode root = mapper().createObjectNode();
104 final ArrayNode deviceIdsNode = root.putArray("deviceIds");
105 deviceIds.forEach(did -> deviceIdsNode.add(did.toString()));
106 return ok(root).build();
107 }
108
109 /**
110 * Creates a new region using the supplied JSON input stream.
111 *
112 * @param stream region JSON stream
113 * @return status of the request - CREATED if the JSON is correct,
114 * BAD_REQUEST if the JSON is invalid
115 * @onos.rsModel RegionPost
116 */
117 @POST
118 @Consumes(MediaType.APPLICATION_JSON)
119 @Produces(MediaType.APPLICATION_JSON)
120 public Response createRegion(InputStream stream) {
121 URI location;
122 try {
Ray Milkeyb784adb2018-04-02 15:33:07 -0700123 ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
Jian Li0c451802016-02-24 22:39:25 +0900124 final Region region = codec(Region.class).decode(jsonTree, this);
125 final Region resultRegion = regionAdminService.createRegion(region.id(),
126 region.name(), region.type(), region.masters());
127 location = new URI(resultRegion.id().id());
128 } catch (IOException | URISyntaxException e) {
129 throw new IllegalArgumentException(e);
130 }
131
132 return Response.created(location).build();
133 }
134
135 /**
136 * Updates the specified region using the supplied JSON input stream.
137 *
138 * @param regionId region identifier
139 * @param stream region JSON stream
140 * @return status of the request - UPDATED if the JSON is correct,
141 * BAD_REQUEST if the JSON is invalid
142 * @onos.rsModel RegionPost
143 */
144 @PUT
145 @Path("{regionId}")
146 @Consumes(MediaType.APPLICATION_JSON)
Jian Li0c451802016-02-24 22:39:25 +0900147 public Response updateRegion(@PathParam("regionId") String regionId,
148 InputStream stream) {
149 try {
Ray Milkeyb784adb2018-04-02 15:33:07 -0700150 ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
Jian Li0c451802016-02-24 22:39:25 +0900151 JsonNode specifiedRegionId = jsonTree.get("id");
152
153 if (specifiedRegionId != null &&
154 !specifiedRegionId.asText().equals(regionId)) {
155 throw new IllegalArgumentException(REGION_INVALID);
156 }
157
158 final Region region = codec(Region.class).decode(jsonTree, this);
159 regionAdminService.updateRegion(region.id(),
160 region.name(), region.type(), region.masters());
161 } catch (IOException e) {
162 throw new IllegalArgumentException(e);
163 }
164
165 return Response.ok().build();
166 }
167
168 /**
169 * Removes the specified region using the given region identifier.
170 *
171 * @param regionId region identifier
Jian Licc730a62016-05-10 16:36:16 -0700172 * @return 204 NO CONTENT
Jian Li0c451802016-02-24 22:39:25 +0900173 */
174 @DELETE
175 @Path("{regionId}")
Jian Li0c451802016-02-24 22:39:25 +0900176 public Response removeRegion(@PathParam("regionId") String regionId) {
177 final RegionId rid = RegionId.regionId(regionId);
178 regionAdminService.removeRegion(rid);
Jian Lic2a542b2016-05-10 11:48:19 -0700179 return Response.noContent().build();
Jian Li0c451802016-02-24 22:39:25 +0900180 }
181
182 /**
183 * Adds the specified collection of devices to the region.
184 *
185 * @param regionId region identifier
186 * @param stream deviceIds JSON stream
187 * @return status of the request - CREATED if the JSON is correct,
188 * BAD_REQUEST if the JSON is invalid
189 * @onos.rsModel RegionDeviceIds
190 */
191 @POST
192 @Path("{regionId}/devices")
193 @Consumes(MediaType.APPLICATION_JSON)
194 @Produces(MediaType.APPLICATION_JSON)
195 public Response addDevices(@PathParam("regionId") String regionId,
196 InputStream stream) {
Jayasree Ghoshfc72e2e2016-11-08 19:55:47 +0530197 RegionId rid = RegionId.regionId(regionId);
198 Region region = nullIsNotFound(regionService.getRegion(rid),
199 REGION_NOT_FOUND + rid);
Jian Li0c451802016-02-24 22:39:25 +0900200
201 URI location;
202 try {
Jayasree Ghoshfc72e2e2016-11-08 19:55:47 +0530203 regionAdminService.addDevices(region.id(), extractDeviceIds(stream));
Jian Li0c451802016-02-24 22:39:25 +0900204 location = new URI(rid.id());
205 } catch (IOException | URISyntaxException e) {
206 throw new IllegalArgumentException(e);
207 }
208
209 return Response.created(location).build();
210 }
211
212 /**
213 * Removes the specified collection of devices from the region.
214 *
215 * @param regionId region identifier
216 * @param stream deviceIds JSON stream
Jian Lic2a542b2016-05-10 11:48:19 -0700217 * @return 204 NO CONTENT
Jian Li0c451802016-02-24 22:39:25 +0900218 * @onos.rsModel RegionDeviceIds
219 */
220 @DELETE
221 @Path("{regionId}/devices")
222 @Consumes(MediaType.APPLICATION_JSON)
Jian Li0c451802016-02-24 22:39:25 +0900223 public Response removeDevices(@PathParam("regionId") String regionId,
224 InputStream stream) {
Jayasree Ghoshfc72e2e2016-11-08 19:55:47 +0530225 RegionId rid = RegionId.regionId(regionId);
226 Region region = nullIsNotFound(regionService.getRegion(rid),
227 REGION_NOT_FOUND + rid);
Jian Li0c451802016-02-24 22:39:25 +0900228
229 try {
230 regionAdminService.removeDevices(rid, extractDeviceIds(stream));
231 } catch (IOException e) {
232 throw new IllegalArgumentException(e);
233 }
234
Jian Lic2a542b2016-05-10 11:48:19 -0700235 return Response.noContent().build();
Jian Li0c451802016-02-24 22:39:25 +0900236 }
237
238 /**
239 * Extracts device ids from a given JSON string.
240 *
241 * @param stream deviceIds JSON stream
242 * @return a set of device identifiers
243 * @throws IOException
244 */
245 private Set<DeviceId> extractDeviceIds(InputStream stream) throws IOException {
Ray Milkeyb784adb2018-04-02 15:33:07 -0700246 ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
Jian Li0c451802016-02-24 22:39:25 +0900247 JsonNode deviceIdsJson = jsonTree.get("deviceIds");
248
249 if (deviceIdsJson == null || deviceIdsJson.size() == 0) {
250 throw new IllegalArgumentException(DEVICE_IDS_INVALID);
251 }
252
253 Set<DeviceId> deviceIds = Sets.newHashSet();
254 deviceIdsJson.forEach(did -> deviceIds.add(DeviceId.deviceId(did.asText())));
255
256 return deviceIds;
257 }
258}