Bug #65 - Fix inconsistencies in the NB REST APIs
[controller.git] / opendaylight / northbound / staticrouting / src / main / java / org / opendaylight / controller / forwarding / staticrouting / northbound / StaticRoutingNorthbound.java
1
2 /*
3  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9
10 package org.opendaylight.controller.forwarding.staticrouting.northbound;
11
12 import java.util.ArrayList;
13 import java.util.List;
14
15 import javax.ws.rs.Consumes;
16 import javax.ws.rs.DELETE;
17 import javax.ws.rs.GET;
18 import javax.ws.rs.POST;
19 import javax.ws.rs.PUT;
20 import javax.ws.rs.Path;
21 import javax.ws.rs.PathParam;
22 import javax.ws.rs.Produces;
23 import javax.ws.rs.core.Context;
24 import javax.ws.rs.core.MediaType;
25 import javax.ws.rs.core.Response;
26 import javax.ws.rs.core.SecurityContext;
27 import javax.ws.rs.core.UriInfo;
28 import javax.xml.bind.JAXBElement;
29
30 import org.codehaus.enunciate.jaxrs.ResponseCode;
31 import org.codehaus.enunciate.jaxrs.StatusCodes;
32 import org.codehaus.enunciate.jaxrs.TypeHint;
33 import org.opendaylight.controller.containermanager.IContainerManager;
34 import org.opendaylight.controller.forwarding.staticrouting.IForwardingStaticRouting;
35 import org.opendaylight.controller.forwarding.staticrouting.StaticRouteConfig;
36 import org.opendaylight.controller.northbound.commons.RestMessages;
37 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
38 import org.opendaylight.controller.northbound.commons.exception.NotAcceptableException;
39 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
40 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
41 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
42 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
43 import org.opendaylight.controller.sal.authorization.Privilege;
44 import org.opendaylight.controller.sal.utils.GlobalConstants;
45 import org.opendaylight.controller.sal.utils.ServiceHelper;
46 import org.opendaylight.controller.sal.utils.Status;
47
48 /**
49  * <p>Static Routing Northbound API allows for the management of the static
50  * routes.</p>
51  * </br>
52  * An example request/response for retrieving the static routes may look like this: </br>
53  * <pre>
54  * GET http://localhost:8080/controller/nb/v2/staticroute/default HTTP/1.1
55  * Accept: application/json
56  *
57  * HTTP/1.1 200 OK
58  * Content-Type: application/json
59  *
60  * {"staticRoute":{"name":"route-1","prefix":"10.10.1.0/24","nextHop":"1.1.1.1"}}
61  *
62  * </pre>
63  *
64  * <br><br>
65  * Authentication scheme : <b>HTTP Basic</b><br>
66  * Authentication realm : <b>opendaylight</b><br>
67  * Transport : <b>HTTP and HTTPS</b><br>
68  * <br>
69  */
70 @Path("/")
71 public class StaticRoutingNorthbound {
72
73     private String username;
74
75     @Context
76     public void setSecurityContext(SecurityContext context) {
77         if (context != null && context.getUserPrincipal() != null) username = context.getUserPrincipal().getName();
78     }
79     protected String getUserName() {
80         return username;
81     }
82
83
84
85     private List<StaticRoute> getStaticRoutesInternal(String containerName) {
86
87         IForwardingStaticRouting staticRouting = (IForwardingStaticRouting) ServiceHelper
88                 .getInstance(IForwardingStaticRouting.class, containerName,
89                         this);
90
91         if (staticRouting == null) {
92             throw new ResourceNotFoundException(RestMessages.NOCONTAINER
93                     .toString());
94         }
95
96         List<StaticRoute> routes = new ArrayList<StaticRoute>();
97
98         for (StaticRouteConfig conf : staticRouting.getStaticRouteConfigs()
99                 .values()) {
100             StaticRoute route = new StaticRoute(conf.getName(), conf
101                     .getStaticRoute(), conf.getNextHop());
102             routes.add(route);
103         }
104         return routes;
105     }
106
107     /**
108      * Get a list of static routes present on the given container.
109      *
110      * @param containerName Name of the Container. The Container name for the base controller is "default".
111      * @return List of configured static routes on the given container
112      *
113      * <pre>
114      * Example:
115      *
116      * Request URL:
117      * GET http://localhost:8080/controller/nb/v2/staticroute/default/routes
118      *
119      * Response in XML:
120      *  &lt;list&gt;
121      *   &lt;staticRoute&gt;
122      *     &lt;name&gt;route-1&lt;/name&gt;
123      *     &lt;prefix&gt;10.10.1.0/24&lt;/prefix&gt;
124      *     &lt;nextHop&gt;1.1.1.1&lt;/nextHop&gt;
125      *   &lt;/staticRoute&gt;
126      *  &lt;/list&gt;
127      *
128      * Response in JSON:
129      * {"staticRoute":{"name":"route-1","prefix":"10.10.1.0/24","nextHop":"1.1.1.1"}}
130      *
131      * </pre>
132      */
133     @Path("/{containerName}/routes")
134     @GET
135     @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
136     @TypeHint(StaticRoutes.class)
137     @StatusCodes( {
138             @ResponseCode(code = 200, condition = "Operation successful"),
139             @ResponseCode(code = 404, condition = "The containerName passed was not found") })
140     public StaticRoutes getStaticRoutes(
141             @PathParam("containerName") String containerName) {
142
143         if(!NorthboundUtils.isAuthorized(getUserName(), containerName,
144                 Privilege.WRITE, this)){
145             throw new
146                 UnauthorizedException("User is not authorized to perform this operation on container "
147                             + containerName);
148         }
149         return new StaticRoutes(getStaticRoutesInternal(containerName));
150     }
151
152     /**
153      * Returns the static route for the provided configuration name on a given container
154      *
155      * @param containerName Name of the Container. The Container name for the base controller is "default".
156      * @param route Name of the Static Route configuration
157      * @return Static route configured with the supplied Name.
158      *
159      * <pre>
160      * Example:
161      *
162      * Request URL:
163      * GET http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
164      *
165      * Response in XML:
166      *
167      *   &lt;staticRoute&gt;
168      *     &lt;name&gt;route-1&lt;/name&gt;
169      *     &lt;prefix&gt;10.10.1.0/24&lt;/prefix&gt;
170      *     &lt;nextHop&gt;1.1.1.1&lt;/nextHop&gt;
171      *   &lt;/staticRoute&gt;
172      *
173      * Response in JSON:
174      * {"name":"route-1","prefix":"10.10.1.0/24","nextHop":"1.1.1.1"}
175      *
176      * </pre>
177      */
178     @Path("/{containerName}/route/{route}")
179     @GET
180     @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
181     @TypeHint(StaticRoute.class)
182     @StatusCodes( {
183             @ResponseCode(code = 200, condition = "Operation successful"),
184             @ResponseCode(code = 404, condition = "The Container Name or Static Route Configuration name passed was not found") })
185     public StaticRoute getStaticRoute(
186             @PathParam("containerName") String containerName,
187             @PathParam("route") String route) {
188
189         if(!NorthboundUtils.isAuthorized(getUserName(), containerName,
190                 Privilege.WRITE, this)){
191             throw new
192                 UnauthorizedException("User is not authorized to perform this operation on container "
193                             + containerName);
194         }
195         List<StaticRoute> routes = this.getStaticRoutesInternal(containerName);
196         for (StaticRoute r : routes) {
197             if (r.getName().equalsIgnoreCase(route)) {
198                 return r;
199             }
200         }
201
202         throw new ResourceNotFoundException(RestMessages.NOSTATICROUTE
203                 .toString());
204     }
205
206     /**
207      *
208      * Add a new Static Route. If a route by the given name already exists, this
209      * method will return a non-successful status response.
210      *
211      * @param containerName Name of the Container. The Container name for the base controller is "default".
212      * @param route Name of the Static Route configuration
213      * @return Response as dictated by the HTTP Response code
214      *
215      * <pre>
216      * Example:
217      *
218      * Request URL:
219      * PUT http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
220      *
221      * Request payload in JSON:
222      * {"name":"route-1","prefix":"10.10.1.0/24","nextHop":"1.1.1.1"}
223      *
224      * </pre>
225      */
226     @Path("/{containerName}/route/{route}")
227     @PUT
228     @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
229     @StatusCodes( {
230             @ResponseCode(code = 201, condition = "Created Static Route successfully"),
231             @ResponseCode(code = 404, condition = "The Container Name passed is not found"),
232             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
233             @ResponseCode(code = 409, condition = "Failed to create Static Route entry due to Conflicting Name or Prefix."), })
234     public Response addStaticRoute(
235             @Context UriInfo uriInfo,
236             @PathParam(value = "containerName") String containerName,
237             @PathParam(value = "route") String route,
238             @TypeHint(StaticRoute.class) StaticRoute staticRouteData) {
239
240
241         if(!NorthboundUtils.isAuthorized(getUserName(), containerName,
242                 Privilege.WRITE, this)){
243             throw new
244                 UnauthorizedException("User is not authorized to perform this operation on container "
245                             + containerName);
246         }
247         handleDefaultDisabled(containerName);
248
249         IForwardingStaticRouting staticRouting = (IForwardingStaticRouting) ServiceHelper
250                 .getInstance(IForwardingStaticRouting.class, containerName,
251                         this);
252
253         if (staticRouting == null) {
254             throw new ResourceNotFoundException(RestMessages.NOCONTAINER
255                     .toString());
256         }
257
258         StaticRoute sRoute = staticRouteData;
259         StaticRouteConfig cfgObject = new StaticRouteConfig(sRoute.getName(),
260                 sRoute.getPrefix(), sRoute.getNextHop());
261         Status response = staticRouting.addStaticRoute(cfgObject);
262         if (response.isSuccess()) {
263             NorthboundUtils.auditlog("Static Route", username, "added", route, containerName);
264             return Response.created(uriInfo.getRequestUri()).build();
265         }
266         throw new ResourceConflictException(response.getDescription());
267     }
268
269     /**
270      *
271      * Delete a Static Route
272      *
273      * @param containerName Name of the Container. The Container name for the base controller is "default".
274      * @param route Name of the Static Route configuration to be removed
275      *
276      * @return Response as dictated by the HTTP Response code
277      *
278      * <pre>
279      * Example:
280      *
281      * Request URL:
282      * DELETE http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
283      *
284      * </pre>
285      */
286     @Path("/{containerName}/route/{route}")
287     @DELETE
288     @StatusCodes( {
289             @ResponseCode(code = 204, condition = "Static route removed successfully"),
290             @ResponseCode(code = 404, condition = "Container Name or Configuration Name not found"),
291             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active") })
292     public Response removeStaticRoute(
293             @PathParam(value = "containerName") String containerName,
294             @PathParam(value = "route") String route) {
295
296         if(!NorthboundUtils.isAuthorized(getUserName(), containerName,
297                 Privilege.WRITE, this)){
298             throw new
299                 UnauthorizedException("User is not authorized to perform this operation on container "
300                             + containerName);
301         }
302         handleDefaultDisabled(containerName);
303
304         IForwardingStaticRouting staticRouting = (IForwardingStaticRouting) ServiceHelper
305                 .getInstance(IForwardingStaticRouting.class, containerName,
306                         this);
307
308         if (staticRouting == null) {
309             throw new ResourceNotFoundException(RestMessages.NOCONTAINER
310                     .toString());
311         }
312
313         Status status = staticRouting.removeStaticRoute(route);
314         if (status.isSuccess()) {
315             NorthboundUtils.auditlog("Static Route", username, "removed", route, containerName);
316             return Response.noContent().build();
317         }
318         return NorthboundUtils.getResponse(status);
319     }
320
321     private void handleDefaultDisabled(String containerName) {
322         IContainerManager containerManager = (IContainerManager) ServiceHelper
323                 .getGlobalInstance(IContainerManager.class, this);
324         if (containerManager == null) {
325             throw new InternalServerErrorException(RestMessages.INTERNALERROR
326                     .toString());
327         }
328         if (containerName.equals(GlobalConstants.DEFAULT.toString())
329                 && containerManager.hasNonDefaultContainer()) {
330             throw new NotAcceptableException(RestMessages.DEFAULTDISABLED
331                     .toString());
332         }
333     }
334 }