Merge "Refactor SubnetConfig"
[controller.git] / opendaylight / northbound / switchmanager / src / main / java / org / opendaylight / controller / switchmanager / northbound / SwitchNorthbound.java
index d3b023512bebd5790559b7e047b813e0558395e9..d88f9efa66ba66efc90fd8f3066cab26add96ccf 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.controller.switchmanager.northbound;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -26,6 +27,7 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.core.UriInfo;
 
 import org.codehaus.enunciate.jaxrs.ResponseCode;
 import org.codehaus.enunciate.jaxrs.StatusCodes;
@@ -33,7 +35,6 @@ import org.codehaus.enunciate.jaxrs.TypeHint;
 import org.opendaylight.controller.containermanager.IContainerManager;
 import org.opendaylight.controller.northbound.commons.RestMessages;
 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
-import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
@@ -45,7 +46,9 @@ import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
 import org.opendaylight.controller.switchmanager.ISwitchManager;
+import org.opendaylight.controller.switchmanager.SwitchConfig;
 
 /**
  * The class provides Northbound REST APIs to access the nodes, node connectors
@@ -60,7 +63,9 @@ public class SwitchNorthbound {
 
     @Context
     public void setSecurityContext(SecurityContext context) {
-        username = context.getUserPrincipal().getName();
+        if (context != null && context.getUserPrincipal() != null) {
+            username = context.getUserPrincipal().getName();
+        }
     }
 
     protected String getUserName() {
@@ -105,11 +110,60 @@ public class SwitchNorthbound {
      * Retrieve a list of all the nodes and their properties in the network
      *
      * @param containerName
-     *            The container for which we want to retrieve the list
+     *            Name of the Container (Eg. 'default')
      * @return A list of Pair each pair represents a
      *         {@link org.opendaylight.controller.sal.core.Node} and Set of
      *         {@link org.opendaylight.controller.sal.core.Property} attached to
      *         it.
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/switchmanager/default/nodes
+     *
+     * Response in XML:
+     * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
+     * &lt;list&gt;
+     *     &#x20;&#x20;&#x20;&lt;nodeProperties&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;node&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;id&gt;00:00:00:00:00:00:00:02&lt;/id&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;type&gt;OF&lt;/type&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/node&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;properties&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;tables&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;-1&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/tables&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;description&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;Switch2&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/description&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;actions&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;4095&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/actions&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;macAddress&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;00:00:00:00:00:02&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/macAddress&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;capabilities&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;199&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/capabilities&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;timeStamp&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;1377291227877&lt;/value&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;connectedSince&lt;/name&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/timeStamp&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;buffers&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;256&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/buffers&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/properties&gt;
+     *     &#x20;&#x20;&#x20;&lt;/nodeProperties&gt;
+     * &lt;/list&gt;
+     *
+     * Response in JSON:
+     * {"nodeProperties":[{"node":{"id":"00:00:00:00:00:00:00:02","type":"OF"},"properties":{"tables":{"value":"-1"},
+     * "description":{"value":"None"},"actions":{"value":"4095"},"macAddress":{"value":"00:00:00:00:00:02"},"capabilities"
+     * :{"value":"199"},"timeStamp":{"value":"1377291227877","name":"connectedSince"},"buffers":{"value":"256"}}}]}
+     *
+     * </pre>
      */
     @Path("/{containerName}/nodes")
     @GET
@@ -117,10 +171,15 @@ public class SwitchNorthbound {
     @TypeHint(Nodes.class)
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public Nodes getNodes(@PathParam("containerName") String containerName) {
 
+        if (!isValidContainer(containerName)) {
+            throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
+        }
+
         if (!NorthboundUtils.isAuthorized(
                 getUserName(), containerName, Privilege.READ, this)) {
             throw new UnauthorizedException(
@@ -137,7 +196,7 @@ public class SwitchNorthbound {
         List<NodeProperties> res = new ArrayList<NodeProperties>();
         Set<Node> nodes = switchManager.getNodes();
         if (nodes == null) {
-            return null;
+            return new Nodes(res);
         }
 
         for (Node node : nodes) {
@@ -155,49 +214,67 @@ public class SwitchNorthbound {
     }
 
     /**
-     * Add a Name/Tier property to a node
+     * Add a Description, Tier and Forwarding mode property to a node. This
+     * method returns a non-successful response if a node by that name already
+     * exists.
      *
      * @param containerName
-     *            Name of the Container
+     *            Name of the Container (Eg. 'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
      *            Node Identifier as specified by
-     *            {@link org.opendaylight.controller.sal.core.Node}
-     * @param propName
-     *            Name of the Property specified by
-     *            {@link org.opendaylight.controller.sal.core.Property} and its
-     *            extended classes
-     * @param propValue
-     *            Value of the Property specified by
-     *            {@link org.opendaylight.controller.sal.core.Property} and its
-     *            extended classes
+     *            {@link org.opendaylight.controller.sal.core.Node} (Eg.
+     *            '00:00:00:00:00:00:00:03')
+     * @param propertyName
+     *            Name of the Property. Properties that can be configured are:
+     *            description, forwarding(only for default container) and tier
+     * @param propertyValue
+     *            Value of the Property. Description can be any string (Eg.
+     *            'Node1'), valid values for tier are non negative numbers, and
+     *            valid values for forwarding are 0 for reactive and 1 for
+     *            proactive forwarding.
      * @return Response as dictated by the HTTP Response Status code
+     *
+     *         <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/switchmanager/default/node/OF/00:00:00:00:00:00:00:03/property/description/Switch3
+     *
+     * </pre>
      */
 
-    @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propName}/{propValue}")
+    @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propertyName}/{propertyValue}")
     @PUT
     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @TypeHint(Response.class)
     @StatusCodes({
-            @ResponseCode(code = 200, condition = "Operation successful"),
-            @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
+            @ResponseCode(code = 201, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "The nodeId or configuration is invalid"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
+            @ResponseCode(code = 404, condition = "The Container Name or node or configuration name is not found"),
+            @ResponseCode(code = 406, condition = "The property cannot be configured in non-default container"),
+            @ResponseCode(code = 409, condition = "Unable to update configuration due to cluster conflict or conflicting description property"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
     public Response addNodeProperty(
+            @Context UriInfo uriInfo,
             @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
             @PathParam("nodeId") String nodeId,
-            @PathParam("propName") String propName,
-            @PathParam("propValue") String propValue) {
+            @PathParam("propertyName") String propertyName,
+            @PathParam("propertyValue") String propertyValue) {
 
+        if (!isValidContainer(containerName)) {
+            throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
+        }
         if (!NorthboundUtils.isAuthorized(
                 getUserName(), containerName, Privilege.WRITE, this)) {
             throw new UnauthorizedException(
                     "User is not authorized to perform this operation on container "
                             + containerName);
         }
-        handleDefaultDisabled(containerName);
-
         ISwitchManager switchManager = getIfSwitchManagerService(containerName);
         if (switchManager == null) {
             throw new ServiceUnavailableException("Switch Manager "
@@ -206,40 +283,57 @@ public class SwitchNorthbound {
 
         handleNodeAvailability(containerName, nodeType, nodeId);
         Node node = Node.fromString(nodeType, nodeId);
-
-        Property prop = switchManager.createProperty(propName, propValue);
+        Property prop = switchManager.createProperty(propertyName, propertyValue);
         if (prop == null) {
-            throw new ResourceNotFoundException(
-                    RestMessages.INVALIDDATA.toString());
-        }
-
-        switchManager.setNodeProp(node, prop);
-        return Response.status(Response.Status.CREATED).build();
+            throw new ResourceNotFoundException("Property with name " + propertyName + " does not exist.");
+        }
+        SwitchConfig switchConfig = switchManager.getSwitchConfig(node.toString());
+        Map<String, Property> nodeProperties = (switchConfig == null) ? new HashMap<String, Property>()
+                : new HashMap<String, Property>(switchConfig.getNodeProperties());
+        nodeProperties.put(prop.getName(), prop);
+        SwitchConfig newSwitchConfig = new SwitchConfig(node.toString(), nodeProperties);
+        Status status = switchManager.updateNodeConfig(newSwitchConfig);
+        if (status.isSuccess()) {
+            return Response.created(uriInfo.getRequestUri()).build();
+        }
+        return NorthboundUtils.getResponse(status);
     }
 
     /**
      * Delete a property of a node
      *
      * @param containerName
-     *            Name of the Container
+     *            Name of the Container (Eg. 'SliceRed')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
      *            Node Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.Node}
+     *            (Eg. '00:00:00:00:00:03:01:02')
      * @param propertyName
-     *            Name of the Property specified by
-     *            {@link org.opendaylight.controller.sal.core.Property} and its
-     *            extended classes
+     *            Name of the Property. Properties that can be deleted are
+     *            description, forwarding(only in default container) and tier.
      * @return Response as dictated by the HTTP Response Status code
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/switchmanager/default/node/OF/00:00:00:00:00:00:00:03/property/forwarding
+     *
+     * </pre>
      */
 
     @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propertyName}")
     @DELETE
     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes({
-            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 204, condition = "Property removed successfully"),
+            @ResponseCode(code = 400, condition = "The nodeId or configuration is invalid"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
+            @ResponseCode(code = 409, condition = "Unable to delete property due to cluster conflict"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
     public Response deleteNodeProperty(
             @PathParam("containerName") String containerName,
@@ -247,14 +341,15 @@ public class SwitchNorthbound {
             @PathParam("nodeId") String nodeId,
             @PathParam("propertyName") String propertyName) {
 
+        if (!isValidContainer(containerName)) {
+            throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
+        }
         if (!NorthboundUtils.isAuthorized(
                 getUserName(), containerName, Privilege.WRITE, this)) {
             throw new UnauthorizedException(
                     "User is not authorized to perform this operation on container "
                             + containerName);
         }
-        handleDefaultDisabled(containerName);
-
         ISwitchManager switchManager = getIfSwitchManagerService(containerName);
         if (switchManager == null) {
             throw new ServiceUnavailableException("Switch Manager "
@@ -263,30 +358,87 @@ public class SwitchNorthbound {
 
         handleNodeAvailability(containerName, nodeType, nodeId);
         Node node = Node.fromString(nodeType, nodeId);
-        Status ret = switchManager.removeNodeProp(node, propertyName);
-        if (ret.isSuccess()) {
-            return Response.ok().build();
+
+        SwitchConfig switchConfig = switchManager.getSwitchConfig(node.toString());
+        Status status;
+        if (switchConfig == null) {
+            status = new Status(StatusCode.NOTFOUND, "Switch Configuration does not exist");
+        } else {
+            Map<String, Property> nodeProperties = new HashMap<String, Property>(switchConfig.getNodeProperties());
+            if (!nodeProperties.containsKey(propertyName.toLowerCase())) {
+                String msg = "Property " + propertyName + " does not exist or not configured for switch " + nodeId;
+                status = new Status(StatusCode.NOTFOUND, msg);
+            } else {
+                nodeProperties.remove(propertyName.toLowerCase());
+                SwitchConfig newSwitchConfig = new SwitchConfig(node.toString(), nodeProperties);
+                status = switchManager.updateNodeConfig(newSwitchConfig);
+                if(status.isSuccess()){
+                    NorthboundUtils.auditlog("Node Property", username, "removed", propertyName  + " from " + nodeId, containerName);
+                    return Response.noContent().build();
+                }
+            }
         }
-        throw new ResourceNotFoundException(ret.getDescription());
+        return NorthboundUtils.getResponse(status);
     }
 
     /**
      *
-     * Retrieve a list of all the node connectors and their properties in a
-     * given node
+     * Retrieve a list of all the nodeconnectors and their properties in a given
+     * node
      *
      * @param containerName
-     *            The container for which we want to retrieve the list
+     *            The container for which we want to retrieve the list (Eg.
+     *            'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
      *            Node Identifier as specified by
-     *            {@link org.opendaylight.controller.sal.core.Node}
+     *            {@link org.opendaylight.controller.sal.core.Node} (Eg.
+     *            '00:00:00:00:00:00:00:03')
      * @return A List of Pair each pair represents a
      *         {@link org.opendaylight.controller.sal.core.NodeConnector} and
      *         its corresponding
      *         {@link org.opendaylight.controller.sal.core.Property} attached to
      *         it.
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/switchmanager/default/node/OF/00:00:00:00:00:00:00:01
+     *
+     * Response in XML:
+     * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
+     * &lt;list&gt;
+     *     &#x20;&#x20;&#x20;&lt;nodeConnectorProperties&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nodeconnector&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;node&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;id&gt;00:00:00:00:00:00:00:01&lt;/id&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;type&gt;OF&lt;/type&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/node&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;id&gt;2&lt;/id&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;type&gt;OF&lt;/type&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/nodeconnector&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;properties&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;state&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;1&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/state&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;config&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;1&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/config&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;
+     *                 &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;value&gt;L1_2-C2_1&lt;/value&gt;
+     *             &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/name&gt;
+     *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/properties&gt;
+     *     &#x20;&#x20;&#x20;&lt;/nodeConnectorProperties&gt;
+     * &lt;/list&gt;
+     *
+     * Response in JSON:
+     * {"nodeConnectorProperties":[{"nodeconnector":{"node":{"id":"00:00:00:00:00:00:00:01","type":"OF"},"id":"2","type":"OF"},
+     * "properties":{"state":{"value":"1"},"config":{"value":"1"},"name":{"value":"L1_2-C2_1"}}}]}
+     *
+     * </pre>
      */
     @Path("/{containerName}/node/{nodeType}/{nodeId}")
     @GET
@@ -294,6 +446,7 @@ public class SwitchNorthbound {
     @TypeHint(NodeConnectors.class)
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public NodeConnectors getNodeConnectors(
@@ -301,6 +454,9 @@ public class SwitchNorthbound {
             @PathParam("nodeType") String nodeType,
             @PathParam("nodeId") String nodeId) {
 
+        if (!isValidContainer(containerName)) {
+            throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
+        }
         if (!NorthboundUtils.isAuthorized(
                 getUserName(), containerName, Privilege.READ, this)) {
             throw new UnauthorizedException(
@@ -338,47 +494,67 @@ public class SwitchNorthbound {
     }
 
     /**
-     * Add a Name/Bandwidth property to a node connector
+     * Add node-connector property to a node connector. This method returns a
+     * non-successful response if a node connector by the given name already
+     * exists.
      *
      * @param containerName
-     *            Name of the Container
+     *            Name of the Container (Eg. 'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
      *            Node Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.Node}
+     *            (Eg. '00:00:00:00:00:00:00:03')
      * @param nodeConnectorType
-     *            Type of the node connector being programmed
+     *            Type of the node connector being programmed (Eg. 'OF')
      * @param nodeConnectorId
      *            NodeConnector Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
-     * @param propName
+     *            (Eg. '2')
+     * @param propertyName
      *            Name of the Property specified by
      *            {@link org.opendaylight.controller.sal.core.Property} and its
      *            extended classes
-     * @param propValue
+     *            Property that can be configured is bandwidth
+     * @param propertyValue
      *            Value of the Property specified by
      *            {@link org.opendaylight.controller.sal.core.Property} and its
      *            extended classes
      * @return Response as dictated by the HTTP Response Status code
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/switchmanager/default/nodeconnector/OF/00:00:00:00:00:00:00:01/OF/2/property/bandwidth/1
+     *
+     * </pre>
      */
 
-    @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propName}/{propValue}")
+    @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propertyName}/{propertyValue}")
     @PUT
     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes({
-            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 201, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
+            @ResponseCode(code = 409, condition = "Unable to add property due to cluster conflict"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
     public Response addNodeConnectorProperty(
+            @Context UriInfo uriInfo,
             @PathParam("containerName") String containerName,
             @PathParam("nodeType") String nodeType,
             @PathParam("nodeId") String nodeId,
             @PathParam("nodeConnectorType") String nodeConnectorType,
             @PathParam("nodeConnectorId") String nodeConnectorId,
-            @PathParam("propName") String propName,
-            @PathParam("propValue") String propValue) {
+            @PathParam("propertyName") String propertyName,
+            @PathParam("propertyValue") String propertyValue) {
 
+        if (!isValidContainer(containerName)) {
+            throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
+        }
         if (!NorthboundUtils.isAuthorized(
                 getUserName(), containerName, Privilege.WRITE, this)) {
             throw new UnauthorizedException(
@@ -386,8 +562,6 @@ public class SwitchNorthbound {
                             + containerName);
         }
 
-        handleDefaultDisabled(containerName);
-
         ISwitchManager switchManager = getIfSwitchManagerService(containerName);
         if (switchManager == null) {
             throw new ServiceUnavailableException("Switch Manager "
@@ -402,7 +576,7 @@ public class SwitchNorthbound {
         NodeConnector nc = NodeConnector
                 .fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
 
-        Property prop = switchManager.createProperty(propName, propValue);
+        Property prop = switchManager.createProperty(propertyName, propertyValue);
         if (prop == null) {
             throw new ResourceNotFoundException(
                     RestMessages.INVALIDDATA.toString());
@@ -410,7 +584,7 @@ public class SwitchNorthbound {
 
         Status ret = switchManager.addNodeConnectorProp(nc, prop);
         if (ret.isSuccess()) {
-            return Response.status(Response.Status.CREATED).build();
+            return Response.created(uriInfo.getRequestUri()).build();
         }
         throw new InternalServerErrorException(ret.getDescription());
     }
@@ -419,29 +593,41 @@ public class SwitchNorthbound {
      * Delete a property of a node connector
      *
      * @param containerName
-     *            Name of the Container
+     *            Name of the Container (Eg. 'default')
      * @param nodeType
-     *            Type of the node being programmed
+     *            Type of the node being programmed (Eg. 'OF')
      * @param nodeId
      *            Node Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.Node}
+     *            (Eg. '00:00:00:00:00:00:00:01')
      * @param nodeConnectorType
-     *            Type of the node connector being programmed
+     *            Type of the node connector being programmed (Eg. 'OF')
      * @param nodeConnectorId
      *            NodeConnector Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
+     *            (Eg. '1')
      * @param propertyName
      *            Name of the Property specified by
      *            {@link org.opendaylight.controller.sal.core.Property} and its
-     *            extended classes
+     *            extended classes. Property that can be deleted is bandwidth
      * @return Response as dictated by the HTTP Response Status code
+     *
+     * <pre>
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/switchmanager/default/nodeconnector/OF/00:00:00:00:00:00:00:01/OF/2/property/bandwidth
+     *
+     * </pre>
      */
 
     @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propertyName}")
     @DELETE
     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes({
-            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 204, condition = "Property removed successfully"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
     public Response deleteNodeConnectorProperty(
@@ -452,6 +638,9 @@ public class SwitchNorthbound {
             @PathParam("nodeConnectorId") String nodeConnectorId,
             @PathParam("propertyName") String propertyName) {
 
+        if (!isValidContainer(containerName)) {
+            throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
+        }
         if (!NorthboundUtils.isAuthorized(
                 getUserName(), containerName, Privilege.WRITE, this)) {
             throw new UnauthorizedException(
@@ -459,8 +648,6 @@ public class SwitchNorthbound {
                             + containerName);
         }
 
-        handleDefaultDisabled(containerName);
-
         ISwitchManager switchManager = getIfSwitchManagerService(containerName);
         if (switchManager == null) {
             throw new ServiceUnavailableException("Switch Manager "
@@ -476,134 +663,43 @@ public class SwitchNorthbound {
                 .fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
         Status ret = switchManager.removeNodeConnectorProp(nc, propertyName);
         if (ret.isSuccess()) {
-            return Response.ok().build();
+            NorthboundUtils.auditlog("Node Connector Property", username, "removed", nc + " from " + nodeConnectorId, containerName);
+            return Response.noContent().build();
         }
         throw new ResourceNotFoundException(ret.getDescription());
     }
 
-    /*    *//**
-     * Retrieve a list of Span ports that were configured previously.
-     *
-     * @param containerName
-     *            Name of the Container
-     * @return list of
-     *         {@link org.opendaylight.controller.switchmanager.SpanConfig}
-     *         resources
-     */
-    /*
-     * @Path("/span-config/{containerName}")
-     *
-     * @GET
-     *
-     * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-     *
-     * @StatusCodes( {
-     *
-     * @ResponseCode(code = 200, condition = "Operation successful"),
-     *
-     * @ResponseCode(code = 404, condition = "The containerName is not found"),
-     *
-     * @ResponseCode(code = 503, condition =
-     * "One or more of Controller Services are unavailable") }) public
-     * List<SpanConfig> getSpanConfigList(@PathParam("containerName") String
-     * containerName) { ISwitchManager switchManager = (ISwitchManager)
-     * getIfSwitchManagerService(containerName); if (switchManager == null) {
-     * throw new ServiceUnavailableException("Switch Manager " +
-     * RestMessages.SERVICEUNAVAILABLE.toString()); }
-     *
-     * return switchManager.getSpanConfigList(); }
-     *//**
-     * Add a span configuration
-     *
-     * @param containerName
-     *            Name of the Container
-     * @param config
-     *            {@link org.opendaylight.controller.switchmanager.SpanConfig}
-     *            in JSON or XML format
-     * @return Response as dictated by the HTTP Response Status code
-     */
-    /*
-     * @Path("/span-config/{containerName}")
-     *
-     * @PUT
-     *
-     * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
-     *
-     * @StatusCodes( {
-     *
-     * @ResponseCode(code = 200, condition = "Operation successful"),
-     *
-     * @ResponseCode(code = 404, condition = "The containerName is not found"),
-     *
-     * @ResponseCode(code = 503, condition =
-     * "One or more of Controller Services are unavailable") }) public Response
-     * addSpanConfig(@PathParam("containerName") String containerName,
-     *
-     * @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
-     * ISwitchManager switchManager = (ISwitchManager)
-     * getIfSwitchManagerService(containerName); if (switchManager == null) {
-     * throw new ServiceUnavailableException("Switch Manager " +
-     * RestMessages.SERVICEUNAVAILABLE.toString()); }
-     *
-     * String ret = switchManager.addSpanConfig(config.getValue()); if
-     * (ret.equals(ReturnString.SUCCESS.toString())) { return
-     * Response.status(Response.Status.CREATED).build(); } throw new
-     * InternalServerErrorException(ret); }
-     *//**
-     * Delete a span configuration
+    /**
+     * Save the current switch configurations
      *
      * @param containerName
-     *            Name of the Container
-     * @param config
-     *            {@link org.opendaylight.controller.switchmanager.SpanConfig}
-     *            in JSON or XML format
+     *            Name of the Container (Eg. 'default')
      * @return Response as dictated by the HTTP Response Status code
-     */
-    /*
-     * @Path("/span-config/{containerName}")
-     *
-     * @DELETE
      *
-     * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+     * <pre>
      *
-     * @StatusCodes( {
+     * Example:
      *
-     * @ResponseCode(code = 200, condition = "Operation successful"),
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/switchmanager/default/save
      *
-     * @ResponseCode(code = 404, condition = "The containerName is not found"),
-     *
-     * @ResponseCode(code = 503, condition =
-     * "One or more of Controller Services are unavailable") }) public Response
-     * deleteSpanConfig(@PathParam("containerName") String containerName,
-     *
-     * @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
-     * ISwitchManager switchManager = (ISwitchManager)
-     * getIfSwitchManagerService(containerName); if (switchManager == null) {
-     * throw new ServiceUnavailableException("Switch Manager " +
-     * RestMessages.SERVICEUNAVAILABLE.toString()); }
-     *
-     * String ret = switchManager.removeSpanConfig(config.getValue()); if
-     * (ret.equals(ReturnString.SUCCESS.toString())) { return
-     * Response.ok().build(); } throw new ResourceNotFoundException(ret); }
+     * </pre>
      */
-
-    /**
-     * Save the current switch configurations
-     *
-     * @param containerName
-     *            Name of the Container
-     * @return Response as dictated by the HTTP Response Status code
-     */
-    @Path("/{containerName}/switch-config")
+    @Path("/{containerName}/save")
     @POST
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
     @StatusCodes({
             @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
             @ResponseCode(code = 404, condition = "The containerName is not found"),
+            @ResponseCode(code = 500, condition = "Failed to save switch configuration. Failure Reason included in HTTP Error response"),
             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
     public Response saveSwitchConfig(
             @PathParam("containerName") String containerName) {
 
+        if (!isValidContainer(containerName)) {
+            throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
+        }
         if (!NorthboundUtils.isAuthorized(
                 getUserName(), containerName, Privilege.WRITE, this)) {
             throw new UnauthorizedException(
@@ -623,20 +719,6 @@ public class SwitchNorthbound {
         throw new InternalServerErrorException(ret.getDescription());
     }
 
-    private void handleDefaultDisabled(String containerName) {
-        IContainerManager containerManager = (IContainerManager) ServiceHelper
-                .getGlobalInstance(IContainerManager.class, this);
-        if (containerManager == null) {
-            throw new InternalServerErrorException(
-                    RestMessages.INTERNALERROR.toString());
-        }
-        if (containerName.equals(GlobalConstants.DEFAULT.toString())
-                && containerManager.hasNonDefaultContainer()) {
-            throw new ResourceConflictException(
-                    RestMessages.DEFAULTDISABLED.toString());
-        }
-    }
-
     private Node handleNodeAvailability(String containerName, String nodeType,
             String nodeId) {
 
@@ -685,4 +767,20 @@ public class SwitchNorthbound {
         }
     }
 
+    private boolean isValidContainer(String containerName) {
+        if (containerName.equals(GlobalConstants.DEFAULT.toString())) {
+            return true;
+        }
+        IContainerManager containerManager = (IContainerManager) ServiceHelper
+                .getGlobalInstance(IContainerManager.class, this);
+        if (containerManager == null) {
+            throw new InternalServerErrorException(
+                    RestMessages.INTERNALERROR.toString());
+        }
+        if (containerManager.getContainerNames().contains(containerName)) {
+            return true;
+       }
+        return false;
+    }
+
 }