toaster-it: add missing version for maven-paxexam-plugin
[controller.git] / opendaylight / northbound / switchmanager / src / main / java / org / opendaylight / controller / switchmanager / northbound / SwitchNorthbound.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.switchmanager.northbound;
10
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17
18 import javax.ws.rs.Consumes;
19 import javax.ws.rs.DELETE;
20 import javax.ws.rs.GET;
21 import javax.ws.rs.POST;
22 import javax.ws.rs.PUT;
23 import javax.ws.rs.Path;
24 import javax.ws.rs.PathParam;
25 import javax.ws.rs.Produces;
26 import javax.ws.rs.core.Context;
27 import javax.ws.rs.core.MediaType;
28 import javax.ws.rs.core.Response;
29 import javax.ws.rs.core.SecurityContext;
30
31 import org.codehaus.enunciate.jaxrs.ResponseCode;
32 import org.codehaus.enunciate.jaxrs.StatusCodes;
33 import org.codehaus.enunciate.jaxrs.TypeHint;
34 import org.opendaylight.controller.containermanager.IContainerManager;
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.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.core.NodeConnector;
44 import org.opendaylight.controller.sal.core.Property;
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.sal.utils.StatusCode;
49 import org.opendaylight.controller.switchmanager.ISwitchManager;
50 import org.opendaylight.controller.switchmanager.SwitchConfig;
51
52 /**
53  * The class provides Northbound REST APIs to access the nodes, node connectors
54  * and their properties.
55  *
56  */
57
58 @Path("/")
59 public class SwitchNorthbound {
60
61     private String username;
62
63     @Context
64     public void setSecurityContext(SecurityContext context) {
65         username = context.getUserPrincipal().getName();
66     }
67
68     protected String getUserName() {
69         return username;
70     }
71
72     private ISwitchManager getIfSwitchManagerService(String containerName) {
73         IContainerManager containerManager = (IContainerManager) ServiceHelper
74                 .getGlobalInstance(IContainerManager.class, this);
75         if (containerManager == null) {
76             throw new ServiceUnavailableException("Container "
77                     + RestMessages.SERVICEUNAVAILABLE.toString());
78         }
79
80         boolean found = false;
81         List<String> containerNames = containerManager.getContainerNames();
82         for (String cName : containerNames) {
83             if (cName.trim().equalsIgnoreCase(containerName.trim())) {
84                 found = true;
85                 break;
86             }
87         }
88
89         if (found == false) {
90             throw new ResourceNotFoundException(containerName + " "
91                     + RestMessages.NOCONTAINER.toString());
92         }
93
94         ISwitchManager switchManager = (ISwitchManager) ServiceHelper
95                 .getInstance(ISwitchManager.class, containerName, this);
96
97         if (switchManager == null) {
98             throw new ServiceUnavailableException("Switch Manager "
99                     + RestMessages.SERVICEUNAVAILABLE.toString());
100         }
101
102         return switchManager;
103     }
104
105     /**
106      *
107      * Retrieve a list of all the nodes and their properties in the network
108      *
109      * @param containerName
110      *            Name of the Container (Eg. 'default')
111      * @return A list of Pair each pair represents a
112      *         {@link org.opendaylight.controller.sal.core.Node} and Set of
113      *         {@link org.opendaylight.controller.sal.core.Property} attached to
114      *         it.
115      *
116      * <pre>
117      *
118      * Example:
119      *
120      * RequestURL:
121      * http://.../default/nodes
122      *
123      * Response in XML:
124      * &lt;list&gt;
125      *     &#x20;&#x20;&#x20;&lt;nodeProperties&gt;
126      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;node type="OF" id="00:00:00:00:00:00:00:02"/&gt;
127      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;properties&gt;
128      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;tables&gt;
129      *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;-1&lt;/value&gt;
130      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/tables&gt;
131      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;description&gt;
132      *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;Switch2&lt;/value&gt;
133      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/description&gt;
134      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;actions&gt;
135      *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;4095&lt;/value&gt;
136      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/actions&gt;
137      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;macAddress&gt;
138      *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;00:00:00:00:00:02&lt;/value&gt;
139      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/macAddress&gt;
140      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;capabilities&gt;
141      *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;199&lt;/value&gt;
142      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/capabilities&gt;
143      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;timeStamp&gt;
144      *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;1377291227877&lt;/value&gt;
145      *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;connectedSince&lt;/name&gt;
146      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/timeStamp&gt;
147      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;buffers&gt;
148      *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;256&lt;/value&gt;
149      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/buffers&gt;
150      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/properties&gt;
151      *     &#x20;&#x20;&#x20;&lt;/nodeProperties&gt;
152      * &lt;/list&gt;
153      *
154      * Response in JSON:
155      * {"nodeProperties":[{"node":{"@type":"OF","@id":"00:00:00:00:00:00:00:02"},"properties":{"tables":{"value":"-1"},
156      * "description":{"value":"None"},"actions":{"value":"4095"},"macAddress":{"value":"00:00:00:00:00:02"},"capabilities"
157      * :{"value":"199"},"timeStamp":{"value":"1377291227877","name":"connectedSince"},"buffers":{"value":"256"}}}]}
158      *
159      * </pre>
160      */
161     @Path("/{containerName}/nodes")
162     @GET
163     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
164     @TypeHint(Nodes.class)
165     @StatusCodes({
166             @ResponseCode(code = 200, condition = "Operation successful"),
167             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
168             @ResponseCode(code = 404, condition = "The containerName is not found"),
169             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
170     public Nodes getNodes(@PathParam("containerName") String containerName) {
171
172         if (!isValidContainer(containerName)) {
173             throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
174         }
175
176         if (!NorthboundUtils.isAuthorized(
177                 getUserName(), containerName, Privilege.READ, this)) {
178             throw new UnauthorizedException(
179                     "User is not authorized to perform this operation on container "
180                             + containerName);
181         }
182
183         ISwitchManager switchManager = getIfSwitchManagerService(containerName);
184         if (switchManager == null) {
185             throw new ServiceUnavailableException("Switch Manager "
186                     + RestMessages.SERVICEUNAVAILABLE.toString());
187         }
188
189         List<NodeProperties> res = new ArrayList<NodeProperties>();
190         Set<Node> nodes = switchManager.getNodes();
191         if (nodes == null) {
192             return null;
193         }
194
195         for (Node node : nodes) {
196             Map<String, Property> propMap = switchManager.getNodeProps(node);
197             if (propMap == null) {
198                 continue;
199             }
200             Set<Property> props = new HashSet<Property>(propMap.values());
201
202             NodeProperties nodeProps = new NodeProperties(node, props);
203             res.add(nodeProps);
204         }
205
206         return new Nodes(res);
207     }
208
209     /**
210      * Add a Description, Tier and Forwarding mode property to a node.
211      *
212      * @param containerName
213      *            Name of the Container (Eg. 'default')
214      * @param nodeType
215      *            Type of the node being programmed (Eg. 'OF')
216      * @param nodeId
217      *            Node Identifier as specified by
218      *            {@link org.opendaylight.controller.sal.core.Node}
219      *            (Eg. '00:00:00:00:00:00:00:03')
220      * @param propertyName
221      *            Name of the Property. Properties that can be
222      *            configured are: description, forwarding(only for default
223      *            container) and tier
224      * @param propertyValue
225      *            Value of the Property. Description can be any string (Eg. 'Node1'),
226      *            valid values for tier are 0, 1 and 2, and valid values for forwarding are 0 for
227      *            reactive and 1 for proactive forwarding.
228      * @return Response as dictated by the HTTP Response Status code
229      *
230      * <pre>
231      *
232      * Example:
233      *
234      * RequestURL:
235      * http://.../default/node/OF/00:00:00:00:00:00:00:03/property/description/Switch3
236      *
237      * </pre>
238      */
239
240     @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propertyName}/{propertyValue}")
241     @PUT
242     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
243     @TypeHint(Response.class)
244     @StatusCodes({
245             @ResponseCode(code = 201, condition = "Operation successful"),
246             @ResponseCode(code = 400, condition = "The nodeId or configuration is invalid"),
247             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
248             @ResponseCode(code = 404, condition = "The Container Name or node or configuration name is not found"),
249             @ResponseCode(code = 406, condition = "The property cannot be configured in non-default container"),
250             @ResponseCode(code = 409, condition = "Unable to update configuration due to cluster conflict or conflicting description property"),
251             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
252     public Response addNodeProperty(
253             @PathParam("containerName") String containerName,
254             @PathParam("nodeType") String nodeType,
255             @PathParam("nodeId") String nodeId,
256             @PathParam("propertyName") String propertyName,
257             @PathParam("propertyValue") String propertyValue) {
258
259         if (!isValidContainer(containerName)) {
260             throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
261         }
262         if (!NorthboundUtils.isAuthorized(
263                 getUserName(), containerName, Privilege.WRITE, this)) {
264             throw new UnauthorizedException(
265                     "User is not authorized to perform this operation on container "
266                             + containerName);
267         }
268         ISwitchManager switchManager = getIfSwitchManagerService(containerName);
269         if (switchManager == null) {
270             throw new ServiceUnavailableException("Switch Manager "
271                     + RestMessages.SERVICEUNAVAILABLE.toString());
272         }
273
274         handleNodeAvailability(containerName, nodeType, nodeId);
275         Node node = Node.fromString(nodeType, nodeId);
276         Property prop = switchManager.createProperty(propertyName, propertyValue);
277         if (prop == null) {
278             throw new ResourceNotFoundException("Property with name " + propertyName + " does not exist.");
279         }
280         SwitchConfig switchConfig = switchManager.getSwitchConfig(node.toString());
281         Map<String, Property> nodeProperties = (switchConfig == null) ? new HashMap<String, Property>()
282                 : new HashMap<String, Property>(switchConfig.getNodeProperties());
283         nodeProperties.put(prop.getName(), prop);
284         SwitchConfig newSwitchConfig = new SwitchConfig(node.toString(), nodeProperties);
285         Status status = switchManager.updateNodeConfig(newSwitchConfig);
286         if (status.isSuccess()) {
287             return Response.status(Response.Status.CREATED).build();
288         }
289         return NorthboundUtils.getResponse(status);
290     }
291
292     /**
293      * Delete a property of a node
294      *
295      * @param containerName
296      *            Name of the Container (Eg. 'SliceRed')
297      * @param nodeType
298      *            Type of the node being programmed (Eg. 'OF')
299      * @param nodeId
300      *            Node Identifier as specified by
301      *            {@link org.opendaylight.controller.sal.core.Node}
302      *            (Eg. '00:00:00:00:00:03:01:02')
303      * @param propertyName
304      *            Name of the Property. Properties that can be deleted are
305      *            description, forwarding(only in default container) and tier.
306      * @return Response as dictated by the HTTP Response Status code
307      *
308      * <pre>
309      *
310      * Example:
311      *
312      * RequestURL:
313      * http://.../default/node/OF/00:00:00:00:00:00:00:03/property/forwarding
314      *
315      * </pre>
316      */
317
318     @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propertyName}")
319     @DELETE
320     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
321     @StatusCodes({
322             @ResponseCode(code = 200, condition = "Operation successful"),
323             @ResponseCode(code = 400, condition = "The nodeId or configuration is invalid"),
324             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
325             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
326             @ResponseCode(code = 409, condition = "Unable to delete property due to cluster conflict"),
327             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
328     public Response deleteNodeProperty(
329             @PathParam("containerName") String containerName,
330             @PathParam("nodeType") String nodeType,
331             @PathParam("nodeId") String nodeId,
332             @PathParam("propertyName") String propertyName) {
333
334         if (!isValidContainer(containerName)) {
335             throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
336         }
337         if (!NorthboundUtils.isAuthorized(
338                 getUserName(), containerName, Privilege.WRITE, this)) {
339             throw new UnauthorizedException(
340                     "User is not authorized to perform this operation on container "
341                             + containerName);
342         }
343         ISwitchManager switchManager = getIfSwitchManagerService(containerName);
344         if (switchManager == null) {
345             throw new ServiceUnavailableException("Switch Manager "
346                     + RestMessages.SERVICEUNAVAILABLE.toString());
347         }
348
349         handleNodeAvailability(containerName, nodeType, nodeId);
350         Node node = Node.fromString(nodeType, nodeId);
351
352         SwitchConfig switchConfig = switchManager.getSwitchConfig(node.toString());
353         Status status;
354         if (switchConfig == null) {
355             status = new Status(StatusCode.NOTFOUND, "Switch Configuration does not exist");
356         } else {
357             Map<String, Property> nodeProperties = new HashMap<String, Property>(switchConfig.getNodeProperties());
358             if (!nodeProperties.containsKey(propertyName.toLowerCase())) {
359                 String msg = "Property " + propertyName + " does not exist or not configured for switch " + nodeId;
360                 status = new Status(StatusCode.NOTFOUND, msg);
361             } else {
362                 nodeProperties.remove(propertyName.toLowerCase());
363                 SwitchConfig newSwitchConfig = new SwitchConfig(node.toString(), nodeProperties);
364                 status = switchManager.updateNodeConfig(newSwitchConfig);
365                 if(status.isSuccess()){
366                     NorthboundUtils.auditlog("Static Route", username, "updated", nodeId, containerName);
367                 }
368             }
369         }
370         return NorthboundUtils.getResponse(status);
371     }
372
373     /**
374      *
375      * Retrieve a list of all the nodeconnectors and their properties in a
376      * given node
377      *
378      * @param containerName
379      *            The container for which we want to retrieve the list (Eg.
380      *            'default')
381      * @param nodeType
382      *            Type of the node being programmed (Eg. 'OF')
383      * @param nodeId
384      *            Node Identifier as specified by
385      *            {@link org.opendaylight.controller.sal.core.Node} (Eg.
386      *            '00:00:00:00:00:00:00:03')
387      * @return A List of Pair each pair represents a
388      *         {@link org.opendaylight.controller.sal.core.NodeConnector} and
389      *         its corresponding
390      *         {@link org.opendaylight.controller.sal.core.Property} attached to
391      *         it.
392      *
393      * <pre>
394      *
395      * Example:
396      *
397      * RequestURL:
398      * http://.../default/node/OF/00:00:00:00:00:00:00:01
399      *
400      * Response in XML:
401      * &lt;list&gt;
402      *     &#x20;&#x20;&#x20;&lt;nodeConnectorProperties&gt;
403      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nodeconnector type="OF" id="2"&gt;
404      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;node type="OF" id="00:00:00:00:00:00:00:01"/&gt;
405      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/nodeconnector&gt;
406      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;properties&gt;
407      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;state&gt;
408      *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;1&lt;/value&gt;
409      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/state&gt;
410      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;config&gt;
411      *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;1&lt;/value&gt;
412      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/config&gt;
413      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;
414      *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;L1_2-C2_1&lt;/value&gt;
415      *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/name&gt;
416      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/properties&gt;
417      *     &#x20;&#x20;&#x20;&lt;/nodeConnectorProperties&gt;
418      * &lt;/list&gt;
419      *
420      * Response in JSON:
421      * {"nodeConnectorProperties":[{"nodeconnector":{"@type":"OF","@id":"2","node":{"@type":"OF","@id":"00:00:00:00:00:00:00:01"}},
422      * "properties":{"state":{"value":"1"},"config":{"value":"1"},"name":{"value":"L1_2-C2_1"}}}]}
423      *
424      * </pre>
425      */
426     @Path("/{containerName}/node/{nodeType}/{nodeId}")
427     @GET
428     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
429     @TypeHint(NodeConnectors.class)
430     @StatusCodes({
431             @ResponseCode(code = 200, condition = "Operation successful"),
432             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
433             @ResponseCode(code = 404, condition = "The containerName is not found"),
434             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
435     public NodeConnectors getNodeConnectors(
436             @PathParam("containerName") String containerName,
437             @PathParam("nodeType") String nodeType,
438             @PathParam("nodeId") String nodeId) {
439
440         if (!isValidContainer(containerName)) {
441             throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
442         }
443         if (!NorthboundUtils.isAuthorized(
444                 getUserName(), containerName, Privilege.READ, this)) {
445             throw new UnauthorizedException(
446                     "User is not authorized to perform this operation on container "
447                             + containerName);
448         }
449
450         ISwitchManager switchManager = getIfSwitchManagerService(containerName);
451         if (switchManager == null) {
452             throw new ServiceUnavailableException("Switch Manager "
453                     + RestMessages.SERVICEUNAVAILABLE.toString());
454         }
455
456         handleNodeAvailability(containerName, nodeType, nodeId);
457         Node node = Node.fromString(nodeType, nodeId);
458         List<NodeConnectorProperties> res = new ArrayList<NodeConnectorProperties>();
459         Set<NodeConnector> ncs = switchManager.getNodeConnectors(node);
460         if (ncs == null) {
461             return null;
462         }
463
464         for (NodeConnector nc : ncs) {
465             Map<String, Property> propMap = switchManager
466                     .getNodeConnectorProps(nc);
467             if (propMap == null) {
468                 continue;
469             }
470             Set<Property> props = new HashSet<Property>(propMap.values());
471             NodeConnectorProperties ncProps = new NodeConnectorProperties(nc,
472                     props);
473             res.add(ncProps);
474         }
475
476         return new NodeConnectors(res);
477     }
478
479     /**
480      * Add Bandwidth property to a node connector
481      *
482      * @param containerName
483      *            Name of the Container (Eg. 'default')
484      * @param nodeType
485      *            Type of the node being programmed (Eg. 'OF')
486      * @param nodeId
487      *            Node Identifier as specified by
488      *            {@link org.opendaylight.controller.sal.core.Node}
489      *            (Eg. '00:00:00:00:00:00:00:03')
490      * @param nodeConnectorType
491      *            Type of the node connector being programmed (Eg. 'OF')
492      * @param nodeConnectorId
493      *            NodeConnector Identifier as specified by
494      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
495      *            (Eg. '2')
496      * @param propertyName
497      *            Name of the Property specified by
498      *            {@link org.opendaylight.controller.sal.core.Property} and its
499      *            extended classes
500      *            Property that can be configured is bandwidth
501      * @param propertyValue
502      *            Value of the Property specified by
503      *            {@link org.opendaylight.controller.sal.core.Property} and its
504      *            extended classes
505      * @return Response as dictated by the HTTP Response Status code
506      *
507      * <pre>
508      *
509      * Example:
510      *
511      * RequestURL:
512      * http://.../default/nodeconnector/OF/00:00:00:00:00:00:00:01/OF/2/property/bandwidth/1
513      *
514      * </pre>
515      */
516
517     @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propertyName}/{propertyValue}")
518     @PUT
519     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
520     @StatusCodes({
521             @ResponseCode(code = 201, condition = "Operation successful"),
522             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
523             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
524             @ResponseCode(code = 409, condition = "Unable to add property due to cluster conflict"),
525             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
526     public Response addNodeConnectorProperty(
527             @PathParam("containerName") String containerName,
528             @PathParam("nodeType") String nodeType,
529             @PathParam("nodeId") String nodeId,
530             @PathParam("nodeConnectorType") String nodeConnectorType,
531             @PathParam("nodeConnectorId") String nodeConnectorId,
532             @PathParam("propertyName") String propertyName,
533             @PathParam("propertyValue") String propertyValue) {
534
535         if (!isValidContainer(containerName)) {
536             throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
537         }
538         if (!NorthboundUtils.isAuthorized(
539                 getUserName(), containerName, Privilege.WRITE, this)) {
540             throw new UnauthorizedException(
541                     "User is not authorized to perform this operation on container "
542                             + containerName);
543         }
544
545         ISwitchManager switchManager = getIfSwitchManagerService(containerName);
546         if (switchManager == null) {
547             throw new ServiceUnavailableException("Switch Manager "
548                     + RestMessages.SERVICEUNAVAILABLE.toString());
549         }
550
551         handleNodeAvailability(containerName, nodeType, nodeId);
552         Node node = Node.fromString(nodeType, nodeId);
553
554         handleNodeConnectorAvailability(containerName, node, nodeConnectorType,
555                 nodeConnectorId);
556         NodeConnector nc = NodeConnector
557                 .fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
558
559         Property prop = switchManager.createProperty(propertyName, propertyValue);
560         if (prop == null) {
561             throw new ResourceNotFoundException(
562                     RestMessages.INVALIDDATA.toString());
563         }
564
565         Status ret = switchManager.addNodeConnectorProp(nc, prop);
566         if (ret.isSuccess()) {
567             return Response.status(Response.Status.CREATED).build();
568         }
569         throw new InternalServerErrorException(ret.getDescription());
570     }
571
572     /**
573      * Delete a property of a node connector
574      *
575      * @param containerName
576      *            Name of the Container (Eg. 'default')
577      * @param nodeType
578      *            Type of the node being programmed (Eg. 'OF')
579      * @param nodeId
580      *            Node Identifier as specified by
581      *            {@link org.opendaylight.controller.sal.core.Node}
582      *            (Eg. '00:00:00:00:00:00:00:01')
583      * @param nodeConnectorType
584      *            Type of the node connector being programmed (Eg. 'OF')
585      * @param nodeConnectorId
586      *            NodeConnector Identifier as specified by
587      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
588      *            (Eg. '1')
589      * @param propertyName
590      *            Name of the Property specified by
591      *            {@link org.opendaylight.controller.sal.core.Property} and its
592      *            extended classes. Property that can be deleted is bandwidth
593      * @return Response as dictated by the HTTP Response Status code
594      *
595      * <pre>
596      *
597      * Example:
598      *
599      * RequestURL:
600      * http://.../default/nodeconnector/OF/00:00:00:00:00:00:00:01/OF/2/property/bandwidth
601      *
602      * </pre>
603      */
604
605     @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propertyName}")
606     @DELETE
607     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
608     @StatusCodes({
609             @ResponseCode(code = 200, condition = "Operation successful"),
610             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
611             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
612             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
613     public Response deleteNodeConnectorProperty(
614             @PathParam("containerName") String containerName,
615             @PathParam("nodeType") String nodeType,
616             @PathParam("nodeId") String nodeId,
617             @PathParam("nodeConnectorType") String nodeConnectorType,
618             @PathParam("nodeConnectorId") String nodeConnectorId,
619             @PathParam("propertyName") String propertyName) {
620
621         if (!isValidContainer(containerName)) {
622             throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
623         }
624         if (!NorthboundUtils.isAuthorized(
625                 getUserName(), containerName, Privilege.WRITE, this)) {
626             throw new UnauthorizedException(
627                     "User is not authorized to perform this operation on container "
628                             + containerName);
629         }
630
631         ISwitchManager switchManager = getIfSwitchManagerService(containerName);
632         if (switchManager == null) {
633             throw new ServiceUnavailableException("Switch Manager "
634                     + RestMessages.SERVICEUNAVAILABLE.toString());
635         }
636
637         handleNodeAvailability(containerName, nodeType, nodeId);
638         Node node = Node.fromString(nodeType, nodeId);
639
640         handleNodeConnectorAvailability(containerName, node, nodeConnectorType,
641                 nodeConnectorId);
642         NodeConnector nc = NodeConnector
643                 .fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
644         Status ret = switchManager.removeNodeConnectorProp(nc, propertyName);
645         if (ret.isSuccess()) {
646             NorthboundUtils.auditlog("Node Connector Property", username, "removed", nc + " from " + nodeConnectorId, containerName);
647             return Response.ok().build();
648         }
649         throw new ResourceNotFoundException(ret.getDescription());
650     }
651
652     /**
653      * Save the current switch configurations
654      *
655      * @param containerName
656      *            Name of the Container (Eg. 'default')
657      * @return Response as dictated by the HTTP Response Status code
658      *
659      * <pre>
660      *
661      * Example:
662      *
663      * RequestURL:
664      * http://.../default/switch-config
665      *
666      * </pre>
667      */
668     @Path("/{containerName}/switch-config")
669     @POST
670     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
671     @StatusCodes({
672             @ResponseCode(code = 200, condition = "Operation successful"),
673             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
674             @ResponseCode(code = 404, condition = "The containerName is not found"),
675             @ResponseCode(code = 500, condition = "Failed to save switch configuration. Failure Reason included in HTTP Error response"),
676             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
677     public Response saveSwitchConfig(
678             @PathParam("containerName") String containerName) {
679
680         if (!isValidContainer(containerName)) {
681             throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
682         }
683         if (!NorthboundUtils.isAuthorized(
684                 getUserName(), containerName, Privilege.WRITE, this)) {
685             throw new UnauthorizedException(
686                     "User is not authorized to perform this operation on container "
687                             + containerName);
688         }
689         ISwitchManager switchManager = getIfSwitchManagerService(containerName);
690         if (switchManager == null) {
691             throw new ServiceUnavailableException("Switch Manager "
692                     + RestMessages.SERVICEUNAVAILABLE.toString());
693         }
694
695         Status ret = switchManager.saveSwitchConfig();
696         if (ret.isSuccess()) {
697             return Response.ok().build();
698         }
699         throw new InternalServerErrorException(ret.getDescription());
700     }
701
702     private Node handleNodeAvailability(String containerName, String nodeType,
703             String nodeId) {
704
705         Node node = Node.fromString(nodeType, nodeId);
706         if (node == null) {
707             throw new ResourceNotFoundException(nodeId + " : "
708                     + RestMessages.NONODE.toString());
709         }
710
711         ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
712                 ISwitchManager.class, containerName, this);
713
714         if (sm == null) {
715             throw new ServiceUnavailableException("Switch Manager "
716                     + RestMessages.SERVICEUNAVAILABLE.toString());
717         }
718
719         if (!sm.getNodes().contains(node)) {
720             throw new ResourceNotFoundException(node.toString() + " : "
721                     + RestMessages.NONODE.toString());
722         }
723         return node;
724     }
725
726     private void handleNodeConnectorAvailability(String containerName,
727             Node node, String nodeConnectorType, String nodeConnectorId) {
728
729         NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType,
730                 nodeConnectorId, node);
731         if (nc == null) {
732             throw new ResourceNotFoundException(nc + " : "
733                     + RestMessages.NORESOURCE.toString());
734         }
735
736         ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
737                 ISwitchManager.class, containerName, this);
738
739         if (sm == null) {
740             throw new ServiceUnavailableException("Switch Manager "
741                     + RestMessages.SERVICEUNAVAILABLE.toString());
742         }
743
744         if (!sm.getNodeConnectors(node).contains(nc)) {
745             throw new ResourceNotFoundException(nc.toString() + " : "
746                     + RestMessages.NORESOURCE.toString());
747         }
748     }
749
750     private boolean isValidContainer(String containerName) {
751         if (containerName.equals(GlobalConstants.DEFAULT.toString())) {
752             return true;
753         }
754         IContainerManager containerManager = (IContainerManager) ServiceHelper
755                 .getGlobalInstance(IContainerManager.class, this);
756         if (containerManager == null) {
757             throw new InternalServerErrorException(
758                     RestMessages.INTERNALERROR.toString());
759         }
760         if (containerManager.getContainerNames().contains(containerName)) {
761             return true;
762        }
763         return false;
764     }
765
766 }