jiangrui
Committed by Gerrit Code Review

[ONOS-2753] add restfull service of router

Change-Id: I7764b05d0a43eeaa2fe868afb817ad94d4b8bc64
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
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 + */
16 +package org.onosproject.vtnweb.resources;
17 +
18 +import static com.google.common.base.Preconditions.checkArgument;
19 +import static com.google.common.base.Preconditions.checkNotNull;
20 +import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
21 +import static javax.ws.rs.core.Response.Status.CONFLICT;
22 +import static javax.ws.rs.core.Response.Status.CREATED;
23 +import static javax.ws.rs.core.Response.Status.NOT_FOUND;
24 +import static javax.ws.rs.core.Response.Status.NO_CONTENT;
25 +
26 +import java.io.IOException;
27 +import java.io.InputStream;
28 +import java.util.ArrayList;
29 +import java.util.Collection;
30 +import java.util.Collections;
31 +import java.util.HashMap;
32 +import java.util.List;
33 +import java.util.Map;
34 +import java.util.Set;
35 +import java.util.concurrent.ConcurrentMap;
36 +
37 +import javax.ws.rs.Consumes;
38 +import javax.ws.rs.DELETE;
39 +import javax.ws.rs.GET;
40 +import javax.ws.rs.POST;
41 +import javax.ws.rs.PUT;
42 +import javax.ws.rs.Path;
43 +import javax.ws.rs.PathParam;
44 +import javax.ws.rs.Produces;
45 +import javax.ws.rs.QueryParam;
46 +import javax.ws.rs.core.MediaType;
47 +import javax.ws.rs.core.Response;
48 +
49 +import org.onlab.packet.IpAddress;
50 +import org.onlab.util.ItemNotFoundException;
51 +import org.onosproject.rest.AbstractWebResource;
52 +import org.onosproject.vtnrsc.DefaultRouter;
53 +import org.onosproject.vtnrsc.FixedIp;
54 +import org.onosproject.vtnrsc.Router;
55 +import org.onosproject.vtnrsc.Router.Status;
56 +import org.onosproject.vtnrsc.RouterGateway;
57 +import org.onosproject.vtnrsc.RouterId;
58 +import org.onosproject.vtnrsc.RouterInterface;
59 +import org.onosproject.vtnrsc.SubnetId;
60 +import org.onosproject.vtnrsc.TenantId;
61 +import org.onosproject.vtnrsc.TenantNetworkId;
62 +import org.onosproject.vtnrsc.VirtualPortId;
63 +import org.onosproject.vtnrsc.router.RouterService;
64 +import org.onosproject.vtnrsc.routerinterface.RouterInterfaceService;
65 +import org.onosproject.vtnweb.web.RouterCodec;
66 +import org.slf4j.Logger;
67 +import org.slf4j.LoggerFactory;
68 +
69 +import com.fasterxml.jackson.databind.JsonNode;
70 +import com.fasterxml.jackson.databind.ObjectMapper;
71 +import com.fasterxml.jackson.databind.node.ObjectNode;
72 +import com.google.common.collect.Maps;
73 +import com.google.common.collect.Sets;
74 +
75 +@Path("routers")
76 +public class RouterWebResource extends AbstractWebResource {
77 + private final Logger log = LoggerFactory.getLogger(RouterWebResource.class);
78 + public static final String CREATE_FAIL = "Router is failed to create!";
79 + public static final String UPDATE_FAIL = "Router is failed to update!";
80 + public static final String GET_FAIL = "Router is failed to get!";
81 + public static final String NOT_EXIST = "Router does not exist!";
82 + public static final String DELETE_SUCCESS = "Router delete success!";
83 + public static final String JSON_NOT_NULL = "JsonNode can not be null";
84 + public static final String INTFACR_ADD_SUCCESS = "Interface add success";
85 + public static final String INTFACR_DEL_SUCCESS = "Interface delete success";
86 +
87 + @GET
88 + @Produces(MediaType.APPLICATION_JSON)
89 + public Response listRouters() {
90 + Collection<Router> routers = get(RouterService.class).getRouters();
91 + ObjectNode result = new ObjectMapper().createObjectNode();
92 + result.set("routers", new RouterCodec().encode(routers, this));
93 + return ok(result.toString()).build();
94 + }
95 +
96 + @GET
97 + @Path("{routerUUID}")
98 + @Produces(MediaType.APPLICATION_JSON)
99 + public Response getRouter(@PathParam("routerUUID") String id,
100 + @QueryParam("fields") List<String> fields) {
101 +
102 + if (!get(RouterService.class).exists(RouterId.valueOf(id))) {
103 + return Response.status(NOT_FOUND)
104 + .entity("The Router does not exists").build();
105 + }
106 + Router sub = nullIsNotFound(get(RouterService.class)
107 + .getRouter(RouterId.valueOf(id)),
108 + NOT_EXIST);
109 +
110 + ObjectNode result = new ObjectMapper().createObjectNode();
111 + if (fields.size() > 0) {
112 + result.set("router",
113 + new RouterCodec().extracFields(sub, this, fields));
114 + } else {
115 + result.set("router", new RouterCodec().encode(sub, this));
116 + }
117 + return ok(result.toString()).build();
118 + }
119 +
120 + @POST
121 + @Produces(MediaType.APPLICATION_JSON)
122 + @Consumes(MediaType.APPLICATION_JSON)
123 + public Response createRouter(final InputStream input) {
124 + try {
125 + ObjectMapper mapper = new ObjectMapper();
126 + JsonNode subnode = mapper.readTree(input);
127 + Collection<Router> routers = createOrUpdateByInputStream(subnode);
128 +
129 + Boolean result = nullIsNotFound((get(RouterService.class)
130 + .createRouters(routers)),
131 + CREATE_FAIL);
132 + if (!result) {
133 + return Response.status(CONFLICT).entity(CREATE_FAIL).build();
134 + }
135 + return Response.status(CREATED).entity(result.toString()).build();
136 +
137 + } catch (Exception e) {
138 + return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
139 + }
140 + }
141 +
142 + @PUT
143 + @Path("{routerUUID}")
144 + @Produces(MediaType.APPLICATION_JSON)
145 + @Consumes(MediaType.APPLICATION_JSON)
146 + public Response updateRouter(@PathParam("routerUUID") String id,
147 + final InputStream input) {
148 + try {
149 + ObjectMapper mapper = new ObjectMapper();
150 + JsonNode subnode = mapper.readTree(input);
151 + Collection<Router> routers = createOrUpdateByInputStream(subnode);
152 + Boolean result = nullIsNotFound(get(RouterService.class)
153 + .updateRouters(routers), UPDATE_FAIL);
154 + if (!result) {
155 + return Response.status(CONFLICT).entity(UPDATE_FAIL).build();
156 + }
157 + return ok(result.toString()).build();
158 + } catch (Exception e) {
159 + return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
160 + }
161 + }
162 +
163 + @Path("{routerUUID}")
164 + @DELETE
165 + public Response deleteSingleRouter(@PathParam("routerUUID") String id)
166 + throws IOException {
167 + try {
168 + RouterId routerId = RouterId.valueOf(id);
169 + Set<RouterId> routerIds = Sets.newHashSet(routerId);
170 + get(RouterService.class).removeRouters(routerIds);
171 + return Response.status(NO_CONTENT).entity(DELETE_SUCCESS).build();
172 + } catch (Exception e) {
173 + return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
174 + }
175 + }
176 +
177 + @PUT
178 + @Path("{routerUUID}/add_router_interface")
179 + @Produces(MediaType.APPLICATION_JSON)
180 + @Consumes(MediaType.APPLICATION_JSON)
181 + public Response addRouterInterface(@PathParam("routerUUID") String id,
182 + final InputStream input) {
183 + if (!get(RouterService.class).exists(RouterId.valueOf(id))) {
184 + return Response.status(NOT_FOUND).entity(NOT_EXIST).build();
185 + }
186 + try {
187 + ObjectMapper mapper = new ObjectMapper();
188 + JsonNode subnode = mapper.readTree(input);
189 + if (!subnode.hasNonNull("id")) {
190 + throw new IllegalArgumentException("id should not be null");
191 + } else if (subnode.get("id").asText().isEmpty()) {
192 + throw new IllegalArgumentException("id should not be empty");
193 + }
194 + RouterId routerId = RouterId.valueOf(id);
195 + if (!subnode.hasNonNull("subnet_id")) {
196 + throw new IllegalArgumentException("subnet_id should not be null");
197 + } else if (subnode.get("subnet_id").asText().isEmpty()) {
198 + throw new IllegalArgumentException("subnet_id should not be empty");
199 + }
200 + SubnetId subnetId = SubnetId.subnetId(subnode.get("subnet_id")
201 + .asText());
202 + if (!subnode.hasNonNull("tenant_id")) {
203 + throw new IllegalArgumentException("tenant_id should not be null");
204 + } else if (subnode.get("tenant_id").asText().isEmpty()) {
205 + throw new IllegalArgumentException("tenant_id should not be empty");
206 + }
207 + TenantId tenentId = TenantId.tenantId(subnode.get("tenant_id")
208 + .asText());
209 + if (!subnode.hasNonNull("port_id")) {
210 + throw new IllegalArgumentException("port_id should not be null");
211 + } else if (subnode.get("port_id").asText().isEmpty()) {
212 + throw new IllegalArgumentException("port_id should not be empty");
213 + }
214 + VirtualPortId portId = VirtualPortId.portId(subnode.get("port_id")
215 + .asText());
216 + RouterInterface routerInterface = RouterInterface
217 + .routerInterface(subnetId, portId, routerId, tenentId);
218 + get(RouterInterfaceService.class)
219 + .addRouterInterface(routerInterface);
220 + return ok(INTFACR_ADD_SUCCESS).build();
221 + } catch (Exception e) {
222 + return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
223 + }
224 + }
225 +
226 + @PUT
227 + @Path("{routerUUID}/remove_router_interface")
228 + @Produces(MediaType.APPLICATION_JSON)
229 + @Consumes(MediaType.APPLICATION_JSON)
230 + public Response removeRouterInterface(@PathParam("routerUUID") String id,
231 + final InputStream input) {
232 + if (!get(RouterService.class).exists(RouterId.valueOf(id))) {
233 + return Response.status(NOT_FOUND).entity(NOT_EXIST).build();
234 + }
235 + try {
236 + ObjectMapper mapper = new ObjectMapper();
237 + JsonNode subnode = mapper.readTree(input);
238 + if (!subnode.hasNonNull("id")) {
239 + throw new IllegalArgumentException("id should not be null");
240 + } else if (subnode.get("id").asText().isEmpty()) {
241 + throw new IllegalArgumentException("id should not be empty");
242 + }
243 + RouterId routerId = RouterId.valueOf(id);
244 + if (!subnode.hasNonNull("subnet_id")) {
245 + throw new IllegalArgumentException("subnet_id should not be null");
246 + } else if (subnode.get("subnet_id").asText().isEmpty()) {
247 + throw new IllegalArgumentException("subnet_id should not be empty");
248 + }
249 + SubnetId subnetId = SubnetId.subnetId(subnode.get("subnet_id")
250 + .asText());
251 + if (!subnode.hasNonNull("port_id")) {
252 + throw new IllegalArgumentException("port_id should not be null");
253 + } else if (subnode.get("port_id").asText().isEmpty()) {
254 + throw new IllegalArgumentException("port_id should not be empty");
255 + }
256 + VirtualPortId portId = VirtualPortId.portId(subnode.get("port_id")
257 + .asText());
258 + if (!subnode.hasNonNull("tenant_id")) {
259 + throw new IllegalArgumentException("tenant_id should not be null");
260 + } else if (subnode.get("tenant_id").asText().isEmpty()) {
261 + throw new IllegalArgumentException("tenant_id should not be empty");
262 + }
263 + TenantId tenentId = TenantId.tenantId(subnode.get("tenant_id")
264 + .asText());
265 + RouterInterface routerInterface = RouterInterface
266 + .routerInterface(subnetId, portId, routerId, tenentId);
267 + get(RouterInterfaceService.class)
268 + .removeRouterInterface(routerInterface);
269 + return ok(INTFACR_DEL_SUCCESS).build();
270 + } catch (Exception e) {
271 + return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
272 + }
273 + }
274 +
275 + private Collection<Router> createOrUpdateByInputStream(JsonNode subnode)
276 + throws Exception {
277 + checkNotNull(subnode, JSON_NOT_NULL);
278 + JsonNode routerNode = subnode.get("routers");
279 + if (routerNode == null) {
280 + routerNode = subnode.get("router");
281 + }
282 + log.debug("routerNode is {}", routerNode.toString());
283 +
284 + if (routerNode.isArray()) {
285 + throw new Exception("only singleton requests allowed");
286 + } else {
287 + return changeJsonToSub(routerNode);
288 + }
289 + }
290 +
291 + /**
292 + * Returns a collection of floatingIps from floatingIpNodes.
293 + *
294 + * @param routerNode the router json node
295 + * @return routers a collection of router
296 + * @throws Exception
297 + */
298 + public Collection<Router> changeJsonToSub(JsonNode routerNode)
299 + throws Exception {
300 + checkNotNull(routerNode, JSON_NOT_NULL);
301 + Map<RouterId, Router> subMap = new HashMap<RouterId, Router>();
302 + if (!routerNode.hasNonNull("id")) {
303 + new IllegalArgumentException("id should not be null");
304 + } else if (routerNode.get("id").asText().isEmpty()) {
305 + throw new IllegalArgumentException("id should not be empty");
306 + }
307 + RouterId id = RouterId.valueOf(routerNode.get("id").asText());
308 +
309 + if (!routerNode.hasNonNull("tenant_id")) {
310 + throw new IllegalArgumentException("tenant_id should not be null");
311 + } else if (routerNode.get("tenant_id").asText().isEmpty()) {
312 + throw new IllegalArgumentException("tenant_id should not be empty");
313 + }
314 + TenantId tenantId = TenantId.tenantId(routerNode.get("tenant_id")
315 + .asText());
316 +
317 + VirtualPortId gwPortId = null;
318 + if (routerNode.hasNonNull("gw_port_id")) {
319 + gwPortId = VirtualPortId.portId(routerNode.get("gw_port_id")
320 + .asText());
321 + }
322 +
323 + if (!routerNode.hasNonNull("status")) {
324 + throw new IllegalArgumentException("status should not be null");
325 + } else if (routerNode.get("status").asText().isEmpty()) {
326 + throw new IllegalArgumentException("status should not be empty");
327 + }
328 + Status status = Status.valueOf(routerNode.get("status").asText());
329 +
330 + String routerName = null;
331 + if (routerNode.hasNonNull("name")) {
332 + routerName = routerNode.get("name").asText();
333 + }
334 +
335 + boolean adminStateUp = true;
336 + checkArgument(routerNode.get("admin_state_up").isBoolean(),
337 + "admin_state_up should be boolean");
338 + if (routerNode.hasNonNull("admin_state_up")) {
339 + adminStateUp = routerNode.get("admin_state_up").asBoolean();
340 + }
341 + boolean distributed = false;
342 + if (routerNode.hasNonNull("distributed")) {
343 + distributed = routerNode.get("distributed").asBoolean();
344 + }
345 + RouterGateway gateway = null;
346 + if (routerNode.hasNonNull("external_gateway_info")) {
347 + gateway = jsonNodeToGateway(routerNode.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 + * Changes JsonNode Gateway to the Gateway.
360 + *
361 + * @param gateway the gateway JsonNode
362 + * @return gateway
363 + */
364 + private RouterGateway jsonNodeToGateway(JsonNode gateway) {
365 + checkNotNull(gateway, JSON_NOT_NULL);
366 + if (!gateway.hasNonNull("network_id")) {
367 + throw new IllegalArgumentException("network_id should not be null");
368 + } else if (gateway.get("network_id").asText().isEmpty()) {
369 + throw new IllegalArgumentException("network_id should not be empty");
370 + }
371 + TenantNetworkId networkId = TenantNetworkId.networkId(gateway
372 + .get("network_id").asText());
373 +
374 + if (!gateway.hasNonNull("enable_snat")) {
375 + throw new IllegalArgumentException("enable_snat should not be null");
376 + } else if (gateway.get("enable_snat").asText().isEmpty()) {
377 + throw new IllegalArgumentException("enable_snat should not be empty");
378 + }
379 + checkArgument(gateway.get("enable_snat").isBoolean(),
380 + "enable_snat should be boolean");
381 + boolean enableSnat = gateway.get("enable_snat").asBoolean();
382 +
383 + if (!gateway.hasNonNull("external_fixed_ips")) {
384 + throw new IllegalArgumentException(
385 + "external_fixed_ips should not be null");
386 + } else if (gateway.get("external_fixed_ips").isNull()) {
387 + throw new IllegalArgumentException(
388 + "external_fixed_ips should not be empty");
389 + }
390 + Collection<FixedIp> fixedIpList = jsonNodeToFixedIp(gateway
391 + .get("external_fixed_ips"));
392 + RouterGateway gatewayObj = RouterGateway.routerGateway(networkId,
393 + enableSnat,
394 + fixedIpList);
395 + return gatewayObj;
396 + }
397 +
398 + /**
399 + * Changes JsonNode fixedIp to a collection of the fixedIp.
400 + *
401 + * @param fixedIp the allocationPools JsonNode
402 + * @return a collection of fixedIp
403 + */
404 + private Collection<FixedIp> jsonNodeToFixedIp(JsonNode fixedIp) {
405 + checkNotNull(fixedIp, JSON_NOT_NULL);
406 + ConcurrentMap<Integer, FixedIp> fixedIpMaps = Maps.newConcurrentMap();
407 + Integer i = 0;
408 + for (JsonNode node : fixedIp) {
409 + if (!node.hasNonNull("subnet_id")) {
410 + throw new IllegalArgumentException("subnet_id should not be null");
411 + } else if (node.get("subnet_id").asText().isEmpty()) {
412 + throw new IllegalArgumentException("subnet_id should not be empty");
413 + }
414 + SubnetId subnetId = SubnetId.subnetId(node.get("subnet_id")
415 + .asText());
416 + if (!node.hasNonNull("ip_address")) {
417 + throw new IllegalArgumentException("ip_address should not be null");
418 + } else if (node.get("ip_address").asText().isEmpty()) {
419 + throw new IllegalArgumentException("ip_address should not be empty");
420 + }
421 + IpAddress ipAddress = IpAddress.valueOf(node.get("ip_address")
422 + .asText());
423 + FixedIp fixedIpObj = FixedIp.fixedIp(subnetId, ipAddress);
424 +
425 + fixedIpMaps.putIfAbsent(i, fixedIpObj);
426 + i++;
427 + }
428 + return Collections.unmodifiableCollection(fixedIpMaps.values());
429 + }
430 +
431 + /**
432 + * Returns the specified item if that items is null; otherwise throws not
433 + * found exception.
434 + *
435 + * @param item item to check
436 + * @param <T> item type
437 + * @param message not found message
438 + * @return item if not null
439 + * @throws org.onlab.util.ItemNotFoundException if item is null
440 + */
441 + protected <T> T nullIsNotFound(T item, String message) {
442 + if (item == null) {
443 + throw new ItemNotFoundException(message);
444 + }
445 + return item;
446 + }
447 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
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 + */
16 +package org.onosproject.vtnweb.web;
17 +
18 +import static com.google.common.base.Preconditions.checkNotNull;
19 +
20 +import java.util.Iterator;
21 +import java.util.List;
22 +
23 +import org.onosproject.codec.CodecContext;
24 +import org.onosproject.codec.JsonCodec;
25 +import org.onosproject.vtnrsc.Router;
26 +
27 +import com.fasterxml.jackson.databind.node.ObjectNode;
28 +
29 +/**
30 + * Router JSON codec.
31 + */
32 +public class RouterCodec extends JsonCodec<Router> {
33 + @Override
34 + public ObjectNode encode(Router router, CodecContext context) {
35 + checkNotNull(router, "router cannot be null");
36 + ObjectNode result = context
37 + .mapper()
38 + .createObjectNode()
39 + .put("id", router.id().routerId())
40 + .put("status", router.status().toString())
41 + .put("name", router.name().toString())
42 + .put("admin_state_up", router.adminStateUp())
43 + .put("tenant_id", router.tenantId().toString())
44 + .put("routes",
45 + router.routes() == null ? null : router.routes()
46 + .toString());
47 + result.set("external_gateway_info",
48 + router.externalGatewayInfo() == null ? null
49 + : new RouterGatewayInfoCodec()
50 + .encode(router.externalGatewayInfo(), context));
51 +
52 + return result;
53 + }
54 +
55 + public ObjectNode extracFields(Router router, CodecContext context,
56 + List<String> fields) {
57 + checkNotNull(router, "router cannot be null");
58 + ObjectNode result = context.mapper().createObjectNode();
59 + Iterator<String> i = fields.iterator();
60 + while (i.hasNext()) {
61 + String s = i.next();
62 + if (s.equals("id")) {
63 + result.put("id", router.id().routerId());
64 + }
65 + if (s.equals("status")) {
66 + result.put("status", router.status().toString());
67 + }
68 + if (s.equals("name")) {
69 + result.put("name", router.name().toString());
70 + }
71 + if (s.equals("admin_state_up")) {
72 + result.put("admin_state_up", router.adminStateUp());
73 + }
74 + if (s.equals("tenant_id")) {
75 + result.put("tenant_id", router.tenantId().toString());
76 + }
77 + if (s.equals("routes")) {
78 + result.put("routes", router.routes() == null ? null : router
79 + .routes().toString());
80 + }
81 + if (s.equals("external_gateway_info")) {
82 + result.set("external_gateway_info",
83 + router.externalGatewayInfo() == null ? null
84 + : new RouterGatewayInfoCodec()
85 + .encode(router.externalGatewayInfo(),
86 + context));
87 + }
88 + }
89 + return result;
90 + }
91 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
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 + */
16 +package org.onosproject.vtnweb.web;
17 +
18 +import static com.google.common.base.Preconditions.checkNotNull;
19 +
20 +import org.onosproject.codec.CodecContext;
21 +import org.onosproject.codec.JsonCodec;
22 +import org.onosproject.vtnrsc.RouterGateway;
23 +
24 +import com.fasterxml.jackson.databind.node.ObjectNode;
25 +
26 +/**
27 + * Subnet Router Gateway Info codec.
28 + */
29 +public class RouterGatewayInfoCodec extends JsonCodec<RouterGateway> {
30 + @Override
31 + public ObjectNode encode(RouterGateway routerGateway, CodecContext context) {
32 + checkNotNull(routerGateway, "routerGateway cannot be null");
33 + ObjectNode result = context.mapper().createObjectNode()
34 + .put("network_id", routerGateway.networkId().toString());
35 + result.set("external_fixed_ips", new FixedIpCodec()
36 + .encode(routerGateway.externalFixedIps(), context));
37 + return result;
38 + }
39 +}