257fbbda670486582949bdb3eab5dd4297ba7d88
[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         if (context != null && context.getUserPrincipal() != null) 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) 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
429         if (flowConfig.getNode() == null) {
430             return Response.status(Response.Status.BAD_REQUEST).entity("Invalid Configuration. Node is null or empty")
431                     .build();
432         }
433         handleResourceCongruence(name, flowConfig.getName());
434         handleResourceCongruence(nodeId, flowConfig.getNode().getNodeIDString());
435         handleDefaultDisabled(containerName);
436
437         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
438
439         if (frm == null) {
440             throw new ServiceUnavailableException("Flow Programmer "
441                     + RestMessages.SERVICEUNAVAILABLE.toString());
442         }
443
444         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
445
446         FlowConfig staticFlow = frm.getStaticFlow(name, node);
447         if (staticFlow != null) {
448             throw new ResourceConflictException(name + " already exists."
449                     + RestMessages.RESOURCECONFLICT.toString());
450         }
451
452         Status status = frm.addStaticFlow(flowConfig);
453
454         if (status.isSuccess()) {
455             NorthboundUtils.auditlog("Flow", username, "added", name, containerName);
456             return Response.status(Response.Status.CREATED).entity("Success").build();
457         }
458         return NorthboundUtils.getResponse(status);
459     }
460
461     /**
462      * Delete a Flow configuration
463      *
464      * @param containerName
465      *            Name of the Container (Eg. 'default')
466      * @param nodeType
467      *            Type of the node being programmed (Eg. 'OF')
468      * @param nodeId
469      *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
470      * @param name
471      *            Name of the Static Flow configuration (Eg. 'Flow1')
472      * @return Response as dictated by the HTTP Response code
473      *
474      * <pre>
475      *
476      * Example:
477      *
478      * RequestURL:
479      * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
480      *
481      * </pre>
482      */
483
484     @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}")
485     @DELETE
486     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
487     @StatusCodes({
488             @ResponseCode(code = 200, condition = "Flow Config deleted successfully"),
489             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
490             @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
491             @ResponseCode(code = 406, condition = "Failed to delete Flow config due to invalid operation. Failure details included in HTTP Error response"),
492             @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"),
493             @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
494     public Response deleteFlow(
495             @PathParam(value = "containerName") String containerName,
496             @PathParam(value = "name") String name,
497             @PathParam("nodeType") String nodeType,
498             @PathParam(value = "nodeId") String nodeId) {
499
500         if (!NorthboundUtils.isAuthorized(
501                 getUserName(), containerName, Privilege.WRITE, this)) {
502             throw new UnauthorizedException(
503                     "User is not authorized to perform this operation on container "
504                             + containerName);
505         }
506         handleDefaultDisabled(containerName);
507
508         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
509
510         if (frm == null) {
511             throw new ServiceUnavailableException("Flow Programmer "
512                     + RestMessages.SERVICEUNAVAILABLE.toString());
513         }
514
515         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
516
517         FlowConfig staticFlow = frm.getStaticFlow(name, node);
518         if (staticFlow == null) {
519             throw new ResourceNotFoundException(name + " : "
520                     + RestMessages.NOFLOW.toString());
521         }
522
523         Status status = frm.removeStaticFlow(name, node);
524         if (status.isSuccess()) {
525             NorthboundUtils.auditlog("Flow", username, "removed", name, containerName);
526         }
527         return NorthboundUtils.getResponse(status);
528     }
529
530     /**
531      * Toggle a Flow configuration
532      *
533      * @param containerName
534      *            Name of the Container (Eg. 'default')
535      * @param nodeType
536      *            Type of the node being programmed (Eg. 'OF')
537      * @param nodeId
538      *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
539      * @param name
540      *            Name of the Static Flow configuration (Eg. 'Flow1')
541      * @return Response as dictated by the HTTP Response code
542      *
543      * <pre>
544      *
545      * Example:
546      *
547      * RequestURL:
548      * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
549      *
550      * </pre>
551      */
552     @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}")
553     @POST
554     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
555     @StatusCodes({
556             @ResponseCode(code = 200, condition = "Flow Config processed successfully"),
557             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
558             @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
559             @ResponseCode(code = 406, condition = "Failed to delete Flow config due to invalid operation. Failure details included in HTTP Error response"),
560             @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"),
561             @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
562     public Response toggleFlow(
563             @PathParam(value = "containerName") String containerName,
564             @PathParam("nodeType") String nodeType,
565             @PathParam(value = "nodeId") String nodeId,
566             @PathParam(value = "name") String name) {
567
568         if (!NorthboundUtils.isAuthorized(
569                 getUserName(), containerName, Privilege.WRITE, this)) {
570             throw new UnauthorizedException(
571                     "User is not authorized to perform this operation on container "
572                             + containerName);
573         }
574
575         handleDefaultDisabled(containerName);
576
577         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
578
579         if (frm == null) {
580             throw new ServiceUnavailableException("Flow Programmer "
581                     + RestMessages.SERVICEUNAVAILABLE.toString());
582         }
583
584         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
585
586         FlowConfig staticFlow = frm.getStaticFlow(name, node);
587         if (staticFlow == null) {
588             throw new ResourceNotFoundException(name + " : "
589                     + RestMessages.NOFLOW.toString());
590         }
591
592         Status status = frm.toggleStaticFlowStatus(staticFlow);
593         if (status.isSuccess()) {
594             NorthboundUtils.auditlog("Flow", username, "toggled", name, containerName);
595         }
596         return NorthboundUtils.getResponse(status);
597     }
598
599     private Node handleNodeAvailability(String containerName, String nodeType,
600             String nodeId) {
601
602         Node node = Node.fromString(nodeType, nodeId);
603         if (node == null) {
604             throw new ResourceNotFoundException(nodeId + " : "
605                     + RestMessages.NONODE.toString());
606         }
607
608         ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
609                 ISwitchManager.class, containerName, this);
610
611         if (sm == null) {
612             throw new ServiceUnavailableException("Switch Manager "
613                     + RestMessages.SERVICEUNAVAILABLE.toString());
614         }
615
616         if (!sm.getNodes().contains(node)) {
617             throw new ResourceNotFoundException(node.toString() + " : "
618                     + RestMessages.NONODE.toString());
619         }
620         return node;
621     }
622
623     private void handleDefaultDisabled(String containerName) {
624         IContainerManager containerManager = (IContainerManager) ServiceHelper
625                 .getGlobalInstance(IContainerManager.class, this);
626         if (containerManager == null) {
627             throw new InternalServerErrorException(
628                     RestMessages.INTERNALERROR.toString());
629         }
630         if (containerName.equals(GlobalConstants.DEFAULT.toString())
631                 && containerManager.hasNonDefaultContainer()) {
632             throw new NotAcceptableException(
633                     RestMessages.DEFAULTDISABLED.toString());
634         }
635     }
636
637     private void handleResourceCongruence(String resource, String configured) {
638         if (!resource.equals(configured)) {
639             throw new MethodNotAllowedException("Path's resource name conflicts with payload's resource name");
640         }
641     }
642
643 }