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