Bug 1029: Remove dead code: samples/clustersession
[controller.git] / opendaylight / northbound / topology / src / main / java / org / opendaylight / controller / topology / northbound / TopologyNorthboundJAXRS.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.topology.northbound;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15 import java.util.concurrent.ConcurrentMap;
16
17 import javax.ws.rs.Consumes;
18 import javax.ws.rs.DELETE;
19 import javax.ws.rs.GET;
20 import javax.ws.rs.PUT;
21 import javax.ws.rs.Path;
22 import javax.ws.rs.PathParam;
23 import javax.ws.rs.Produces;
24 import javax.ws.rs.QueryParam;
25 import javax.ws.rs.core.Context;
26 import javax.ws.rs.core.MediaType;
27 import javax.ws.rs.core.Response;
28 import javax.ws.rs.core.SecurityContext;
29 import javax.ws.rs.ext.ContextResolver;
30
31 import org.codehaus.enunciate.jaxrs.ResponseCode;
32 import org.codehaus.enunciate.jaxrs.StatusCodes;
33 import org.codehaus.enunciate.jaxrs.TypeHint;
34 import org.opendaylight.controller.northbound.commons.RestMessages;
35 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
36 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
37 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
38 import org.opendaylight.controller.northbound.commons.query.QueryContext;
39 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
40 import org.opendaylight.controller.sal.authorization.Privilege;
41 import org.opendaylight.controller.sal.core.Edge;
42 import org.opendaylight.controller.sal.core.NodeConnector;
43 import org.opendaylight.controller.sal.core.Property;
44 import org.opendaylight.controller.sal.utils.ServiceHelper;
45 import org.opendaylight.controller.sal.utils.Status;
46 import org.opendaylight.controller.topologymanager.ITopologyManager;
47 import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig;
48
49 /**
50  * Topology Northbound REST API
51  *
52  * <br>
53  * <br>
54  * Authentication scheme : <b>HTTP Basic</b><br>
55  * Authentication realm : <b>opendaylight</b><br>
56  * Transport : <b>HTTP and HTTPS</b><br>
57  * <br>
58  * HTTPS Authentication is disabled by default.
59  */
60
61 @Path("/")
62 public class TopologyNorthboundJAXRS {
63
64     private String username;
65     private QueryContext queryContext;
66
67     @Context
68     public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
69       if (queryCtxResolver != null) {
70         queryContext = queryCtxResolver.getContext(QueryContext.class);
71       }
72     }
73     @Context
74     public void setSecurityContext(SecurityContext context) {
75         if (context != null && context.getUserPrincipal() != null) {
76             username = context.getUserPrincipal().getName();
77         }
78     }
79
80     protected String getUserName() {
81         return username;
82     }
83
84     /**
85      *
86      * Retrieve the Topology
87      *
88      * @param containerName
89      *            The container for which we want to retrieve the topology (Eg.
90      *            'default')
91      *
92      * @return A List of EdgeProps each EdgeProp represent an Edge of the graph
93      *         with the corresponding properties attached to it.
94      *
95      *         <pre>
96      *
97      * Example:
98      *
99      * Request URL:
100      * http://localhost:8080/controller/nb/v2/topology/default
101      *
102      * Response body in XML:
103      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
104      * &lt;topology&gt;
105      *     &lt;edgeProperties&gt;
106      *         &lt;edge&gt;
107      *             &lt;tailNodeConnector&gt;
108      *                 &lt;node&gt;
109      *                     &lt;id&gt;00:00:00:00:00:00:00:02&lt;/id&gt;
110      *                     &lt;type&gt;OF&lt;/type&gt;
111      *                 &lt;/node&gt;
112      *                 &lt;id&gt;2&lt;/id&gt;
113      *                 &lt;type&gt;OF&lt;/type&gt;
114      *             &lt;/tailNodeConnector&gt;
115      *             &lt;headNodeConnector&gt;
116      *                 &lt;node&gt;
117      *                     &lt;id&gt;00:00:00:00:00:00:00:51&lt;/id&gt;
118      *                     &lt;type&gt;OF&lt;/type&gt;
119      *                 &lt;/node&gt;
120      *                 &lt;id&gt;2&lt;/id&gt;
121      *                 &lt;type&gt;OF&lt;/type&gt;
122      *             &lt;/headNodeConnector&gt;
123      *         &lt;/edge&gt;
124      *         &lt;properties&gt;
125      *             &lt;state&gt;
126      *                 &lt;value&gt;1&lt;/value&gt;
127      *             &lt;/state&gt;
128      *             &lt;config&gt;
129      *                 &lt;value&gt;1&lt;/value&gt;
130      *             &lt;/config&gt;
131      *             &lt;name&gt;
132      *                 &lt;value&gt;C1_2-L2_2&lt;/value&gt;
133      *             &lt;/name&gt;
134      *             &lt;timeStamp&gt;
135      *                 &lt;value&gt;1377279422032&lt;/value&gt;
136      *                 &lt;name&gt;creation&lt;/name&gt;
137      *             &lt;/timeStamp&gt;
138      *         &lt;/properties&gt;
139      *     &lt;/edgeProperties&gt;
140      *     &lt;edgeProperties&gt;
141      *         &lt;edge&gt;
142      *             &lt;tailNodeConnector&gt;
143      *                 &lt;node&gt;
144      *                     &lt;id&gt;00:00:00:00:00:00:00:51&lt;/id&gt;
145      *                     &lt;type&gt;OF&lt;/type&gt;
146      *                 &lt;/node&gt;
147      *                 &lt;id&gt;2&lt;/id&gt;
148      *                 &lt;type&gt;OF&lt;/type&gt;
149      *             &lt;/tailNodeConnector&gt;
150      *             &lt;headNodeConnector&gt;
151      *                 &lt;node&gt;
152      *                     &lt;id&gt;00:00:00:00:00:00:00:02&lt;/id&gt;
153      *                     &lt;type&gt;OF&lt;/type&gt;
154      *                 &lt;/node&gt;
155      *                 &lt;id&gt;2&lt;/id&gt;
156      *                 &lt;type&gt;OF&lt;/type&gt;
157      *             &lt;/headNodeConnector&gt;
158      *         &lt;/edge&gt;
159      *         &lt;properties&gt;
160      *             &lt;state&gt;
161      *                 &lt;value&gt;1&lt;/value&gt;
162      *             &lt;/state&gt;
163      *             &lt;name&gt;
164      *                 &lt;value&gt;L2_2-C1_2&lt;/value&gt;
165      *             &lt;/name&gt;
166      *             &lt;config&gt;
167      *                 &lt;value&gt;1&lt;/value&gt;
168      *             &lt;/config&gt;
169      *             &lt;timeStamp&gt;
170      *                 &lt;value&gt;1377279423564&lt;/value&gt;
171      *                 &lt;name&gt;creation&lt;/name&gt;
172      *             &lt;/timeStamp&gt;
173      *         &lt;/properties&gt;
174      *     &lt;/edgeProperties&gt;
175      * &lt;/topology&gt;
176      *
177      * Response body in JSON:
178      * {
179      *    "edgeProperties":[
180      *       {
181      *          "edge":{
182      *             "tailNodeConnector":{
183      *                "node":{
184      *                   "id":"00:00:00:00:00:00:00:02",
185      *                   "type":"OF"
186      *                },
187      *                "id":"2",
188      *                "type":"OF"
189      *             },
190      *             "headNodeConnector":{
191      *                "node":{
192      *                   "id":"00:00:00:00:00:00:00:51",
193      *                   "type":"OF"
194      *                },
195      *                "id":"2",
196      *                "type":"OF"
197      *             }
198      *          },
199      *          "properties":{
200      *             "timeStamp": {
201      *                "value": 1379527162648,
202      *                "name": "creation",
203      *             },
204      *             "name": {
205      *                "value": "s2-eth3"
206      *             },
207      *             "state": {
208      *                "value": 1
209      *             },
210      *             "config": {
211      *                "value": 1
212      *             },
213      *             "bandwidth": {
214      *                "value": 10000000000
215      *             }
216      *          }
217      *       },
218      *       {
219      *          "edge":{
220      *             "tailNodeConnector":{
221      *                "node":{
222      *                   "id":"00:00:00:00:00:00:00:51",
223      *                   "type":"OF"
224      *                },
225      *                "id":"2",
226      *                "type":"OF"
227      *             },
228      *             "headNodeConnector":{
229      *                "node":{
230      *                   "id":"00:00:00:00:00:00:00:02",
231      *                   "type":"OF"
232      *                },
233      *                "id":"2",
234      *                "type":"OF"
235      *             }
236      *           },
237      *           "properties":{
238      *             "timeStamp": {
239      *                "value": 1379527162648,
240      *                "name": "creation",
241      *             }
242      *          }
243      *        }
244      *     ]
245      *  }
246      * </pre>
247      */
248     @Path("/{containerName}")
249     @GET
250     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
251     @TypeHint(Topology.class)
252     @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
253     public Topology getTopology(@PathParam("containerName") String containerName,
254         @QueryParam("_q") String queryString) {
255
256         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
257             throw new UnauthorizedException("User is not authorized to perform this operation on container "
258                     + containerName);
259         }
260         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper.getInstance(ITopologyManager.class,
261                 containerName, this);
262         if (topologyManager == null) {
263             throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
264         }
265
266         Map<Edge, Set<Property>> topo = topologyManager.getEdges();
267         if (topo == null) {
268             return null;
269         }
270         List<EdgeProperties> res = new ArrayList<EdgeProperties>();
271         for (Map.Entry<Edge, Set<Property>> entry : topo.entrySet()) {
272             EdgeProperties el = new EdgeProperties(entry.getKey(), entry.getValue());
273             res.add(el);
274         }
275         Topology result = new Topology(res);
276
277         if (queryString != null) {
278             queryContext.createQuery(queryString, Topology.class)
279                 .filter(result, EdgeProperties.class);
280         }
281         return result;
282     }
283
284     /**
285      * Retrieve the user configured links
286      *
287      * @param containerName
288      *            The container for which we want to retrieve the user links
289      *            (Eg. 'default')
290      *
291      * @return A List of user configured links
292      *
293      *         <pre>
294      *
295      * Example:
296      *
297      * Request URL:
298      * http://localhost:8080/controller/nb/v2/topology/default/userLinks
299      *
300      * Response body in XML:
301      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
302      * &lt;list&gt;
303      * &lt;userLinks&gt;
304      * &lt;status&gt;Success&lt;/status&gt;
305      * &lt;name&gt;link1&lt;/name&gt;
306      * &lt;srcNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:02&lt;/srcNodeConnector&gt;
307      * &lt;dstNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:51&lt;/dstNodeConnector&gt;
308      * &lt;/userLinks&gt;
309      * &lt;/list&gt;
310      *
311      * Response body in JSON:
312     * {
313      *   "userLinks": [
314      *    {
315      *      "status": "Success",
316      *      "name": "link1",
317      *      "srcNodeConnector": "OF|2@OF|00:00:00:00:00:00:00:02",
318      *      "dstNodeConnector": "OF|5@OF|00:00:00:00:00:00:00:05"
319      *    }
320      *  ]
321      * }
322      *
323      * </pre>
324      */
325     @Path("/{containerName}/userLinks")
326     @GET
327     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
328     @TypeHint(TopologyUserLinks.class)
329     @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
330     public TopologyUserLinks getUserLinks(@PathParam("containerName") String containerName,
331         @QueryParam("_q") String queryString) {
332
333         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
334             throw new UnauthorizedException("User is not authorized to perform this operation on container "
335                     + containerName);
336         }
337         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper.getInstance(ITopologyManager.class,
338                 containerName, this);
339         if (topologyManager == null) {
340             throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
341         }
342
343         ConcurrentMap<String, TopologyUserLinkConfig> userLinks = topologyManager.getUserLinks();
344         if ((userLinks == null) || (userLinks.values() == null)) {
345             return null;
346         }
347         TopologyUserLinks result = new TopologyUserLinks(
348                 new ArrayList<TopologyUserLinkConfig>(userLinks.values()));
349         if (queryString != null) {
350             queryContext.createQuery(queryString, TopologyUserLinks.class)
351                 .filter(result, TopologyUserLinkConfig.class);
352         }
353         return result;
354     }
355
356     /**
357      * Add an User Link
358      *
359      * @param containerName
360      *            Name of the Container (Eg. 'default')
361      * @param name
362      *            Name of the user link
363      * @param TopologyUserLinkConfig
364      *            in JSON or XML format
365      * @return Response as dictated by the HTTP Response Status code
366      *
367      *         <pre>
368      *
369      * Example:
370      *
371      * Request URL:
372      * http://localhost:8080/controller/nb/v2/topology/default/userLink/link1
373      *
374      * Request body in XML:
375      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
376      * &lt;topologyUserLinkConfig&gt;
377      * &lt;status&gt;Success&lt;/status&gt;
378      * &lt;name&gt;link1&lt;/name&gt;
379      * &lt;srcNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:02&lt;/srcNodeConnector&gt;
380      * &lt;dstNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:51&lt;/dstNodeConnector&gt;
381      * &lt;/topologyUserLinkConfig&gt;
382      *
383      * Request body in JSON:
384      * {
385      *    "status":"Success",
386      *    "name":"link1",
387      *    "srcNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:02",
388      *    "dstNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:51"
389      * }
390      *
391      * </pre>
392      */
393     @Path("/{containerName}/userLink/{name}")
394     @PUT
395     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
396     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
397     @StatusCodes({
398         @ResponseCode(code = 201, condition = "User Link added successfully"),
399         @ResponseCode(code = 404, condition = "The Container Name was not found"),
400         @ResponseCode(code = 409, condition = "Failed to add User Link due to Conflicting Name"),
401         @ResponseCode(code = 500, condition = "Failed to add User Link. Failure Reason included in HTTP Error response"),
402         @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
403     public Response addUserLink(@PathParam(value = "containerName") String containerName,
404             @PathParam(value = "name") String name,
405             @TypeHint(TopologyUserLinkConfig.class) TopologyUserLinkConfig userLinkConfig) {
406
407         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
408             throw new UnauthorizedException("User is not authorized to perform this operation on container "
409                     + containerName);
410         }
411         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper.getInstance(ITopologyManager.class,
412                 containerName, this);
413         if (topologyManager == null) {
414             throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
415         }
416
417         Status status = topologyManager.addUserLink(userLinkConfig);
418         if (status.isSuccess()) {
419             NorthboundUtils
420             .auditlog(
421                     "User Link",username,"added", userLinkConfig.getName() + " from " + NorthboundUtils.getPortName(
422                             NodeConnector.fromString(userLinkConfig.getSrcNodeConnector()),
423                             containerName, this) + " to "
424                             + NorthboundUtils.getPortName(NodeConnector.fromString
425                                     (userLinkConfig.getDstNodeConnector()),containerName, this), containerName);
426             return Response.status(Response.Status.CREATED).build();
427         }
428         throw new InternalServerErrorException(status.getDescription());
429     }
430
431     /**
432      * Delete an User Link
433      *
434      * @param containerName
435      *            Name of the Container (Eg. 'default')
436      * @param name
437      *            Name of the Link Configuration (Eg. 'config1')
438      * @return Response as dictated by the HTTP Response Status code
439      *
440      *         <pre>
441      *
442      * Example:
443      *
444      * Request URL:
445      * http://localhost:8080/controller/nb/v2/topology/default/userLink/config1
446      *
447      * </pre>
448      */
449     @Path("/{containerName}/userLink/{name}")
450     @DELETE
451     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
452     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
453     @StatusCodes({ @ResponseCode(code = 204, condition = "User link removed successfully"),
454         @ResponseCode(code = 404, condition = "The Container Name or Link Configuration Name was not found"),
455         @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
456     public Response deleteUserLink(@PathParam("containerName") String containerName, @PathParam("name") String name) {
457
458         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
459             throw new UnauthorizedException("User is not authorized to perform this operation on container "
460                     + containerName);
461         }
462         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper.getInstance(ITopologyManager.class,
463                 containerName, this);
464         if (topologyManager == null) {
465             throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
466         }
467
468         Status ret = topologyManager.deleteUserLink(name);
469         if (ret.isSuccess()) {
470             NorthboundUtils.auditlog("User Link", username, "removed", name, containerName);
471             return Response.noContent().build();
472         }
473         return NorthboundUtils.getResponse(ret);
474     }
475 }