blob: 332bd41822a2a27aee1e2c864ac113d68c0b1afb [file] [log] [blame]
jiangrui330b0c92015-11-28 14:09:50 +08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
jiangrui330b0c92015-11-28 14:09:50 +08003 *
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.vtnweb.resources;
17
Jian Lic2a542b2016-05-10 11:48:19 -070018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import com.google.common.collect.Maps;
22import com.google.common.collect.Sets;
jiangrui330b0c92015-11-28 14:09:50 +080023import org.onlab.packet.IpAddress;
24import org.onlab.util.ItemNotFoundException;
25import org.onosproject.rest.AbstractWebResource;
26import org.onosproject.vtnrsc.DefaultRouter;
27import org.onosproject.vtnrsc.FixedIp;
28import org.onosproject.vtnrsc.Router;
29import org.onosproject.vtnrsc.Router.Status;
30import org.onosproject.vtnrsc.RouterGateway;
31import org.onosproject.vtnrsc.RouterId;
32import org.onosproject.vtnrsc.RouterInterface;
33import org.onosproject.vtnrsc.SubnetId;
34import org.onosproject.vtnrsc.TenantId;
35import org.onosproject.vtnrsc.TenantNetworkId;
36import org.onosproject.vtnrsc.VirtualPortId;
37import org.onosproject.vtnrsc.router.RouterService;
38import org.onosproject.vtnrsc.routerinterface.RouterInterfaceService;
39import org.onosproject.vtnweb.web.RouterCodec;
40import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42
Jian Lic2a542b2016-05-10 11:48:19 -070043import javax.ws.rs.Consumes;
44import javax.ws.rs.DELETE;
45import javax.ws.rs.GET;
46import javax.ws.rs.POST;
47import javax.ws.rs.PUT;
48import javax.ws.rs.Path;
49import javax.ws.rs.PathParam;
50import javax.ws.rs.Produces;
51import javax.ws.rs.QueryParam;
52import javax.ws.rs.core.MediaType;
53import javax.ws.rs.core.Response;
54import java.io.IOException;
55import java.io.InputStream;
56import java.util.ArrayList;
57import java.util.Collection;
58import java.util.Collections;
59import java.util.HashMap;
60import java.util.List;
61import java.util.Map;
62import java.util.Set;
63import java.util.concurrent.ConcurrentMap;
64
65import static com.google.common.base.Preconditions.checkArgument;
66import static com.google.common.base.Preconditions.checkNotNull;
67import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
68import static javax.ws.rs.core.Response.Status.CONFLICT;
69import static javax.ws.rs.core.Response.Status.CREATED;
70import static javax.ws.rs.core.Response.Status.NOT_FOUND;
jiangrui330b0c92015-11-28 14:09:50 +080071
72@Path("routers")
73public class RouterWebResource extends AbstractWebResource {
74 private final Logger log = LoggerFactory.getLogger(RouterWebResource.class);
75 public static final String CREATE_FAIL = "Router is failed to create!";
76 public static final String UPDATE_FAIL = "Router is failed to update!";
77 public static final String GET_FAIL = "Router is failed to get!";
78 public static final String NOT_EXIST = "Router does not exist!";
79 public static final String DELETE_SUCCESS = "Router delete success!";
80 public static final String JSON_NOT_NULL = "JsonNode can not be null";
81 public static final String INTFACR_ADD_SUCCESS = "Interface add success";
82 public static final String INTFACR_DEL_SUCCESS = "Interface delete success";
83
84 @GET
85 @Produces(MediaType.APPLICATION_JSON)
Wu wenbind0b119f2016-05-11 18:03:41 +080086 @Consumes(MediaType.APPLICATION_JSON)
jiangrui330b0c92015-11-28 14:09:50 +080087 public Response listRouters() {
88 Collection<Router> routers = get(RouterService.class).getRouters();
89 ObjectNode result = new ObjectMapper().createObjectNode();
90 result.set("routers", new RouterCodec().encode(routers, this));
91 return ok(result.toString()).build();
92 }
93
94 @GET
95 @Path("{routerUUID}")
96 @Produces(MediaType.APPLICATION_JSON)
Wu wenbind0b119f2016-05-11 18:03:41 +080097 @Consumes(MediaType.APPLICATION_JSON)
jiangrui330b0c92015-11-28 14:09:50 +080098 public Response getRouter(@PathParam("routerUUID") String id,
99 @QueryParam("fields") List<String> fields) {
100
101 if (!get(RouterService.class).exists(RouterId.valueOf(id))) {
102 return Response.status(NOT_FOUND)
103 .entity("The Router does not exists").build();
104 }
105 Router sub = nullIsNotFound(get(RouterService.class)
lishuaid6f0c9e2015-12-16 11:40:01 +0800106 .getRouter(RouterId.valueOf(id)), NOT_EXIST);
jiangrui330b0c92015-11-28 14:09:50 +0800107
108 ObjectNode result = new ObjectMapper().createObjectNode();
Jon Hallcbd1b392017-01-18 20:15:44 -0800109 if (!fields.isEmpty()) {
jiangrui330b0c92015-11-28 14:09:50 +0800110 result.set("router",
111 new RouterCodec().extracFields(sub, this, fields));
112 } else {
113 result.set("router", new RouterCodec().encode(sub, this));
114 }
115 return ok(result.toString()).build();
116 }
117
118 @POST
119 @Produces(MediaType.APPLICATION_JSON)
120 @Consumes(MediaType.APPLICATION_JSON)
121 public Response createRouter(final InputStream input) {
122 try {
123 ObjectMapper mapper = new ObjectMapper();
124 JsonNode subnode = mapper.readTree(input);
125 Collection<Router> routers = createOrUpdateByInputStream(subnode);
126
127 Boolean result = nullIsNotFound((get(RouterService.class)
lishuaid6f0c9e2015-12-16 11:40:01 +0800128 .createRouters(routers)), CREATE_FAIL);
jiangrui330b0c92015-11-28 14:09:50 +0800129 if (!result) {
130 return Response.status(CONFLICT).entity(CREATE_FAIL).build();
131 }
132 return Response.status(CREATED).entity(result.toString()).build();
133
134 } catch (Exception e) {
135 return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
136 }
137 }
138
139 @PUT
140 @Path("{routerUUID}")
141 @Produces(MediaType.APPLICATION_JSON)
142 @Consumes(MediaType.APPLICATION_JSON)
143 public Response updateRouter(@PathParam("routerUUID") String id,
144 final InputStream input) {
145 try {
146 ObjectMapper mapper = new ObjectMapper();
147 JsonNode subnode = mapper.readTree(input);
lishuaid6f0c9e2015-12-16 11:40:01 +0800148 Collection<Router> routers = changeUpdateJsonToSub(subnode, id);
jiangrui330b0c92015-11-28 14:09:50 +0800149 Boolean result = nullIsNotFound(get(RouterService.class)
150 .updateRouters(routers), UPDATE_FAIL);
151 if (!result) {
152 return Response.status(CONFLICT).entity(UPDATE_FAIL).build();
153 }
154 return ok(result.toString()).build();
155 } catch (Exception e) {
156 return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
157 }
158 }
159
jiangrui330b0c92015-11-28 14:09:50 +0800160 @DELETE
Wu wenbinb0bd6132016-05-10 19:20:23 +0800161 @Path("{routerUUID}")
162 @Consumes(MediaType.APPLICATION_JSON)
163 @Produces(MediaType.APPLICATION_JSON)
jiangrui330b0c92015-11-28 14:09:50 +0800164 public Response deleteSingleRouter(@PathParam("routerUUID") String id)
165 throws IOException {
166 try {
167 RouterId routerId = RouterId.valueOf(id);
168 Set<RouterId> routerIds = Sets.newHashSet(routerId);
169 get(RouterService.class).removeRouters(routerIds);
Jian Lic2a542b2016-05-10 11:48:19 -0700170 return Response.noContent().entity(DELETE_SUCCESS).build();
jiangrui330b0c92015-11-28 14:09:50 +0800171 } catch (Exception e) {
172 return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
173 }
174 }
175
176 @PUT
177 @Path("{routerUUID}/add_router_interface")
178 @Produces(MediaType.APPLICATION_JSON)
179 @Consumes(MediaType.APPLICATION_JSON)
180 public Response addRouterInterface(@PathParam("routerUUID") String id,
181 final InputStream input) {
182 if (!get(RouterService.class).exists(RouterId.valueOf(id))) {
183 return Response.status(NOT_FOUND).entity(NOT_EXIST).build();
184 }
185 try {
186 ObjectMapper mapper = new ObjectMapper();
187 JsonNode subnode = mapper.readTree(input);
188 if (!subnode.hasNonNull("id")) {
189 throw new IllegalArgumentException("id should not be null");
190 } else if (subnode.get("id").asText().isEmpty()) {
191 throw new IllegalArgumentException("id should not be empty");
192 }
193 RouterId routerId = RouterId.valueOf(id);
194 if (!subnode.hasNonNull("subnet_id")) {
195 throw new IllegalArgumentException("subnet_id should not be null");
196 } else if (subnode.get("subnet_id").asText().isEmpty()) {
197 throw new IllegalArgumentException("subnet_id should not be empty");
198 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800199 SubnetId subnetId = SubnetId
200 .subnetId(subnode.get("subnet_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800201 if (!subnode.hasNonNull("tenant_id")) {
202 throw new IllegalArgumentException("tenant_id should not be null");
203 } else if (subnode.get("tenant_id").asText().isEmpty()) {
204 throw new IllegalArgumentException("tenant_id should not be empty");
205 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800206 TenantId tenentId = TenantId
207 .tenantId(subnode.get("tenant_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800208 if (!subnode.hasNonNull("port_id")) {
209 throw new IllegalArgumentException("port_id should not be null");
210 } else if (subnode.get("port_id").asText().isEmpty()) {
211 throw new IllegalArgumentException("port_id should not be empty");
212 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800213 VirtualPortId portId = VirtualPortId
214 .portId(subnode.get("port_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800215 RouterInterface routerInterface = RouterInterface
216 .routerInterface(subnetId, portId, routerId, tenentId);
217 get(RouterInterfaceService.class)
218 .addRouterInterface(routerInterface);
219 return ok(INTFACR_ADD_SUCCESS).build();
220 } catch (Exception e) {
221 return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
222 }
223 }
224
225 @PUT
226 @Path("{routerUUID}/remove_router_interface")
227 @Produces(MediaType.APPLICATION_JSON)
228 @Consumes(MediaType.APPLICATION_JSON)
229 public Response removeRouterInterface(@PathParam("routerUUID") String id,
230 final InputStream input) {
231 if (!get(RouterService.class).exists(RouterId.valueOf(id))) {
232 return Response.status(NOT_FOUND).entity(NOT_EXIST).build();
233 }
234 try {
235 ObjectMapper mapper = new ObjectMapper();
236 JsonNode subnode = mapper.readTree(input);
237 if (!subnode.hasNonNull("id")) {
238 throw new IllegalArgumentException("id should not be null");
239 } else if (subnode.get("id").asText().isEmpty()) {
240 throw new IllegalArgumentException("id should not be empty");
241 }
242 RouterId routerId = RouterId.valueOf(id);
243 if (!subnode.hasNonNull("subnet_id")) {
244 throw new IllegalArgumentException("subnet_id should not be null");
245 } else if (subnode.get("subnet_id").asText().isEmpty()) {
246 throw new IllegalArgumentException("subnet_id should not be empty");
247 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800248 SubnetId subnetId = SubnetId
249 .subnetId(subnode.get("subnet_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800250 if (!subnode.hasNonNull("port_id")) {
251 throw new IllegalArgumentException("port_id should not be null");
252 } else if (subnode.get("port_id").asText().isEmpty()) {
253 throw new IllegalArgumentException("port_id should not be empty");
254 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800255 VirtualPortId portId = VirtualPortId
256 .portId(subnode.get("port_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800257 if (!subnode.hasNonNull("tenant_id")) {
258 throw new IllegalArgumentException("tenant_id should not be null");
259 } else if (subnode.get("tenant_id").asText().isEmpty()) {
260 throw new IllegalArgumentException("tenant_id should not be empty");
261 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800262 TenantId tenentId = TenantId
263 .tenantId(subnode.get("tenant_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800264 RouterInterface routerInterface = RouterInterface
265 .routerInterface(subnetId, portId, routerId, tenentId);
266 get(RouterInterfaceService.class)
267 .removeRouterInterface(routerInterface);
268 return ok(INTFACR_DEL_SUCCESS).build();
269 } catch (Exception e) {
270 return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
271 }
272 }
273
274 private Collection<Router> createOrUpdateByInputStream(JsonNode subnode)
275 throws Exception {
276 checkNotNull(subnode, JSON_NOT_NULL);
277 JsonNode routerNode = subnode.get("routers");
278 if (routerNode == null) {
279 routerNode = subnode.get("router");
280 }
281 log.debug("routerNode is {}", routerNode.toString());
282
283 if (routerNode.isArray()) {
284 throw new Exception("only singleton requests allowed");
285 } else {
286 return changeJsonToSub(routerNode);
287 }
288 }
289
290 /**
291 * Returns a collection of floatingIps from floatingIpNodes.
292 *
293 * @param routerNode the router json node
294 * @return routers a collection of router
Bharat saraswald270b182015-12-01 01:53:06 +0530295 * @throws Exception when any argument is illegal
jiangrui330b0c92015-11-28 14:09:50 +0800296 */
297 public Collection<Router> changeJsonToSub(JsonNode routerNode)
298 throws Exception {
299 checkNotNull(routerNode, JSON_NOT_NULL);
300 Map<RouterId, Router> subMap = new HashMap<RouterId, Router>();
301 if (!routerNode.hasNonNull("id")) {
302 new IllegalArgumentException("id should not be null");
303 } else if (routerNode.get("id").asText().isEmpty()) {
304 throw new IllegalArgumentException("id should not be empty");
305 }
306 RouterId id = RouterId.valueOf(routerNode.get("id").asText());
307
308 if (!routerNode.hasNonNull("tenant_id")) {
309 throw new IllegalArgumentException("tenant_id should not be null");
310 } else if (routerNode.get("tenant_id").asText().isEmpty()) {
311 throw new IllegalArgumentException("tenant_id should not be empty");
312 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800313 TenantId tenantId = TenantId
314 .tenantId(routerNode.get("tenant_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800315
316 VirtualPortId gwPortId = null;
317 if (routerNode.hasNonNull("gw_port_id")) {
lishuaid6f0c9e2015-12-16 11:40:01 +0800318 gwPortId = VirtualPortId
319 .portId(routerNode.get("gw_port_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800320 }
321
322 if (!routerNode.hasNonNull("status")) {
323 throw new IllegalArgumentException("status should not be null");
324 } else if (routerNode.get("status").asText().isEmpty()) {
325 throw new IllegalArgumentException("status should not be empty");
326 }
327 Status status = Status.valueOf(routerNode.get("status").asText());
328
329 String routerName = null;
330 if (routerNode.hasNonNull("name")) {
331 routerName = routerNode.get("name").asText();
332 }
333
334 boolean adminStateUp = true;
335 checkArgument(routerNode.get("admin_state_up").isBoolean(),
336 "admin_state_up should be boolean");
337 if (routerNode.hasNonNull("admin_state_up")) {
338 adminStateUp = routerNode.get("admin_state_up").asBoolean();
339 }
340 boolean distributed = false;
341 if (routerNode.hasNonNull("distributed")) {
342 distributed = routerNode.get("distributed").asBoolean();
343 }
344 RouterGateway gateway = null;
345 if (routerNode.hasNonNull("external_gateway_info")) {
lishuaid6f0c9e2015-12-16 11:40:01 +0800346 gateway = jsonNodeToGateway(routerNode
347 .get("external_gateway_info"));
348 }
349 List<String> routes = new ArrayList<String>();
350 DefaultRouter routerObj = new DefaultRouter(id, routerName,
351 adminStateUp, status,
352 distributed, gateway,
353 gwPortId, tenantId, routes);
354 subMap.put(id, routerObj);
355 return Collections.unmodifiableCollection(subMap.values());
356 }
357
358 /**
359 * Returns a collection of floatingIps from floatingIpNodes.
360 *
361 * @param subnode the router json node
362 * @param routerId the router identify
363 * @return routers a collection of router
364 * @throws Exception when any argument is illegal
365 */
366 public Collection<Router> changeUpdateJsonToSub(JsonNode subnode,
367 String routerId)
368 throws Exception {
369 checkNotNull(subnode, JSON_NOT_NULL);
370 checkNotNull(routerId, "routerId should not be null");
371 Map<RouterId, Router> subMap = new HashMap<RouterId, Router>();
372 JsonNode routerNode = subnode.get("router");
373 RouterId id = RouterId.valueOf(routerId);
374 Router sub = nullIsNotFound(get(RouterService.class).getRouter(id),
375 NOT_EXIST);
376 TenantId tenantId = sub.tenantId();
377
378 VirtualPortId gwPortId = null;
379 if (routerNode.hasNonNull("gw_port_id")) {
380 gwPortId = VirtualPortId
381 .portId(routerNode.get("gw_port_id").asText());
382 }
383 Status status = sub.status();
384
385 String routerName = routerNode.get("name").asText();
386
387 checkArgument(routerNode.get("admin_state_up").isBoolean(),
388 "admin_state_up should be boolean");
389 boolean adminStateUp = routerNode.get("admin_state_up").asBoolean();
390
391 boolean distributed = sub.distributed();
392 if (routerNode.hasNonNull("distributed")) {
393 distributed = routerNode.get("distributed").asBoolean();
394 }
395 RouterGateway gateway = sub.externalGatewayInfo();
396 if (routerNode.hasNonNull("external_gateway_info")) {
397 gateway = jsonNodeToGateway(routerNode
398 .get("external_gateway_info"));
jiangrui330b0c92015-11-28 14:09:50 +0800399 }
400 List<String> routes = new ArrayList<String>();
401 DefaultRouter routerObj = new DefaultRouter(id, routerName,
402 adminStateUp, status,
403 distributed, gateway,
404 gwPortId, tenantId, routes);
405 subMap.put(id, routerObj);
406 return Collections.unmodifiableCollection(subMap.values());
407 }
408
409 /**
410 * Changes JsonNode Gateway to the Gateway.
411 *
412 * @param gateway the gateway JsonNode
413 * @return gateway
414 */
415 private RouterGateway jsonNodeToGateway(JsonNode gateway) {
416 checkNotNull(gateway, JSON_NOT_NULL);
417 if (!gateway.hasNonNull("network_id")) {
418 throw new IllegalArgumentException("network_id should not be null");
419 } else if (gateway.get("network_id").asText().isEmpty()) {
420 throw new IllegalArgumentException("network_id should not be empty");
421 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800422 TenantNetworkId networkId = TenantNetworkId
423 .networkId(gateway.get("network_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800424
425 if (!gateway.hasNonNull("enable_snat")) {
426 throw new IllegalArgumentException("enable_snat should not be null");
427 } else if (gateway.get("enable_snat").asText().isEmpty()) {
428 throw new IllegalArgumentException("enable_snat should not be empty");
429 }
430 checkArgument(gateway.get("enable_snat").isBoolean(),
431 "enable_snat should be boolean");
432 boolean enableSnat = gateway.get("enable_snat").asBoolean();
433
434 if (!gateway.hasNonNull("external_fixed_ips")) {
lishuaid6f0c9e2015-12-16 11:40:01 +0800435 throw new IllegalArgumentException("external_fixed_ips should not be null");
jiangrui330b0c92015-11-28 14:09:50 +0800436 } else if (gateway.get("external_fixed_ips").isNull()) {
lishuaid6f0c9e2015-12-16 11:40:01 +0800437 throw new IllegalArgumentException("external_fixed_ips should not be empty");
jiangrui330b0c92015-11-28 14:09:50 +0800438 }
yuanyoue2ed3862016-05-06 13:18:08 +0800439 Iterable<FixedIp> fixedIpList = jsonNodeToFixedIp(gateway
jiangrui330b0c92015-11-28 14:09:50 +0800440 .get("external_fixed_ips"));
lishuaid6f0c9e2015-12-16 11:40:01 +0800441 RouterGateway gatewayObj = RouterGateway
yuanyoue2ed3862016-05-06 13:18:08 +0800442 .routerGateway(networkId, enableSnat, Sets.newHashSet(fixedIpList));
jiangrui330b0c92015-11-28 14:09:50 +0800443 return gatewayObj;
444 }
445
446 /**
447 * Changes JsonNode fixedIp to a collection of the fixedIp.
448 *
449 * @param fixedIp the allocationPools JsonNode
450 * @return a collection of fixedIp
451 */
yuanyoue2ed3862016-05-06 13:18:08 +0800452 private Iterable<FixedIp> jsonNodeToFixedIp(JsonNode fixedIp) {
jiangrui330b0c92015-11-28 14:09:50 +0800453 checkNotNull(fixedIp, JSON_NOT_NULL);
454 ConcurrentMap<Integer, FixedIp> fixedIpMaps = Maps.newConcurrentMap();
455 Integer i = 0;
456 for (JsonNode node : fixedIp) {
457 if (!node.hasNonNull("subnet_id")) {
458 throw new IllegalArgumentException("subnet_id should not be null");
459 } else if (node.get("subnet_id").asText().isEmpty()) {
460 throw new IllegalArgumentException("subnet_id should not be empty");
461 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800462 SubnetId subnetId = SubnetId
463 .subnetId(node.get("subnet_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800464 if (!node.hasNonNull("ip_address")) {
465 throw new IllegalArgumentException("ip_address should not be null");
466 } else if (node.get("ip_address").asText().isEmpty()) {
467 throw new IllegalArgumentException("ip_address should not be empty");
468 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800469 IpAddress ipAddress = IpAddress
470 .valueOf(node.get("ip_address").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800471 FixedIp fixedIpObj = FixedIp.fixedIp(subnetId, ipAddress);
472
473 fixedIpMaps.putIfAbsent(i, fixedIpObj);
474 i++;
475 }
476 return Collections.unmodifiableCollection(fixedIpMaps.values());
477 }
478
479 /**
480 * Returns the specified item if that items is null; otherwise throws not
481 * found exception.
482 *
483 * @param item item to check
484 * @param <T> item type
485 * @param message not found message
486 * @return item if not null
487 * @throws org.onlab.util.ItemNotFoundException if item is null
488 */
489 protected <T> T nullIsNotFound(T item, String message) {
490 if (item == null) {
491 throw new ItemNotFoundException(message);
492 }
493 return item;
494 }
495}