Merge "Fix Match intersection logic"
[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.POST;
21 import javax.ws.rs.Path;
22 import javax.ws.rs.PathParam;
23 import javax.ws.rs.Produces;
24 import javax.ws.rs.core.Context;
25 import javax.ws.rs.core.MediaType;
26 import javax.ws.rs.core.Response;
27 import javax.ws.rs.core.SecurityContext;
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.northbound.commons.RestMessages;
34 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
35 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
36 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
37 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
38 import org.opendaylight.controller.sal.authorization.Privilege;
39 import org.opendaylight.controller.sal.core.Edge;
40 import org.opendaylight.controller.sal.core.Property;
41 import org.opendaylight.controller.sal.utils.ServiceHelper;
42 import org.opendaylight.controller.sal.utils.Status;
43 import org.opendaylight.controller.topologymanager.ITopologyManager;
44 import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig;
45
46 /**
47  * Topology Northbound REST API
48  *
49  * <br>
50  * <br>
51  * Authentication scheme : <b>HTTP Basic</b><br>
52  * Authentication realm : <b>opendaylight</b><br>
53  * Transport : <b>HTTP and HTTPS</b><br>
54  * <br>
55  * HTTPS Authentication is disabled by default. Administrator can enable it in
56  * tomcat-server.xml after adding a proper keystore / SSL certificate from a
57  * trusted authority.<br>
58  * More info :
59  * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
60  */
61
62 @Path("/")
63 public class TopologyNorthboundJAXRS {
64
65     private String username;
66
67     @Context
68     public void setSecurityContext(SecurityContext context) {
69         username = context.getUserPrincipal().getName();
70     }
71
72     protected String getUserName() {
73         return username;
74     }
75
76     /**
77      *
78      * Retrieve the Topology
79      *
80      * @param containerName
81      *            The container for which we want to retrieve the topology (Eg. 'default')
82      *
83      * @return A List of EdgeProps each EdgeProp represent an Edge of the grap
84      *         with the corresponding properties attached to it.
85      *
86      * <pre>
87      *
88      * Example:
89      *
90      * RequestURL:
91      * http://localhost:8080/controller/nb/v2/topology/default
92      *
93      * Response in XML:
94      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;topology&gt;&lt;edgeProperties&gt;&lt;edge&gt;&lt;tailNodeConnector id="2" type="OF"&gt;&lt;node id="00:00:00:00:00:00:00:02" type="OF"/&gt;&lt;/tailNodeConnector&gt;&lt;headNodeConnector id="2" type="OF"&gt;&lt;node id="00:00:00:00:00:00:00:51" type="OF"/&gt;&lt;/headNodeConnector&gt;&lt;/edge&gt;&lt;properties&gt;&lt;state&gt;&lt;value&gt;1&lt;/value&gt;&lt;/state&gt;&lt;config&gt;&lt;value&gt;1&lt;/value&gt;&lt;/config&gt;&lt;name&gt;&lt;value&gt;C1_2-L2_2&lt;/value&gt;&lt;/name&gt;&lt;timeStamp&gt;&lt;value&gt;1377279422032&lt;/value&gt;&lt;name&gt;creation&lt;/name&gt;&lt;/timeStamp&gt;&lt;/properties&gt;&lt;/edgeProperties&gt;&lt;edgeProperties&gt;&lt;edge&gt;&lt;tailNodeConnector id="2" type="OF"&gt;&lt;node id="00:00:00:00:00:00:00:51" type="OF"/&gt;&lt;/tailNodeConnector&gt;&lt;headNodeConnector id="2" type="OF"&gt;&lt;node id="00:00:00:00:00:00:00:02" type="OF"/&gt;&lt;/headNodeConnector&gt;&lt;/edge&gt;&lt;properties&gt;&lt;state&gt;&lt;value&gt;1&lt;/value&gt;&lt;/state&gt;&lt;name&gt;&lt;value&gt;L2_2-C1_2&lt;/value&gt;&lt;/name&gt;&lt;config&gt;&lt;value&gt;1&lt;/value&gt;&lt;/config&gt;&lt;timeStamp&gt;&lt;value&gt;1377279423564&lt;/value&gt;&lt;name&gt;creation&lt;/name&gt;&lt;/timeStamp&gt;&lt;/properties&gt;&lt;/edgeProperties&gt;&lt;/topology&gt;
95      *
96      * Response in JSON:
97      * {"edgeProperties":[{"edge":{"tailNodeConnector":{"@id":"2","@type":"OF","node":{"@id":"00:00:00:00:00:00:00:02","@type":"OF"}},"headNodeConnector":{"@id":"2","@type":"OF","node":{"@id":"00:00:00:00:00:00:00:51","@type":"OF"}}},"properties":{"timeStamp":{"value":"1377278961017","name":"creation"}}},{"edge":{"tailNodeConnector":{"@id":"2","@type":"OF","node":{"@id":"00:00:00:00:00:00:00:51","@type":"OF"}},"headNodeConnector":{"@id":"2","@type":"OF","node":{"@id":"00:00:00:00:00:00:00:02","@type":"OF"}}},"properties":{"timeStamp":{"value":"1377278961018","name":"creation"}}}]}
98      *
99      * </pre>
100      */
101     @Path("/{containerName}")
102     @GET
103     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
104     @TypeHint(Topology.class)
105     @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
106     public Topology getTopology(@PathParam("containerName") String containerName) {
107
108         if (!NorthboundUtils.isAuthorized(
109                 getUserName(), containerName, Privilege.READ, this)) {
110             throw new UnauthorizedException(
111                     "User is not authorized to perform this operation on container "
112                             + containerName);
113         }
114         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
115                 .getInstance(ITopologyManager.class, containerName, this);
116         if (topologyManager == null) {
117             throw new ResourceNotFoundException(
118                     RestMessages.NOCONTAINER.toString());
119         }
120
121         Map<Edge, Set<Property>> topo = topologyManager.getEdges();
122         if (topo != null) {
123             List<EdgeProperties> res = new ArrayList<EdgeProperties>();
124             for (Map.Entry<Edge, Set<Property>> entry : topo.entrySet()) {
125                 EdgeProperties el = new EdgeProperties(entry.getKey(),
126                         entry.getValue());
127                 res.add(el);
128             }
129             return new Topology(res);
130         }
131
132         return null;
133     }
134
135     /**
136      * Retrieve the user configured links
137      *
138      * @param containerName
139      *            The container for which we want to retrieve the user links (Eg. 'default')
140      *
141      * @return A List of user configured links
142      *
143      * <pre>
144      *
145      * Example:
146      *
147      * RequestURL:
148      * http://localhost:8080/controller/nb/v2/topology/default/user-link
149      *
150      * Response in XML:
151      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;topologyUserLinks&gt;&lt;userLinks&gt;&lt;status&gt;Success&lt;/status&gt;&lt;name&gt;link1&lt;/name&gt;&lt;srcNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:02&lt;/srcNodeConnector&gt;&lt;dstNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:51&lt;/dstNodeConnector&gt;&lt;/userLinks&gt;&lt;/topologyUserLinks&gt;
152      *
153      * Response in JSON:
154      * {"userLinks":{"status":"Success","name":"link1","srcNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:02","dstNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:51"}}
155      *
156      * </pre>
157      */
158     @Path("/{containerName}/user-link")
159     @GET
160     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
161     @TypeHint(TopologyUserLinks.class)
162     @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
163     public TopologyUserLinks getUserLinks(
164             @PathParam("containerName") String containerName) {
165
166         if (!NorthboundUtils.isAuthorized(
167                 getUserName(), containerName, Privilege.READ, this)) {
168             throw new UnauthorizedException(
169                     "User is not authorized to perform this operation on container "
170                             + containerName);
171         }
172         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
173                 .getInstance(ITopologyManager.class, containerName, this);
174         if (topologyManager == null) {
175             throw new ResourceNotFoundException(
176                     RestMessages.NOCONTAINER.toString());
177         }
178
179         ConcurrentMap<String, TopologyUserLinkConfig> userLinks = topologyManager
180                 .getUserLinks();
181         if ((userLinks != null) && (userLinks.values() != null)) {
182             List<TopologyUserLinkConfig> res = new ArrayList<TopologyUserLinkConfig>(
183                     userLinks.values());
184             return new TopologyUserLinks(res);
185         }
186
187         return null;
188     }
189
190     /**
191      * Add an User Link
192      *
193      * @param containerName
194      *            Name of the Container (Eg. 'default')
195      * @param TopologyUserLinkConfig
196      *            in JSON or XML format
197      * @return Response as dictated by the HTTP Response Status code
198      *
199      * <pre>
200      *
201      * Example:
202      *
203      * RequestURL:
204      * http://localhost:8080/controller/nb/v2/topology/default/user-link/config1-content
205      *
206      * Request in XML:
207      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;topologyUserLinks&gt;&lt;status&gt;Success&lt;/status&gt;&lt;name&gt;link1&lt;/name&gt;&lt;srcNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:02&lt;/srcNodeConnector&gt;&lt;dstNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:51&lt;/dstNodeConnector&gt;&lt;/topologyUserLinks&gt;
208      *
209      * Request in JSON:
210      * {"status":"Success","name":"link1","srcNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:02","dstNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:51"}
211      *
212      * </pre>
213      */
214     @Path("/{containerName}/user-link")
215     @POST
216     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
217     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
218     @StatusCodes({
219             @ResponseCode(code = 201, condition = "User Link added successfully"),
220             @ResponseCode(code = 404, condition = "The Container Name was not found"),
221             @ResponseCode(code = 409, condition = "Failed to add User Link due to Conflicting Name"),
222             @ResponseCode(code = 500, condition = "Failed to add User Link. Failure Reason included in HTTP Error response"),
223             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
224     public Response addUserLink(
225             @PathParam(value = "containerName") String containerName,
226             @TypeHint(TopologyUserLinkConfig.class) JAXBElement<TopologyUserLinkConfig> userLinkConfig) {
227
228         if (!NorthboundUtils.isAuthorized(
229                 getUserName(), containerName, Privilege.WRITE, this)) {
230             throw new UnauthorizedException(
231                     "User is not authorized to perform this operation on container "
232                             + containerName);
233         }
234         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
235                 .getInstance(ITopologyManager.class, containerName, this);
236         if (topologyManager == null) {
237             throw new ResourceNotFoundException(
238                     RestMessages.NOCONTAINER.toString());
239         }
240
241         Status status = topologyManager.addUserLink(userLinkConfig.getValue());
242         if (status.isSuccess()) {
243             NorthboundUtils.auditlog("User Link", username, "added", userLinkConfig.getValue().getName(), containerName);
244             return Response.status(Response.Status.CREATED).build();
245         }
246         throw new InternalServerErrorException(status.getDescription());
247     }
248
249     /**
250      * Delete an User Link
251      *
252      * @param containerName
253      *            Name of the Container (Eg. 'default')
254      * @param name
255      *            Name of the Link Configuration (Eg. 'config1')
256      * @return Response as dictated by the HTTP Response Status code
257      *
258      * <pre>
259      *
260      * Example:
261      *
262      * RequestURL:
263      * http://localhost:8080/controller/nb/v2/topology/default/user-link/config1
264      *
265      * </pre>
266      */
267     @Path("/{containerName}/user-link/{name}")
268     @DELETE
269     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
270     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
271     @StatusCodes({
272             @ResponseCode(code = 200, condition = "Operation successful"),
273             @ResponseCode(code = 404, condition = "The Container Name or Link Configuration Name was not found"),
274             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
275     public Response deleteUserLink(
276             @PathParam("containerName") String containerName,
277             @PathParam("name") String name) {
278
279         if (!NorthboundUtils.isAuthorized(
280                 getUserName(), containerName, Privilege.WRITE, this)) {
281             throw new UnauthorizedException(
282                     "User is not authorized to perform this operation on container "
283                             + containerName);
284         }
285         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
286                 .getInstance(ITopologyManager.class, containerName, this);
287         if (topologyManager == null) {
288             throw new ResourceNotFoundException(
289                     RestMessages.NOCONTAINER.toString());
290         }
291
292         Status ret = topologyManager.deleteUserLink(name);
293         if (ret.isSuccess()) {
294             NorthboundUtils.auditlog("User Link", username, "removed", name, containerName);
295             return Response.ok().build();
296         }
297         throw new ResourceNotFoundException(ret.getDescription());
298     }
299 }