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