refactoring of rest intents

Change-Id: I6b1a9710693eecc95001873218d386bf7decb858
diff --git a/src/main/java/net/onrc/onos/datagrid/web/IntentResource.java b/src/main/java/net/onrc/onos/datagrid/web/IntentResource.java
index 416ab76..0d50865 100755
--- a/src/main/java/net/onrc/onos/datagrid/web/IntentResource.java
+++ b/src/main/java/net/onrc/onos/datagrid/web/IntentResource.java
@@ -5,11 +5,12 @@
 package net.onrc.onos.datagrid.web;
 
 import java.io.IOException;
-import java.util.Collection;
 import java.util.Iterator;
 import net.onrc.onos.datagrid.IDatagridService;
 import net.onrc.onos.intent.ConstrainedShortestPathIntent;
 import net.onrc.onos.intent.ShortestPathIntent;
+import net.onrc.onos.intent.IntentOperation;
+import net.onrc.onos.intent.IntentMap;
 import net.onrc.onos.ofcontroller.networkgraph.INetworkGraphService;
 import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
 import net.onrc.onos.registry.controller.IControllerRegistryService;
@@ -20,39 +21,67 @@
 import org.restlet.resource.Post;
 import org.restlet.resource.ServerResource;
 import org.codehaus.jackson.map.ObjectMapper;
-import org.slf4j.LoggerFactory;
 import net.floodlightcontroller.util.MACAddress;
-import net.onrc.onos.ofcontroller.networkgraph.Port;
-import net.onrc.onos.ofcontroller.networkgraph.Switch;
 import com.esotericsoftware.kryo.Kryo;
-import com.esotericsoftware.kryo.io.Input;
 import com.esotericsoftware.kryo.io.Output;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import org.codehaus.jackson.node.ArrayNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * 
  * @author nickkaranatsios
  */
 public class IntentResource extends ServerResource {
-
-    private final static org.slf4j.Logger log = LoggerFactory
-	    .getLogger(IntentResource.class);
+    private final static Logger log = LoggerFactory.getLogger(IntentResource.class);
     private final String sep = ":";
     private IdBlock idBlock = null;
     private long nextIdBlock = 0;
 
+    private class IntentStatus {
+        String intentId;
+        boolean status;
+        
+        public IntentStatus() {}
+        
+        public IntentStatus(String intentId, boolean status) {
+            this.intentId = intentId;
+            this.status = status;
+        }
+        
+        public String getIntentId() {
+            return intentId;
+        }
+        
+        public void setIntentId(String intentId) {
+            this.intentId = intentId;
+        }
+        
+        public boolean getStatus() {
+            return status;
+        }
+        
+        public void setStatus(boolean status) {
+            this.status = status;
+        }
+    }
+    
     @Post("json")
-    public void store(String jsonFlowIntent) {
+    public String store(String jsonFlowIntent) throws IOException {
 	IDatagridService datagridService = (IDatagridService) getContext()
 		.getAttributes().get(IDatagridService.class.getCanonicalName());
 	if (datagridService == null) {
 	    log.debug("FlowIntentResource ONOS Datagrid Service not found");
-	    return;
+	    return "";
 	}
 	INetworkGraphService networkGraphService = (INetworkGraphService) getContext()
 		.getAttributes().get(
 			INetworkGraphService.class.getCanonicalName());
 	NetworkGraph graph = networkGraphService.getNetworkGraph();
-
+        String reply = "";
 	ObjectMapper mapper = new ObjectMapper();
 	JsonNode jNode = null;
 	try {
@@ -68,84 +97,99 @@
 
 	if (jNode != null) {
 	    Kryo kryo = new Kryo();
-	    parseJsonNode(kryo, jNode.getElements(), datagridService);
+	    reply = parseJsonNode(kryo, jNode.getElements(), datagridService);
 	    // datagridService.registerIntent(intents);
 	}
+        return reply;
     }
 
-    private void parseJsonNode(Kryo kryo, Iterator<JsonNode> nodes,
-	    IDatagridService datagridService) {
-	StringBuilder sb = new StringBuilder();
-	sb.ensureCapacity(256);
-
+    private String parseJsonNode(Kryo kryo, Iterator<JsonNode> nodes,
+	    IDatagridService datagridService) throws IOException {
+        LinkedList<IntentOperation> operations = new LinkedList<>();
+        ObjectMapper mapper = new ObjectMapper();
+        ArrayNode arrayNode = mapper.createArrayNode();
 	while (nodes.hasNext()) {
 	    JsonNode node = nodes.next();
 	    if (node.isObject()) {
-		JsonNode data = null;
+		JsonNode data;
 		Iterator<String> fieldNames = node.getFieldNames();
-		String intentId = null;
-		String pathTypeName = null;
-		long srcSwitch = 0, dstSwitch = 0;
-		String srcMac = null, dstMac = null;
-		long srcPort = 0, dstPort = 0;
-		Double bandwidth = null;
+                Map<String, Object> fields = new HashMap<>();
 		while (fieldNames.hasNext()) {
 		    String fieldName = fieldNames.next();
 		    data = node.get(fieldName);
-		    if (fieldName.equals("type")) {
-			if (data != null) {
-			    System.out.println("type is not null "
-				    + data.getTextValue());
-			    // uuid = setPathIntentId();
-			    pathTypeName = data.getTextValue();
-			    setPathIntentType(pathTypeName, sb);
-			}
-		    } else if (fieldName.equals("intentId")) {
-			intentId = data.getTextValue();
-		    } else if (fieldName.equals("srcSwitch")) {
-			srcSwitch = Long.decode(data.getTextValue());
-		    } else if (fieldName.equals("dstSwitch")) {
-			dstSwitch = Long.decode(data.getTextValue());
-		    } else if (fieldName.equals("srcMac")) {
-			srcMac = data.getTextValue();
-		    } else if (fieldName.equals("dstMac")) {
-			dstMac = data.getTextValue();
-		    } else if (fieldName.equals("srcPort")) {
-			srcPort = data.getLongValue();
-		    } else if (fieldName.equals("dstPort")) {
-			dstPort = data.getLongValue();
-		    } else if (fieldName.equals("bandwidth")) {
-			bandwidth = data.getDoubleValue();
-		    }
+                    parseFields(data, fieldName, fields);
 		}
-		if (pathTypeName.equals("shortest-path")) {
-		    ShortestPathIntent spi = new ShortestPathIntent(intentId, 
-                            srcSwitch, 
-                            srcPort, 
-                            MACAddress.valueOf(srcMac).toLong(), 
-                            dstSwitch, 
-                            dstPort,
-			    MACAddress.valueOf(dstMac).toLong());
-		    sb.append(toBytes(kryo, spi));
-
-		} else {
-		    ConstrainedShortestPathIntent cspi = new ConstrainedShortestPathIntent(intentId, 
-                            srcSwitch, 
-                            srcPort, 
-                            MACAddress.valueOf(srcMac).toLong(), dstSwitch,
-			    dstPort, MACAddress.valueOf(dstMac).toLong(),
-			    bandwidth);
-		    sb.append(toBytes(kryo, cspi));
-
-		}
-		System.out.println("constructed node " + sb.toString());
+                System.out.println("recv fields " + fields);
+                boolean status = processIntent(fields, operations);
+                appendIntentStatus(status, (String)fields.get("intent_id"), mapper, arrayNode);
 		// datagridService.registerIntent(Long.toString(uuid),
 		// sb.toString().getBytes());
-		sb.delete(0, sb.length());
 	    }
 	}
+        IntentMap intents = new IntentMap();
+        intents.executeOperations(operations);
+        return mapper.writeValueAsString(arrayNode);
+        
     }
 
+    private void appendIntentStatus(boolean status, final String applnIntentId, 
+            ObjectMapper mapper, ArrayNode arrayNode) throws IOException {
+        String intentId = applnIntentId.split(":")[1];
+        String boolStr = Boolean.TRUE.toString();
+        if (status == false) {
+            boolStr = Boolean.FALSE.toString();
+        }
+        String jsonString = "{\"intent_id\":" + intentId + "," + "\"status\":" + boolStr + "}";
+        JsonNode parsedNode = mapper.readValue(jsonString, JsonNode.class);
+        arrayNode.add(parsedNode);
+    }
+    
+    private boolean processIntent(Map<String, Object> fields, LinkedList<IntentOperation> operations) {
+        String intentType = (String)fields.get("intent_type");
+        boolean status = false;
+        
+        if (intentType.equals("shortest_intent_type")) {
+            ShortestPathIntent spi = new ShortestPathIntent((String) fields.get("intent_id"),
+                    Long.decode((String) fields.get("srcSwitch")),
+                    (long) fields.get("srcPort"),
+                    MACAddress.valueOf((String) fields.get("srcMac")).toLong(),
+                    Long.decode((String) fields.get("dstSwitch")),
+                    (long) fields.get("dstPort"),
+                    MACAddress.valueOf((String) fields.get("dstMac")).toLong());
+            operations.add(new IntentOperation(IntentOperation.Operator.ADD, spi));
+            status = true;
+        } else {
+            ConstrainedShortestPathIntent cspi = new ConstrainedShortestPathIntent((String) fields.get("intent_id"),
+                    Long.decode((String) fields.get("srcSwitch")),
+                    (long) fields.get("srcPort"),
+                    MACAddress.valueOf((String) fields.get("srcMac")).toLong(),
+                    Long.decode((String) fields.get("dstSwitch")),
+                    (long) fields.get("dstPort"),
+                    MACAddress.valueOf((String) fields.get("dstMac")).toLong(),
+                    (double) fields.get("bandwidth"));
+            operations.add(new IntentOperation(IntentOperation.Operator.ADD, cspi));
+            status = true;
+        }
+        return status;
+    }
+
+    private void parseFields(JsonNode node, String fieldName, Map<String, Object> fields) {
+        if ((node.isTextual())) {
+            System.out.println("textual fieldname = " + fieldName);
+            fields.put(fieldName, node.getTextValue());
+        } else if ((node.isInt())) {
+            System.out.println("int fieldname = " + fieldName);
+            fields.put(fieldName, (long)node.getIntValue());
+        } else if (node.isDouble()) {
+            System.out.println("double fieldname = " + fieldName);
+            fields.put(fieldName, node.getDoubleValue());
+        } else if ((node.isLong())) {
+            System.out.println("long fieldname = " + fieldName);
+            fields.put(fieldName, node.getLongValue());
+        }
+    }
+    
+    @Deprecated
     private long setPathIntentId() {
 	long uuid = 0;
 	if (idBlock == null || nextIdBlock + 1 == idBlock.getSize()) {
@@ -164,12 +208,13 @@
 	return uuid;
     }
 
-    private void setPathIntentType(final String pathIntentType, StringBuilder sb) {
+    @Deprecated
+    private void setIntentType(final String intentType, StringBuilder sb) {
 	String canonicalName = null;
-	if (pathIntentType.equals("shortest-path")) {
+	if (intentType.equals("shortest-path")) {
 	    canonicalName = ShortestPathIntent.class.getCanonicalName();
 	    sb.append(ShortestPathIntent.class.getCanonicalName());
-	} else if (pathIntentType.equals("constrained-shortest-path")) {
+	} else if (intentType.equals("constrained-shortest-path")) {
 	    canonicalName = ShortestPathIntent.class.getCanonicalName();
 	}
 	sb.append(canonicalName);
@@ -181,6 +226,7 @@
 		IControllerRegistryService.class.getCanonicalName());
     }
 
+    @Deprecated
     private byte[] toBytes(Kryo kryo, Object value) {
 	Output output = new Output(1024);
         kryo.writeObject(output, value);
diff --git a/web/add-intent.rb b/web/add-intent.rb
index 1b480b3..b1d8dfd 100644
--- a/web/add-intent.rb
+++ b/web/add-intent.rb
@@ -1,8 +1,7 @@
 require "rest-client"
 require "optparse"
 
-
-options = { :intent_id => 123, :path_intent => "shortest_path_intent", :max_switches => 4 }
+options = { :intent_id => 123, :intent_type => "shortest_intent_type", :max_switches => 4 }
 
 parser = OptionParser.new do |opts|
   opts.banner = "Usage add-intent [options]"
@@ -10,19 +9,19 @@
     options[:max_intents] = max_intents
   end
   opts.on('-a', '--application application_id', 'set application id') do |appl_id|
-    options[:application_id] = appl_id
+    options[:application_id] = appl_id.to_i
   end
   opts.on('-i', '--intent_id intent_id', 'global intent id') do |id|
-    options[:intent_id] = id
+    options[:intent_id] = id.to_i
   end
-  opts.on('-s', '--shortest path intent', 'create a shortest path intent') do
-    options[:path_intent] = "shortest_path_intent"
+  opts.on('-s', '--shortest', 'create a shortest path intent') do
+    options[:intent_type] = "shortest_intent_type"
   end
-  opts.on('-c', '--constrained shortest path intent', 'create a constrained shortest path intent') do |cspi|
-    options[:path_intent] = "constrained_shortest_path_intent"
+  opts.on('-c', '--constrained', 'create a constrained shortest path intent') do
+    options[:intent_type] = "constrained_shortest_intent_type"
   end
   opts.on('-m', '--max_switches max_switches', 'max. number of switches') do |max_switches|
-    options[:max_switches] = max_switches;
+    options[:max_switches] = max_switches.to_i
   end
   opts.on('-h', '--help', 'Display help') do
     puts opts
@@ -32,8 +31,10 @@
 parser.parse!
 
 puts options.inspect
-server = options[:server] || "127.0.0.1"
-port = options[:port] || 8080
+server = options[:server]
+server ||= "127.0.0.1"
+port = options[:port]
+port ||= 8080
 
 def rand_mac
   mac = `openssl rand -hex 6`
@@ -45,7 +46,11 @@
 end
 
 class Intent
-  attr_reader :switches, :ports, :intent_id, :application_id
+  attr_reader :switches
+  attr_reader :ports
+  attr_reader :intent_id
+  attr_reader :application_id
+  attr_reader :intent_type
 
   def initialize options
     parse_options options
@@ -57,36 +62,42 @@
       rest = switches - [sw]
       json_intents = _create_intent sw, rest, json_intents
     end
-puts json_intents.inspect
+    json_intents
   end
 
   def parse_options options
     max_switches = options[:max_switches].to_i || 4
     @switches = (1..max_switches).to_a
     @ports = (1..(max_switches - 1)).to_a
-    @intent_id = options[:intent_id].to_i || 1
-    @application_id = options[:application_id].to_i || 1
+    @intent_id = options[:intent_id]
+    @intent_id ||= 1
+    @application_id = options[:application_id]
+    @application_id ||= 1
+    @intent_type = options[:intent_type]
   end
 
 
   def _create_intent src_switch, iterable_switches, json_intents
+    network_id = 1
     iterable_switches.each_index do |sw_i|
       dst_switch = iterable_switches[sw_i]
       sw_set = @switches - [dst_switch]
       dst_port = sw_set.index(src_switch)
       dst_port = dst_port + 1
       intent = {
-        :applicationId => @application_id,
-        :intentId => @intent_id,
+        :intent_id => "#{@application_id}:#{@intent_id}",
+        :intent_type => @intent_type,
         :srcSwitch => src_switch.to_s,
         :srcPort => @ports[sw_i],
-        :srcMac => "00:00:00:c0:a8:01:#{@ports[sw_i]}",
-        :dstSwitch => iterable_switches[sw_i],
+        :srcMac => "00:00:c0:a8:#{mac_format(src_switch)}",
+        :dstSwitch => iterable_switches[sw_i].to_s,
         :dstPort => dst_port,
-        :dstMac => "00:00:00:c0:a8:01:#{dst_port}"
+        :dstMac => "00:00:c0:a8:#{mac_format(iterable_switches[sw_i].to_i)}"
       }
+puts intent
       @intent_id = @intent_id + 1
       json_intents << intent
+puts
     end
     #sha256 = Digest::SHA256.new
     #sha256.update intent_hash.to_s
@@ -94,33 +105,18 @@
     #puts "intent hash = #{intent_hash}"
     json_intents
   end
+
+  def mac_format number
+    if number > 255
+      divisor = number / 256 
+      remainder = number % 256
+      return sprintf("%02x:%02x",divisor ,remainder)
+    end
+    "00:%02x" % number
+  end
 end
 
-# the program accepts the number of switches and ports and outputs a number of intents
-json_data = [{
-  :intentId => 12345,
-  :type => "shortest-path", 
-  :srcSwitch => "0x0000000000000001", 
-  :srcPort => 1, 
-  :srcMac =>"#{rand_mac}", 
-  :dstSwitch => "0x0000000000000002",
-  :dstPort => 4, 
-  :dstMac => "00:00:00:00:00:02"} 
-#  {:type => "constrained-shortest-path", 
-#  :srcSwitch => "0x#{rand_switch}",
-#  :srcPort => 2, 
-#  :srcMac => "00:00:00:00:00:11", 
-#  :dstSwitch => "0x#{rand_switch}",
-#  :dstPort => 3, 
-#  :dstMac => "00:00:00:00:00:22", 
-#  :bandwidth => 5.0 }
-]
-#puts json_data.to_json
-
-
-ports = [1,2,3]
-switches = [1,2,3,4]
 intent = Intent.new options
 json_data = intent.create_intent
-#response = RestClient.post 'http://#{server}:#{port}/wm/onos/datagrid/add/intent/json', json_data.to_json, :content_type => :json, :accept => :json
-#puts response.inspect
+response = RestClient.post "http://#{server}:#{port}/wm/onos/datagrid/add/intent/json", json_data.to_json, :content_type => :json, :accept => :json
+puts response.inspect