Bug #65 - Fix inconsistencies in the NB REST APIs
[controller.git] / opendaylight / northbound / flowprogrammer / src / main / java / org / opendaylight / controller / flowprogrammer / northbound / FlowProgrammerNorthbound.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.flowprogrammer.northbound;
10
11 import java.util.ArrayList;
12 import java.util.List;
13
14 import javax.ws.rs.Consumes;
15 import javax.ws.rs.DELETE;
16 import javax.ws.rs.GET;
17 import javax.ws.rs.POST;
18 import javax.ws.rs.PUT;
19 import javax.ws.rs.Path;
20 import javax.ws.rs.PathParam;
21 import javax.ws.rs.Produces;
22 import javax.ws.rs.core.Context;
23 import javax.ws.rs.core.MediaType;
24 import javax.ws.rs.core.Response;
25 import javax.ws.rs.core.SecurityContext;
26 import javax.xml.bind.JAXBElement;
27
28 import org.codehaus.enunciate.jaxrs.ResponseCode;
29 import org.codehaus.enunciate.jaxrs.StatusCodes;
30 import org.codehaus.enunciate.jaxrs.TypeHint;
31 import org.opendaylight.controller.containermanager.IContainerManager;
32 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
33 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
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.MethodNotAllowedException;
37 import org.opendaylight.controller.northbound.commons.exception.NotAcceptableException;
38 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
39 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
40 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
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.core.Node;
45 import org.opendaylight.controller.sal.utils.GlobalConstants;
46 import org.opendaylight.controller.sal.utils.ServiceHelper;
47 import org.opendaylight.controller.sal.utils.Status;
48 import org.opendaylight.controller.switchmanager.ISwitchManager;
49
50 /**
51  * Flow Configuration Northbound API provides capabilities to program flows.
52  *
53  * <br>
54  * <br>
55  * Authentication scheme : <b>HTTP Basic</b><br>
56  * Authentication realm : <b>opendaylight</b><br>
57  * Transport : <b>HTTP and HTTPS</b><br>
58  * <br>
59  * HTTPS Authentication is disabled by default.
60  *
61  */
62 @Path("/")
63 public class FlowProgrammerNorthbound {
64
65     private String username;
66
67     @Context
68     public void setSecurityContext(SecurityContext context) {
69         if (context != null && context.getUserPrincipal() != null) username = context.getUserPrincipal().getName();
70     }
71
72     protected String getUserName() {
73         return username;
74     }
75
76     private IForwardingRulesManager getForwardingRulesManagerService(
77             String containerName) {
78         IContainerManager containerManager = (IContainerManager) ServiceHelper
79                 .getGlobalInstance(IContainerManager.class, this);
80         if (containerManager == null) {
81             throw new ServiceUnavailableException("Container "
82                     + RestMessages.SERVICEUNAVAILABLE.toString());
83         }
84
85         boolean found = false;
86         List<String> containerNames = containerManager.getContainerNames();
87         for (String cName : containerNames) {
88             if (cName.trim().equalsIgnoreCase(containerName.trim())) {
89                 found = true;
90             }
91         }
92
93         if (found == false) {
94             throw new ResourceNotFoundException(containerName + " "
95                     + RestMessages.NOCONTAINER.toString());
96         }
97
98         IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper
99                 .getInstance(IForwardingRulesManager.class, containerName, this);
100
101         if (frm == null) {
102             throw new ServiceUnavailableException("Flow Programmer "
103                     + RestMessages.SERVICEUNAVAILABLE.toString());
104         }
105
106         return frm;
107     }
108
109     private List<FlowConfig> getStaticFlowsInternal(String containerName,
110             Node node) {
111         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
112
113         if (frm == null) {
114             throw new ServiceUnavailableException("Flow Programmer "
115                     + RestMessages.SERVICEUNAVAILABLE.toString());
116         }
117
118         List<FlowConfig> flows = new ArrayList<FlowConfig>();
119
120         if (node == null) {
121             for (FlowConfig flow : frm.getStaticFlows()) {
122                 flows.add(flow);
123             }
124         } else {
125             ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
126                     ISwitchManager.class, containerName, this);
127
128             if (sm == null) {
129                 throw new ServiceUnavailableException("Switch Manager "
130                         + RestMessages.SERVICEUNAVAILABLE.toString());
131             }
132
133             if (!sm.getNodes().contains(node)) {
134                 throw new ResourceNotFoundException(node.toString() + " : "
135                         + RestMessages.NONODE.toString());
136             }
137
138             for (FlowConfig flow : frm.getStaticFlows(node)) {
139                 flows.add(flow);
140             }
141         }
142         return flows;
143     }
144
145     /**
146      * Returns a list of Flows configured on the given container
147      *
148      * @param containerName
149      *            Name of the Container (Eg. 'default')
150      * @return List of flows configured on a given container
151      *
152      * <pre>
153      *
154      * Example:
155      *
156      * RequestURL:
157      * http://localhost:8080/controller/nb/v2/flowprogrammer/default
158      *
159      * Response in XML:
160      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
161      * &lt;list&gt;
162      *     &#x20;&#x20;&#x20;&lt;flowConfig&gt;
163      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;installInHw&gt;true&lt;/installInHw&gt;
164      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;flow1&lt;/name&gt;
165      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;node&gt;
166      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;id&gt;00:00:00:00:00:00:00:01&lt;/id&gt;
167      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;type&gt;OF&lt;/type&gt;
168      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/node&gt;
169      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;ingressPort&gt;1&lt;/ingressPort&gt;
170      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;priority&gt;500&lt;/priority&gt;
171      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;etherType&gt;0x800&lt;/etherType&gt;
172      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nwSrc&gt;9.9.1.1&lt;/nwSrc&gt;
173      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;actions&gt;OUTPUT=2&lt;/actions&gt;
174      *     &#x20;&#x20;&#x20;&lt;/flowConfig&gt;
175      * &lt;/list&gt;
176      *
177      * Response in JSON:
178      * {"flowConfig":{"installInHw":"true","name":"flow1","node":{"id":"00:00:00:00:00:00:00:01","type":"OF"},
179      * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}}
180      *
181      * </pre>
182      */
183     @Path("/{containerName}")
184     @GET
185     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
186     @TypeHint(FlowConfigs.class)
187     @StatusCodes({
188             @ResponseCode(code = 200, condition = "Operation successful"),
189             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
190             @ResponseCode(code = 404, condition = "The containerName is not found"),
191             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
192     public FlowConfigs getStaticFlows(
193             @PathParam("containerName") String containerName) {
194         if (!NorthboundUtils.isAuthorized(
195                 getUserName(), containerName, Privilege.READ, this)) {
196             throw new UnauthorizedException(
197                     "User is not authorized to perform this operation on container "
198                             + containerName);
199         }
200
201         List<FlowConfig> flowConfigs = getStaticFlowsInternal(containerName,
202                 null);
203         return new FlowConfigs(flowConfigs);
204     }
205
206     /**
207      * Returns a list of Flows configured on a Node in a given container
208      *
209      * @param containerName
210      *            Name of the Container (Eg. 'default')
211      * @param nodeType
212      *            Type of the node being programmed (Eg. 'OF')
213      * @param nodeId
214      *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
215      * @return List of flows configured on a Node in a container
216      *
217      * <pre>
218      *
219      * Example:
220      *
221      * RequestURL:
222      * http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01
223      *
224      * Response in XML:
225      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
226      * &lt;list&gt;
227      *     &#x20;&#x20;&#x20;&lt;flowConfig&gt;
228      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;installInHw&gt;true&lt;/installInHw&gt;
229      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;flow1&lt;/name&gt;
230      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;node&gt;
231      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;id&gt;00:00:00:00:00:00:00:01&lt;/id&gt;
232      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;type&gt;OF&lt;/type&gt;
233      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/node&gt;
234      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;ingressPort&gt;1&lt;/ingressPort&gt;
235      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;priority&gt;500&lt;/priority&gt;
236      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;etherType&gt;0x800&lt;/etherType&gt;
237      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nwSrc&gt;9.9.1.1&lt;/nwSrc&gt;
238      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;actions&gt;OUTPUT=2&lt;/actions&gt;
239      *     &#x20;&#x20;&#x20;&lt;/flowConfig&gt;
240      * &lt;/list&gt;
241      *
242      * Response in JSON:
243      * {"flowConfig":{"installInHw":"true","name":"flow1","node":{"id":"00:00:00:00:00:00:00:01","type":"OF"},
244      * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}}
245      *
246      * </pre>
247      */
248     @Path("/{containerName}/node/{nodeType}/{nodeId}")
249     @GET
250     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
251     @TypeHint(FlowConfigs.class)
252     @StatusCodes({
253             @ResponseCode(code = 200, condition = "Operation successful"),
254             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
255             @ResponseCode(code = 404, condition = "The containerName or nodeId is not found"),
256             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
257     public FlowConfigs getStaticFlows(
258             @PathParam("containerName") String containerName,
259             @PathParam("nodeType") String nodeType,
260             @PathParam("nodeId") String nodeId) {
261         if (!NorthboundUtils.isAuthorized(
262                 getUserName(), containerName, Privilege.READ, this)) {
263             throw new UnauthorizedException(
264                     "User is not authorized to perform this operation on container "
265                             + containerName);
266         }
267         Node node = Node.fromString(nodeType, nodeId);
268         if (node == null) {
269             throw new ResourceNotFoundException(nodeId + " : "
270                     + RestMessages.NONODE.toString());
271         }
272         List<FlowConfig> flows = getStaticFlowsInternal(containerName, node);
273         return new FlowConfigs(flows);
274     }
275
276     /**
277      * Returns the flow configuration matching a human-readable name and nodeId
278      * on a given Container.
279      *
280      * @param containerName
281      *            Name of the Container (Eg. 'default')
282      * @param nodeType
283      *            Type of the node being programmed (Eg. 'OF')
284      * @param nodeId
285      *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
286      * @param name
287      *            Human-readable name for the configured flow (Eg. 'Flow1')
288      * @return Flow configuration matching the name and nodeId on a Container
289      *
290      * <pre>
291      *
292      * Example:
293      *
294      * RequestURL:
295      * http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01/staticFlow/flow1
296      *
297      * Response in XML:
298      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
299      * &lt;flowConfig&gt;
300      *     &#x20;&#x20;&#x20;&lt;installInHw&gt;true&lt;/installInHw&gt;
301      *     &#x20;&#x20;&#x20;&lt;name&gt;flow1&lt;/name&gt;
302      *     &#x20;&#x20;&#x20;&lt;node&gt;
303      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;id&gt;00:00:00:00:00:00:00:01&lt;/id&gt;
304      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;type&gt;OF&lt;/type&gt;
305      *     &#x20;&#x20;&#x20;&lt;/node&gt;
306      *     &#x20;&#x20;&#x20;&lt;ingressPort&gt;1&lt;/ingressPort&gt;
307      *     &#x20;&#x20;&#x20;&lt;priority&gt;500&lt;/priority&gt;
308      *     &#x20;&#x20;&#x20;&lt;etherType&gt;0x800&lt;/etherType&gt;
309      *     &#x20;&#x20;&#x20;&lt;nwSrc&gt;9.9.1.1&lt;/nwSrc&gt;
310      *     &#x20;&#x20;&#x20;&lt;actions&gt;OUTPUT=2&lt;/actions&gt;
311      * &lt;/flowConfig&gt;
312      *
313      * Response in JSON:
314      * {"installInHw":"true","name":"flow1","node":{"id":"00:00:00:00:00:00:00:01","type":"OF"},
315      * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}
316      *
317      * </pre>
318      */
319     @Path("/{containerName}/node/{nodeType}/{nodeId}/staticFlow/{name}")
320     @GET
321     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
322     @TypeHint(FlowConfig.class)
323     @StatusCodes({
324             @ResponseCode(code = 200, condition = "Operation successful"),
325             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
326             @ResponseCode(code = 404, condition = "The containerName or NodeId or Configuration name is not found"),
327             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
328     public FlowConfig getStaticFlow(
329             @PathParam("containerName") String containerName,
330             @PathParam("nodeType") String nodeType,
331             @PathParam("nodeId") String nodeId, @PathParam("name") String name) {
332         if (!NorthboundUtils.isAuthorized(
333                 getUserName(), containerName, Privilege.READ, this)) {
334             throw new UnauthorizedException(
335                     "User is not authorized to perform this operation on container "
336                             + containerName);
337         }
338         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
339
340         if (frm == null) {
341             throw new ServiceUnavailableException("Flow Programmer "
342                     + RestMessages.SERVICEUNAVAILABLE.toString());
343         }
344
345         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
346
347         FlowConfig staticFlow = frm.getStaticFlow(name, node);
348         if (staticFlow == null) {
349             throw new ResourceNotFoundException(RestMessages.NOFLOW.toString());
350         }
351
352         return new FlowConfig(staticFlow);
353     }
354
355     /**
356      * Add a flow configuration. If a flow by the given name already
357      * exists, this method will respond with a non-successful status response.
358      *
359      * @param containerName
360      *            Name of the Container (Eg. 'default')
361      * @param nodeType
362      *            Type of the node being programmed (Eg. 'OF')
363      * @param nodeId
364      *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
365      * @param name
366      *            Name of the Static Flow configuration (Eg. 'Flow2')
367      * @param FlowConfig
368      *            Flow Configuration in JSON or XML format
369      * @return Response as dictated by the HTTP Response Status code
370      *
371      * <pre>
372      *
373      * Example:
374      *
375      * RequestURL:
376      * http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01/staticFlow/flow1
377      *
378      * Request in XML:
379      * &lt;flowConfig&gt;
380      *         &#x20;&#x20;&#x20;&lt;installInHw&gt;true&lt;/installInHw&gt;
381      *         &#x20;&#x20;&#x20;&lt;name&gt;flow1&lt;/name&gt;
382      *         &#x20;&#x20;&#x20;&lt;node&gt;
383      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;id&gt;00:00:00:00:00:00:00:01&lt;/id&gt;
384      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;type&gt;OF&lt;/type&gt;
385      *         &#x20;&#x20;&#x20;&lt;/node&gt;
386      *         &#x20;&#x20;&#x20;&lt;ingressPort&gt;1&lt;/ingressPort&gt;
387      *         &#x20;&#x20;&#x20;&lt;priority&gt;500&lt;/priority&gt;
388      *         &#x20;&#x20;&#x20;&lt;etherType&gt;0x800&lt;/etherType&gt;
389      *         &#x20;&#x20;&#x20;&lt;nwSrc&gt;9.9.1.1&lt;/nwSrc&gt;
390      *         &#x20;&#x20;&#x20;&lt;actions&gt;OUTPUT=2&lt;/actions&gt;
391      * &lt;/flowConfig&gt;
392      *
393      * Request in JSON:
394      * {"installInHw":"true","name":"flow1","node":{"id":"00:00:00:00:00:00:00:01","type":"OF"},
395      * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}
396      *
397      * </pre>
398      */
399
400     @Path("/{containerName}/node/{nodeType}/{nodeId}/staticFlow/{name}")
401     @PUT
402     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
403     @StatusCodes({
404             @ResponseCode(code = 201, condition = "Flow Config processed successfully"),
405             @ResponseCode(code = 400, condition = "Failed to create Static Flow entry due to invalid flow configuration"),
406             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
407             @ResponseCode(code = 404, condition = "The Container Name or nodeId is not found"),
408             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
409             @ResponseCode(code = 409, condition = "Failed to create Static Flow entry due to Conflicting Name or configuration"),
410             @ResponseCode(code = 500, condition = "Failed to create Static Flow entry. Failure Reason included in HTTP Error response"),
411             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
412     public Response addFlow(
413             @PathParam(value = "containerName") String containerName,
414             @PathParam(value = "name") String name,
415             @PathParam("nodeType") String nodeType,
416             @PathParam(value = "nodeId") String nodeId,
417             @TypeHint(FlowConfig.class) FlowConfig flowConfig) {
418
419         if (!NorthboundUtils.isAuthorized(
420                 getUserName(), containerName, Privilege.WRITE, this)) {
421             throw new UnauthorizedException(
422                     "User is not authorized to perform this operation on container "
423                             + containerName);
424         }
425
426         if (flowConfig.getNode() == null) {
427             return Response.status(Response.Status.BAD_REQUEST).entity("Invalid Configuration. Node is null or empty")
428                     .build();
429         }
430         handleResourceCongruence(name, flowConfig.getName());
431         handleResourceCongruence(nodeId, flowConfig.getNode().getNodeIDString());
432         handleDefaultDisabled(containerName);
433
434         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
435
436         if (frm == null) {
437             throw new ServiceUnavailableException("Flow Programmer "
438                     + RestMessages.SERVICEUNAVAILABLE.toString());
439         }
440
441         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
442
443         FlowConfig staticFlow = frm.getStaticFlow(name, node);
444         if (staticFlow != null) {
445             throw new ResourceConflictException(name + " already exists."
446                     + RestMessages.RESOURCECONFLICT.toString());
447         }
448
449         Status status = frm.addStaticFlow(flowConfig);
450
451         if (status.isSuccess()) {
452             NorthboundUtils.auditlog("Flow", username, "added", name, containerName);
453             return Response.status(Response.Status.CREATED).entity("Success").build();
454         }
455         return NorthboundUtils.getResponse(status);
456     }
457
458     /**
459      * Delete a Flow configuration
460      *
461      * @param containerName
462      *            Name of the Container (Eg. 'default')
463      * @param nodeType
464      *            Type of the node being programmed (Eg. 'OF')
465      * @param nodeId
466      *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
467      * @param name
468      *            Name of the Static Flow configuration (Eg. 'Flow1')
469      * @return Response as dictated by the HTTP Response code
470      *
471      * <pre>
472      *
473      * Example:
474      *
475      * RequestURL:
476      * http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01/staticFlow/flow1
477      *
478      * </pre>
479      */
480
481     @Path("/{containerName}/node/{nodeType}/{nodeId}/staticFlow/{name}")
482     @DELETE
483     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
484     @StatusCodes({
485             @ResponseCode(code = 204, condition = "Flow Config deleted successfully"),
486             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
487             @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
488             @ResponseCode(code = 406, condition = "Failed to delete Flow config due to invalid operation. Failure details included in HTTP Error response"),
489             @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"),
490             @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
491     public Response deleteFlow(
492             @PathParam(value = "containerName") String containerName,
493             @PathParam(value = "name") String name,
494             @PathParam("nodeType") String nodeType,
495             @PathParam(value = "nodeId") String nodeId) {
496
497         if (!NorthboundUtils.isAuthorized(
498                 getUserName(), containerName, Privilege.WRITE, this)) {
499             throw new UnauthorizedException(
500                     "User is not authorized to perform this operation on container "
501                             + containerName);
502         }
503         handleDefaultDisabled(containerName);
504
505         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
506
507         if (frm == null) {
508             throw new ServiceUnavailableException("Flow Programmer "
509                     + RestMessages.SERVICEUNAVAILABLE.toString());
510         }
511
512         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
513
514         FlowConfig staticFlow = frm.getStaticFlow(name, node);
515         if (staticFlow == null) {
516             throw new ResourceNotFoundException(name + " : "
517                     + RestMessages.NOFLOW.toString());
518         }
519
520         Status status = frm.removeStaticFlow(name, node);
521         if (status.isSuccess()) {
522             NorthboundUtils.auditlog("Flow", username, "removed", name, containerName);
523             return Response.noContent().build();
524         }
525         return NorthboundUtils.getResponse(status);
526     }
527
528     /**
529      * Toggle a Flow configuration
530      *
531      * @param containerName
532      *            Name of the Container (Eg. 'default')
533      * @param nodeType
534      *            Type of the node being programmed (Eg. 'OF')
535      * @param nodeId
536      *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
537      * @param name
538      *            Name of the Static Flow configuration (Eg. 'Flow1')
539      * @return Response as dictated by the HTTP Response code
540      *
541      * <pre>
542      *
543      * Example:
544      *
545      * RequestURL:
546      * http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01/staticFlow/flow1
547      *
548      * </pre>
549      */
550     @Path("/{containerName}/node/{nodeType}/{nodeId}/staticFlow/{name}")
551     @POST
552     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
553     @StatusCodes({
554             @ResponseCode(code = 200, condition = "Flow Config processed successfully"),
555             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
556             @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
557             @ResponseCode(code = 406, condition = "Failed to delete Flow config due to invalid operation. Failure details included in HTTP Error response"),
558             @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"),
559             @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
560     public Response toggleFlow(
561             @PathParam(value = "containerName") String containerName,
562             @PathParam("nodeType") String nodeType,
563             @PathParam(value = "nodeId") String nodeId,
564             @PathParam(value = "name") String name) {
565
566         if (!NorthboundUtils.isAuthorized(
567                 getUserName(), containerName, Privilege.WRITE, this)) {
568             throw new UnauthorizedException(
569                     "User is not authorized to perform this operation on container "
570                             + containerName);
571         }
572
573         handleDefaultDisabled(containerName);
574
575         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
576
577         if (frm == null) {
578             throw new ServiceUnavailableException("Flow Programmer "
579                     + RestMessages.SERVICEUNAVAILABLE.toString());
580         }
581
582         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
583
584         FlowConfig staticFlow = frm.getStaticFlow(name, node);
585         if (staticFlow == null) {
586             throw new ResourceNotFoundException(name + " : "
587                     + RestMessages.NOFLOW.toString());
588         }
589
590         Status status = frm.toggleStaticFlowStatus(staticFlow);
591         if (status.isSuccess()) {
592             NorthboundUtils.auditlog("Flow", username, "toggled", name, containerName);
593         }
594         return NorthboundUtils.getResponse(status);
595     }
596
597     private Node handleNodeAvailability(String containerName, String nodeType,
598             String nodeId) {
599
600         Node node = Node.fromString(nodeType, nodeId);
601         if (node == null) {
602             throw new ResourceNotFoundException(nodeId + " : "
603                     + RestMessages.NONODE.toString());
604         }
605
606         ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
607                 ISwitchManager.class, containerName, this);
608
609         if (sm == null) {
610             throw new ServiceUnavailableException("Switch Manager "
611                     + RestMessages.SERVICEUNAVAILABLE.toString());
612         }
613
614         if (!sm.getNodes().contains(node)) {
615             throw new ResourceNotFoundException(node.toString() + " : "
616                     + RestMessages.NONODE.toString());
617         }
618         return node;
619     }
620
621     private void handleDefaultDisabled(String containerName) {
622         IContainerManager containerManager = (IContainerManager) ServiceHelper
623                 .getGlobalInstance(IContainerManager.class, this);
624         if (containerManager == null) {
625             throw new InternalServerErrorException(
626                     RestMessages.INTERNALERROR.toString());
627         }
628         if (containerName.equals(GlobalConstants.DEFAULT.toString())
629                 && containerManager.hasNonDefaultContainer()) {
630             throw new NotAcceptableException(
631                     RestMessages.DEFAULTDISABLED.toString());
632         }
633     }
634
635     private void handleResourceCongruence(String resource, String configured) {
636         if (!resource.equals(configured)) {
637             throw new MethodNotAllowedException("Path's resource name conflicts with payload's resource name");
638         }
639     }
640
641 }