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