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