Major refactoring of the BMv2 protocol module

- Created 3 separate sub-modules: API (doesn't depend on
    Thrift), CTL (depends on Thrift), THRIFT-API (to generate Thrift
    sources)
- Implemented 2 new services (for device configuration swapping and
    table entry management) needed to distribute BMv2-specific state
    among ONOS instances.
- Implemented a BMv2 controller (previously other modules where
    using separately a Thrift client and a server)
- Added a default BMv2 JSON configuration (default.json) and interpreter
    to be used for devices that connect for the first time to ONOS.
    This allows for basic services to work (i.e. LLDP link discovery,
    ARP proxy. etc.).
- Changed behavior of the flow rule translator and extension selector,
    now it allows extension to specify only some of the match parameters
    (before extension selectors were expected to describe the whole
    match key, i.e. all fields)
- Various renaming to better represent the API
- Various java doc fixes / improvements

Change-Id: Ida4b5e546b0def97c3552a6c05f7bce76fd32c28
diff --git a/protocols/bmv2/api/src/test/java/org/onosproject/bmv2/api/context/Bmv2ConfigurationTest.java b/protocols/bmv2/api/src/test/java/org/onosproject/bmv2/api/context/Bmv2ConfigurationTest.java
new file mode 100644
index 0000000..bc1659d
--- /dev/null
+++ b/protocols/bmv2/api/src/test/java/org/onosproject/bmv2/api/context/Bmv2ConfigurationTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.bmv2.api.context;
+
+import com.eclipsesource.json.Json;
+import com.eclipsesource.json.JsonObject;
+import com.google.common.testing.EqualsTester;
+import org.hamcrest.collection.IsIterableContainingInOrder;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.bmv2.api.runtime.Bmv2MatchParam;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.core.IsEqual.equalTo;
+
+/**
+ * BMv2 JSON configuration parser test.
+ */
+public class Bmv2ConfigurationTest {
+
+    private JsonObject json;
+    private JsonObject json2;
+
+    @Before
+    public void setUp() throws Exception {
+        json = Json.parse(new BufferedReader(new InputStreamReader(
+                this.getClass().getResourceAsStream("/simple.json")))).asObject();
+        json2 = Json.parse(new BufferedReader(new InputStreamReader(
+                this.getClass().getResourceAsStream("/simple.json")))).asObject();
+    }
+
+    @Test
+    public void testParse() throws Exception {
+        Bmv2Configuration config = Bmv2DefaultConfiguration.parse(json);
+        Bmv2Configuration config2 = Bmv2DefaultConfiguration.parse(json2);
+
+        new EqualsTester()
+                .addEqualityGroup(config, config2)
+                .testEquals();
+
+        /* Check header types */
+        Bmv2HeaderTypeModel stdMetaT = config.headerType("standard_metadata_t");
+        Bmv2HeaderTypeModel ethernetT = config.headerType("ethernet_t");
+        Bmv2HeaderTypeModel intrinsicMetaT = config.headerType("intrinsic_metadata_t");
+
+        Bmv2HeaderTypeModel stdMetaT2 = config2.headerType("standard_metadata_t");
+        Bmv2HeaderTypeModel ethernetT2 = config2.headerType("ethernet_t");
+        Bmv2HeaderTypeModel intrinsicMetaT2 = config2.headerType("intrinsic_metadata_t");
+
+        new EqualsTester()
+                .addEqualityGroup(stdMetaT, stdMetaT2)
+                .addEqualityGroup(ethernetT, ethernetT2)
+                .addEqualityGroup(intrinsicMetaT, intrinsicMetaT2)
+                .testEquals();
+
+        // existence
+        assertThat("Json parsed value is null", stdMetaT, notNullValue());
+        assertThat("Json parsed value is null", ethernetT, notNullValue());
+        assertThat("Json parsed value is null", intrinsicMetaT, notNullValue());
+
+        // fields size
+        assertThat("Incorrect size for header type fields",
+                   stdMetaT.fields(), hasSize(8));
+        assertThat("Incorrect size for header type fields",
+                   ethernetT.fields(), hasSize(3));
+        assertThat("Incorrect size for header type fields",
+                   intrinsicMetaT.fields(), hasSize(4));
+
+        // check that fields are in order
+        assertThat("Incorrect order for header type fields",
+                   stdMetaT.fields(), IsIterableContainingInOrder.contains(
+                        stdMetaT.field("ingress_port"),
+                        stdMetaT.field("packet_length"),
+                        stdMetaT.field("egress_spec"),
+                        stdMetaT.field("egress_port"),
+                        stdMetaT.field("egress_instance"),
+                        stdMetaT.field("instance_type"),
+                        stdMetaT.field("clone_spec"),
+                        stdMetaT.field("_padding")));
+
+        /* Check actions */
+        Bmv2ActionModel floodAction = config.action("flood");
+        Bmv2ActionModel dropAction = config.action("_drop");
+        Bmv2ActionModel fwdAction = config.action("set_egress_port");
+
+        Bmv2ActionModel floodAction2 = config2.action("flood");
+        Bmv2ActionModel dropAction2 = config2.action("_drop");
+        Bmv2ActionModel fwdAction2 = config2.action("set_egress_port");
+
+        new EqualsTester()
+                .addEqualityGroup(floodAction, floodAction2)
+                .addEqualityGroup(dropAction, dropAction2)
+                .addEqualityGroup(fwdAction, fwdAction2)
+                .testEquals();
+
+        // existence
+        assertThat("Json parsed value is null", floodAction, notNullValue());
+        assertThat("Json parsed value is null", dropAction, notNullValue());
+        assertThat("Json parsed value is null", fwdAction, notNullValue());
+
+        // runtime data size
+        assertThat("Incorrect size for action runtime data",
+                   floodAction.runtimeDatas().size(), is(equalTo(0)));
+        assertThat("Incorrect size for action runtime data",
+                   dropAction.runtimeDatas().size(), is(equalTo(0)));
+        assertThat("Incorrect size for action runtime data",
+                   fwdAction.runtimeDatas().size(), is(equalTo(1)));
+
+        // runtime data existence and parsing
+        assertThat("Parsed Json value is null",
+                   fwdAction.runtimeData("port"), notNullValue());
+        assertThat("Incorrect value for action runtime data bitwidth",
+                   fwdAction.runtimeData("port").bitWidth(), is(equalTo(9)));
+
+        /* Check tables */
+        Bmv2TableModel table0 = config.table(0);
+        Bmv2TableModel table02 = config2.table(0);
+
+        new EqualsTester()
+                .addEqualityGroup(table0, table02)
+                .testEquals();
+
+        // existence
+        assertThat("Parsed Json value is null", table0, notNullValue());
+
+        // id and name correspondence
+        assertThat("Incorrect value for table name",
+                   table0.name(), is(equalTo("table0")));
+
+        // keys size
+        assertThat("Incorrect size for table keys",
+                   table0.keys().size(), is(equalTo(4)));
+
+        // key match type
+        assertThat("Incorrect value for table key match type",
+                   table0.keys().get(0).matchType(), is(equalTo(Bmv2MatchParam.Type.TERNARY)));
+
+        // header type
+        assertThat("Incorrect value for table key header type",
+                   table0.keys().get(0).field().header().type(), is(equalTo(stdMetaT)));
+    }
+}
\ No newline at end of file
diff --git a/protocols/bmv2/api/src/test/resources/simple.json b/protocols/bmv2/api/src/test/resources/simple.json
new file mode 100644
index 0000000..9be7b89
--- /dev/null
+++ b/protocols/bmv2/api/src/test/resources/simple.json
@@ -0,0 +1,397 @@
+{
+    "header_types": [
+        {
+            "name": "standard_metadata_t",
+            "id": 0,
+            "fields": [
+                [
+                    "ingress_port",
+                    9
+                ],
+                [
+                    "packet_length",
+                    32
+                ],
+                [
+                    "egress_spec",
+                    9
+                ],
+                [
+                    "egress_port",
+                    9
+                ],
+                [
+                    "egress_instance",
+                    32
+                ],
+                [
+                    "instance_type",
+                    32
+                ],
+                [
+                    "clone_spec",
+                    32
+                ],
+                [
+                    "_padding",
+                    5
+                ]
+            ],
+            "length_exp": null,
+            "max_length": null
+        },
+        {
+            "name": "ethernet_t",
+            "id": 1,
+            "fields": [
+                [
+                    "dstAddr",
+                    48
+                ],
+                [
+                    "srcAddr",
+                    48
+                ],
+                [
+                    "etherType",
+                    16
+                ]
+            ],
+            "length_exp": null,
+            "max_length": null
+        },
+        {
+            "name": "intrinsic_metadata_t",
+            "id": 2,
+            "fields": [
+                [
+                    "ingress_global_timestamp",
+                    32
+                ],
+                [
+                    "lf_field_list",
+                    32
+                ],
+                [
+                    "mcast_grp",
+                    16
+                ],
+                [
+                    "egress_rid",
+                    16
+                ]
+            ],
+            "length_exp": null,
+            "max_length": null
+        }
+    ],
+    "headers": [
+        {
+            "name": "standard_metadata",
+            "id": 0,
+            "header_type": "standard_metadata_t",
+            "metadata": true
+        },
+        {
+            "name": "ethernet",
+            "id": 1,
+            "header_type": "ethernet_t",
+            "metadata": false
+        },
+        {
+            "name": "intrinsic_metadata",
+            "id": 2,
+            "header_type": "intrinsic_metadata_t",
+            "metadata": true
+        }
+    ],
+    "header_stacks": [],
+    "parsers": [
+        {
+            "name": "parser",
+            "id": 0,
+            "init_state": "start",
+            "parse_states": [
+                {
+                    "name": "start",
+                    "id": 0,
+                    "parser_ops": [],
+                    "transition_key": [],
+                    "transitions": [
+                        {
+                            "value": "default",
+                            "mask": null,
+                            "next_state": "parse_ethernet"
+                        }
+                    ]
+                },
+                {
+                    "name": "parse_ethernet",
+                    "id": 1,
+                    "parser_ops": [
+                        {
+                            "op": "extract",
+                            "parameters": [
+                                {
+                                    "type": "regular",
+                                    "value": "ethernet"
+                                }
+                            ]
+                        }
+                    ],
+                    "transition_key": [],
+                    "transitions": [
+                        {
+                            "value": "default",
+                            "mask": null,
+                            "next_state": null
+                        }
+                    ]
+                }
+            ]
+        }
+    ],
+    "deparsers": [
+        {
+            "name": "deparser",
+            "id": 0,
+            "order": [
+                "ethernet"
+            ]
+        }
+    ],
+    "meter_arrays": [],
+    "actions": [
+        {
+            "name": "set_egress_port",
+            "id": 0,
+            "runtime_data": [
+                {
+                    "name": "port",
+                    "bitwidth": 9
+                }
+            ],
+            "primitives": [
+                {
+                    "op": "modify_field",
+                    "parameters": [
+                        {
+                            "type": "field",
+                            "value": [
+                                "standard_metadata",
+                                "egress_spec"
+                            ]
+                        },
+                        {
+                            "type": "runtime_data",
+                            "value": 0
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "name": "_drop",
+            "id": 1,
+            "runtime_data": [],
+            "primitives": [
+                {
+                    "op": "modify_field",
+                    "parameters": [
+                        {
+                            "type": "field",
+                            "value": [
+                                "standard_metadata",
+                                "egress_spec"
+                            ]
+                        },
+                        {
+                            "type": "hexstr",
+                            "value": "0x1ff"
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "name": "flood",
+            "id": 2,
+            "runtime_data": [],
+            "primitives": [
+                {
+                    "op": "modify_field",
+                    "parameters": [
+                        {
+                            "type": "field",
+                            "value": [
+                                "intrinsic_metadata",
+                                "mcast_grp"
+                            ]
+                        },
+                        {
+                            "type": "field",
+                            "value": [
+                                "standard_metadata",
+                                "ingress_port"
+                            ]
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "name": "send_to_cpu",
+            "id": 3,
+            "runtime_data": [],
+            "primitives": [
+                {
+                    "op": "modify_field",
+                    "parameters": [
+                        {
+                            "type": "field",
+                            "value": [
+                                "standard_metadata",
+                                "egress_spec"
+                            ]
+                        },
+                        {
+                            "type": "hexstr",
+                            "value": "0xff"
+                        }
+                    ]
+                }
+            ]
+        }
+    ],
+    "pipelines": [
+        {
+            "name": "ingress",
+            "id": 0,
+            "init_table": "table0",
+            "tables": [
+                {
+                    "name": "table0",
+                    "id": 0,
+                    "match_type": "ternary",
+                    "type": "simple",
+                    "max_size": 16384,
+                    "with_counters": false,
+                    "direct_meters": null,
+                    "support_timeout": false,
+                    "key": [
+                        {
+                            "match_type": "ternary",
+                            "target": [
+                                "standard_metadata",
+                                "ingress_port"
+                            ],
+                            "mask": null
+                        },
+                        {
+                            "match_type": "ternary",
+                            "target": [
+                                "ethernet",
+                                "dstAddr"
+                            ],
+                            "mask": null
+                        },
+                        {
+                            "match_type": "ternary",
+                            "target": [
+                                "ethernet",
+                                "srcAddr"
+                            ],
+                            "mask": null
+                        },
+                        {
+                            "match_type": "ternary",
+                            "target": [
+                                "ethernet",
+                                "etherType"
+                            ],
+                            "mask": null
+                        }
+                    ],
+                    "actions": [
+                        "set_egress_port",
+                        "flood",
+                        "send_to_cpu",
+                        "_drop"
+                    ],
+                    "next_tables": {
+                        "set_egress_port": null,
+                        "flood": null,
+                        "send_to_cpu": null,
+                        "_drop": null
+                    },
+                    "default_action": null,
+                    "base_default_next": null
+                }
+            ],
+            "conditionals": []
+        },
+        {
+            "name": "egress",
+            "id": 1,
+            "init_table": null,
+            "tables": [],
+            "conditionals": []
+        }
+    ],
+    "calculations": [],
+    "checksums": [],
+    "learn_lists": [],
+    "field_lists": [],
+    "counter_arrays": [],
+    "register_arrays": [],
+    "force_arith": [
+        [
+            "standard_metadata",
+            "ingress_port"
+        ],
+        [
+            "standard_metadata",
+            "packet_length"
+        ],
+        [
+            "standard_metadata",
+            "egress_spec"
+        ],
+        [
+            "standard_metadata",
+            "egress_port"
+        ],
+        [
+            "standard_metadata",
+            "egress_instance"
+        ],
+        [
+            "standard_metadata",
+            "instance_type"
+        ],
+        [
+            "standard_metadata",
+            "clone_spec"
+        ],
+        [
+            "standard_metadata",
+            "_padding"
+        ],
+        [
+            "intrinsic_metadata",
+            "ingress_global_timestamp"
+        ],
+        [
+            "intrinsic_metadata",
+            "lf_field_list"
+        ],
+        [
+            "intrinsic_metadata",
+            "mcast_grp"
+        ],
+        [
+            "intrinsic_metadata",
+            "egress_rid"
+        ]
+    ]
+}
\ No newline at end of file