Enhancement in switch configuration
[controller.git] / opendaylight / northbound / integrationtest / src / test / java / org / opendaylight / controller / northbound / integrationtest / NorthboundIT.java
1 package org.opendaylight.controller.northbound.integrationtest;
2
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertNotNull;
5 import static org.ops4j.pax.exam.CoreOptions.junitBundles;
6 import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
7 import static org.ops4j.pax.exam.CoreOptions.options;
8 import static org.ops4j.pax.exam.CoreOptions.systemPackages;
9 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
10
11 import java.io.BufferedReader;
12 import java.io.InputStream;
13 import java.io.InputStreamReader;
14 import java.io.OutputStreamWriter;
15 import java.net.HttpURLConnection;
16 import java.net.URL;
17 import java.nio.charset.Charset;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Set;
23
24 import javax.inject.Inject;
25
26 import org.apache.commons.codec.binary.Base64;
27 import org.codehaus.jettison.json.JSONArray;
28 import org.codehaus.jettison.json.JSONException;
29 import org.codehaus.jettison.json.JSONObject;
30 import org.codehaus.jettison.json.JSONTokener;
31 import org.junit.Assert;
32 import org.junit.Before;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.opendaylight.controller.hosttracker.IfIptoHost;
36 import org.opendaylight.controller.sal.core.Bandwidth;
37 import org.opendaylight.controller.sal.core.ConstructionException;
38 import org.opendaylight.controller.sal.core.Edge;
39 import org.opendaylight.controller.sal.core.Latency;
40 import org.opendaylight.controller.sal.core.Node;
41 import org.opendaylight.controller.sal.core.NodeConnector;
42 import org.opendaylight.controller.sal.core.Property;
43 import org.opendaylight.controller.sal.core.State;
44 import org.opendaylight.controller.sal.core.UpdateType;
45 import org.opendaylight.controller.sal.topology.IListenTopoUpdates;
46 import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
47 import org.opendaylight.controller.switchmanager.IInventoryListener;
48 import org.opendaylight.controller.usermanager.IUserManager;
49 import org.ops4j.pax.exam.Option;
50 import org.ops4j.pax.exam.junit.Configuration;
51 import org.ops4j.pax.exam.junit.PaxExam;
52 import org.ops4j.pax.exam.util.PathUtils;
53 import org.osgi.framework.Bundle;
54 import org.osgi.framework.BundleContext;
55 import org.osgi.framework.ServiceReference;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 @RunWith(PaxExam.class)
60 public class NorthboundIT {
61     private final Logger log = LoggerFactory.getLogger(NorthboundIT.class);
62     // get the OSGI bundle context
63     @Inject
64     private BundleContext bc;
65     private IUserManager userManager = null;
66     private IInventoryListener invtoryListener = null;
67     private IListenTopoUpdates topoUpdates = null;
68
69     private final Boolean debugMsg = false;
70
71     private String stateToString(int state) {
72         switch (state) {
73         case Bundle.ACTIVE:
74             return "ACTIVE";
75         case Bundle.INSTALLED:
76             return "INSTALLED";
77         case Bundle.RESOLVED:
78             return "RESOLVED";
79         case Bundle.UNINSTALLED:
80             return "UNINSTALLED";
81         default:
82             return "Not CONVERTED";
83         }
84     }
85
86     @Before
87     public void areWeReady() {
88         assertNotNull(bc);
89         boolean debugit = false;
90         Bundle b[] = bc.getBundles();
91         for (int i = 0; i < b.length; i++) {
92             int state = b[i].getState();
93             if (state != Bundle.ACTIVE && state != Bundle.RESOLVED) {
94                 log.debug("Bundle:" + b[i].getSymbolicName() + " state:" + stateToString(state));
95                 debugit = true;
96             }
97         }
98         if (debugit) {
99             log.debug("Do some debugging because some bundle is " + "unresolved");
100         }
101         // Assert if true, if false we are good to go!
102         assertFalse(debugit);
103
104         ServiceReference r = bc.getServiceReference(IUserManager.class.getName());
105         if (r != null) {
106             this.userManager = (IUserManager) bc.getService(r);
107         }
108         // If UserManager is null, cannot login to run tests.
109         assertNotNull(this.userManager);
110
111         r = bc.getServiceReference(IfIptoHost.class.getName());
112         if (r != null) {
113             this.invtoryListener = (IInventoryListener) bc.getService(r);
114         }
115
116         // If inventoryListener is null, cannot run hosttracker tests.
117         assertNotNull(this.invtoryListener);
118
119         r = bc.getServiceReference(IListenTopoUpdates.class.getName());
120         if (r != null) {
121             this.topoUpdates = (IListenTopoUpdates) bc.getService(r);
122         }
123
124         // If topologyManager is null, cannot run topology North tests.
125         assertNotNull(this.topoUpdates);
126
127     }
128
129     // static variable to pass response code from getJsonResult()
130     private static Integer httpResponseCode = null;
131
132     private String getJsonResult(String restUrl) {
133         return getJsonResult(restUrl, "GET", null);
134     }
135
136     private String getJsonResult(String restUrl, String method) {
137         return getJsonResult(restUrl, method, null);
138     }
139
140     private String getJsonResult(String restUrl, String method, String body) {
141         // initialize response code to indicate error
142         httpResponseCode = 400;
143
144         if (debugMsg) {
145             System.out.println("HTTP method: " + method + " url: " + restUrl.toString());
146             if (body != null)
147                 System.out.println("body: " + body);
148         }
149
150         try {
151             URL url = new URL(restUrl);
152             this.userManager.getAuthorizationList();
153             this.userManager.authenticate("admin", "admin");
154             String authString = "admin:admin";
155             byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());
156             String authStringEnc = new String(authEncBytes);
157
158             HttpURLConnection connection = (HttpURLConnection) url.openConnection();
159             connection.setRequestMethod(method);
160             connection.setRequestProperty("Authorization", "Basic " + authStringEnc);
161             connection.setRequestProperty("Content-Type", "application/json");
162             connection.setRequestProperty("Accept", "application/json");
163
164             if (body != null) {
165                 connection.setDoOutput(true);
166                 OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream());
167                 wr.write(body);
168                 wr.flush();
169             }
170             connection.connect();
171             connection.getContentType();
172
173             // Response code for success should be 2xx
174             httpResponseCode = connection.getResponseCode();
175             if (httpResponseCode > 299)
176                 return httpResponseCode.toString();
177
178             if (debugMsg) {
179                 System.out.println("HTTP response code: " + connection.getResponseCode());
180                 System.out.println("HTTP response message: " + connection.getResponseMessage());
181             }
182
183             InputStream is = connection.getInputStream();
184             BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
185             StringBuilder sb = new StringBuilder();
186             int cp;
187             while ((cp = rd.read()) != -1) {
188                 sb.append((char) cp);
189             }
190             is.close();
191             connection.disconnect();
192             return sb.toString();
193         } catch (Exception e) {
194             return null;
195         }
196     }
197
198     private void testNodeProperties(JSONObject node, Integer nodeId, String nodeType, Integer timestamp,
199             String timestampName, Integer actionsValue, Integer capabilitiesValue, Integer tablesValue,
200             Integer buffersValue) throws JSONException {
201
202         JSONObject nodeInfo = node.getJSONObject("node");
203         Assert.assertEquals(nodeId, (Integer) nodeInfo.getInt("@id"));
204         Assert.assertEquals(nodeType, nodeInfo.getString("@type"));
205
206         JSONObject properties = node.getJSONObject("properties");
207
208         if (timestamp == null || timestampName == null) {
209             Assert.assertFalse(properties.has("timeStamp"));
210         } else {
211             Assert.assertEquals(timestamp, (Integer) properties.getJSONObject("timeStamp").getInt("timestamp"));
212             Assert.assertEquals(timestampName, properties.getJSONObject("timeStamp").getString("timestampName"));
213         }
214         if (actionsValue == null) {
215             Assert.assertFalse(properties.has("actions"));
216         } else {
217             Assert.assertEquals(actionsValue, (Integer) properties.getJSONObject("actions").getInt("actionsValue"));
218         }
219         if (capabilitiesValue == null) {
220             Assert.assertFalse(properties.has("capabilities"));
221         } else {
222             Assert.assertEquals(capabilitiesValue,
223                     (Integer) properties.getJSONObject("capabilities").getInt("capabilitiesValue"));
224         }
225         if (tablesValue == null) {
226             Assert.assertFalse(properties.has("tables"));
227         } else {
228             Assert.assertEquals(tablesValue, (Integer) properties.getJSONObject("tables").getInt("tablesValue"));
229         }
230         if (buffersValue == null) {
231             Assert.assertFalse(properties.has("buffers"));
232         } else {
233             Assert.assertEquals(buffersValue, (Integer) properties.getJSONObject("buffers").getInt("buffersValue"));
234         }
235     }
236
237     private void testNodeConnectorProperties(JSONObject nodeConnectorProperties, Integer ncId, String ncType,
238             Integer nodeId, String nodeType, Integer state, Integer capabilities, Integer bandwidth)
239             throws JSONException {
240
241         JSONObject nodeConnector = nodeConnectorProperties.getJSONObject("nodeconnector");
242         JSONObject node = nodeConnector.getJSONObject("node");
243         JSONObject properties = nodeConnectorProperties.getJSONObject("properties");
244
245         Assert.assertEquals(ncId, (Integer) nodeConnector.getInt("@id"));
246         Assert.assertEquals(ncType, nodeConnector.getString("@type"));
247         Assert.assertEquals(nodeId, (Integer) node.getInt("@id"));
248         Assert.assertEquals(nodeType, node.getString("@type"));
249         if (state == null) {
250             Assert.assertFalse(properties.has("state"));
251         } else {
252             Assert.assertEquals(state, (Integer) properties.getJSONObject("state").getInt("stateValue"));
253         }
254         if (capabilities == null) {
255             Assert.assertFalse(properties.has("capabilities"));
256         } else {
257             Assert.assertEquals(capabilities,
258                     (Integer) properties.getJSONObject("capabilities").getInt("capabilitiesValue"));
259         }
260         if (bandwidth == null) {
261             Assert.assertFalse(properties.has("bandwidth"));
262         } else {
263             Assert.assertEquals(bandwidth, (Integer) properties.getJSONObject("bandwidth").getInt("bandwidthValue"));
264         }
265
266     }
267
268     @Test
269     public void testSubnetsNorthbound() throws JSONException {
270         System.out.println("Starting Subnets JAXB client.");
271         String baseURL = "http://127.0.0.1:8080/controller/nb/v2/subnet/";
272
273         String name1 = "testSubnet1";
274         String subnet1 = "1.1.1.1/24";
275         String name2 = "testSubnet2";
276         String subnet2 = "2.2.2.2/24";
277
278         // Test GET subnets in default container
279         String result = getJsonResult(baseURL + "default");
280         JSONTokener jt = new JSONTokener(result);
281         JSONObject json = new JSONObject(jt);
282         Assert.assertEquals("{}", result);
283
284         // Test GET subnet1 expecting 404
285         result = getJsonResult(baseURL + "default/" + name1);
286         Assert.assertEquals(404, httpResponseCode.intValue());
287
288         // Test POST subnet1
289         String queryParameter = new QueryParameter("subnetName", name1).add("subnet", subnet1).getString();
290         result = getJsonResult(baseURL + "default/" + name1 + queryParameter, "POST");
291         Assert.assertEquals(201, httpResponseCode.intValue());
292
293         // Test GET subnet1
294         result = getJsonResult(baseURL + "default/" + name1);
295         jt = new JSONTokener(result);
296         json = new JSONObject(jt);
297         Assert.assertEquals(200, httpResponseCode.intValue());
298         Assert.assertEquals(name1, json.getString("@name"));
299         Assert.assertEquals(subnet1, json.getString("@subnet"));
300
301         // Test POST subnet2
302         queryParameter = new QueryParameter("subnetName", name2).add("subnet", subnet2).getString();
303         result = getJsonResult(baseURL + "default/" + name2 + queryParameter, "POST");
304         Assert.assertEquals(201, httpResponseCode.intValue());
305
306         // Test GET all subnets in default container
307         result = getJsonResult(baseURL + "default");
308         jt = new JSONTokener(result);
309         json = new JSONObject(jt);
310         JSONArray subnetConfigArray = json.getJSONArray("subnetConfig");
311         JSONObject subnetConfig;
312         Assert.assertEquals(2, subnetConfigArray.length());
313         for (int i = 0; i < subnetConfigArray.length(); i++) {
314             subnetConfig = subnetConfigArray.getJSONObject(i);
315             if (subnetConfig.getString("@name").equals(name1)) {
316                 Assert.assertEquals(subnet1, subnetConfig.getString("@subnet"));
317             } else if (subnetConfig.getString("@name").equals(name2)) {
318                 Assert.assertEquals(subnet2, subnetConfig.getString("@subnet"));
319             } else {
320                 // Unexpected config name
321                 Assert.assertTrue(false);
322             }
323         }
324
325         // Test DELETE subnet1
326         result = getJsonResult(baseURL + "default/" + name1, "DELETE");
327         Assert.assertEquals(200, httpResponseCode.intValue());
328
329         // Test GET deleted subnet1
330         result = getJsonResult(baseURL + "default/" + name1);
331         Assert.assertEquals(404, httpResponseCode.intValue());
332
333     }
334
335     @Test
336     public void testStaticRoutingNorthbound() throws JSONException {
337         System.out.println("Starting StaticRouting JAXB client.");
338         String baseURL = "http://127.0.0.1:8080/controller/nb/v2/staticroute/";
339
340         String name1 = "testRoute1";
341         String prefix1 = "192.168.1.1/24";
342         String nextHop1 = "0.0.0.0";
343         String name2 = "testRoute2";
344         String prefix2 = "192.168.1.1/16";
345         String nextHop2 = "1.1.1.1";
346
347         // Test GET static routes in default container, expecting no results
348         String result = getJsonResult(baseURL + "default");
349         JSONTokener jt = new JSONTokener(result);
350         JSONObject json = new JSONObject(jt);
351         Assert.assertEquals("{}", result);
352
353         // Test insert static route
354         String requestBody = "{\"name\":\"" + name1 + "\", \"prefix\":\"" + prefix1 + "\", \"nextHop\":\"" + nextHop1
355                 + "\"}";
356         result = getJsonResult(baseURL + "default/" + name1, "POST", requestBody);
357         Assert.assertEquals(201, httpResponseCode.intValue());
358
359         requestBody = "{\"name\":\"" + name2 + "\", \"prefix\":\"" + prefix2 + "\", \"nextHop\":\"" + nextHop2 + "\"}";
360         result = getJsonResult(baseURL + "default/" + name2, "POST", requestBody);
361         Assert.assertEquals(201, httpResponseCode.intValue());
362
363         // Test Get all static routes
364         result = getJsonResult(baseURL + "default");
365         jt = new JSONTokener(result);
366         json = new JSONObject(jt);
367         JSONArray staticRoutes = json.getJSONArray("staticRoute");
368         Assert.assertEquals(2, staticRoutes.length());
369         JSONObject route;
370         for (int i = 0; i < staticRoutes.length(); i++) {
371             route = staticRoutes.getJSONObject(i);
372             if (route.getString("name").equals(name1)) {
373                 Assert.assertEquals(prefix1, route.getString("prefix"));
374                 Assert.assertEquals(nextHop1, route.getString("nextHop"));
375             } else if (route.getString("name").equals(name2)) {
376                 Assert.assertEquals(prefix2, route.getString("prefix"));
377                 Assert.assertEquals(nextHop2, route.getString("nextHop"));
378             } else {
379                 // static route has unknown name
380                 Assert.assertTrue(false);
381             }
382         }
383
384         // Test get specific static route
385         result = getJsonResult(baseURL + "default/" + name1);
386         jt = new JSONTokener(result);
387         json = new JSONObject(jt);
388
389         Assert.assertEquals(name1, json.getString("name"));
390         Assert.assertEquals(prefix1, json.getString("prefix"));
391         Assert.assertEquals(nextHop1, json.getString("nextHop"));
392
393         result = getJsonResult(baseURL + "default/" + name2);
394         jt = new JSONTokener(result);
395         json = new JSONObject(jt);
396
397         Assert.assertEquals(name2, json.getString("name"));
398         Assert.assertEquals(prefix2, json.getString("prefix"));
399         Assert.assertEquals(nextHop2, json.getString("nextHop"));
400
401         // Test delete static route
402         result = getJsonResult(baseURL + "default/" + name1, "DELETE");
403         Assert.assertEquals(200, httpResponseCode.intValue());
404
405         result = getJsonResult(baseURL + "default");
406         jt = new JSONTokener(result);
407         json = new JSONObject(jt);
408         JSONObject singleStaticRoute = json.getJSONObject("staticRoute");
409         Assert.assertEquals(name2, singleStaticRoute.getString("name"));
410
411     }
412
413     @Test
414     public void testSwitchManager() throws JSONException {
415         System.out.println("Starting SwitchManager JAXB client.");
416         String baseURL = "http://127.0.0.1:8080/controller/nb/v2/switch/default/";
417
418         // define Node/NodeConnector attributes for test
419         int nodeId_1 = 51966;
420         int nodeId_2 = 3366;
421         int nodeId_3 = 4477;
422         int nodeConnectorId_1 = 51966;
423         int nodeConnectorId_2 = 12;
424         int nodeConnectorId_3 = 34;
425         String nodeType = "STUB";
426         String ncType = "STUB";
427         int timestamp_1 = 100000;
428         String timestampName_1 = "connectedSince";
429         int actionsValue_1 = 2;
430         int capabilitiesValue_1 = 3;
431         int tablesValue_1 = 1;
432         int buffersValue_1 = 1;
433         int ncState = 1;
434         int ncCapabilities = 1;
435         int ncBandwidth = 1000000000;
436
437         // Test GET all nodes
438
439         String result = getJsonResult(baseURL + "nodes");
440         JSONTokener jt = new JSONTokener(result);
441         JSONObject json = new JSONObject(jt);
442
443         // Test for first node
444         JSONObject node = getJsonInstance(json, "nodeProperties", nodeId_1);
445         Assert.assertNotNull(node);
446         testNodeProperties(node, nodeId_1, nodeType, timestamp_1, timestampName_1, actionsValue_1, capabilitiesValue_1,
447                 tablesValue_1, buffersValue_1);
448
449         // Test 2nd node, properties of 2nd node same as first node
450         node = getJsonInstance(json, "nodeProperties", nodeId_2);
451         Assert.assertNotNull(node);
452         testNodeProperties(node, nodeId_2, nodeType, timestamp_1, timestampName_1, actionsValue_1, capabilitiesValue_1,
453                 tablesValue_1, buffersValue_1);
454
455         // Test 3rd node, properties of 3rd node same as first node
456         node = getJsonInstance(json, "nodeProperties", nodeId_3);
457         Assert.assertNotNull(node);
458         testNodeProperties(node, nodeId_3, nodeType, timestamp_1, timestampName_1, actionsValue_1, capabilitiesValue_1,
459                 tablesValue_1, buffersValue_1);
460
461         // Test GET nodeConnectors of a node
462         // Test first node
463         result = getJsonResult(baseURL + "node/STUB/" + nodeId_1);
464         jt = new JSONTokener(result);
465         json = new JSONObject(jt);
466         JSONObject nodeConnectorProperties = json.getJSONObject("nodeConnectorProperties");
467
468         testNodeConnectorProperties(nodeConnectorProperties, nodeConnectorId_1, ncType, nodeId_1, nodeType, ncState,
469                 ncCapabilities, ncBandwidth);
470
471         // Test second node
472         result = getJsonResult(baseURL + "node/STUB/" + nodeId_2);
473         jt = new JSONTokener(result);
474         json = new JSONObject(jt);
475         nodeConnectorProperties = json.getJSONObject("nodeConnectorProperties");
476
477         testNodeConnectorProperties(nodeConnectorProperties, nodeConnectorId_2, ncType, nodeId_2, nodeType, ncState,
478                 ncCapabilities, ncBandwidth);
479
480         // Test third node
481         result = getJsonResult(baseURL + "node/STUB/" + nodeId_3);
482         jt = new JSONTokener(result);
483         json = new JSONObject(jt);
484
485         nodeConnectorProperties = json.getJSONObject("nodeConnectorProperties");
486         testNodeConnectorProperties(nodeConnectorProperties, nodeConnectorId_3, ncType, nodeId_3, nodeType, ncState,
487                 ncCapabilities, ncBandwidth);
488
489         // Test delete node property
490         // Delete timestamp property from node1
491         result = getJsonResult(baseURL + "node/STUB/" + nodeId_1 + "/property/timeStamp", "DELETE");
492         Assert.assertEquals(200, httpResponseCode.intValue());
493
494         // Check node1
495         result = getJsonResult(baseURL + "nodes");
496         jt = new JSONTokener(result);
497         json = new JSONObject(jt);
498         node = getJsonInstance(json, "nodeProperties", nodeId_1);
499         Assert.assertNotNull(node);
500         testNodeProperties(node, nodeId_1, nodeType, null, null, actionsValue_1, capabilitiesValue_1, tablesValue_1,
501                 buffersValue_1);
502
503         // Delete actions property from node2
504         result = getJsonResult(baseURL + "node/STUB/" + nodeId_2 + "/property/actions", "DELETE");
505         Assert.assertEquals(200, httpResponseCode.intValue());
506
507         // Check node2
508         result = getJsonResult(baseURL + "nodes");
509         jt = new JSONTokener(result);
510         json = new JSONObject(jt);
511         node = getJsonInstance(json, "nodeProperties", nodeId_2);
512         Assert.assertNotNull(node);
513         testNodeProperties(node, nodeId_2, nodeType, timestamp_1, timestampName_1, null, capabilitiesValue_1,
514                 tablesValue_1, buffersValue_1);
515
516         // Test add property to node
517         // Add Tier and Bandwidth property to node1
518         result = getJsonResult(baseURL + "node/STUB/" + nodeId_1 + "/property/tier/1001", "PUT");
519         Assert.assertEquals(201, httpResponseCode.intValue());
520         result = getJsonResult(baseURL + "node/STUB/" + nodeId_1 + "/property/bandwidth/1002", "PUT");
521         Assert.assertEquals(201, httpResponseCode.intValue());
522
523         // Test for first node
524         result = getJsonResult(baseURL + "nodes");
525         jt = new JSONTokener(result);
526         json = new JSONObject(jt);
527         node = getJsonInstance(json, "nodeProperties", nodeId_1);
528         Assert.assertNotNull(node);
529         Assert.assertEquals(1001, node.getJSONObject("properties").getJSONObject("tier").getInt("tierValue"));
530         Assert.assertEquals(1002, node.getJSONObject("properties").getJSONObject("bandwidth").getInt("bandwidthValue"));
531
532         // Test delete nodeConnector property
533         // Delete state property of nodeconnector1
534         result = getJsonResult(baseURL + "nodeconnector/STUB/" + nodeId_1 + "/STUB/" + nodeConnectorId_1
535                 + "/property/state", "DELETE");
536         Assert.assertEquals(200, httpResponseCode.intValue());
537
538         result = getJsonResult(baseURL + "node/STUB/" + nodeId_1);
539         jt = new JSONTokener(result);
540         json = new JSONObject(jt);
541         nodeConnectorProperties = json.getJSONObject("nodeConnectorProperties");
542
543         testNodeConnectorProperties(nodeConnectorProperties, nodeConnectorId_1, ncType, nodeId_1, nodeType, null,
544                 ncCapabilities, ncBandwidth);
545
546         // Delete capabilities property of nodeconnector2
547         result = getJsonResult(baseURL + "nodeconnector/STUB/" + nodeId_2 + "/STUB/" + nodeConnectorId_2
548                 + "/property/capabilities", "DELETE");
549         Assert.assertEquals(200, httpResponseCode.intValue());
550
551         result = getJsonResult(baseURL + "node/STUB/" + nodeId_2);
552         jt = new JSONTokener(result);
553         json = new JSONObject(jt);
554         nodeConnectorProperties = json.getJSONObject("nodeConnectorProperties");
555
556         testNodeConnectorProperties(nodeConnectorProperties, nodeConnectorId_2, ncType, nodeId_2, nodeType, ncState,
557                 null, ncBandwidth);
558
559         // Test PUT nodeConnector property
560         int newBandwidth = 1001;
561
562         // Add Name/Bandwidth property to nodeConnector1
563         result = getJsonResult(baseURL + "nodeconnector/STUB/" + nodeId_1 + "/STUB/" + nodeConnectorId_1
564                 + "/property/bandwidth/" + newBandwidth, "PUT");
565         Assert.assertEquals(201, httpResponseCode.intValue());
566
567         result = getJsonResult(baseURL + "node/STUB/" + nodeId_1);
568         jt = new JSONTokener(result);
569         json = new JSONObject(jt);
570         nodeConnectorProperties = json.getJSONObject("nodeConnectorProperties");
571
572         // Check for new bandwidth value, state value removed from previous
573         // test
574         testNodeConnectorProperties(nodeConnectorProperties, nodeConnectorId_1, ncType, nodeId_1, nodeType, null,
575                 ncCapabilities, newBandwidth);
576
577     }
578
579     @Test
580     public void testStatistics() throws JSONException {
581         final String actionTypes[] = { "drop", "loopback", "flood", "floodAll", "controller", "swPath", "hwPath", "output",
582                 "setDlSrc", "setDlDst", "setDlType", "setVlanId", "setVlanPcp", "setVlanCfi", "popVlan", "pushVlan",
583                 "setNwSrc", "setNwDst", "setNwTos", "setTpSrc", "setTpDst" };
584         System.out.println("Starting Statistics JAXB client.");
585
586         String baseURL = "http://127.0.0.1:8080/controller/nb/v2/statistics/default/";
587
588         String result = getJsonResult(baseURL + "flowstats");
589         JSONTokener jt = new JSONTokener(result);
590         JSONObject json = new JSONObject(jt);
591         JSONObject flowStatistics = getJsonInstance(json, "flowStatistics", 0xCAFE);
592         JSONObject node = flowStatistics.getJSONObject("node");
593         // test that node was returned properly
594         Assert.assertTrue(node.getInt("@id") == 0xCAFE);
595         Assert.assertEquals(node.getString("@type"), "STUB");
596
597         // test that flow statistics results are correct
598         JSONArray flowStats = flowStatistics.getJSONArray("flowStat");
599         for (int i = 0; i < flowStats.length(); i++) {
600
601             JSONObject flowStat = flowStats.getJSONObject(i);
602             testFlowStat(flowStat, actionTypes[i], i);
603
604         }
605
606         // for /controller/nb/v2/statistics/default/portstats
607         result = getJsonResult(baseURL + "portstats");
608         jt = new JSONTokener(result);
609         json = new JSONObject(jt);
610         JSONObject portStatistics = getJsonInstance(json, "portStatistics", 0xCAFE);
611         JSONObject node2 = portStatistics.getJSONObject("node");
612         // test that node was returned properly
613         Assert.assertTrue(node2.getInt("@id") == 0xCAFE);
614         Assert.assertEquals(node2.getString("@type"), "STUB");
615
616         // test that port statistic results are correct
617         JSONObject portStat = portStatistics.getJSONObject("portStat");
618         Assert.assertTrue(portStat.getInt("receivePackets") == 250);
619         Assert.assertTrue(portStat.getInt("transmitPackets") == 500);
620         Assert.assertTrue(portStat.getInt("receiveBytes") == 1000);
621         Assert.assertTrue(portStat.getInt("transmitBytes") == 5000);
622         Assert.assertTrue(portStat.getInt("receiveDrops") == 2);
623         Assert.assertTrue(portStat.getInt("transmitDrops") == 50);
624         Assert.assertTrue(portStat.getInt("receiveErrors") == 3);
625         Assert.assertTrue(portStat.getInt("transmitErrors") == 10);
626         Assert.assertTrue(portStat.getInt("receiveFrameError") == 5);
627         Assert.assertTrue(portStat.getInt("receiveOverRunError") == 6);
628         Assert.assertTrue(portStat.getInt("receiveCrcError") == 1);
629         Assert.assertTrue(portStat.getInt("collisionCount") == 4);
630
631         // test for getting one specific node's stats
632         result = getJsonResult(baseURL + "flowstats/STUB/51966");
633         jt = new JSONTokener(result);
634         json = new JSONObject(jt);
635         node = json.getJSONObject("node");
636         // test that node was returned properly
637         Assert.assertTrue(node.getInt("@id") == 0xCAFE);
638         Assert.assertEquals(node.getString("@type"), "STUB");
639
640         // test that flow statistics results are correct
641         flowStats = json.getJSONArray("flowStat");
642         for (int i = 0; i < flowStats.length(); i++) {
643             JSONObject flowStat = flowStats.getJSONObject(i);
644             testFlowStat(flowStat, actionTypes[i], i);
645         }
646
647         result = getJsonResult(baseURL + "portstats/STUB/51966");
648         jt = new JSONTokener(result);
649         json = new JSONObject(jt);
650         node2 = json.getJSONObject("node");
651         // test that node was returned properly
652         Assert.assertTrue(node2.getInt("@id") == 0xCAFE);
653         Assert.assertEquals(node2.getString("@type"), "STUB");
654
655         // test that port statistic results are correct
656         portStat = json.getJSONObject("portStat");
657         Assert.assertTrue(portStat.getInt("receivePackets") == 250);
658         Assert.assertTrue(portStat.getInt("transmitPackets") == 500);
659         Assert.assertTrue(portStat.getInt("receiveBytes") == 1000);
660         Assert.assertTrue(portStat.getInt("transmitBytes") == 5000);
661         Assert.assertTrue(portStat.getInt("receiveDrops") == 2);
662         Assert.assertTrue(portStat.getInt("transmitDrops") == 50);
663         Assert.assertTrue(portStat.getInt("receiveErrors") == 3);
664         Assert.assertTrue(portStat.getInt("transmitErrors") == 10);
665         Assert.assertTrue(portStat.getInt("receiveFrameError") == 5);
666         Assert.assertTrue(portStat.getInt("receiveOverRunError") == 6);
667         Assert.assertTrue(portStat.getInt("receiveCrcError") == 1);
668         Assert.assertTrue(portStat.getInt("collisionCount") == 4);
669     }
670
671     private void testFlowStat(JSONObject flowStat, String actionType, int actIndex) throws JSONException {
672         Assert.assertTrue(flowStat.getInt("tableId") == 1);
673         Assert.assertTrue(flowStat.getInt("durationSeconds") == 40);
674         Assert.assertTrue(flowStat.getInt("durationNanoseconds") == 400);
675         Assert.assertTrue(flowStat.getInt("packetCount") == 200);
676         Assert.assertTrue(flowStat.getInt("byteCount") == 100);
677
678         // test that flow information is correct
679         JSONObject flow = flowStat.getJSONObject("flow");
680         Assert.assertTrue(flow.getInt("priority") == (3500 + actIndex));
681         Assert.assertTrue(flow.getInt("idleTimeout") == 1000);
682         Assert.assertTrue(flow.getInt("hardTimeout") == 2000);
683         Assert.assertTrue(flow.getInt("id") == 12345);
684
685         JSONObject match = (flow.getJSONObject("match").getJSONObject("matchField"));
686         Assert.assertTrue(match.getString("type").equals("NW_DST"));
687         Assert.assertTrue(match.getString("value").equals("1.1.1.1"));
688
689         JSONObject act = flow.getJSONObject("actions");
690         Assert.assertTrue(act.getString("@type").equals(actionType));
691
692         if (act.getString("@type").equals("output")) {
693             JSONObject port = act.getJSONObject("port");
694             JSONObject port_node = port.getJSONObject("node");
695             Assert.assertTrue(port.getInt("@id") == 51966);
696             Assert.assertTrue(port.getString("@type").equals("STUB"));
697             Assert.assertTrue(port_node.getInt("@id") == 51966);
698             Assert.assertTrue(port_node.getString("@type").equals("STUB"));
699         }
700
701         if (act.getString("@type").equals("setDlSrc")) {
702             byte srcMatch[] = { (byte) 5, (byte) 4, (byte) 3, (byte) 2, (byte) 1 };
703             String src = act.getString("address");
704             byte srcBytes[] = new byte[5];
705             srcBytes[0] = Byte.parseByte(src.substring(0, 2));
706             srcBytes[1] = Byte.parseByte(src.substring(2, 4));
707             srcBytes[2] = Byte.parseByte(src.substring(4, 6));
708             srcBytes[3] = Byte.parseByte(src.substring(6, 8));
709             srcBytes[4] = Byte.parseByte(src.substring(8, 10));
710             Assert.assertTrue(Arrays.equals(srcBytes, srcMatch));
711         }
712
713         if (act.getString("@type").equals("setDlDst")) {
714             byte dstMatch[] = { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5 };
715             String dst = act.getString("address");
716             byte dstBytes[] = new byte[5];
717             dstBytes[0] = Byte.parseByte(dst.substring(0, 2));
718             dstBytes[1] = Byte.parseByte(dst.substring(2, 4));
719             dstBytes[2] = Byte.parseByte(dst.substring(4, 6));
720             dstBytes[3] = Byte.parseByte(dst.substring(6, 8));
721             dstBytes[4] = Byte.parseByte(dst.substring(8, 10));
722             Assert.assertTrue(Arrays.equals(dstBytes, dstMatch));
723         }
724         if (act.getString("@type").equals("setDlType"))
725             Assert.assertTrue(act.getInt("dlType") == 10);
726         if (act.getString("@type").equals("setVlanId"))
727             Assert.assertTrue(act.getInt("vlanId") == 2);
728         if (act.getString("@type").equals("setVlanPcp"))
729             Assert.assertTrue(act.getInt("pcp") == 3);
730         if (act.getString("@type").equals("setVlanCfi"))
731             Assert.assertTrue(act.getInt("cfi") == 1);
732
733         if (act.getString("@type").equals("setNwSrc"))
734             Assert.assertTrue(act.getString("address").equals("2.2.2.2"));
735         if (act.getString("@type").equals("setNwDst"))
736             Assert.assertTrue(act.getString("address").equals("1.1.1.1"));
737
738         if (act.getString("@type").equals("pushVlan")) {
739             int head = act.getInt("VlanHeader");
740             // parsing vlan header
741             int id = head & 0xfff;
742             int cfi = (head >> 12) & 0x1;
743             int pcp = (head >> 13) & 0x7;
744             int tag = (head >> 16) & 0xffff;
745             Assert.assertTrue(id == 1234);
746             Assert.assertTrue(cfi == 1);
747             Assert.assertTrue(pcp == 1);
748             Assert.assertTrue(tag == 0x8100);
749         }
750         if (act.getString("@type").equals("setNwTos"))
751             Assert.assertTrue(act.getInt("tos") == 16);
752         if (act.getString("@type").equals("setTpSrc"))
753             Assert.assertTrue(act.getInt("port") == 4201);
754         if (act.getString("@type").equals("setTpDst"))
755             Assert.assertTrue(act.getInt("port") == 8080);
756     }
757
758     @Test
759     public void testFlowProgrammer() throws JSONException {
760         System.out.println("Starting FlowProgrammer JAXB client.");
761         String baseURL = "http://127.0.0.1:8080/controller/nb/v2/flow/default/";
762         // Attempt to get a flow that doesn't exit. Should return 404
763         // status.
764         String result = getJsonResult(baseURL + "STUB/51966/test1", "GET");
765         Assert.assertTrue(result.equals("404"));
766
767         // test add flow1
768         String fc = "{\"dynamic\":\"false\", \"name\":\"test1\", \"node\":{\"@id\":\"51966\",\"@type\":\"STUB\"}, \"actions\":[\"DROP\"]}";
769         result = getJsonResult(baseURL + "STUB/51966/test1", "POST", fc);
770         Assert.assertTrue(httpResponseCode == 201);
771
772         // test get returns flow that was added.
773         result = getJsonResult(baseURL + "STUB/51966/test1", "GET");
774         // check that result came out fine.
775         Assert.assertTrue(httpResponseCode == 200);
776         JSONTokener jt = new JSONTokener(result);
777         JSONObject json = new JSONObject(jt);
778         Assert.assertEquals(json.getString("name"), "test1");
779         Assert.assertEquals(json.getString("actions"), "DROP");
780         Assert.assertEquals(json.getString("installInHw"), "true");
781         JSONObject node = json.getJSONObject("node");
782         Assert.assertEquals(node.getString("@type"), "STUB");
783         Assert.assertEquals(node.getString("@id"), "51966");
784         // test adding same flow again fails due to repeat name..return 409
785         // code
786         result = getJsonResult(baseURL + "STUB/51966/test1", "POST", fc);
787         Assert.assertTrue(result.equals("409"));
788
789         fc = "{\"dynamic\":\"false\", \"name\":\"test2\", \"node\":{\"@id\":\"51966\",\"@type\":\"STUB\"}, \"actions\":[\"DROP\"]}";
790         result = getJsonResult(baseURL + "STUB/51966/test2", "POST", fc);
791         // test should return 500 for error due to same flow being added.
792         Assert.assertTrue(result.equals("500"));
793
794         // add second flow that's different
795         fc = "{\"dynamic\":\"false\", \"name\":\"test2\", \"nwSrc\":\"1.1.1.1\", \"node\":{\"@id\":\"51966\",\"@type\":\"STUB\"}, \"actions\":[\"DROP\"]}";
796         result = getJsonResult(baseURL + "STUB/51966/test2", "POST", fc);
797         Assert.assertTrue(httpResponseCode == 201);
798
799         // check that request returns both flows given node.
800         result = getJsonResult(baseURL + "STUB/51966/", "GET");
801         jt = new JSONTokener(result);
802         json = new JSONObject(jt);
803         Assert.assertTrue(json.get("flowConfig") instanceof JSONArray);
804         JSONArray ja = json.getJSONArray("flowConfig");
805         Integer count = ja.length();
806         Assert.assertTrue(count == 2);
807
808         // check that request returns both flows given just container.
809         result = getJsonResult(baseURL);
810         jt = new JSONTokener(result);
811         json = new JSONObject(jt);
812         Assert.assertTrue(json.get("flowConfig") instanceof JSONArray);
813         ja = json.getJSONArray("flowConfig");
814         count = ja.length();
815         Assert.assertTrue(count == 2);
816
817         // delete a flow, check that it's no longer in list.
818         result = getJsonResult(baseURL + "STUB/51966/test2", "DELETE");
819         Assert.assertTrue(httpResponseCode == 200);
820
821         result = getJsonResult(baseURL + "STUB/51966/test2", "GET");
822         Assert.assertTrue(result.equals("404"));
823     }
824
825     // method to extract a JSONObject with specified node ID from a JSONObject
826     // that may contain an array of JSONObjects
827     // This is specifically written for statistics manager northbound REST
828     // interface
829     // array_name should be either "flowStatistics" or "portStatistics"
830     private JSONObject getJsonInstance(JSONObject json, String array_name, Integer nodeId) throws JSONException {
831         JSONObject result = null;
832         if (json.get(array_name) instanceof JSONArray) {
833             JSONArray json_array = json.getJSONArray(array_name);
834             for (int i = 0; i < json_array.length(); i++) {
835                 result = json_array.getJSONObject(i);
836                 Integer nid = result.getJSONObject("node").getInt("@id");
837                 if (nid.equals(nodeId))
838                     break;
839             }
840         } else {
841             result = json.getJSONObject(array_name);
842             Integer nid = result.getJSONObject("node").getInt("@id");
843             if (!nid.equals(nodeId))
844                 result = null;
845         }
846         return result;
847     }
848
849     // a class to construct query parameter for HTTP request
850     private class QueryParameter {
851         StringBuilder queryString = null;
852
853         // constructor
854         QueryParameter(String key, String value) {
855             queryString = new StringBuilder();
856             queryString.append("?").append(key).append("=").append(value);
857         }
858
859         // method to add more query parameter
860         QueryParameter add(String key, String value) {
861             this.queryString.append("&").append(key).append("=").append(value);
862             return this;
863         }
864
865         // method to get the query parameter string
866         String getString() {
867             return this.queryString.toString();
868         }
869
870     }
871
872     @Test
873     public void testHostTracker() throws JSONException {
874
875         System.out.println("Starting HostTracker JAXB client.");
876
877         // setup 2 host models for @POST method
878         // 1st host
879         String networkAddress_1 = "192.168.0.8";
880         String dataLayerAddress_1 = "11:22:33:44:55:66";
881         String nodeType_1 = "STUB";
882         Integer nodeId_1 = 3366;
883         String nodeConnectorType_1 = "STUB";
884         Integer nodeConnectorId_1 = 12;
885         String vlan_1 = "4";
886
887         // 2nd host
888         String networkAddress_2 = "10.1.1.1";
889         String dataLayerAddress_2 = "1A:2B:3C:4D:5E:6F";
890         String nodeType_2 = "STUB";
891         Integer nodeId_2 = 4477;
892         String nodeConnectorType_2 = "STUB";
893         Integer nodeConnectorId_2 = 34;
894         String vlan_2 = "0";
895
896         String baseURL = "http://127.0.0.1:8080/controller/nb/v2/host/default";
897
898         // test POST method: addHost()
899         String queryParameter = new QueryParameter("dataLayerAddress", dataLayerAddress_1).add("nodeType", nodeType_1)
900                 .add("nodeId", nodeId_1.toString()).add("nodeConnectorType", nodeConnectorType_1)
901                 .add("nodeConnectorId", nodeConnectorId_1.toString()).add("vlan", vlan_1).getString();
902
903         String result = getJsonResult(baseURL + "/" + networkAddress_1 + queryParameter, "POST");
904         Assert.assertTrue(httpResponseCode == 201);
905
906         // vlan is not passed through query parameter but should be
907         // defaulted to "0"
908         queryParameter = new QueryParameter("dataLayerAddress", dataLayerAddress_2).add("nodeType", nodeType_2)
909                 .add("nodeId", nodeId_2.toString()).add("nodeConnectorType", nodeConnectorType_2)
910                 .add("nodeConnectorId", nodeConnectorId_2.toString()).getString();
911
912         result = getJsonResult(baseURL + "/" + networkAddress_2 + queryParameter, "POST");
913         Assert.assertTrue(httpResponseCode == 201);
914
915         // define variables for decoding returned strings
916         String networkAddress;
917         JSONObject host_jo, dl_jo, nc_jo, node_jo;
918
919         // the two hosts should be in inactive host DB
920         // test GET method: getInactiveHosts()
921         result = getJsonResult(baseURL + "/inactive", "GET");
922         Assert.assertTrue(httpResponseCode == 200);
923
924         JSONTokener jt = new JSONTokener(result);
925         JSONObject json = new JSONObject(jt);
926         // there should be at least two hosts in the DB
927         Assert.assertTrue(json.get("host") instanceof JSONArray);
928         JSONArray ja = json.getJSONArray("host");
929         Integer count = ja.length();
930         Assert.assertTrue(count == 2);
931
932         for (int i = 0; i < count; i++) {
933             host_jo = ja.getJSONObject(i);
934             dl_jo = host_jo.getJSONObject("dataLayerAddress");
935             nc_jo = host_jo.getJSONObject("nodeConnector");
936             node_jo = nc_jo.getJSONObject("node");
937
938             networkAddress = host_jo.getString("networkAddress");
939             if (networkAddress.equalsIgnoreCase(networkAddress_1)) {
940                 Assert.assertTrue(dl_jo.getString("macAddress").equalsIgnoreCase(dataLayerAddress_1));
941                 Assert.assertTrue(nc_jo.getString("@type").equalsIgnoreCase(nodeConnectorType_1));
942                 Assert.assertTrue(nc_jo.getInt("@id") == nodeConnectorId_1);
943                 Assert.assertTrue(node_jo.getString("@type").equalsIgnoreCase(nodeType_1));
944                 Assert.assertTrue(node_jo.getInt("@id") == nodeId_1);
945                 Assert.assertTrue(host_jo.getString("vlan").equalsIgnoreCase(vlan_1));
946             } else if (networkAddress.equalsIgnoreCase(networkAddress_2)) {
947                 Assert.assertTrue(dl_jo.getString("macAddress").equalsIgnoreCase(dataLayerAddress_2));
948                 Assert.assertTrue(nc_jo.getString("@type").equalsIgnoreCase(nodeConnectorType_2));
949                 Assert.assertTrue(nc_jo.getInt("@id") == nodeConnectorId_2);
950                 Assert.assertTrue(node_jo.getString("@type").equalsIgnoreCase(nodeType_2));
951                 Assert.assertTrue(node_jo.getInt("@id") == nodeId_2);
952                 Assert.assertTrue(host_jo.getString("vlan").equalsIgnoreCase(vlan_2));
953             } else {
954                 Assert.assertTrue(false);
955             }
956         }
957
958         // test GET method: getActiveHosts() - no host expected
959         result = getJsonResult(baseURL, "GET");
960         Assert.assertTrue(httpResponseCode == 200);
961
962         jt = new JSONTokener(result);
963         json = new JSONObject(jt);
964         Assert.assertFalse(hostInJson(json, networkAddress_1));
965         Assert.assertFalse(hostInJson(json, networkAddress_2));
966
967         // put the 1st host into active host DB
968         Node nd;
969         NodeConnector ndc;
970         try {
971             nd = new Node(nodeType_1, nodeId_1);
972             ndc = new NodeConnector(nodeConnectorType_1, nodeConnectorId_1, nd);
973             this.invtoryListener.notifyNodeConnector(ndc, UpdateType.ADDED, null);
974         } catch (ConstructionException e) {
975             ndc = null;
976             nd = null;
977         }
978
979         // verify the host shows up in active host DB
980
981         result = getJsonResult(baseURL, "GET");
982         Assert.assertTrue(httpResponseCode == 200);
983
984         jt = new JSONTokener(result);
985         json = new JSONObject(jt);
986
987         Assert.assertTrue(hostInJson(json, networkAddress_1));
988
989         // test GET method for getHostDetails()
990
991         result = getJsonResult(baseURL + "/" + networkAddress_1, "GET");
992         Assert.assertTrue(httpResponseCode == 200);
993
994         jt = new JSONTokener(result);
995         json = new JSONObject(jt);
996
997         Assert.assertFalse(json.length() == 0);
998
999         dl_jo = json.getJSONObject("dataLayerAddress");
1000         nc_jo = json.getJSONObject("nodeConnector");
1001         node_jo = nc_jo.getJSONObject("node");
1002
1003         Assert.assertTrue(json.getString("networkAddress").equalsIgnoreCase(networkAddress_1));
1004         Assert.assertTrue(dl_jo.getString("macAddress").equalsIgnoreCase(dataLayerAddress_1));
1005         Assert.assertTrue(nc_jo.getString("@type").equalsIgnoreCase(nodeConnectorType_1));
1006         Assert.assertTrue(Integer.parseInt(nc_jo.getString("@id")) == nodeConnectorId_1);
1007         Assert.assertTrue(node_jo.getString("@type").equalsIgnoreCase(nodeType_1));
1008         Assert.assertTrue(Integer.parseInt(node_jo.getString("@id")) == nodeId_1);
1009         Assert.assertTrue(json.getString("vlan").equalsIgnoreCase(vlan_1));
1010
1011         // test DELETE method for deleteFlow()
1012
1013         result = getJsonResult(baseURL + "/" + networkAddress_1, "DELETE");
1014         Assert.assertTrue(httpResponseCode == 200);
1015
1016         // verify host_1 removed from active host DB
1017         // test GET method: getActiveHosts() - no host expected
1018
1019         result = getJsonResult(baseURL, "GET");
1020         Assert.assertTrue(httpResponseCode == 200);
1021
1022         jt = new JSONTokener(result);
1023         json = new JSONObject(jt);
1024
1025         Assert.assertFalse(hostInJson(json, networkAddress_1));
1026
1027     }
1028
1029     private Boolean hostInJson(JSONObject json, String hostIp) throws JSONException {
1030         // input JSONObject may be empty
1031         if (json.length() == 0) {
1032             return false;
1033         }
1034         if (json.get("host") instanceof JSONArray) {
1035             JSONArray ja = json.getJSONArray("host");
1036             for (int i = 0; i < ja.length(); i++) {
1037                 String na = ja.getJSONObject(i).getString("networkAddress");
1038                 if (na.equalsIgnoreCase(hostIp))
1039                     return true;
1040             }
1041             return false;
1042         } else {
1043             String na = json.getJSONObject("host").getString("networkAddress");
1044             return (na.equalsIgnoreCase(hostIp)) ? true : false;
1045         }
1046     }
1047
1048     @Test
1049     public void testTopology() throws JSONException, ConstructionException {
1050         System.out.println("Starting Topology JAXB client.");
1051         String baseURL = "http://127.0.0.1:8080/controller/nb/v2/topology/default";
1052
1053         // === test GET method for getTopology()
1054         short state_1 = State.EDGE_UP, state_2 = State.EDGE_DOWN;
1055         long bw_1 = Bandwidth.BW10Gbps, bw_2 = Bandwidth.BW100Mbps;
1056         long lat_1 = Latency.LATENCY100ns, lat_2 = Latency.LATENCY1ms;
1057         String nodeType = "STUB";
1058         String nodeConnType = "STUB";
1059         int headNC1_nodeId = 1, headNC1_nodeConnId = 11;
1060         int tailNC1_nodeId = 2, tailNC1_nodeConnId = 22;
1061         int headNC2_nodeId = 2, headNC2_nodeConnId = 21;
1062         int tailNC2_nodeId = 1, tailNC2_nodeConnId = 12;
1063
1064         List<TopoEdgeUpdate> topoedgeupdateList = new ArrayList<TopoEdgeUpdate>();
1065         NodeConnector headnc1 = new NodeConnector(nodeConnType, headNC1_nodeConnId, new Node(nodeType, headNC1_nodeId));
1066         NodeConnector tailnc1 = new NodeConnector(nodeConnType, tailNC1_nodeConnId, new Node(nodeType, tailNC1_nodeId));
1067         Edge e1 = new Edge(tailnc1, headnc1);
1068         Set<Property> props_1 = new HashSet<Property>();
1069         props_1.add(new State(state_1));
1070         props_1.add(new Bandwidth(bw_1));
1071         props_1.add(new Latency(lat_1));
1072         TopoEdgeUpdate teu1 = new TopoEdgeUpdate(e1, props_1, UpdateType.ADDED);
1073         topoedgeupdateList.add(teu1);
1074
1075         NodeConnector headnc2 = new NodeConnector(nodeConnType, headNC2_nodeConnId, new Node(nodeType, headNC2_nodeId));
1076         NodeConnector tailnc2 = new NodeConnector(nodeConnType, tailNC2_nodeConnId, new Node(nodeType, tailNC2_nodeId));
1077         Edge e2 = new Edge(tailnc2, headnc2);
1078         Set<Property> props_2 = new HashSet<Property>();
1079         props_2.add(new State(state_2));
1080         props_2.add(new Bandwidth(bw_2));
1081         props_2.add(new Latency(lat_2));
1082
1083         TopoEdgeUpdate teu2 = new TopoEdgeUpdate(e2, props_2, UpdateType.ADDED);
1084         topoedgeupdateList.add(teu2);
1085
1086         topoUpdates.edgeUpdate(topoedgeupdateList);
1087
1088         // HTTP request
1089         String result = getJsonResult(baseURL, "GET");
1090         Assert.assertTrue(httpResponseCode == 200);
1091         if (debugMsg) {
1092             System.out.println("Get Topology: " + result);
1093         }
1094
1095         // returned data must be an array of edges
1096         JSONTokener jt = new JSONTokener(result);
1097         JSONObject json = new JSONObject(jt);
1098         Assert.assertTrue(json.get("edgeProperties") instanceof JSONArray);
1099         JSONArray ja = json.getJSONArray("edgeProperties");
1100
1101         for (int i = 0; i < ja.length(); i++) {
1102             JSONObject edgeProp = ja.getJSONObject(i);
1103             JSONObject edge = edgeProp.getJSONObject("edge");
1104             JSONObject tailNC = edge.getJSONObject("tailNodeConnector");
1105             JSONObject tailNode = tailNC.getJSONObject("node");
1106
1107             JSONObject headNC = edge.getJSONObject("headNodeConnector");
1108             JSONObject headNode = headNC.getJSONObject("node");
1109             JSONObject Props = edgeProp.getJSONObject("properties");
1110             JSONObject bandw = Props.getJSONObject("bandwidth");
1111             JSONObject stt = Props.getJSONObject("state");
1112             JSONObject ltc = Props.getJSONObject("latency");
1113
1114             if (headNC.getInt("@id") == headNC1_nodeConnId) {
1115                 Assert.assertEquals(headNode.getString("@type"), nodeType);
1116                 Assert.assertEquals(headNode.getLong("@id"), headNC1_nodeId);
1117                 Assert.assertEquals(headNC.getString("@type"), nodeConnType);
1118                 Assert.assertEquals(tailNode.getString("@type"),nodeType);
1119                 Assert.assertEquals(tailNode.getString("@type"), nodeConnType);
1120                 Assert.assertEquals(tailNC.getLong("@id"), tailNC1_nodeConnId);
1121                 Assert.assertEquals(bandw.getLong("bandwidthValue"), bw_1);
1122                 Assert.assertTrue((short) stt.getInt("stateValue") == state_1);
1123                 Assert.assertEquals(ltc.getLong("latencyValue"), lat_1);
1124             } else if (headNC.getInt("@id") == headNC2_nodeConnId) {
1125                 Assert.assertEquals(headNode.getString("@type"),nodeType);
1126                 Assert.assertEquals(headNode.getLong("@id"), headNC2_nodeId);
1127                 Assert.assertEquals(headNC.getString("@type"), nodeConnType);
1128                 Assert.assertEquals(tailNode.getString("@type"), nodeType);
1129                 Assert.assertTrue(tailNode.getInt("@id") == tailNC2_nodeId);
1130                 Assert.assertEquals(tailNC.getString("@type"), nodeConnType);
1131                 Assert.assertEquals(tailNC.getLong("@id"), tailNC2_nodeConnId);
1132                 Assert.assertEquals(bandw.getLong("bandwidthValue"), bw_2);
1133                 Assert.assertTrue((short) stt.getInt("stateValue") == state_2);
1134                 Assert.assertEquals(ltc.getLong("latencyValue"), lat_2);
1135             }
1136         }
1137
1138         // === test POST method for addUserLink()
1139         // define 2 sample nodeConnectors for user link configuration tests
1140         String nodeType_1 = "STUB";
1141         Integer nodeId_1 = 3366;
1142         String nodeConnectorType_1 = "STUB";
1143         Integer nodeConnectorId_1 = 12;
1144
1145         String nodeType_2 = "STUB";
1146         Integer nodeId_2 = 4477;
1147         String nodeConnectorType_2 = "STUB";
1148         Integer nodeConnectorId_2 = 34;
1149
1150         JSONObject jo = new JSONObject()
1151                 .append("name", "userLink_1")
1152                 .append("srcNodeConnector",
1153                         nodeConnectorType_1 + "|" + nodeConnectorId_1 + "@" + nodeType_1 + "|" + nodeId_1)
1154                 .append("dstNodeConnector",
1155                         nodeConnectorType_2 + "|" + nodeConnectorId_2 + "@" + nodeType_2 + "|" + nodeId_2);
1156         // execute HTTP request and verify response code
1157         result = getJsonResult(baseURL + "/userLink", "POST", jo.toString());
1158         Assert.assertTrue(httpResponseCode == 201);
1159
1160         // === test GET method for getUserLinks()
1161         result = getJsonResult(baseURL + "/userLink", "GET");
1162         Assert.assertTrue(httpResponseCode == 200);
1163         if (debugMsg) {
1164             System.out.println("result:" + result);
1165         }
1166
1167         jt = new JSONTokener(result);
1168         json = new JSONObject(jt);
1169
1170         // should have at least one object returned
1171         Assert.assertFalse(json.length() == 0);
1172         JSONObject userlink = new JSONObject();
1173
1174         if (json.get("userLinks") instanceof JSONArray) {
1175             ja = json.getJSONArray("userLinks");
1176             int i;
1177             for (i = 0; i < ja.length(); i++) {
1178                 userlink = ja.getJSONObject(i);
1179                 if (userlink.getString("name").equalsIgnoreCase("userLink_1"))
1180                     break;
1181             }
1182             Assert.assertFalse(i == ja.length());
1183         } else {
1184             userlink = json.getJSONObject("userLinks");
1185             Assert.assertTrue(userlink.getString("name").equalsIgnoreCase("userLink_1"));
1186         }
1187
1188         String[] level_1, level_2;
1189         level_1 = userlink.getString("srcNodeConnector").split("\\@");
1190         level_2 = level_1[0].split("\\|");
1191         Assert.assertTrue(level_2[0].equalsIgnoreCase(nodeConnectorType_1));
1192         Assert.assertTrue(Integer.parseInt(level_2[1]) == nodeConnectorId_1);
1193         level_2 = level_1[1].split("\\|");
1194         Assert.assertTrue(level_2[0].equalsIgnoreCase(nodeType_1));
1195         Assert.assertTrue(Integer.parseInt(level_2[1]) == nodeId_1);
1196         level_1 = userlink.getString("dstNodeConnector").split("\\@");
1197         level_2 = level_1[0].split("\\|");
1198         Assert.assertTrue(level_2[0].equalsIgnoreCase(nodeConnectorType_2));
1199         Assert.assertTrue(Integer.parseInt(level_2[1]) == nodeConnectorId_2);
1200         level_2 = level_1[1].split("\\|");
1201         Assert.assertTrue(level_2[0].equalsIgnoreCase(nodeType_2));
1202         Assert.assertTrue(Integer.parseInt(level_2[1]) == nodeId_2);
1203
1204         // === test DELETE method for deleteUserLink()
1205         String userName = "userLink_1";
1206         result = getJsonResult(baseURL + "/userLink/" + userName, "DELETE");
1207         Assert.assertTrue(httpResponseCode == 200);
1208
1209         // execute another getUserLinks() request to verify that userLink_1 is
1210         // removed
1211         result = getJsonResult(baseURL + "/userLink", "GET");
1212         Assert.assertTrue(httpResponseCode == 200);
1213         if (debugMsg) {
1214             System.out.println("result:" + result);
1215         }
1216         jt = new JSONTokener(result);
1217         json = new JSONObject(jt);
1218
1219         if (json.length() != 0) {
1220             if (json.get("userLinks") instanceof JSONArray) {
1221                 ja = json.getJSONArray("userLinks");
1222                 for (int i = 0; i < ja.length(); i++) {
1223                     userlink = ja.getJSONObject(i);
1224                     Assert.assertFalse(userlink.getString("name").equalsIgnoreCase("userLink_1"));
1225                 }
1226             } else {
1227                 userlink = json.getJSONObject("userLinks");
1228                 Assert.assertFalse(userlink.getString("name").equalsIgnoreCase("userLink_1"));
1229             }
1230         }
1231     }
1232
1233     // Configure the OSGi container
1234     @Configuration
1235     public Option[] config() {
1236         return options(
1237                 //
1238                 systemProperty("logback.configurationFile").value(
1239                         "file:" + PathUtils.getBaseDir() + "/src/test/resources/logback.xml"),
1240                 // To start OSGi console for inspection remotely
1241                 systemProperty("osgi.console").value("2401"),
1242                 systemProperty("org.eclipse.gemini.web.tomcat.config.path").value(
1243                         PathUtils.getBaseDir() + "/src/test/resources/tomcat-server.xml"),
1244
1245                 // setting default level. Jersey bundles will need to be started
1246                 // earlier.
1247                 systemProperty("osgi.bundles.defaultStartLevel").value("4"),
1248
1249                 // Set the systemPackages (used by clustering)
1250                 systemPackages("sun.reflect", "sun.reflect.misc", "sun.misc"),
1251                 mavenBundle("javax.servlet", "servlet-api", "2.5"),
1252
1253                 mavenBundle("org.slf4j", "jcl-over-slf4j", "1.7.2"),
1254                 mavenBundle("org.slf4j", "slf4j-api", "1.7.2"),
1255                 mavenBundle("org.slf4j", "log4j-over-slf4j", "1.7.2"),
1256                 mavenBundle("ch.qos.logback", "logback-core", "1.0.9"),
1257                 mavenBundle("ch.qos.logback", "logback-classic", "1.0.9"),
1258                 mavenBundle("org.apache.commons", "commons-lang3", "3.1"),
1259                 mavenBundle("org.apache.felix", "org.apache.felix.dependencymanager", "3.1.0"),
1260
1261                 // the plugin stub to get data for the tests
1262                 mavenBundle("org.opendaylight.controller", "protocol_plugins.stub", "0.4.0-SNAPSHOT"),
1263
1264                 // List all the opendaylight modules
1265                 mavenBundle("org.opendaylight.controller", "configuration", "0.4.0-SNAPSHOT"),
1266                 mavenBundle("org.opendaylight.controller", "configuration.implementation", "0.4.0-SNAPSHOT"),
1267                 mavenBundle("org.opendaylight.controller", "containermanager", "0.4.0-SNAPSHOT"),
1268                 mavenBundle("org.opendaylight.controller", "containermanager.implementation", "0.4.0-SNAPSHOT"),
1269                 mavenBundle("org.opendaylight.controller", "clustering.services", "0.4.0-SNAPSHOT"),
1270                 mavenBundle("org.opendaylight.controller", "clustering.services-implementation", "0.4.0-SNAPSHOT"),
1271                 mavenBundle("org.opendaylight.controller", "security", "0.4.0-SNAPSHOT").noStart(),
1272                 mavenBundle("org.opendaylight.controller", "sal", "0.5.0-SNAPSHOT"),
1273                 mavenBundle("org.opendaylight.controller", "sal.implementation", "0.4.0-SNAPSHOT"),
1274                 mavenBundle("org.opendaylight.controller", "switchmanager", "0.5.0-SNAPSHOT"),
1275                 mavenBundle("org.opendaylight.controller", "switchmanager.implementation", "0.4.0-SNAPSHOT"),
1276                 mavenBundle("org.opendaylight.controller", "forwardingrulesmanager", "0.4.0-SNAPSHOT"),
1277                 mavenBundle("org.opendaylight.controller", "forwardingrulesmanager.implementation", "0.4.0-SNAPSHOT"),
1278                 mavenBundle("org.opendaylight.controller", "statisticsmanager", "0.4.0-SNAPSHOT"),
1279                 mavenBundle("org.opendaylight.controller", "statisticsmanager.implementation", "0.4.0-SNAPSHOT"),
1280                 mavenBundle("org.opendaylight.controller", "arphandler", "0.4.0-SNAPSHOT"),
1281                 mavenBundle("org.opendaylight.controller", "hosttracker", "0.4.0-SNAPSHOT"),
1282                 mavenBundle("org.opendaylight.controller", "hosttracker.implementation", "0.4.0-SNAPSHOT"),
1283                 mavenBundle("org.opendaylight.controller", "arphandler", "0.4.0-SNAPSHOT"),
1284                 mavenBundle("org.opendaylight.controller", "routing.dijkstra_implementation", "0.4.0-SNAPSHOT"),
1285                 mavenBundle("org.opendaylight.controller", "topologymanager", "0.4.0-SNAPSHOT"),
1286                 mavenBundle("org.opendaylight.controller", "usermanager", "0.4.0-SNAPSHOT"),
1287                 mavenBundle("org.opendaylight.controller", "usermanager.implementation", "0.4.0-SNAPSHOT"),
1288                 mavenBundle("org.opendaylight.controller", "logging.bridge", "0.4.0-SNAPSHOT"),
1289                 mavenBundle("org.opendaylight.controller", "clustering.test", "0.4.0-SNAPSHOT"),
1290                 mavenBundle("org.opendaylight.controller", "forwarding.staticrouting", "0.4.0-SNAPSHOT"),
1291
1292                 // Northbound bundles
1293                 mavenBundle("org.opendaylight.controller", "commons.northbound", "0.4.0-SNAPSHOT"),
1294                 mavenBundle("org.opendaylight.controller", "forwarding.staticrouting.northbound", "0.4.0-SNAPSHOT"),
1295                 mavenBundle("org.opendaylight.controller", "statistics.northbound", "0.4.0-SNAPSHOT"),
1296                 mavenBundle("org.opendaylight.controller", "topology.northbound", "0.4.0-SNAPSHOT"),
1297                 mavenBundle("org.opendaylight.controller", "hosttracker.northbound", "0.4.0-SNAPSHOT"),
1298                 mavenBundle("org.opendaylight.controller", "switchmanager.northbound", "0.4.0-SNAPSHOT"),
1299                 mavenBundle("org.opendaylight.controller", "flowprogrammer.northbound", "0.4.0-SNAPSHOT"),
1300                 mavenBundle("org.opendaylight.controller", "subnets.northbound", "0.4.0-SNAPSHOT"),
1301
1302                 mavenBundle("org.codehaus.jackson", "jackson-mapper-asl", "1.9.8"),
1303                 mavenBundle("org.codehaus.jackson", "jackson-core-asl", "1.9.8"),
1304                 mavenBundle("org.codehaus.jackson", "jackson-jaxrs", "1.9.8"),
1305                 mavenBundle("org.codehaus.jettison", "jettison", "1.3.3"),
1306
1307                 mavenBundle("commons-io", "commons-io", "2.3"),
1308
1309                 mavenBundle("commons-fileupload", "commons-fileupload", "1.2.2"),
1310
1311                 mavenBundle("equinoxSDK381", "javax.servlet", "3.0.0.v201112011016"),
1312                 mavenBundle("equinoxSDK381", "javax.servlet.jsp", "2.2.0.v201112011158"),
1313                 mavenBundle("equinoxSDK381", "org.eclipse.equinox.ds", "1.4.0.v20120522-1841"),
1314                 mavenBundle("orbit", "javax.xml.rpc", "1.1.0.v201005080400"),
1315                 mavenBundle("equinoxSDK381", "org.eclipse.equinox.util", "1.0.400.v20120522-2049"),
1316                 mavenBundle("equinoxSDK381", "org.eclipse.osgi.services", "3.3.100.v20120522-1822"),
1317                 mavenBundle("equinoxSDK381", "org.apache.felix.gogo.command", "0.8.0.v201108120515"),
1318                 mavenBundle("equinoxSDK381", "org.apache.felix.gogo.runtime", "0.8.0.v201108120515"),
1319                 mavenBundle("equinoxSDK381", "org.apache.felix.gogo.shell", "0.8.0.v201110170705"),
1320                 mavenBundle("equinoxSDK381", "org.eclipse.equinox.cm", "1.0.400.v20120522-1841"),
1321                 mavenBundle("equinoxSDK381", "org.eclipse.equinox.console", "1.0.0.v20120522-1841"),
1322                 mavenBundle("equinoxSDK381", "org.eclipse.equinox.launcher", "1.3.0.v20120522-1813"),
1323
1324                 mavenBundle("geminiweb", "org.eclipse.gemini.web.core", "2.2.0.RELEASE"),
1325                 mavenBundle("geminiweb", "org.eclipse.gemini.web.extender", "2.2.0.RELEASE"),
1326                 mavenBundle("geminiweb", "org.eclipse.gemini.web.tomcat", "2.2.0.RELEASE"),
1327                 mavenBundle("geminiweb", "org.eclipse.virgo.kernel.equinox.extensions", "3.6.0.RELEASE").noStart(),
1328                 mavenBundle("geminiweb", "org.eclipse.virgo.util.common", "3.6.0.RELEASE"),
1329                 mavenBundle("geminiweb", "org.eclipse.virgo.util.io", "3.6.0.RELEASE"),
1330                 mavenBundle("geminiweb", "org.eclipse.virgo.util.math", "3.6.0.RELEASE"),
1331                 mavenBundle("geminiweb", "org.eclipse.virgo.util.osgi", "3.6.0.RELEASE"),
1332                 mavenBundle("geminiweb", "org.eclipse.virgo.util.osgi.manifest", "3.6.0.RELEASE"),
1333                 mavenBundle("geminiweb", "org.eclipse.virgo.util.parser.manifest", "3.6.0.RELEASE"),
1334
1335                 mavenBundle("org.apache.felix", "org.apache.felix.dependencymanager", "3.1.0"),
1336                 mavenBundle("org.apache.felix", "org.apache.felix.dependencymanager.shell", "3.0.1"),
1337
1338                 mavenBundle("com.google.code.gson", "gson", "2.1"),
1339                 mavenBundle("org.jboss.spec.javax.transaction", "jboss-transaction-api_1.1_spec", "1.0.1.Final"),
1340                 mavenBundle("org.apache.felix", "org.apache.felix.fileinstall", "3.1.6"),
1341                 mavenBundle("org.apache.commons", "commons-lang3", "3.1"),
1342                 mavenBundle("commons-codec", "commons-codec"),
1343                 mavenBundle("virgomirror", "org.eclipse.jdt.core.compiler.batch", "3.8.0.I20120518-2145"),
1344                 mavenBundle("eclipselink", "javax.persistence", "2.0.4.v201112161009"),
1345
1346                 mavenBundle("orbit", "javax.activation", "1.1.0.v201211130549"),
1347                 mavenBundle("orbit", "javax.annotation", "1.1.0.v201209060031"),
1348                 mavenBundle("orbit", "javax.ejb", "3.1.1.v201204261316"),
1349                 mavenBundle("orbit", "javax.el", "2.2.0.v201108011116"),
1350                 mavenBundle("orbit", "javax.mail.glassfish", "1.4.1.v201108011116"),
1351                 mavenBundle("orbit", "javax.xml.rpc", "1.1.0.v201005080400"),
1352                 mavenBundle("orbit", "org.apache.catalina", "7.0.32.v201211201336"),
1353                 // these are bundle fragments that can't be started on its own
1354                 mavenBundle("orbit", "org.apache.catalina.ha", "7.0.32.v201211201952").noStart(),
1355                 mavenBundle("orbit", "org.apache.catalina.tribes", "7.0.32.v201211201952").noStart(),
1356                 mavenBundle("orbit", "org.apache.coyote", "7.0.32.v201211201952").noStart(),
1357                 mavenBundle("orbit", "org.apache.jasper", "7.0.32.v201211201952").noStart(),
1358
1359                 mavenBundle("orbit", "org.apache.el", "7.0.32.v201211081135"),
1360                 mavenBundle("orbit", "org.apache.juli.extras", "7.0.32.v201211081135"),
1361                 mavenBundle("orbit", "org.apache.tomcat.api", "7.0.32.v201211081135"),
1362                 mavenBundle("orbit", "org.apache.tomcat.util", "7.0.32.v201211201952").noStart(),
1363                 mavenBundle("orbit", "javax.servlet.jsp.jstl", "1.2.0.v201105211821"),
1364                 mavenBundle("orbit", "javax.servlet.jsp.jstl.impl", "1.2.0.v201210211230"),
1365
1366                 mavenBundle("org.ops4j.pax.exam", "pax-exam-container-native"),
1367                 mavenBundle("org.ops4j.pax.exam", "pax-exam-junit4"),
1368                 mavenBundle("org.ops4j.pax.exam", "pax-exam-link-mvn"),
1369                 mavenBundle("org.ops4j.pax.url", "pax-url-aether"),
1370
1371                 mavenBundle("org.springframework", "org.springframework.asm", "3.1.3.RELEASE"),
1372                 mavenBundle("org.springframework", "org.springframework.aop", "3.1.3.RELEASE"),
1373                 mavenBundle("org.springframework", "org.springframework.context", "3.1.3.RELEASE"),
1374                 mavenBundle("org.springframework", "org.springframework.context.support", "3.1.3.RELEASE"),
1375                 mavenBundle("org.springframework", "org.springframework.core", "3.1.3.RELEASE"),
1376                 mavenBundle("org.springframework", "org.springframework.beans", "3.1.3.RELEASE"),
1377                 mavenBundle("org.springframework", "org.springframework.expression", "3.1.3.RELEASE"),
1378                 mavenBundle("org.springframework", "org.springframework.web", "3.1.3.RELEASE"),
1379
1380                 mavenBundle("org.aopalliance", "com.springsource.org.aopalliance", "1.0.0"),
1381                 mavenBundle("org.springframework", "org.springframework.web.servlet", "3.1.3.RELEASE"),
1382                 mavenBundle("org.springframework.security", "spring-security-config", "3.1.3.RELEASE"),
1383                 mavenBundle("org.springframework.security", "spring-security-core", "3.1.3.RELEASE"),
1384                 mavenBundle("org.springframework.security", "spring-security-web", "3.1.3.RELEASE"),
1385                 mavenBundle("org.springframework.security", "spring-security-taglibs", "3.1.3.RELEASE"),
1386                 mavenBundle("org.springframework", "org.springframework.transaction", "3.1.3.RELEASE"),
1387
1388                 mavenBundle("org.ow2.chameleon.management", "chameleon-mbeans", "1.0.0"),
1389                 mavenBundle("org.opendaylight.controller.thirdparty", "net.sf.jung2", "2.0.1-SNAPSHOT"),
1390                 mavenBundle("org.opendaylight.controller.thirdparty", "com.sun.jersey.jersey-servlet", "1.17-SNAPSHOT"),
1391
1392                 // Jersey needs to be started before the northbound application
1393                 // bundles, using a lower start level
1394                 mavenBundle("com.sun.jersey", "jersey-client", "1.17"),
1395                 mavenBundle("com.sun.jersey", "jersey-server", "1.17").startLevel(2),
1396                 mavenBundle("com.sun.jersey", "jersey-core", "1.17").startLevel(2),
1397                 mavenBundle("com.sun.jersey", "jersey-json", "1.17").startLevel(2), junitBundles());
1398     }
1399
1400 }