diff options
Diffstat (limited to 'sdnr')
145 files changed, 5549 insertions, 1420 deletions
diff --git a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/configuration/ConfigurationFileRepresentation.java b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/configuration/ConfigurationFileRepresentation.java index fe43837e2..96bfa070b 100644 --- a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/configuration/ConfigurationFileRepresentation.java +++ b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/configuration/ConfigurationFileRepresentation.java @@ -29,7 +29,6 @@ import java.io.FileWriter; import java.io.IOException; import java.util.HashMap; import java.util.Optional; - import org.onap.ccsdk.features.sdnr.wt.common.configuration.filechange.ConfigFileObserver; import org.onap.ccsdk.features.sdnr.wt.common.configuration.filechange.IConfigChangedListener; import org.onap.ccsdk.features.sdnr.wt.common.configuration.subtypes.Section; @@ -71,6 +70,8 @@ public class ConfigurationFileRepresentation implements IConfigChangedListener { if (!this.mFile.createNewFile()) { LOG.error("Can not create file {}", f.getAbsolutePath()); } + this.mFile.setReadable(true, false); + this.mFile.setWritable(true, false); } reLoad(); diff --git a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/configuration/subtypes/Section.java b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/configuration/subtypes/Section.java index 7fb58a165..c6b121ae3 100644 --- a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/configuration/subtypes/Section.java +++ b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/configuration/subtypes/Section.java @@ -29,7 +29,6 @@ import java.util.Objects; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; - import org.eclipse.jdt.annotation.NonNull; import org.onap.ccsdk.features.sdnr.wt.common.configuration.exception.ConversionException; import org.slf4j.Logger; @@ -51,7 +50,8 @@ public class Section { // constants private static final Logger LOG = LoggerFactory.getLogger(Section.class); private static final String DELIMITER = "="; - private static final String COMMENTCHARS[] = {"#", ";"}; + private static final String DEFAULT_COMMENTCHAR = "#"; + private static final String COMMENTCHARS[] = {DEFAULT_COMMENTCHAR, ";"}; private static final String ENVVARIABLE = "${"; private static final String REGEXENVVARIABLE = "(\\$\\{[A-Z0-9_-]+\\})"; // end of constants @@ -132,6 +132,20 @@ public class Section { return value; } + public boolean addComment(String key,String comment) { + if (this.values.containsKey(key)) { + this.values.get(key).addComment(DEFAULT_COMMENTCHAR+comment); + } + return false; + } + + public boolean removeComment(String key,String comment) { + if (this.values.containsKey(key)) { + this.values.get(key).removeComment(DEFAULT_COMMENTCHAR+comment); + } + return false; + } + public void setProperty(String key, String value) { boolean isuncommented = this.isCommentLine(key); if (isuncommented) { diff --git a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/configuration/subtypes/SectionValue.java b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/configuration/subtypes/SectionValue.java index a4758f1b5..f513e011c 100644 --- a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/configuration/subtypes/SectionValue.java +++ b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/configuration/subtypes/SectionValue.java @@ -25,7 +25,7 @@ import java.util.ArrayList; import java.util.List; /** - * + * * @author Michael Dürre, Herbert Eiselt * */ @@ -35,7 +35,7 @@ class SectionValue { private String value; private final List<String> comments; private boolean isUncommented; - // end of variables + // end of variables // constructors public SectionValue(String value, List<String> commentsForValue, boolean isuncommented) { @@ -72,6 +72,16 @@ class SectionValue { return this; } + public void addComment(String comment) { + this.comments.add(comment); + this.isUncommented = false; + } + + public void removeComment(String comment) { + this.comments.remove(comment); + this.isUncommented = this.comments.size()==0; + } + public List<String> getComments() { return comments; } diff --git a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/database/ExtRestClient.java b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/database/ExtRestClient.java index 836c0fae7..f8734d5a6 100644 --- a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/database/ExtRestClient.java +++ b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/database/ExtRestClient.java @@ -91,7 +91,6 @@ import org.onap.ccsdk.features.sdnr.wt.common.database.responses.SearchResponse; import org.onap.ccsdk.features.sdnr.wt.common.database.responses.UpdateByQueryResponse; import org.onap.ccsdk.features.sdnr.wt.common.database.responses.UpdateResponse; import org.onap.ccsdk.features.sdnr.wt.common.http.BaseHTTPClient; -import org.osgi.framework.Version; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/database/Portstatus.java b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/database/Portstatus.java index 475178b4c..8b43eb157 100644 --- a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/database/Portstatus.java +++ b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/database/Portstatus.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP : ccsdk features * ================================================================================ - * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. * All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,13 +18,13 @@ * limitations under the License. * ============LICENSE_END========================================================= */ + package org.onap.ccsdk.features.sdnr.wt.common.database; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.SocketChannel; - import org.onap.ccsdk.features.sdnr.wt.common.database.config.HostInfo; public class Portstatus { diff --git a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/database/responses/ListAliasesResponse.java b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/database/responses/ListAliasesResponse.java index 7956b2bfc..c73af27fa 100644 --- a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/database/responses/ListAliasesResponse.java +++ b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/database/responses/ListAliasesResponse.java @@ -22,7 +22,6 @@ package org.onap.ccsdk.features.sdnr.wt.common.database.responses; import java.text.ParseException; -import java.util.ArrayList; import java.util.List; import org.elasticsearch.client.Response; diff --git a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/test/JSONAssert.java b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/test/JSONAssert.java index f95dfe0b2..8b651cbe9 100644 --- a/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/test/JSONAssert.java +++ b/sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/test/JSONAssert.java @@ -60,7 +60,7 @@ public class JSONAssert { } else if ((o1 instanceof String) && (o2 instanceof String)) { - return ((String) o1).equals(((String) o2)) ? 0 : -1; + return ((String) o1).equals((o2)) ? 0 : -1; } else if ((o1 instanceof JSONObject) && (o2 instanceof JSONObject)) { if (((JSONObject) o1).length() != ((JSONObject) o2).length()) { return ((JSONObject) o1).length() - ((JSONObject) o2).length() < 0 ? -1 : 1; @@ -137,7 +137,7 @@ public class JSONAssert { } else if ((o1 instanceof String) && (o2 instanceof String)) { - return ((String) o1).equals(((String) o2)) ? 0 : -1; + return ((String) o1).equals((o2)) ? 0 : -1; } else if ((o1 instanceof JSONObject) && (o2 instanceof JSONObject)) { if (((JSONObject) o1).length() == 0 && ((JSONObject) o2).length() == 0) { return 0; @@ -181,6 +181,56 @@ public class JSONAssert { } } + + public static void assertContainsOnlyKey(JSONObject o, String key) { + if(o==null) { + throw new AssertionError("object is null"); + } + if(key==null) { + throw new AssertionError("key is null"); + } + + Object[] keys= o.keySet().toArray(); + if(keys.length>1) { + throw new AssertionError("more than one key found"); + } + if(keys.length==0) { + throw new AssertionError("no key found"); + } + if(!key.equals(keys[0])) { + throw new AssertionError("different key found "+key+" <=> "+ keys[0]); + } + } + + + public static void assertContainsExactKeys(JSONObject o, String[] keys) { + if(o==null) { + throw new AssertionError("object is null"); + } + if(keys==null) { + throw new AssertionError("keys is null"); + } + Object[] okeys= o.keySet().toArray(); + if(okeys.length!=keys.length) { + throw new AssertionError("found different amount of keys"); + } + for(String k:keys) { + if(!o.keySet().contains(k)) { + throw new AssertionError("key "+ k+ " not found"); + } + } + } + public static void assertContainsNoKeys(JSONObject o) { + if(o==null) { + throw new AssertionError("object is null"); + } + + Object[] okeys= o.keySet().toArray(); + if(okeys.length!=0) { + throw new AssertionError("found keys"); + } + } + private static void assertEqualsNonStrict(String message, String def, String toTest) throws JSONException { JSONObject d1 = new JSONObject(def); @@ -188,6 +238,7 @@ public class JSONAssert { if (nonStrictComarator.compare(d1, d2) != 0) { throw new AssertionError(message); } + } private static void assertEqualsStrict(String message, String def, String toTest) throws JSONException { @@ -198,4 +249,6 @@ public class JSONAssert { } } + + } diff --git a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestConfig.java b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestConfig.java index cbe0b9c4d..7f1dc962c 100644 --- a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestConfig.java +++ b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestConfig.java @@ -25,13 +25,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; - import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Files; - import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -53,6 +51,8 @@ public class TestConfig { private static final int TESTVALUE1 = 123; private static final int TESTVALUE1_2 = 1234; private static final boolean TESTVALUE2 = true; + private static final String TESTCOMMENT1 = "my comment for this value"; + private static final String TESTCOMMENT1_2 = "my comment line 2 for this value"; private static final String TESTVALUE3 = "http://localhost:2223"; private static final String TESTVALUE4 = "httasdasdas"; private static final String TESTCONTENT1 = " [test]\n" + TESTKEY1 + "=" + TESTVALUE1 + "\n" + "#her a comment\n" @@ -102,6 +102,8 @@ public class TestConfig { Section section = confiuration.addSection(SECTIONNAME); section.setProperty(TESTKEY1, String.valueOf(TESTVALUE1)); + section.addComment(TESTKEY1, TESTCOMMENT1); + section.addComment(TESTKEY1, TESTCOMMENT1_2); section.setProperty(TESTKEY2, String.valueOf(TESTVALUE2)); section.setProperty(TESTKEY3, String.valueOf(TESTVALUE3)); confiuration.save(); diff --git a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestDbQueries.java b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestDbQueries.java index 127908c08..b2e5e857f 100644 --- a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestDbQueries.java +++ b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestDbQueries.java @@ -30,76 +30,194 @@ import org.onap.ccsdk.features.sdnr.wt.common.database.queries.BoolQueryBuilder; import org.onap.ccsdk.features.sdnr.wt.common.database.queries.QueryBuilder; import org.onap.ccsdk.features.sdnr.wt.common.database.queries.QueryBuilders; import org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder; -import org.onap.ccsdk.features.sdnr.wt.common.test.JSONAssert; public class TestDbQueries { + // @formatter:off private static final String MATCH_ALL_QUERY = - "{\n" + " \"query\": {\n" + " \"match_all\" : {\n" + " }\n" + " }\n" + "}"; + "{\n" + + " \"query\": {\n" + + " \"match_all\" : {\n" + + " }\n" + + " }\n" + + "}"; private static final String MATCH_QUERY_KEY = "is-required"; private static final Object MATCH_QUERY_VALUE = true; - private static final String MATCH_QUERY = "{\n" + " \"query\": {\n" + " \"match\" : {\n" - + " \"" + MATCH_QUERY_KEY + "\" : " + MATCH_QUERY_VALUE + "\n" + " }\n" + " }\n" + "}"; + private static final String MATCH_QUERY = "{\n" + + " \"query\": {\n" + + " \"match\" : {\n" + + " \"" + + MATCH_QUERY_KEY + "\" : " + + MATCH_QUERY_VALUE + "\n" + + " }\n" + + " }\n" + + "}"; private static final String MATCH_QUERY_KEY2 = "node-id"; private static final Object MATCH_QUERY_VALUE2 = "sim2"; private static final String BOOL_QUERY_MUST = - "{\n" + " \"query\": {\n" + " \"bool\": {\n" + " \"must\": [\n" + " {\n" - + " \"match\": {\n" + " \"" + MATCH_QUERY_KEY + "\": " - + MATCH_QUERY_VALUE + "\n" + " }\n" + " },\n" - + " {\n" + " \"match\": {\n" + " \"" - + MATCH_QUERY_KEY2 + "\":" + MATCH_QUERY_VALUE2 + " \n" + " }\n" - + " }\n" + " ]\n" + " }\n" + " }\n" + "}"; - private static final String BOOL_QUERY_MUST_SINGLE = "{\n" + " \"query\": {\n" + " \"bool\": {\n" - + " \"must\": {\n" + " \"match\": {\n" + " \"" - + MATCH_QUERY_KEY + "\": " + MATCH_QUERY_VALUE + "\n" + " }\n" + " }\n" - + " }\n" + " }\n" + "}"; - private static final String BOOL_QUERY_SHOULD = "{\n" + " \"query\": {\n" + " \"bool\": {\n" - + " \"should\": [\n" + " {\n" + " \"match\": {\n" - + " \"" + MATCH_QUERY_KEY + "\": " + MATCH_QUERY_VALUE + "\n" - + " }\n" + " },\n" + " {\n" - + " \"match\": {\n" + " \"" + MATCH_QUERY_KEY2 + "\":" - + MATCH_QUERY_VALUE2 + " \n" + " }\n" + " }\n" + " ]\n" - + " }\n" + " }\n" + "}"; - private static final String BOOL_QUERY_SHOULD_SINGLE = "{\n" + " \"query\": {\n" + " \"bool\": {\n" - + " \"should\": {\n" + " \"match\": {\n" + " \"" - + MATCH_QUERY_KEY + "\": " + MATCH_QUERY_VALUE + "\n" + " }\n" + " }\n" - + " }\n" + " }\n" + "}"; + "{\n" + + " \"query\": {\n" + + " \"bool\": {\n" + + " \"must\": [\n" + + " {\n" + + " \"match\": {\n" + + " \"" + + MATCH_QUERY_KEY + "\": " + + MATCH_QUERY_VALUE + "\n" + + " }\n" + + " },\n" + + " {\n" + + " \"match\": {\n" + + " \"" + + MATCH_QUERY_KEY2 + "\":" + + MATCH_QUERY_VALUE2 + " \n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + "}"; + private static final String BOOL_QUERY_MUST_SINGLE = "{\n" + + " \"query\": {\n" + + " \"bool\": {\n" + + " \"must\": {\n" + + " \"match\": {\n" + + " \"" + + MATCH_QUERY_KEY + "\": " + + MATCH_QUERY_VALUE + "\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + private static final String BOOL_QUERY_SHOULD = "{\n" + + " \"query\": {\n" + + " \"bool\": {\n" + + " \"should\": [\n" + + " {\n" + + " \"match\": {\n" + + " \"" + + MATCH_QUERY_KEY + "\": " + + MATCH_QUERY_VALUE + "\n" + + " }\n" + + " },\n" + + " {\n" + + " \"match\": {\n" + + " \"" + + MATCH_QUERY_KEY2 + "\":" + + MATCH_QUERY_VALUE2 + " \n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + "}"; + private static final String BOOL_QUERY_SHOULD_SINGLE = "{\n" + + " \"query\": {\n" + + " \"bool\": {\n" + + " \"should\": {\n" + + " \"match\": {\n" + + " \"" + + MATCH_QUERY_KEY + "\": " + + MATCH_QUERY_VALUE + "\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; private static final String RANGE_QUERY_KEY = "timestamp"; private static final String RANGE_QUERY_LTEND = "2017-08-10T20:00:00.0Z"; - private static final String RANGE_QUERY = "{\n" + " \"query\": {\n" + " \"range\" : {\n" - + " \"" + RANGE_QUERY_KEY + "\" : {\n" + " \"lte\" : \"" + RANGE_QUERY_LTEND - + "\",\n" + " \"boost\": 2.0\n" + " }\n" + " }\n" + " }\n" + "}"; - private static final String RANGEBOOL_QUERY = "{\n" + " \"query\": {\n" + " \"bool\": {\n" - + " \"must\": [\n" + " {\n" + " \"match\": {\n" - + " \"is-required\": true\n" + " }\n" + " },\n" - + " {\n" + " \"regexp\": {\n" + " \"node-id\": {\n" + private static final String RANGE_QUERY = "{\n" + + " \"query\": {\n" + + " \"range\" : {\n" + + " \"" + RANGE_QUERY_KEY + "\" : {\n" + + " \"lte\" : \"" + RANGE_QUERY_LTEND + "\",\n" + + " \"boost\": 2.0\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + private static final String RANGEBOOL_QUERY = "{\n" + + " \"query\": {\n" + + " \"bool\": {\n" + + " \"must\": [\n" + + " {\n" + + " \"match\": {\n" + + " \"is-required\": true\n" + + " }\n" + + " },\n" + + " {\n" + + " \"regexp\": {\n" + + " \"node-id\": {\n" + " \"max_determinized_states\": 10000,\n" - + " \"flags\": \"ALL\",\n" + " \"value\": \"sim.*\"\n" - + " }\n" + " }\n" + " }\n" + " ]\n" - + " }\n" + " }\n" + "}"; + + " \"flags\": \"ALL\",\n" + + " \"value\": \"sim.*\"\n" + + " }\n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + "}"; private static final String AGG_FIELD = "severity"; private static final String AGG_QUERY = - "{\n" + " \"query\": {\n" + " \"match_all\": {}\n" + " },\n" + " \"aggs\": {\n" - + " \"severity\": {\n" + " \"terms\": {\n" + " \"field\": \"" - + AGG_FIELD + "\"\n" + " }\n" + " }\n" + " }\n" + "}"; + "{\n" + + " \"query\": {\n" + + " \"match_all\": {}\n" + + " },\n" + + " \"aggs\": {\n" + + " \"severity\": {\n" + + " \"terms\": {\n" + + " \"field\": \"" + AGG_FIELD + "\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; private static final long FROMANDSIZE_QUERY_SIZE = 20; private static final long FROMANDSIZE_QUERY_FROM = 120; - private static final String FROMANDSIZE_QUERY = "{\n" + " \"size\": " + FROMANDSIZE_QUERY_SIZE + ",\n" - + " \"query\": {\n" + " \"match_all\": {}\n" + " },\n" + " \"from\":" - + FROMANDSIZE_QUERY_FROM + "\n" + "}"; + private static final String FROMANDSIZE_QUERY = "{\n" + + " \"size\": " + FROMANDSIZE_QUERY_SIZE + ",\n" + + " \"query\": {\n" + + " \"match_all\": {}\n" + + " },\n" + + " \"from\":" + FROMANDSIZE_QUERY_FROM + "\n" + + "}"; private static final String TERMQUERY_KEY = "node-id"; private static final String TERMQUERY_VALUE = "abc"; - private static final String TERM_QUERY = "{\n" + " \"query\": {\n" + " \"term\": {\n" + " \"" - + TERMQUERY_KEY + "\": \"" + TERMQUERY_VALUE + "\"\n" + " }\n" + " }\n" + "}"; + private static final String TERM_QUERY = "{\n" + + " \"query\": {\n" + + " \"term\": {\n" + + " \"" + TERMQUERY_KEY + "\": \"" + TERMQUERY_VALUE + "\"\n" + + " }\n" + + " }\n" + + "}"; private static final String SORTING_PROPERTY = "node-id"; - private static final String SORTING_QUERY_ASC = "{\n" + " \"query\": {\n" + " \"match_all\": {}\n" - + " },\n" + " \"sort\": [\n" + " {\n" + " \"" + SORTING_PROPERTY + "\": {\n" - + " \"order\": \"asc\"\n" + " }\n" + " }\n" + " ]\n" + "}"; - private static final String SORTING_QUERY_DESC = "{\n" + " \"query\": {\n" + " \"match_all\": {}\n" - + " },\n" + " \"sort\": [\n" + " {\n" + " \"" + SORTING_PROPERTY + "\": {\n" - + " \"order\": \"desc\"\n" + " }\n" + " }\n" + " ]\n" + "}"; - + private static final String SORTING_QUERY_ASC = "{\n" + + " \"query\": {\n" + + " \"match_all\": {}\n" + + " },\n" + + " \"sort\": [\n" + + " {\n" + + " \"" + SORTING_PROPERTY + "\": {\n" + + " \"order\": \"asc\"\n" + + " }\n" + + " }\n" + + " ]\n" + + "}"; + private static final String SORTING_QUERY_DESC = "{\n" + + " \"query\": {\n" + + " \"match_all\": {}\n" + + " },\n" + + " \"sort\": [\n" + + " {\n" + + " \"" + SORTING_PROPERTY + "\": {\n" + + " \"order\": \"desc\"\n" + + " }\n" + + " }\n" + + " ]\n" + + "}"; + // @formatter:on private void testEquals(String message, String json, QueryBuilder query) { this.testEquals(message, json, query, true); } diff --git a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestJsonAssert.java b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestJsonAssert.java index 72eba38e8..4ce92b130 100644 --- a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestJsonAssert.java +++ b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestJsonAssert.java @@ -21,13 +21,13 @@ */ package org.onap.ccsdk.features.sdnr.wt.common.test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import org.json.JSONArray; import org.json.JSONException; import org.junit.Test; import org.onap.ccsdk.features.sdnr.wt.common.HtAssert; -import org.onap.ccsdk.features.sdnr.wt.common.test.JSONAssert; public class TestJsonAssert { diff --git a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestPomfile.java b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestPomfile.java index 9de285d1b..7089a809d 100644 --- a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestPomfile.java +++ b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestPomfile.java @@ -24,12 +24,9 @@ package org.onap.ccsdk.features.sdnr.wt.common.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; - import java.io.ByteArrayInputStream; -import java.io.FileInputStream; import java.io.IOException; import javax.xml.parsers.ParserConfigurationException; - import org.junit.Test; import org.onap.ccsdk.features.sdnr.wt.common.file.PomFile; import org.onap.ccsdk.features.sdnr.wt.common.file.PomPropertiesFile; @@ -39,17 +36,16 @@ public class TestPomfile { private static final String TESTPROPERTY_KEY = "elasticsearch-rest-client.version"; private static final String TESTPROPERTY_VALUE = "6.4.3"; - private static final String POMFILENAME = "pom.xml"; + private static final String POMFILENAME = "/testpom.xml"; private static final String POM_PROPERTY = "#Generated by org.apache.felix.bundleplugin\n" + "#Tue Nov 19 11:20:33 CET 2019\n" + "version=0.7.0-SNAPSHOT\n" + "groupId=org.onap.ccsdk.features.sdnr.wt\n" + "artifactId=sdnr-wt-data-provider-provider\n"; - //private static final Date DATE_EXPECTED = new Date(119, 10, 19, 11, 20, 33); @Test public void test() { PomFile pom = null; try { - pom = new PomFile(new FileInputStream(POMFILENAME)); + pom = new PomFile(this.getClass().getResourceAsStream(POMFILENAME)); } catch (ParserConfigurationException | SAXException | IOException e) { fail(e.getMessage()); } @@ -59,14 +55,9 @@ public class TestPomfile { } @Test - public void testProp() { + public void testProp() throws IOException { PomPropertiesFile file = null; - try { - file = new PomPropertiesFile(new ByteArrayInputStream(POM_PROPERTY.getBytes())); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + file = new PomPropertiesFile(new ByteArrayInputStream(POM_PROPERTY.getBytes())); assertNotNull(file); assertNotNull(file.getBuildDate()); } diff --git a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestPortstatus.java b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestPortstatus.java index 3ddbcebd0..ec18e0a84 100644 --- a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestPortstatus.java +++ b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/TestPortstatus.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP : ccsdk features * ================================================================================ - * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. * All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,6 @@ package org.onap.ccsdk.features.sdnr.wt.common.test; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; - import java.io.IOException; import java.net.ServerSocket; import java.time.Duration; diff --git a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/helper/HelpServlet.java b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/helper/HelpServlet.java index a6f77c72d..a99e1222a 100644 --- a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/helper/HelpServlet.java +++ b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/helper/HelpServlet.java @@ -89,13 +89,11 @@ public class HelpServlet extends BaseServlet implements IPublicServlet { @Override protected boolean doTrustAll() { - // TODO Auto-generated method stub return false; } @Override protected void trustAll(boolean trust) { - // TODO Auto-generated method stub } @@ -120,13 +118,11 @@ public class HelpServlet extends BaseServlet implements IPublicServlet { @Override protected boolean trustInsecure() { - // TODO Auto-generated method stub return false; } @Override protected boolean isCorsEnabled() { - // TODO Auto-generated method stub return false; } @@ -135,6 +131,5 @@ public class HelpServlet extends BaseServlet implements IPublicServlet { */ public void setOffline(boolean b) { this.isoff = b; - } } diff --git a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/helper/HelpServletBase.java b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/helper/HelpServletBase.java index c163c746f..dbdaace34 100644 --- a/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/helper/HelpServletBase.java +++ b/sdnr/wt/common/src/test/java/org/onap/ccsdk/features/sdnr/wt/common/test/helper/HelpServletBase.java @@ -46,10 +46,12 @@ import javax.servlet.http.HttpServletResponse; import org.junit.After; import org.junit.Before; + import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; +@SuppressWarnings("restriction") public class HelpServletBase { public static final String RESPONSE_GET = "This is the response get"; diff --git a/sdnr/wt/common/src/test/resources/testpom.xml b/sdnr/wt/common/src/test/resources/testpom.xml new file mode 100644 index 000000000..6fba87af9 --- /dev/null +++ b/sdnr/wt/common/src/test/resources/testpom.xml @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ ============LICENSE_START======================================================= + ~ ONAP : ccsdk features + ~ ================================================================================ + ~ Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. + ~ All rights reserved. + ~ ================================================================================ + ~ Update Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + ~ ================================================================================ + ~ 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. + ~ ============LICENSE_END======================================================= + ~ + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>binding-parent</artifactId> + <version>2.0.0-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.features.sdnr.wt</groupId> + <artifactId>sdnr-wt-common</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>ccsdk-features :: ${project.artifactId}</name> + <licenses> + <license> + <name>Apache License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0</url> + </license> + </licenses> + + <properties> + <checkstyle.skip>true</checkstyle.skip> <!-- POM configuration --> + <maven.javadoc.skip>true</maven.javadoc.skip> + <maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format> + <buildtime>${maven.build.timestamp} UTC</buildtime> + <databaseport>49400</databaseport> + <elasticsearch-rest-client.version>6.4.3</elasticsearch-rest-client.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + </dependency> + <dependency> + <groupId>org.elasticsearch.client</groupId> + <artifactId>elasticsearch-rest-client</artifactId> + <version>${elasticsearch-rest-client.version}</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </dependency> + <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>annotations</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <configuration> + <excludes> + <exclude>**/gen/**</exclude> + <exclude>**/generated-sources/**</exclude> + <exclude>**/yang-gen-sal/**</exclude> + <exclude>**/pax/**</exclude> + </excludes> + </configuration> + </plugin> + <plugin> + <groupId>com.github.alexcojocaru</groupId> + <artifactId>elasticsearch-maven-plugin</artifactId> + <version>6.16</version> + <configuration> + <skip>${skipTests}</skip> + <clusterName>testCluster</clusterName> + <transportPort>9500</transportPort> + <httpPort>${databaseport}</httpPort> + <version>7.1.1</version> + <timeout>120</timeout> + </configuration> + <executions> + <execution> + <id>start-elasticsearch</id> + <phase>process-test-classes</phase> + <goals> + <goal>runforked</goal> + </goals> + </execution> + <execution> + <id>stop-elasticsearch</id> + <phase>prepare-package</phase> + <goals> + <goal>stop</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <systemProperties> + <property> + <name>databaseport</name> + <value>${databaseport}</value> + </property> + </systemProperties> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/sdnr/wt/data-provider/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/model/DataProvider.java b/sdnr/wt/data-provider/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/model/DataProvider.java index f4578d5dc..639fe301b 100644 --- a/sdnr/wt/data-provider/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/model/DataProvider.java +++ b/sdnr/wt/data-provider/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/model/DataProvider.java @@ -102,10 +102,13 @@ public interface DataProvider extends ArchiveCleanProvider { /** * @param list */ - void doWritePerformanceData(List<PmdataEntity> list); + void doWritePerformanceData(List<PmdataEntity> list); + + void doWritePerformanceData2(List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.v2.rev200702.PmdataEntity> list); + /** - * @return + * @return raw database client */ HtDatabaseClient getRawClient(); diff --git a/sdnr/wt/data-provider/model/src/main/java/org/opendaylight/yang/gen/v1/http/org/openroadm/pm/types/rev200327/PmDataTypeBuilder.java b/sdnr/wt/data-provider/model/src/main/java/org/opendaylight/yang/gen/v1/http/org/openroadm/pm/types/rev191129/PmDataTypeBuilder.java index f470fb6ba..98e93c363 100644 --- a/sdnr/wt/data-provider/model/src/main/java/org/opendaylight/yang/gen/v1/http/org/openroadm/pm/types/rev200327/PmDataTypeBuilder.java +++ b/sdnr/wt/data-provider/model/src/main/java/org/opendaylight/yang/gen/v1/http/org/openroadm/pm/types/rev191129/PmDataTypeBuilder.java @@ -1,4 +1,4 @@ -package org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev200327; +package org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev191129; import java.lang.String; import java.lang.UnsupportedOperationException; diff --git a/sdnr/wt/data-provider/model/src/main/yang/data-provider-v2@2020-07-02.yang b/sdnr/wt/data-provider/model/src/main/yang/data-provider-v2@2020-07-02.yang index 358e30c8b..47cc009f1 100644 --- a/sdnr/wt/data-provider/model/src/main/yang/data-provider-v2@2020-07-02.yang +++ b/sdnr/wt/data-provider/model/src/main/yang/data-provider-v2@2020-07-02.yang @@ -6,6 +6,7 @@ module data-provider-v2 { import org-openroadm-pm-types { prefix org-openroadm-pm-types; + revision-date 2019-11-29; reference "OpenROADM: YANG definitions of performance management types"; } diff --git a/sdnr/wt/devicemanager-openroadm/provider/src/main/yang/org-openroadm-pm-types.yang b/sdnr/wt/data-provider/model/src/main/yang/org-openroadm-pm-types@2019-11-29.yang index 78dd8934e..78dd8934e 100644 --- a/sdnr/wt/devicemanager-openroadm/provider/src/main/yang/org-openroadm-pm-types.yang +++ b/sdnr/wt/data-provider/model/src/main/yang/org-openroadm-pm-types@2019-11-29.yang diff --git a/sdnr/wt/data-provider/model/src/main/yang/org-openroadm-pm-types@2020-03-27.yang b/sdnr/wt/data-provider/model/src/main/yang/org-openroadm-pm-types@2020-03-27.yang deleted file mode 100644 index 1fbd72e0f..000000000 --- a/sdnr/wt/data-provider/model/src/main/yang/org-openroadm-pm-types@2020-03-27.yang +++ /dev/null @@ -1,709 +0,0 @@ -module org-openroadm-pm-types { - namespace "http://org/openroadm/pm-types"; - prefix org-openroadm-pm-types; - - organization - "Open ROADM MSA"; - contact - "OpenROADM.org"; - description - "YANG definitions of performance management types. - - Copyright of the Members of the Open ROADM MSA Agreement dated (c) 2016, - All other rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - * Neither the Members of the Open ROADM MSA Agreement nor the names of its - contributors may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE MEMBERS OF THE OPEN ROADM MSA AGREEMENT ''AS IS'' - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT THE MEMBERS OF THE OPEN ROADM MSA AGREEMENT BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE"; - - revision 2020-03-27 { - description - "Version 7.0.0"; - } - revision 2019-11-29 { - description - "Version 6.1.0"; - } - revision 2019-03-29 { - description - "Version 5.0.0"; - } - revision 2018-11-30 { - description - "Version 4.1.0"; - } - revision 2017-12-15 { - description - "Version 2.2"; - } - revision 2017-09-29 { - description - "Version 2.1"; - } - revision 2017-06-26 { - description - "Version 2.0"; - } - revision 2016-10-14 { - description - "Version 1.2"; - } - - typedef pm-granularity { - type enumeration { - enum notApplicable { - value 1; - description - "This is for total statistic counters on devices that support - them."; - } - enum 15min { - value 2; - } - enum 24Hour { - value 3; - } - } - description - "Granularity of PM bin"; - } - - typedef pm-data-type { - type union { - type uint64; - type int64; - type decimal64 { - fraction-digits 2; - } - type decimal64 { - fraction-digits 17; - } - } - } - - typedef validity { - type enumeration { - enum complete { - value 1; - } - enum partial { - value 2; - } - enum suspect { - value 3; - } - } - description - "Validity of data"; - } - - typedef pm-names-enum { - type enumeration { - enum vendorExtension { - value 1; - description - "vendor extension"; - } - enum bitErrorRate { - value 2; - description - "Bit error rate (BER)"; - } - enum opticalPowerOutput { - value 3; - description - "Optical Power Output (OPOUT-OTS, OPOUT-OMS, OPT-OCH). Total optical power includes Variable Optical Attenuator (VOA) attenuation"; - } - enum opticalReturnLoss { - value 4; - description - "Optical Return Loss (ORL-OTS) - at MW port(s) B"; - } - enum opticalPowerInput { - value 5; - description - "Optical Power Input (OPIN-OTS, OPIN-OMS, OPR-OCH). Total optical power"; - } - enum codeViolations { - value 8; - description - "Code Violations (CV)"; - } - enum erroredSeconds { - value 9; - description - "Errored Seconds (ES)"; - } - enum severelyErroredSeconds { - value 10; - description - "Severely Errored Seconds (SES)"; - } - enum unavailableSeconds { - value 11; - description - "Unavailable Seconds (UAS)"; - } - enum inFrames { - value 12; - description - "In frames (INFRAMES-E)"; - } - enum inFramesErrored { - value 13; - description - "In frames errored (INFRAMESERR-E)"; - } - enum outFrames { - value 14; - description - "Out frames (OUTFRAMES-E)"; - } - enum erroredSecondsEthernet { - value 15; - description - "Errored Seconds Ethernet (ES-E)"; - } - enum severelyErroredSecondsEthernet { - value 16; - description - "Severely Errored Seconds, Ethernet (SES-E)"; - } - enum unavailableSecondsEthernet { - value 17; - description - "Unavailable Seconds, Ethernet (UAS-E)"; - } - enum erroredBlockCount { - value 18; - description - "Errored block count"; - } - enum delay { - value 19; - description - "Number of frames between a DMValue toggle event and the received DMp signal value toggle event"; - } - enum defectSeconds { - value 20; - description - "Defect Seconds (DS)"; - } - enum backwardIncomingAlignmentError { - value 21; - description - "Backward Incoming Alignment Error (BIAE)"; - } - enum incomingAlignmentError { - value 22; - description - "Incoming Alignment Error (IAE)"; - } - enum opticalPowerOutputMin { - value 23; - description - "Minimum Optical Power Output (OPOUT-OTS). Total optical power includes Variable Optical Attenuator (VOA) attenuation"; - } - enum opticalPowerOutputMax { - value 24; - description - "Maximum Optical Power Output (OPOUT-OTS). Total optical power includes Variable Optical Attenuator (VOA) attenuation"; - } - enum opticalPowerOutputAvg { - value 25; - description - "Average Optical Power Output (OPOUT-OTS). Total optical power includes Variable Optical Attenuator (VOA) attenuation"; - } - enum opticalPowerInputMin { - value 26; - description - "Minimum Optical Power Input (OPIN-OTS). Total optical power"; - } - enum opticalPowerInputMax { - value 27; - description - "Maximum Optical Power Input (OPIN-OTS). Total optical power"; - } - enum opticalPowerInputAvg { - value 28; - description - "Average Optical Power Input (OPIN-OTS). Total optical power"; - } - enum opticalPowerOutputOSC { - value 29; - description - "OSC Optical Power Output (OPT-OSC). OSC Transmit power on MW port"; - } - enum opticalPowerOutputOSCMin { - value 30; - description - "Minimum OSC Optical Power Output (OPT-OSC). OSC Transmit power on MW port"; - } - enum opticalPowerOutputOSCMax { - value 31; - description - "Maximum OSC Optical Power Output (OPT-OSC). OSC Transmit power on MW port"; - } - enum opticalPowerOutputOSCAvg { - value 32; - description - "Average OSC Optical Power Output (OPT-OSC). OSC Transmit power on MW port"; - } - enum opticalPowerInputOSC { - value 33; - description - "OSC Optical Power Input (OPR-OSC). OSC Receive power on MW port"; - } - enum opticalPowerInputOSCMin { - value 34; - description - "Minimum OSC Optical Power Input (OPR-OSC). OSC Receive power on MW port"; - } - enum opticalPowerInputOSCMax { - value 35; - description - "Maximum OSC Optical Power Input (OPR-OSC). OSC Receive power on MW port"; - } - enum opticalPowerInputOSCAvg { - value 36; - description - "Average OSC Optical Power Input (OPR-OSC). OSC Receive power on MW port"; - } - enum preFECCorrectedErrors { - value 37; - description - "pFEC corrected Errors"; - } - enum totalOpticalPowerInput { - value 38; - description - "Total Optical Power Input."; - } - enum totalOpticalPowerInputMin { - value 39; - description - "Minimum Total Optical Power Input."; - } - enum totalOpticalPowerInputMax { - value 40; - description - "Maximum Total Optical Power Input."; - } - enum totalOpticalPowerInputAvg { - value 41; - description - "Average Total Optical Power Input."; - } - enum FECCorrectableBlocks { - value 42; - description - "FEC Correctable Blocks."; - } - enum FECUncorrectableBlocks { - value 43; - description - "FEC Uncorrectable Blocks."; - } - enum BIPErrorCounter { - value 56; - description - "BIP Error Counter"; - } - enum protectionSwitchingCount { - value 57; - description - "Protection Switching Count (PSC)"; - } - enum protectionSwitchingDuration { - value 58; - description - "Protection Switching Duration in seconds (PSD)"; - } - enum erroredBlockCountTCM1-up { - value 59; - description - "errored Blocks Count on TCM1 up direction."; - } - enum erroredBlockCountTCM2-up { - value 60; - description - "errored Blocks Count on TCM2 up direction."; - } - enum erroredBlockCountTCM3-up { - value 61; - description - "errored Blocks Count on TCM3 up direction."; - } - enum erroredBlockCountTCM4-up { - value 62; - description - "errored Blocks Count on TCM4 up direction."; - } - enum erroredBlockCountTCM5-up { - value 63; - description - "errored Blocks Count on TCM5 up direction."; - } - enum erroredBlockCountTCM6-up { - value 64; - description - "errored Blocks Count on TCM6 up direction."; - } - enum delayTCM1-up { - value 65; - description - "Delay on TCM1 up direction."; - } - enum delayTCM2-up { - value 66; - description - "Delay on TCM2 up direction."; - } - enum delayTCM3-up { - value 67; - description - "Delay on TCM3 up direction."; - } - enum delayTCM4-up { - value 68; - description - "Delay on TCM4 up direction."; - } - enum delayTCM5-up { - value 69; - description - "Delay on TCM5 up direction."; - } - enum delayTCM6-up { - value 70; - description - "Delay on TCM6 up direction."; - } - enum erroredBlockCountTCM1-down { - value 71; - description - "errored Blocks Count on TCM1 down direction."; - } - enum erroredBlockCountTCM2-down { - value 72; - description - "errored Blocks Count on TCM2 down direction."; - } - enum erroredBlockCountTCM3-down { - value 73; - description - "errored Blocks Count on TCM3 down direction."; - } - enum erroredBlockCountTCM4-down { - value 74; - description - "errored Blocks Count on TCM4 down direction."; - } - enum erroredBlockCountTCM5-down { - value 75; - description - "errored Blocks Count on TCM5 down direction."; - } - enum erroredBlockCountTCM6-down { - value 76; - description - "errored Blocks Count on TCM6 down direction."; - } - enum delayTCM1-down { - value 77; - description - "Delay on TCM1 down direction."; - } - enum delayTCM2-down { - value 78; - description - "Delay on TCM2 down direction."; - } - enum delayTCM3-down { - value 79; - description - "Delay on TCM3 down direction."; - } - enum delayTCM4-down { - value 80; - description - "Delay on TCM4 down direction."; - } - enum delayTCM5-down { - value 81; - description - "Delay on TCM5 down direction."; - } - enum delayTCM6-down { - value 82; - description - "Delay on TCM6 down direction."; - } - enum partialRateDiscard { - value 83; - description - "Discarded packet as a result of policing or rate limiting for subrate ethernet."; - } - enum erroredSecondsTCM1-up { - value 84; - description - "errored Seconds Count on TCM1 up direction."; - } - enum erroredSecondsTCM2-up { - value 85; - description - "errored Seconds Count on TCM2 up direction."; - } - enum erroredSecondsTCM3-up { - value 86; - description - "errored Seconds Count on TCM3 up direction."; - } - enum erroredSecondsTCM4-up { - value 87; - description - "errored Seconds Count on TCM4 up direction."; - } - enum erroredSecondsTCM5-up { - value 88; - description - "errored Seconds Count on TCM5 up direction."; - } - enum erroredSecondsTCM6-up { - value 89; - description - "errored Seconds Count on TCM6 up direction."; - } - enum severelyErroredSecondsTCM1-up { - value 90; - description - "severely Errored Seconds Count on TCM1 up direction."; - } - enum severelyErroredSecondsTCM2-up { - value 91; - description - "severely Errored Seconds Count on TCM2 up direction."; - } - enum severelyErroredSecondsTCM3-up { - value 92; - description - "severely Errored Seconds Count on TCM3 up direction."; - } - enum severelyErroredSecondsTCM4-up { - value 93; - description - "severely Errored Seconds Count on TCM4 up direction."; - } - enum severelyErroredSecondsTCM5-up { - value 94; - description - "severely Errored Seconds Count on TCM5 up direction."; - } - enum severelyErroredSecondsTCM6-up { - value 95; - description - "severely Errored Seconds Count on TCM6 up direction."; - } - enum unavailableSecondsTCM1-up { - value 96; - description - "unavailable Seconds Count on TCM1 up direction."; - } - enum unavailableSecondsTCM2-up { - value 97; - description - "unavailable Seconds Count on TCM2 up direction."; - } - enum unavailableSecondsTCM3-up { - value 98; - description - "unavailable Seconds Count on TCM3 up direction."; - } - enum unavailableSecondsTCM4-up { - value 99; - description - "unavailable Seconds Count on TCM4 up direction."; - } - enum unavailableSecondsTCM5-up { - value 100; - description - "unavailable Seconds Count on TCM5 up direction."; - } - enum unavailableSecondsTCM6-up { - value 101; - description - "unavailable Seconds Count on TCM6 up direction."; - } - enum erroredSecondsTCM1-down { - value 102; - description - "errored Seconds Count on TCM1 down direction."; - } - enum erroredSecondsTCM2-down { - value 103; - description - "errored Seconds Count on TCM2 down direction."; - } - enum erroredSecondsTCM3-down { - value 104; - description - "errored Seconds Count on TCM3 down direction."; - } - enum erroredSecondsTCM4-down { - value 105; - description - "errored Seconds Count on TCM4 down direction."; - } - enum erroredSecondsTCM5-down { - value 106; - description - "errored Seconds Count on TCM5 down direction."; - } - enum erroredSecondsTCM6-down { - value 107; - description - "errored Seconds Count on TCM6 down direction."; - } - enum severelyErroredSecondsTCM1-down { - value 108; - description - "severely Errored Seconds Count on TCM1 down direction."; - } - enum severelyErroredSecondsTCM2-down { - value 109; - description - "severely Errored Seconds Count on TCM2 down direction."; - } - enum severelyErroredSecondsTCM3-down { - value 110; - description - "severely Errored Seconds Count on TCM3 down direction."; - } - enum severelyErroredSecondsTCM4-down { - value 111; - description - "severely Errored Seconds Count on TCM4 down direction."; - } - enum severelyErroredSecondsTCM5-down { - value 112; - description - "severely Errored Seconds Count on TCM5 down direction."; - } - enum severelyErroredSecondsTCM6-down { - value 113; - description - "severely Errored Seconds Count on TCM6 down direction."; - } - enum unavailableSecondsTCM1-down { - value 114; - description - "unavailable Seconds Count on TCM1 down direction."; - } - enum unavailableSecondsTCM2-down { - value 115; - description - "unavailable Seconds Count on TCM2 down direction."; - } - enum unavailableSecondsTCM3-down { - value 116; - description - "unavailable Seconds Count on TCM3 down direction."; - } - enum unavailableSecondsTCM4-down { - value 117; - description - "unavailable Seconds Count on TCM4 down direction."; - } - enum unavailableSecondsTCM5-down { - value 118; - description - "unavailable Seconds Count on TCM5 down direction."; - } - enum unavailableSecondsTCM6-down { - value 119; - description - "unavailable Seconds Count on TCM6 down direction."; - } - enum fecCorrectedCodewords { - value 120; - description - "FEC Corrected Codewords Counter"; - } - enum fecUncorrectedCodewords { - value 121; - description - "FEC Uncorrected Codewords Counter"; - } - enum fecSymbolErrors { - value 122; - description - "FEC Symbol Error Counter"; - } - enum localFaultSeconds { - value 123; - description - "Local Fault Seconds"; - } - enum remoteFaultSeconds { - value 124; - description - "Remote Fault Seconds"; - } - } - } - - grouping pm-measurement { - description - "Set of parameters related to a PM Measurement"; - leaf pmParameterValue { - type pm-data-type; - config false; - mandatory true; - } - leaf pmParameterUnit { - type string; - mandatory false; - description - "Unit PM parameter has been measured - frames, packets, u, etc"; - } - leaf validity { - type validity; - mandatory false; - } - } - - grouping pm-names { - description - "Name of PM parameter. Consists of a set list of parameters, - plus an extension field to support addition parameters."; - leaf type { - type pm-names-enum; - mandatory true; - } - leaf extension { - type string; - description - "name of parameter, when enum value set to vendorExtension because - name not found in pm-names-enum"; - } - } -}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/pom.xml b/sdnr/wt/data-provider/provider/pom.xml index a536d64b1..85b8f308d 100644 --- a/sdnr/wt/data-provider/provider/pom.xml +++ b/sdnr/wt/data-provider/provider/pom.xml @@ -58,6 +58,10 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.apache.karaf.bundle</groupId> + <artifactId>org.apache.karaf.bundle.core</artifactId> + </dependency> + <dependency> <groupId>${project.groupId}</groupId> <artifactId>sdnr-wt-data-provider-setup</artifactId> <version>${project.version}</version> @@ -82,6 +86,7 @@ <artifactId>org.osgi.core</artifactId> <scope>provided</scope> </dependency> + <dependency> <groupId>org.apache.karaf.shell</groupId> <artifactId>org.apache.karaf.shell.core</artifactId> @@ -162,13 +167,12 @@ <plugin> <groupId>com.github.alexcojocaru</groupId> <artifactId>elasticsearch-maven-plugin</artifactId> - <version>6.16</version> <configuration> <skip>${skipTests}</skip> <clusterName>testCluster</clusterName> <transportPort>9500</transportPort> <httpPort>${databaseport}</httpPort> - <version>7.1.1</version> + <version>7.6.1</version> <timeout>120</timeout> <pathInitScript>${project.build.directory}/EsInit.script</pathInitScript> </configuration> diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/entity/HtDatabaseEventsService.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/entity/HtDatabaseEventsService.java index 46475f02d..de6870571 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/entity/HtDatabaseEventsService.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/entity/HtDatabaseEventsService.java @@ -25,9 +25,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; - import javax.annotation.Nonnull; - import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; @@ -83,6 +81,8 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid private final EsDataObjectReaderWriter2<NetworkElementConnectionEntity> networkelementConnectionDB; private final EsDataObjectReaderWriter2<PmdataEntity> pmData15mDB; private final EsDataObjectReaderWriter2<PmdataEntity> pmData24hDB; + private final EsDataObjectReaderWriter2<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.v2.rev200702.PmdataEntity> pmData15mDBv2; + private final EsDataObjectReaderWriter2<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.v2.rev200702.PmdataEntity> pmData24hDBv2; @SuppressWarnings("unused") private final ElasticSearchDataProvider dataProvider; @@ -124,6 +124,15 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid pmData24hDB = new EsDataObjectReaderWriter2<>(client, Entity.Historicalperformance24h, PmdataEntity.class, PmdataEntityBuilder.class); + pmData15mDBv2 = new EsDataObjectReaderWriter2<>(client, Entity.Historicalperformance15min, + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.v2.rev200702.PmdataEntity.class, + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.v2.rev200702.PmdataEntityBuilder.class); + + pmData24hDBv2 = new EsDataObjectReaderWriter2<>(client, Entity.Historicalperformance24h, + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.v2.rev200702.PmdataEntity.class, + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.v2.rev200702.PmdataEntityBuilder.class); + + } catch (Exception e) { LOG.error("Can not start database client. Exception: {}", e); throw new Exception("Can not start database client. Exception: {}", e); @@ -251,7 +260,7 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid /** * write internal equipment to database - * + * * @param internalEquipment with mandatory fields. */ @Override @@ -276,7 +285,7 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid /** * join base with parameters of toJoin (only non null values) - * + * * @param base base object * @param toJoin object with new property values * @return new joined object @@ -335,7 +344,7 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid /** * Update after new mountpoint registration - * + * * @param networkElementConnectionEntitiy data * @param nodeId of device (mountpoint name) */ @@ -411,7 +420,7 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid /** * Verify status of client - * + * * @param event that is printed with message * @return true if client is null */ @@ -425,7 +434,7 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid /** * Verify status of client - * + * * @param message to print including {} for object printout. * @return true if client is null */ @@ -443,7 +452,7 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid private static class EsEventBase { /** * Query to get older Elements - * + * * @param netconfTimeStamp to identify older Elements * @return QueryBuilder for older elements related to timestamp */ @@ -454,7 +463,7 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid private static class EsFaultLogDevicemanager { /** * Get older Elements - * + * * @param netconfTimeStamp to identify query elements older than this timestamp. * @return QueryBuilder for related elements */ @@ -513,15 +522,51 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid }); } + @Override + public void doWritePerformanceData2( + List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.v2.rev200702.PmdataEntity> list) { + + list.forEach(elem -> { + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.v2.rev200702.GranularityPeriodType + granularityPeriod = nnGetGranularityPeriodType2(elem.getGranularityPeriod()); + //_id": "Sim12600/LP-MWPS-TTP-01/2017-07-04T15:15:00.0+00:00" + StringBuffer id = new StringBuffer(); + DateAndTime date = elem.getTimeStamp(); + id.append(elem.getNodeName()); + id.append("/"); + id.append(elem.getUuidInterface()); + id.append("/"); + id.append(date != null ? date.getValue() : "null"); + switch (granularityPeriod) { + case Period15Min: + pmData15mDB.write(elem, id.toString()); + break; + case Period24Hours: + pmData24hDB.write(elem, id.toString()); + break; + case Unknown: + default: + LOG.debug("Unknown granularity {} id {}", granularityPeriod, id); + break; + } + }); + } @NonNull GranularityPeriodType nnGetGranularityPeriodType(@Nullable GranularityPeriodType granularityPeriod) { return granularityPeriod != null ? granularityPeriod : GranularityPeriodType.Unknown; } + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.v2.rev200702.GranularityPeriodType nnGetGranularityPeriodType2( + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.v2.rev200702.@Nullable GranularityPeriodType granularityPeriod) { + return granularityPeriod != null ? granularityPeriod : + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.v2.rev200702.GranularityPeriodType.Unknown; + } @Override public HtDatabaseClient getRawClient() { return this.client; } + + } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/ReadyHttpServlet.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/ReadyHttpServlet.java index e20f453a1..284365021 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/ReadyHttpServlet.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/ReadyHttpServlet.java @@ -22,28 +22,39 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.http; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - +import org.apache.karaf.bundle.core.BundleInfo; +import org.apache.karaf.bundle.core.BundleService; +import org.apache.karaf.bundle.core.BundleState; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.about.MarkdownTable; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ReadyHttpServlet extends HttpServlet { /** - * + * */ private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(ReadyHttpServlet.class); private static boolean status; + + private BundleService bundleService = null; + + public void setBundleService(BundleService bundleService) { + this.bundleService = bundleService; + } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - if (isReady()) { + if (isReady() && this.getBundleStatesReady()) { resp.setStatus(HttpServletResponse.SC_OK); } else { @@ -63,4 +74,67 @@ public class ReadyHttpServlet extends HttpServlet { status = s; LOG.info("status is set to ready: {}", status); } + + private boolean getBundleStatesReady() { + Bundle thisbundle = FrameworkUtil.getBundle(this.getClass()); + BundleContext context = thisbundle ==null?null:thisbundle.getBundleContext(); + if (context == null) { + LOG.debug("no bundle context available"); + return true; + } + Bundle[] bundles = context.getBundles(); + if (bundles == null || bundles.length <= 0) { + LOG.debug("no bundles found"); + return true; + } + LOG.debug("found {} bundles", bundles.length); + MarkdownTable table = new MarkdownTable(); + table.setHeader(new String[] {"Bundle-Id","Version","Symbolic-Name","Status"}); + int cntNotActive=0; + + for (Bundle bundle : bundles) { + if(this.bundleService!=null) { + BundleInfo info = this.bundleService.getInfo(bundle); + if(info.getState()==BundleState.Active ) { + continue; + } + if(info.getState()==BundleState.Resolved ) { + if(!this.isBundleImportant(bundle.getSymbolicName())) { + LOG.trace("ignore not important bundle {} with state {}",bundle.getSymbolicName(),info.getState()); + continue; + } + } + + LOG.trace("bundle {} is in state {}",bundle.getSymbolicName(),info.getState()); + } + else { + LOG.warn("bundle service is null"); + } + cntNotActive++; + } + + return cntNotActive==0; + } + + private boolean isBundleImportant(String symbolicName) { + symbolicName = symbolicName.toLowerCase(); + if(symbolicName.contains("mdsal")) { + return true; + } + if(symbolicName.contains("netconf")) { + return true; + } + if(symbolicName.contains("ccsdk")) { + return true; + } + if(symbolicName.contains("devicemanager")) { + return true; + } + if(symbolicName.contains("restconf")) { + return true; + } + + return false; + } + } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/about/AboutHttpServlet.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/about/AboutHttpServlet.java index 9ac0cc0c3..81b9645fe 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/about/AboutHttpServlet.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/about/AboutHttpServlet.java @@ -38,6 +38,9 @@ import javax.servlet.http.HttpServletResponse; import org.onap.ccsdk.features.sdnr.wt.common.Resources; import org.onap.ccsdk.features.sdnr.wt.common.file.PomFile; import org.onap.ccsdk.features.sdnr.wt.common.file.PomPropertiesFile; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,7 +62,6 @@ public class AboutHttpServlet extends HttpServlet { private static final String PLACEHOLDER_ONAP_RELEASEVERSION = "{release-version}"; private static final String PLACEHOLDER_ODL_RELEASENAME = "{odl-version}"; private static final String PLACEHOLDER_BUILD_TIMESTAMP = "{build-time}"; - private static final String PLACEHOLDER_ODLUX_REVISION = "{odlux-revision}"; private static final String PLACEHOLDER_PACKAGE_GITHASH = "{package-githash}"; private static final String PLACEHOLDER_PACAKGE_VERSION = "{package-version}"; private static final String PLACEHOLDER_CCSDK_VERSION = "{ccsdk-version}"; @@ -69,10 +71,12 @@ public class AboutHttpServlet extends HttpServlet { private static final String PLACEHOLDER_KARAF_INFO = "{karaf-info}"; private static final String PLACEHOLDER_DEVICEMANAGER_TABLE = "{devicemanagers}"; private static final String README_FILE = "README.md"; + private static final String NO_DEVICEMANAGERS_RUNNING_MESSAGE = null; private final String groupId = "org.onap.ccsdk.features.sdnr.wt"; private final String artifactId = "sdnr-wt-data-provider-provider"; + private final Map<Integer,String> BUNDLESTATE_LUT; private final Map<String, String> data; private final String readmeContent; // private BundleService bundleService; @@ -83,7 +87,13 @@ public class AboutHttpServlet extends HttpServlet { this.data = new HashMap<>(); this.collectStaticData(); this.readmeContent = this.render(this.getResourceFileContent(README_FILE)); - //BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); + this.BUNDLESTATE_LUT = new HashMap<>(); + this.BUNDLESTATE_LUT.put(Bundle.UNINSTALLED, "uninstalled"); + this.BUNDLESTATE_LUT.put(Bundle.INSTALLED, "installed"); + this.BUNDLESTATE_LUT.put(Bundle.RESOLVED, "resolved"); + this.BUNDLESTATE_LUT.put(Bundle.STARTING, "starting"); + this.BUNDLESTATE_LUT.put(Bundle.STOPPING, "stopping"); + this.BUNDLESTATE_LUT.put(Bundle.ACTIVE, "active"); } @@ -97,13 +107,14 @@ public class AboutHttpServlet extends HttpServlet { private void collectStaticData() { PomPropertiesFile props = this.getPomProperties(); final String ccsdkVersion = this.getPomParentVersion(); + final String mdsalVersion = SystemInfo.getMdSalVersion(UNKNOWN); this.data.put(PLACEHOLDER_ONAP_RELEASENAME, ODLVersionLUT.getONAPReleaseName(ccsdkVersion, UNKNOWN)); - this.data.put(PLACEHOLDER_ODL_RELEASENAME, ODLVersionLUT.getOdlVersion(ccsdkVersion, UNKNOWN)); + this.data.put(PLACEHOLDER_ODL_RELEASENAME, ODLVersionLUT.getOdlVersion(mdsalVersion, UNKNOWN)); this.data.put(PLACEHOLDER_BUILD_TIMESTAMP, props != null ? props.getBuildDate().toString() : ""); this.data.put(PLACEHOLDER_PACAKGE_VERSION, this.getManifestValue("Bundle-Version")); this.data.put(PLACEHOLDER_CCSDK_VERSION, ccsdkVersion); - this.data.put(PLACEHOLDER_ONAP_RELEASEVERSION, "2.0.0-SNAPSHOT"); - this.data.put(PLACEHOLDER_MDSAL_VERSION, SystemInfo.getMdSalVersion(UNKNOWN)); + this.data.put(PLACEHOLDER_ONAP_RELEASEVERSION, SystemInfo.getOnapVersion(UNKNOWN)); + this.data.put(PLACEHOLDER_MDSAL_VERSION, mdsalVersion); this.data.put(PLACEHOLDER_YANGTOOLS_VERSION, SystemInfo.getYangToolsVersion(UNKNOWN)); this.data.put(PLACEHOLDER_PACKAGE_GITHASH, this.getGitHash(UNKNOWN)); } @@ -272,25 +283,34 @@ public class AboutHttpServlet extends HttpServlet { } private String getDevicemanagerBundles() { - // if(this.bundleService==null) { - // LOG.debug("no bundle service available"); - // return ""; - // } - // - // List<String> ids = new ArrayList<String>(); - // List<Bundle> bundles = bundleService.selectBundles("0", ids , true); - // if(bundles==null || bundles.size()<=0) { - // LOG.debug("no bundles found"); - // return ""; - // } - // LOG.debug("found {} bundles",bundles.size()); - // MarkdownTable table = new MarkdownTable(); - // for(Bundle bundle:bundles) { - // BundleInfo info = this.bundleService.getInfo(bundle); - // table.addRow(new String[] {String.valueOf(info.getBundleId()),info.getVersion(),info.getName(),info.getState().toString()}); - // } - // return table.toMarkDown(); - return ""; + Bundle thisbundle = FrameworkUtil.getBundle(this.getClass()); + BundleContext context = thisbundle ==null?null:thisbundle.getBundleContext(); + if (context == null) { + LOG.debug("no bundle context available"); + return ""; + } + Bundle[] bundles = context.getBundles(); + if (bundles == null || bundles.length <= 0) { + LOG.debug("no bundles found"); + return NO_DEVICEMANAGERS_RUNNING_MESSAGE; + } + LOG.debug("found {} bundles", bundles.length); + MarkdownTable table = new MarkdownTable(); + table.setHeader(new String[] {"Bundle-Id","Version","Symbolic-Name","Status"}); + String name; + for (Bundle bundle : bundles) { + name = bundle.getSymbolicName(); + if(!(name.contains("devicemanager") && name.contains("provider"))) { + continue; + } + if(name.equals("org.onap.ccsdk.features.sdnr.wt.sdnr-wt-devicemanager-provider")) { + continue; + } + table.addRow(new String[] {String.valueOf(bundle.getBundleId()), bundle.getVersion().toString(), name, + BUNDLESTATE_LUT.getOrDefault(bundle.getState(),"unknown")}); + + } + return table.toMarkDown(); } /** diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/about/ODLVersionLUT.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/about/ODLVersionLUT.java index bd8fae6a0..991231f87 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/about/ODLVersionLUT.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/about/ODLVersionLUT.java @@ -21,8 +21,13 @@ */ package org.onap.ccsdk.features.sdnr.wt.dataprovider.http.about; +import java.util.HashMap; +import java.util.Map; + public class ODLVersionLUT { + private static Map<String,String> odlMdsalVersionLUT=null; + public static String getONAPReleaseName(String onapCCSDKVersion, String def) { if (onapCCSDKVersion == null) { return def; @@ -45,26 +50,26 @@ public class ODLVersionLUT { return def; } - public static String getOdlVersion(String onapCCSDKVersion, String def) { + public static String getOdlVersion(String mdsalVersion, String def) { - if (onapCCSDKVersion == null) { + if (mdsalVersion == null) { return def; } - if (onapCCSDKVersion.startsWith("2.")) { - return "sodium-SR3 (0.11.3)"; - } - if (onapCCSDKVersion.startsWith("1.5.")) { - return "neon-SR1 (0.10.1)"; - } - if (onapCCSDKVersion.startsWith("1.4.")) { - return "neon-SR1 (0.10.1)"; + if(odlMdsalVersionLUT==null) { + odlMdsalVersionLUT = new HashMap<>(); + odlMdsalVersionLUT.put("5.0.14","magnesium-SR2 (0.12.2)"); + odlMdsalVersionLUT.put("5.0.10","magnesium-SR1 (0.12.1)"); + odlMdsalVersionLUT.put("5.0.9","magnesium-SR0 (0.12.0)"); + odlMdsalVersionLUT.put("4.0.14","sodium-SR3 (0.11.3)"); + odlMdsalVersionLUT.put("4.0.11","sodium-SR2 (0.11.2)"); + odlMdsalVersionLUT.put("4.0.6","sodium-SR1 (0.11.1)"); + odlMdsalVersionLUT.put("4.0.4","sodium-SR0 (0.11.0)"); + odlMdsalVersionLUT.put("3.0.13","neon-SR3 (0.10.3)"); + odlMdsalVersionLUT.put("3.0.10","neon-SR2 (0.10.2)"); + odlMdsalVersionLUT.put("3.0.8","neon-SR1 (0.10.1)"); + odlMdsalVersionLUT.put("3.0.6","neon-SR0 (0.10.0)"); } - if (onapCCSDKVersion.startsWith("1.3.")) { - return "fluorine-SR2 (0.9.2)"; - } - if (onapCCSDKVersion.startsWith("1.2.")) { - return "sodium-SR3 (0.11.3)"; - } - return def; + + return odlMdsalVersionLUT.getOrDefault(mdsalVersion, def); } } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/about/SystemInfo.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/about/SystemInfo.java index 1497362a6..134e3d37b 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/about/SystemInfo.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/about/SystemInfo.java @@ -42,7 +42,6 @@ import java.util.concurrent.Callable; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; - import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; @@ -54,6 +53,10 @@ public class SystemInfo { private static OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean(); protected static boolean showMemoryPools = false; + public static String getOnapVersion(String def) { + return getOnapVersion("", def); + } + public static String getMdSalVersion(String def) { return getMdSalVersion("", def); } @@ -62,6 +65,10 @@ public class SystemInfo { return getYangToolsVersion("", def); } + public static String getOnapVersion(String baseOdlDirectory, String def) { + return getFeatureVersionByFolder(baseOdlDirectory, "system/org/onap/sdnc/northbound/sdnc-northbound-all/", def); + } + public static String getMdSalVersion(String baseOdlDirectory, String def) { return getFeatureVersionByFolder(baseOdlDirectory, "system/org/opendaylight/mdsal/mdsal-binding-api/", def); } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/yangtools/YangToolsCloner.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/yangtools/YangToolsCloner.java deleted file mode 100644 index a9a658387..000000000 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/yangtools/YangToolsCloner.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP : ccsdk features - * ================================================================================ - * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. - * All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - * - */ -package org.onap.ccsdk.features.sdnr.wt.dataprovider.yangtools; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nullable; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class YangToolsCloner { - - private static YangToolsMapper yangtoolsMapper = new YangToolsMapper(); - private static final Logger LOG = LoggerFactory.getLogger(YangToolsCloner.class); - public static final int ACCESSOR_FIELD = 0; - public static final int ACCESSOR_METHOD = 1; - - - private final int accessor; - - private YangToolsCloner(int ac) { - this.accessor = ac; - } - - public static YangToolsCloner instance() { - return instance(ACCESSOR_METHOD); - } - - public static YangToolsCloner instance(int ac) { - return new YangToolsCloner(ac); - } - - /** - * - * @param source source object - * @param clazz Class of return object - * @return list of cloned object - * @return - */ - public <S extends DataObject, T extends DataObject> List<T> cloneList(List<S> source, Class<T> clazz) { - return cloneList(source, clazz, null); - } - - /** - * - * @param source source object - * @param clazz Class of return object - * @attrList filter for attribute Names to clone - * @return list of cloned object - */ - public <S extends DataObject, T extends DataObject> List<T> cloneList(List<S> source, Class<T> clazz, - @Nullable List<String> attrList) { - if (source == null) { - return null; - } - List<T> list = new ArrayList<>(); - for (S s : source) { - list.add(clone(s, clazz, attrList)); - } - return list; - } - - /** - * - * @param source source object - * @param clazz Class of return object - * @return cloned object - */ - public <S, T extends DataObject> T clone(S source, Class<T> clazz) { - return clone(source, clazz, null); - } - - /** - * - * @param source source object - * @param clazz Class of return object - * @attrList if empty copy all else list of attribute Names to clone - * @return cloned object - */ - public <S, T extends DataObject> T clone(S source, Class<T> clazz, @Nullable List<String> attrList) { - if (source == null) { - return (T) null; - } - Field[] attributeFields; - Field sourceField; - Method m; - Builder<T> builder = yangtoolsMapper.getBuilder(clazz); - T object = builder.build(); - attributeFields = object.getClass().getDeclaredFields(); - for (Field attributeField : attributeFields) { - // check if attr is in inclusion list - if (attrList != null && !attrList.contains(attributeField.getName())) { - continue; - } - // ignore QNAME - if (attributeField.getName().equals("QNAME")) { - continue; - } - - attributeField.setAccessible(true); - try { - if (accessor == ACCESSOR_FIELD) { - sourceField = source.getClass().getDeclaredField(attributeField.getName()); - sourceField.setAccessible(true); - if (attributeField.getType().equals(String.class) && !sourceField.getType().equals(String.class)) { - attributeField.set(object, String.valueOf(sourceField.get(source))); - } else { - attributeField.set(object, sourceField.get(source)); - } - } else if (accessor == ACCESSOR_METHOD) { - String getter = getter(attributeField.getName()); - System.out.println("getter=" + getter); - m = source.getClass().getDeclaredMethod(getter); - m.setAccessible(true); - if (attributeField.getType().equals(String.class) && !m.getReturnType().equals(String.class)) { - attributeField.set(object, String.valueOf(m.invoke(source))); - } else { - attributeField.set(object, m.invoke(source)); - } - } - - } catch (NoSuchMethodException | NoSuchFieldException e) { - // Convert to run-time exception - String msg = "no such field " + attributeField.getName() + " in class " + source.getClass().getName(); - LOG.debug(msg); - // throw new IllegalArgumentException(msg); - } catch (IllegalAccessException | SecurityException e) { - LOG.debug("Access problem " + attributeField.getName(), e); - } catch (IllegalArgumentException e) { - LOG.debug("argument problem " + attributeField.getName(), e); - } catch (InvocationTargetException e) { - LOG.debug("invocation problem " + attributeField.getName(), e); - } - } - - return object; - } - - private static String getter(String name) { - return String.format("%s%s%s", "get", name.substring(1, 2).toUpperCase(), name.substring(2)); - } - - public <S extends DataObject, T extends DataObject, B extends Builder<T>> B cloneToBuilder(S source, B builder) { - return cloneToBuilder(source, builder, null); - } - - public <S extends DataObject, T extends DataObject, B extends Builder<T>> B cloneToBuilder(S source, B builder, - @Nullable List<String> attrList) { - Field[] attributeFields; - Field sourceField; - Method m; - attributeFields = builder.getClass().getDeclaredFields(); - for (Field attributeField : attributeFields) { - // check if attr is in inclusion list - if (attrList != null && !attrList.contains(attributeField.getName())) { - continue; - } - // ignore QNAME - if (attributeField.getName().equals("QNAME")) { - continue; - } - - attributeField.setAccessible(true); - try { - if (accessor == ACCESSOR_FIELD) { - sourceField = source.getClass().getDeclaredField(attributeField.getName()); - sourceField.setAccessible(true); - if (attributeField.getType().equals(String.class) && !sourceField.getType().equals(String.class)) { - attributeField.set(builder, String.valueOf(sourceField.get(source))); - } else { - attributeField.set(builder, sourceField.get(source)); - } - } else if (accessor == ACCESSOR_METHOD) { - m = source.getClass().getDeclaredMethod(getter(attributeField.getName())); - m.setAccessible(true); - if (attributeField.getType().equals(String.class) && !m.getReturnType().equals(String.class)) { - attributeField.set(builder, String.valueOf(m.invoke(source))); - } else { - attributeField.set(builder, m.invoke(source)); - } - } - - } catch (NoSuchMethodException | NoSuchFieldException e) { - // Convert to run-time exception - String msg = "no such field " + attributeField.getName() + " in class " + source.getClass().getName(); - LOG.debug(msg); - // throw new IllegalArgumentException(msg); - } catch (IllegalAccessException | SecurityException e) { - LOG.debug("Access problem " + attributeField.getName(), e); - } catch (IllegalArgumentException e) { - LOG.debug("argument problem " + attributeField.getName(), e); - } catch (InvocationTargetException e) { - LOG.debug("invocation problem " + attributeField.getName(), e); - } - } - return builder; - } -} diff --git a/sdnr/wt/data-provider/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml b/sdnr/wt/data-provider/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml index ad9661f66..1be114612 100644 --- a/sdnr/wt/data-provider/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml +++ b/sdnr/wt/data-provider/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml @@ -29,11 +29,12 @@ <reference id="rpcProviderService" interface="org.opendaylight.mdsal.binding.api.RpcProviderService" odl:type="default"/> - -<!-- <reference id="bundleService" interface="org.apache.karaf.bundle.core.BundleService" odl:type="default"/> --> + <reference id="bundleService" + interface="org.apache.karaf.bundle.core.BundleService" /> <bean id="readyServlet" class="org.onap.ccsdk.features.sdnr.wt.dataprovider.http.ReadyHttpServlet"> + <property name="bundleService" ref="bundleService"/> </bean> <service interface="javax.servlet.http.HttpServlet" ref="readyServlet"> diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestTree.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestTree.java index f2a7ff951..970816514 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestTree.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestTree.java @@ -22,14 +22,18 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.test; import java.io.IOException; +import java.net.URISyntaxException; import java.util.Arrays; import java.util.concurrent.TimeUnit; +import org.apache.sshd.common.util.io.IoUtils; +import org.json.JSONObject; import org.junit.BeforeClass; import org.junit.Test; import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; import org.onap.ccsdk.features.sdnr.wt.common.database.config.HostInfo; import org.onap.ccsdk.features.sdnr.wt.common.database.queries.QueryBuilders; import org.onap.ccsdk.features.sdnr.wt.common.database.requests.DeleteByQueryRequest; +import org.onap.ccsdk.features.sdnr.wt.common.test.JSONAssert; import org.onap.ccsdk.features.sdnr.wt.dataprovider.data.ElasticSearchDataProvider; import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.DataTreeHttpServlet; import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.DataTreeHttpServlet.EntityWithTree; @@ -54,23 +58,89 @@ public class TestTree { dbProvider = new ElasticSearchDataProvider(hosts); dbProvider.waitForYellowDatabaseStatus(30, TimeUnit.SECONDS); dbRawProvider = HtDatabaseClient.getClient(hosts); + DeleteByQueryRequest query = new DeleteByQueryRequest(Entity.Inventoryequipment.getName(), true); + query.setQuery(QueryBuilders.matchAllQuery().toJSON()); + dbRawProvider.deleteByQuery(query); + fillTestData(); + } + + private static void fillTestData() throws IOException { + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/a2.module-1.1.5.5", getFileContent("/testequipment/1.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/CARD-1.1.7.0", getFileContent("/testequipment/2.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/a2.module-1.55.1.2", getFileContent("/testequipment/3.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/a2.module-1.65.1.2", getFileContent("/testequipment/4.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/SHELF-1.1.0.0", getFileContent("/testequipment/5.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/a2.module-1.1.1.5", getFileContent("/testequipment/6.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/a2.module-1.1.1.8", getFileContent("/testequipment/7.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/a2.module-1.1.6.5", getFileContent("/testequipment/8.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/ODU-1.56.0.0", getFileContent("/testequipment/9.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/a2.module-1.56.1.2", getFileContent("/testequipment/10.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/IDU-1.65.0.0", getFileContent("/testequipment/11.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/CARD-1.65.1.4", getFileContent("/testequipment/12.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/CARD-1.1.6.0", getFileContent("/testequipment/13.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/CARD-1.1.8.0", getFileContent("/testequipment/14.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/CARD-1.1.9.0", getFileContent("/testequipment/15.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/CARD-1.55.1.4", getFileContent("/testequipment/16.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/a2.module-1.1.1.7", getFileContent("/testequipment/17.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/IDU-1.55.0.0", getFileContent("/testequipment/18.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/CARD-1.1.1.0", getFileContent("/testequipment/19.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/CARD-1.1.5.0", getFileContent("/testequipment/20.json")); + dbRawProvider.doWriteRaw(Entity.Inventoryequipment.getName(), "sim1/a2.module-1.1.5.6", getFileContent("/testequipment/21.json")); + + } + /** + * @param string + * @return + * @throws URISyntaxException + * @throws IOException + */ + private static String getFileContent(String filename) throws IOException { + return String.join("\n",IoUtils.readAllLines(TestTree.class.getResourceAsStream(filename))); } @Test public void testInventoryTree() throws IOException { DataTreeProviderImpl provider = new DataTreeProviderImpl(); provider.setDatabaseClient(dbRawProvider); - DeleteByQueryRequest query = new DeleteByQueryRequest(Entity.Inventoryequipment.getName(), true); - query.setQuery(QueryBuilders.matchAllQuery().toJSON()); - dbRawProvider.deleteByQuery(query); + DataTreeObject tree = provider.readInventoryTree(null, null, FilterMode.Lazy); + System.out.println(tree.toJSON()); + JSONObject o = new JSONObject(tree.toJSON()); + JSONAssert.assertContainsOnlyKey(o, "sim1"); + JSONObject children = o.getJSONObject("sim1").getJSONObject("children"); + this.assertSim1(children); - tree = provider.readInventoryTree(Arrays.asList("sim1"), "CARD", FilterMode.Lazy); + tree = provider.readInventoryTree(Arrays.asList("sim1"), "*", FilterMode.Lazy); + this.assertSim1(new JSONObject(tree.toJSON())); System.out.println(tree.toJSON()); } + private void assertSim1(JSONObject sim1Children) { + JSONAssert.assertContainsExactKeys(sim1Children,new String[] {"sim1/ODU-1.56.0.0", "sim1/IDU-1.55.0.0", "sim1/IDU-1.65.0.0", "sim1/SHELF-1.1.0.0"}); + JSONObject c1 = sim1Children.getJSONObject("sim1/ODU-1.56.0.0"); + JSONObject c2 = sim1Children.getJSONObject("sim1/IDU-1.55.0.0"); + JSONObject c3 = sim1Children.getJSONObject("sim1/IDU-1.65.0.0"); + JSONObject c4 = sim1Children.getJSONObject("sim1/SHELF-1.1.0.0"); + JSONAssert.assertContainsExactKeys(c1.getJSONObject("children"),new String[] {"sim1/a2.module-1.56.1.2"}); + JSONAssert.assertContainsExactKeys(c2.getJSONObject("children"),new String[] {"sim1/a2.module-1.55.1.2","sim1/CARD-1.55.1.4"}); + JSONAssert.assertContainsExactKeys(c3.getJSONObject("children"),new String[] {"sim1/a2.module-1.65.1.2","sim1/CARD-1.65.1.4"}); + JSONAssert.assertContainsExactKeys(c4.getJSONObject("children"),new String[] {"sim1/CARD-1.1.1.0", + "sim1/CARD-1.1.5.0", "sim1/CARD-1.1.7.0","sim1/CARD-1.1.6.0", "sim1/CARD-1.1.9.0","sim1/CARD-1.1.8.0"}); + JSONObject c41 = c4.getJSONObject("children").getJSONObject("sim1/CARD-1.1.1.0"); + JSONObject c42 = c4.getJSONObject("children").getJSONObject("sim1/CARD-1.1.5.0"); + JSONObject c43 = c4.getJSONObject("children").getJSONObject("sim1/CARD-1.1.7.0"); + JSONObject c44 = c4.getJSONObject("children").getJSONObject("sim1/CARD-1.1.6.0"); + JSONObject c45 = c4.getJSONObject("children").getJSONObject("sim1/CARD-1.1.9.0"); + JSONObject c46 = c4.getJSONObject("children").getJSONObject("sim1/CARD-1.1.8.0"); + JSONAssert.assertContainsExactKeys(c41.getJSONObject("children"),new String[] {"sim1/a2.module-1.1.1.7","sim1/a2.module-1.1.1.5","sim1/a2.module-1.1.1.8"}); + JSONAssert.assertContainsExactKeys(c42.getJSONObject("children"),new String[] {"sim1/a2.module-1.1.5.6","sim1/a2.module-1.1.5.5"}); + JSONAssert.assertContainsNoKeys(c43.getJSONObject("children")); + JSONAssert.assertContainsExactKeys(c44.getJSONObject("children"),new String[] {"sim1/a2.module-1.1.6.5"}); + JSONAssert.assertContainsNoKeys(c45.getJSONObject("children")); + JSONAssert.assertContainsNoKeys(c46.getJSONObject("children")); + } @Test public void testUriConversion() { EntityWithTree e = DataTreeHttpServlet.getEntity("/tree/read-inventoryequipment-tree/sim1/sim1%2FODU"); diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/util/HostInfoForTest.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/util/HostInfoForTest.java index 8ea4b13aa..bd7e8ce5d 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/util/HostInfoForTest.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/util/HostInfoForTest.java @@ -41,7 +41,7 @@ public class HostInfoForTest { int port; String portAsString = System.getProperty("databaseport"); - if (portAsString == null | portAsString.isEmpty()) + if (portAsString == null || portAsString.isEmpty()) port = 49200; else port = Integer.valueOf(portAsString); diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/1.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/1.json new file mode 100644 index 000000000..bcf5e1d0a --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/1.json @@ -0,0 +1,17 @@ + { + "description": "WS/p8.module/a2.module#5", + "date": "2013-04-13T00:00:00.0Z", + "version": "a2.module-newest", + "node-id": "sim1", + "uuid": "a2.module-1.1.5.5", + "parent-uuid": "CARD-1.1.5.0", + "contained-holder": [ + "SUBRACK-1.55.0.0" + ], + "tree-level": 2, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "310330015", + "part-type-id": "3EM23141AD01", + "model-identifier": "CRPQABVFAA", + "type-name": "a2.module" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/10.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/10.json new file mode 100644 index 000000000..6eed5d6a8 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/10.json @@ -0,0 +1,15 @@ + { + "description": "MWR#56Ch#1/a2.moduletraff", + "date": "2017-09-09T00:00:00.0Z", + "version": "a2.module-newest", + "node-id": "sim1", + "uuid": "a2.module-1.56.1.2", + "parent-uuid": "ODU-1.56.0.0", + "contained-holder": [], + "tree-level": 1, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "Serial1", + "part-type-id": "Partnumber", + "model-identifier": "model-id", + "type-name": "a2.module" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/11.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/11.json new file mode 100644 index 000000000..46a4d0650 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/11.json @@ -0,0 +1,18 @@ + { + "description": "MWR-ng Dir#6.5-Ch#1", + "date": "2014-01-16T00:00:00.0Z", + "version": "MWR-ng", + "node-id": "sim1", + "uuid": "IDU-1.65.0.0", + "parent-uuid": "network-element", + "contained-holder": [ + "PORT-1.65.1.4", + "PORT-1.65.1.2" + ], + "tree-level": 0, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "WAUZZI", + "part-type-id": "3DB76047BAAA02", + "model-identifier": "model-id-s3s", + "type-name": "MWR-ng" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/12.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/12.json new file mode 100644 index 000000000..02d592e56 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/12.json @@ -0,0 +1,15 @@ + { + "description": "MWR#55Ch#0/RxDiv", + "date": "2014-01-08T00:00:00.0Z", + "version": "2017", + "node-id": "sim1", + "uuid": "CARD-1.65.1.4", + "parent-uuid": "IDU-1.65.0.0", + "contained-holder": [], + "tree-level": 1, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "Serie2017-13", + "part-type-id": "partNo2017-12", + "model-identifier": "model-id-s3s", + "type-name": "RxDiv" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/13.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/13.json new file mode 100644 index 000000000..85c3723b7 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/13.json @@ -0,0 +1,20 @@ + { + "description": "WS/p8.module", + "date": "2013-11-23T00:00:00.0Z", + "version": "234", + "node-id": "sim1", + "uuid": "CARD-1.1.6.0", + "parent-uuid": "SHELF-1.1.0.0", + "contained-holder": [ + "PORT-1.1.6.5", + "PORT-1.1.6.7", + "PORT-1.1.6.6", + "PORT-1.1.6.8" + ], + "tree-level": 1, + "manufacturer-identifier": "SAN", + "serial": "serial-number-124", + "part-type-id": "part-number-12", + "model-identifier": "model-id-12", + "type-name": "p8.module" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/14.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/14.json new file mode 100644 index 000000000..1fa236e10 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/14.json @@ -0,0 +1,15 @@ +{ + "description": "WS/DS3", + "date": "2008-10-21T00:00:00.0Z", + "version": "unknown", + "node-id": "sim1", + "uuid": "CARD-1.1.8.0", + "parent-uuid": "SHELF-1.1.0.0", + "contained-holder": [], + "tree-level": 1, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "sd-dsa-eqw", + "part-type-id": "unknown", + "model-identifier": "model-id-s3s", + "type-name": "p4.module" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/15.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/15.json new file mode 100644 index 000000000..ff40c4e8b --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/15.json @@ -0,0 +1,15 @@ +{ + "description": "WS/wind", + "date": "2007-02-19T00:00:00.0Z", + "version": "wind", + "node-id": "sim1", + "uuid": "CARD-1.1.9.0", + "parent-uuid": "SHELF-1.1.0.0", + "contained-holder": [], + "tree-level": 1, + "manufacturer-identifier": "CIT", + "serial": "proto-type", + "part-type-id": "party-yea", + "model-identifier": "model-id-s3s", + "type-name": "wind" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/16.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/16.json new file mode 100644 index 000000000..fbd62e04d --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/16.json @@ -0,0 +1,15 @@ + { + "description": "MWR#55Ch#1/RxDiv", + "date": "2014-01-07T00:00:00.0Z", + "version": "2017", + "node-id": "sim1", + "uuid": "CARD-1.55.1.4", + "parent-uuid": "IDU-1.55.0.0", + "contained-holder": [], + "tree-level": 1, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "Serie2017-12", + "part-type-id": "partNo2017-12", + "model-identifier": "model-id-s3s", + "type-name": "RxDiv" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/17.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/17.json new file mode 100644 index 000000000..1704468f3 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/17.json @@ -0,0 +1,17 @@ +{ + "description": "WS/CORE-MAIN/a2.module#7", + "date": "2009-01-19T00:00:00.0Z", + "version": "a2.module-newest", + "node-id": "sim1", + "uuid": "a2.module-1.1.1.7", + "parent-uuid": "CARD-1.1.1.0", + "contained-holder": [ + "SUBRACK-1.17.0.0" + ], + "tree-level": 2, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "91T403003322", + "part-type-id": "1AB187280031", + "model-identifier": "mod2", + "type-name": "a2.module" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/18.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/18.json new file mode 100644 index 000000000..eaec335b4 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/18.json @@ -0,0 +1,18 @@ + { + "description": "MWR-ng Dir#5.5-Ch#1", + "date": "2014-01-15T00:00:00.0Z", + "version": "MWR-ng", + "node-id": "sim1", + "uuid": "IDU-1.55.0.0", + "parent-uuid": "network-element", + "contained-holder": [ + "PORT-1.55.1.2", + "PORT-1.55.1.4" + ], + "tree-level": 0, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "Serie2017-14", + "part-type-id": "3DB76047BAAA02", + "model-identifier": "model-id-s3s", + "type-name": "MWR-ng" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/19.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/19.json new file mode 100644 index 000000000..9a7eb62a7 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/19.json @@ -0,0 +1,20 @@ + { + "description": "WS/CORE-MAIN", + "date": "2015-08-17T00:00:00.0Z", + "version": "123", + "node-id": "sim1", + "uuid": "CARD-1.1.1.0", + "parent-uuid": "SHELF-1.1.0.0", + "contained-holder": [ + "PORT-1.1.1.6", + "PORT-1.1.1.5", + "PORT-1.1.1.8", + "PORT-1.1.1.7" + ], + "tree-level": 1, + "manufacturer-identifier": "SAN", + "serial": "asdf-asdasd-asd", + "part-type-id": "part-number-2", + "model-identifier": "model-id-2", + "type-name": "latest" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/2.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/2.json new file mode 100644 index 000000000..ff352653a --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/2.json @@ -0,0 +1,15 @@ + { + "description": "WS/DS1", + "date": "2007-08-27T00:00:00.0Z", + "version": "p1.module", + "node-id": "sim1", + "uuid": "CARD-1.1.7.0", + "parent-uuid": "SHELF-1.1.0.0", + "contained-holder": [], + "tree-level": 1, + "manufacturer-identifier": "CIT", + "serial": "serial-number-s3s", + "part-type-id": "part-number-s3s", + "model-identifier": "model-id-s3s", + "type-name": "p1.module_A" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/20.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/20.json new file mode 100644 index 000000000..179794027 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/20.json @@ -0,0 +1,20 @@ + { + "description": "WS/p8.module", + "date": "2013-10-21T00:00:00.0Z", + "version": "234", + "node-id": "sim1", + "uuid": "CARD-1.1.5.0", + "parent-uuid": "SHELF-1.1.0.0", + "contained-holder": [ + "PORT-1.1.5.6", + "PORT-1.1.5.5", + "PORT-1.1.5.8", + "PORT-1.1.5.7" + ], + "tree-level": 1, + "manufacturer-identifier": "SAN", + "serial": "africa", + "part-type-id": "part-number-12", + "model-identifier": "model-id-12", + "type-name": "p8.module" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/21.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/21.json new file mode 100644 index 000000000..c76d6715e --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/21.json @@ -0,0 +1,17 @@ +{ + "description": "WS/p8.module/a2.module#6", + "date": "", + "version": "", + "node-id": "sim1", + "uuid": "a2.module-1.1.5.6", + "parent-uuid": "CARD-1.1.5.0", + "contained-holder": [ + "SUBRACK-1.56.0.0" + ], + "tree-level": 2, + "manufacturer-identifier": "", + "serial": "", + "part-type-id": "", + "model-identifier": "", + "type-name": "a2.module" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/3.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/3.json new file mode 100644 index 000000000..1dc6dfce2 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/3.json @@ -0,0 +1,15 @@ +{ + "description": "MWR#55Ch#1/a2.moduletraff", + "date": "2013-04-13T00:00:00.0Z", + "version": "a2.module-newest", + "node-id": "sim1", + "uuid": "a2.module-1.55.1.2", + "parent-uuid": "IDU-1.55.0.0", + "contained-holder": [], + "tree-level": 1, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "310330015", + "part-type-id": "3EM23141AD01", + "model-identifier": "CRPQABVFAA", + "type-name": "a2.module" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/4.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/4.json new file mode 100644 index 000000000..ab1132692 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/4.json @@ -0,0 +1,15 @@ + { + "description": "MWR#65Ch#1/a2.moduletraff", + "date": "2013-04-13T00:00:00.0Z", + "version": "a2.module-newest", + "node-id": "sim1", + "uuid": "a2.module-1.65.1.2", + "parent-uuid": "IDU-1.65.0.0", + "contained-holder": [], + "tree-level": 1, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "310330008", + "part-type-id": "3EM23141AD01", + "model-identifier": "CRPQABVFAA", + "type-name": "a2.module" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/5.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/5.json new file mode 100644 index 000000000..e54173fe6 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/5.json @@ -0,0 +1,25 @@ +{ + "description": "WS-8", + "date": "2017-09-09T00:00:00.0Z", + "version": "a2.module-newest", + "node-id": "sim1", + "uuid": "SHELF-1.1.0.0", + "parent-uuid": "network-element", + "contained-holder": [ + "SLOT-1.1.1.0", + "SLOT-1.1.2.0", + "SLOT-1.1.3.0", + "SLOT-1.1.4.0", + "SLOT-1.1.5.0", + "SLOT-1.1.6.0", + "SLOT-1.1.7.0", + "SLOT-1.1.8.0", + "SLOT-1.1.9.0" + ], + "tree-level": 0, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "Serial1", + "part-type-id": "Partnumber", + "model-identifier": "model-id", + "type-name": "WS-8" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/6.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/6.json new file mode 100644 index 000000000..8486033b0 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/6.json @@ -0,0 +1,17 @@ + { + "description": "WS/CORE-MAIN/a2.module#5", + "date": "2005-11-09T00:00:00.0Z", + "version": "a2.module-newest", + "node-id": "sim1", + "uuid": "a2.module-1.1.1.5", + "parent-uuid": "CARD-1.1.1.0", + "contained-holder": [ + "SUBRACK-1.15.0.0" + ], + "tree-level": 2, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "0003548168", + "part-type-id": "3FE25774AA01", + "model-identifier": "VAUIAEYAAA", + "type-name": "a2.module" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/7.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/7.json new file mode 100644 index 000000000..5c583bec7 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/7.json @@ -0,0 +1,17 @@ +{ + "description": "WS/CORE-MAIN/a2.module#8", + "date": "2010-02-05T00:00:00.0Z", + "version": "a2.module-newest", + "node-id": "sim1", + "uuid": "a2.module-1.1.1.8", + "parent-uuid": "CARD-1.1.1.0", + "contained-holder": [ + "SUBRACK-1.18.0.0" + ], + "tree-level": 2, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "01T441601301", + "part-type-id": "1AB376720002", + "model-identifier": "NGI7AMLMAA", + "type-name": "a2.module" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/8.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/8.json new file mode 100644 index 000000000..a86819a7d --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/8.json @@ -0,0 +1,17 @@ +{ + "description": "WS/p8.module/a2.module#5", + "date": "2013-04-13T00:00:00.0Z", + "version": "a2.module-newest", + "node-id": "sim1", + "uuid": "a2.module-1.1.6.5", + "parent-uuid": "CARD-1.1.6.0", + "contained-holder": [ + "SUBRACK-1.65.0.0" + ], + "tree-level": 2, + "manufacturer-identifier": "ONF-Wireless-Transport", + "serial": "310330008", + "part-type-id": "3EM23141AD01", + "model-identifier": "CRPQABVFAA", + "type-name": "a2.module" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/test/resources/testequipment/9.json b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/9.json new file mode 100644 index 000000000..914033bb4 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/resources/testequipment/9.json @@ -0,0 +1,19 @@ + { + "description": "MWR-hyper Dir#5.6-Ch#1", + "date": "", + "version": "extrem-hyper", + "node-id": "sim1", + "uuid": "ODU-1.56.0.0", + "parent-uuid": "network-element", + "contained-holder": [ + "PORT-1.56.1.2", + "PORT-1.56.1.3", + "PORT-1.56.1.4" + ], + "tree-level": 0, + "manufacturer-identifier": "", + "serial": "", + "part-type-id": "", + "model-identifier": "", + "type-name": "MWR-hyper" +}
\ No newline at end of file diff --git a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/DataMigrationProviderImpl.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/DataMigrationProviderImpl.java index 100f52371..7d2adc5ad 100644 --- a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/DataMigrationProviderImpl.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/DataMigrationProviderImpl.java @@ -344,6 +344,7 @@ public class DataMigrationProviderImpl implements DataMigrationProviderService { } //check aliases AliasesEntryList entries = this.readAliases(); + IndicesEntryList entries2 = this.readIndices(); if (entries == null) { return false; } @@ -381,9 +382,22 @@ public class DataMigrationProviderImpl implements DataMigrationProviderService { return false; } } + else { + //try to find malformed typed index with alias name + IndicesEntry entry2ToDelete = entries2.findByIndex(aliasToDelete); + if (entry2ToDelete != null) { + try { + LOG.info("deleting index {}", entry2ToDelete.getName()); + response = this.dbClient.deleteIndex(new DeleteIndexRequest(entry2ToDelete.getName())); + LOG.info(response.isResponseSucceeded() ? "succeeded" : "failed"); + } catch (IOException e) { + LOG.error(e.getMessage()); + return false; + } + } + } } } - IndicesEntryList entries2 = this.readIndices(); if (entries2 == null) { return false; } diff --git a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/Program.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/Program.java index 4b201bccc..54204f170 100644 --- a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/Program.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/Program.java @@ -23,8 +23,13 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup; import java.util.Arrays; import java.util.List; - -import org.apache.commons.cli.*; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.log4j.ConsoleAppender; @@ -293,17 +298,13 @@ public class Program { } private static void cmd_dbimport(CommandLine cmd) throws Exception { - String dbUrl = getOptionOrDefault(cmd, OPTION_DATABASE_SHORT, DEFAULT_DBURL); - String username = getOptionOrDefault(cmd, OPTION_DATABASEUSER_SHORT, null); - String password = getOptionOrDefault(cmd, OPTION_DATABASEPASSWORD_SHORT, null); + DatabaseOptions options = new DatabaseOptions(cmd); String filename = getOptionOrDefault(cmd, OPTION_OUTPUTFILE_SHORT, null); - boolean trustAll = getOptionOrDefault(cmd, OPTION_TRUSTINSECURESSL_SHORT, DEFAULT_TRUSTINSECURESSL); if (filename == null) { throw new Exception("please add output file parameter"); } - long timeoutms = getTimeoutOptionMillis(cmd); - DataMigrationProviderImpl service = new DataMigrationProviderImpl(new HostInfo[] {HostInfo.parse(dbUrl)}, - username, password, trustAll, timeoutms); + DataMigrationProviderImpl service = new DataMigrationProviderImpl(new HostInfo[] {HostInfo.parse(options.getUrl())}, + options.getUsername(), options.getPassword(), options.doTrustAll(), options.getTimeoutMs()); DataMigrationReport report = service.importData(filename, false); LOG.info(report); if (!report.completed()) { @@ -313,17 +314,13 @@ public class Program { } private static void cmd_dbexport(CommandLine cmd) throws Exception { - String dbUrl = getOptionOrDefault(cmd, OPTION_DATABASE_SHORT, DEFAULT_DBURL); - String username = getOptionOrDefault(cmd, OPTION_DATABASEUSER_SHORT, null); - String password = getOptionOrDefault(cmd, OPTION_DATABASEPASSWORD_SHORT, null); + DatabaseOptions options = new DatabaseOptions(cmd); String filename = getOptionOrDefault(cmd, OPTION_OUTPUTFILE_SHORT, null); - boolean trustAll = getOptionOrDefault(cmd, OPTION_TRUSTINSECURESSL_SHORT, DEFAULT_TRUSTINSECURESSL); if (filename == null) { throw new Exception("please add output file parameter"); } - long timeoutms = getTimeoutOptionMillis(cmd); - DataMigrationProviderImpl service = new DataMigrationProviderImpl(new HostInfo[] {HostInfo.parse(dbUrl)}, - username, password, trustAll, timeoutms); + DataMigrationProviderImpl service = new DataMigrationProviderImpl(new HostInfo[] {HostInfo.parse(options.getUrl())}, + options.getUsername(), options.getPassword(), options.doTrustAll(), options.getTimeoutMs()); DataMigrationReport report = service.exportData(filename); LOG.info(report); if (!report.completed()) { @@ -343,29 +340,21 @@ public class Program { private static void cmd_clear_db(CommandLine cmd) throws Exception { Release r = getOptionOrDefault(cmd, OPTION_VERSION_SHORT, (Release) null); - String dbUrl = getOptionOrDefault(cmd, OPTION_DATABASE_SHORT, DEFAULT_DBURL); + DatabaseOptions options = new DatabaseOptions(cmd); String dbPrefix = getOptionOrDefault(cmd, OPTION_DATABASEPREFIX_SHORT, DEFAULT_DBPREFIX); - String username = getOptionOrDefault(cmd, OPTION_DATABASEUSER_SHORT, null); - String password = getOptionOrDefault(cmd, OPTION_DATABASEPASSWORD_SHORT, null); - boolean trustAll = getOptionOrDefault(cmd, OPTION_TRUSTINSECURESSL_SHORT, DEFAULT_TRUSTINSECURESSL); - long timeoutms = getTimeoutOptionMillis(cmd); - DataMigrationProviderImpl service = new DataMigrationProviderImpl(new HostInfo[] {HostInfo.parse(dbUrl)}, - username, password, trustAll, timeoutms); - if (!service.clearDatabase(r, dbPrefix, timeoutms)) { + DataMigrationProviderImpl service = new DataMigrationProviderImpl(new HostInfo[] {HostInfo.parse(options.getUrl())}, + options.getUsername(), options.getPassword(), options.doTrustAll(), options.getTimeoutMs()); + if (!service.clearDatabase(r, dbPrefix, options.getTimeoutMs())) { throw new Exception("failed to init database"); } LOG.info("database clear completed successfully"); } private static void cmd_clear_db_complete(CommandLine cmd) throws Exception { - String dbUrl = getOptionOrDefault(cmd, OPTION_DATABASE_SHORT, DEFAULT_DBURL); - String username = getOptionOrDefault(cmd, OPTION_DATABASEUSER_SHORT, null); - String password = getOptionOrDefault(cmd, OPTION_DATABASEPASSWORD_SHORT, null); - boolean trustAll = getOptionOrDefault(cmd, OPTION_TRUSTINSECURESSL_SHORT, DEFAULT_TRUSTINSECURESSL); - long timeoutms = getTimeoutOptionMillis(cmd); - DataMigrationProviderImpl service = new DataMigrationProviderImpl(new HostInfo[] {HostInfo.parse(dbUrl)}, - username, password, trustAll, timeoutms); - if (!service.clearCompleteDatabase(timeoutms)) { + DatabaseOptions options = new DatabaseOptions(cmd); + DataMigrationProviderImpl service = new DataMigrationProviderImpl(new HostInfo[] {HostInfo.parse(options.getUrl())}, + options.getUsername(), options.getPassword(), options.doTrustAll(), options.getTimeoutMs()); + if (!service.clearCompleteDatabase(options.getTimeoutMs())) { throw new Exception("failed to init database"); } LOG.info("database complete clear completed successfully"); @@ -375,16 +364,12 @@ public class Program { Release r = getOptionOrDefault(cmd, OPTION_VERSION_SHORT, (Release) null); int numShards = getOptionOrDefault(cmd, OPTION_SHARDS_SHORT, DEFAULT_SHARDS); int numReplicas = getOptionOrDefault(cmd, OPTION_REPLICAS_SHORT, DEFAULT_REPLICAS); - String dbUrl = getOptionOrDefault(cmd, OPTION_DATABASE_SHORT, DEFAULT_DBURL); + DatabaseOptions options = new DatabaseOptions(cmd); String dbPrefix = getOptionOrDefault(cmd, OPTION_DATABASEPREFIX_SHORT, DEFAULT_DBPREFIX); - String username = getOptionOrDefault(cmd, OPTION_DATABASEUSER_SHORT, null); - String password = getOptionOrDefault(cmd, OPTION_DATABASEPASSWORD_SHORT, null); - boolean trustAll = getOptionOrDefault(cmd, OPTION_TRUSTINSECURESSL_SHORT, DEFAULT_TRUSTINSECURESSL); - long timeoutms = getTimeoutOptionMillis(cmd); - DataMigrationProviderImpl service = new DataMigrationProviderImpl(new HostInfo[] {HostInfo.parse(dbUrl)}, - username, password, trustAll, timeoutms); + DataMigrationProviderImpl service = new DataMigrationProviderImpl(new HostInfo[] {HostInfo.parse(options.getUrl())}, + options.getUsername(), options.getPassword(), options.doTrustAll(), options.getTimeoutMs()); boolean forceRecreate = cmd.hasOption(OPTION_FORCE_RECREATE_SHORT); - if (!service.initDatabase(r, numShards, numReplicas, dbPrefix, forceRecreate, timeoutms)) { + if (!service.initDatabase(r, numShards, numReplicas, dbPrefix, forceRecreate, options.getTimeoutMs())) { throw new Exception("failed to init database"); } LOG.info("database init completed successfully"); @@ -425,7 +410,7 @@ public class Program { /** * create option for argparse lib - * + * * @param opt short option string * @param longOpt long option string * @param hasArg flag if has a parameter after option tag @@ -440,4 +425,35 @@ public class Program { return o; } // end of private methods + + private static class DatabaseOptions{ + private final String url; + private final String username; + private final String password; + private final boolean trustAll; + private final long timeoutMs; + + public String getUrl() { + return this.url; + } + public String getUsername() { + return this.username; + } + public String getPassword() { + return this.password; + } + public boolean doTrustAll() { + return this.trustAll; + } + public long getTimeoutMs() { + return this.timeoutMs; + } + public DatabaseOptions(CommandLine cmd) throws ParseException { + this.url = getOptionOrDefault(cmd, OPTION_DATABASE_SHORT, DEFAULT_DBURL); + this.username = getOptionOrDefault(cmd, OPTION_DATABASEUSER_SHORT, null); + this.password = getOptionOrDefault(cmd, OPTION_DATABASEPASSWORD_SHORT, null); + this.trustAll = getOptionOrDefault(cmd, OPTION_TRUSTINSECURESSL_SHORT, DEFAULT_TRUSTINSECURESSL); + this.timeoutMs = getTimeoutOptionMillis(cmd); + } + } } diff --git a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/ReleaseInformation.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/ReleaseInformation.java index d772dc296..9b7a49346 100644 --- a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/ReleaseInformation.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/ReleaseInformation.java @@ -23,7 +23,6 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup; import java.util.Map; import java.util.Set; - import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; import org.onap.ccsdk.features.sdnr.wt.common.database.data.IndicesEntryList; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.ComponentName; @@ -35,7 +34,6 @@ import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.elalto.ElAltoReleaseIn import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.frankfurt.FrankfurtReleaseInformation; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.frankfurt.FrankfurtReleaseInformationR2; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.guilin.GuilinReleaseInformation; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.guilin.GuilinReleaseInformationR2; public abstract class ReleaseInformation { @@ -53,7 +51,7 @@ public abstract class ReleaseInformation { /** * get database alias for component - * + * * @param name * @return alias or null if not exists */ @@ -67,7 +65,7 @@ public abstract class ReleaseInformation { /** * get index name for component - * + * * @param comp * @return null if component does not exists in this release, otherwise index name */ @@ -77,7 +75,7 @@ public abstract class ReleaseInformation { /** * get index name for component with prefix - * + * * @param comp * @param prefix * @return null if component does not exists in this release, otherwise index name @@ -88,7 +86,7 @@ public abstract class ReleaseInformation { /** * get database datatype (doctype) for component - * + * * @param name * @return datatype or null if not exists */ @@ -102,7 +100,7 @@ public abstract class ReleaseInformation { /** * get database doctype definition for component - * + * * @param name * @return mappings or null if not exists */ @@ -112,7 +110,7 @@ public abstract class ReleaseInformation { /** * get database settings definition for component - * + * * @param name * @return settings or null if not exists */ @@ -122,7 +120,7 @@ public abstract class ReleaseInformation { /** * get converter for component data - * + * * @param dst destination release * @param comp component to convert * @return @@ -144,8 +142,6 @@ public abstract class ReleaseInformation { return new FrankfurtReleaseInformationR2(); case GUILIN_R1: return new GuilinReleaseInformation(); - case GUILIN_R2: - return new GuilinReleaseInformationR2(); default: return null; } @@ -192,7 +188,7 @@ public abstract class ReleaseInformation { protected abstract boolean runPreInitCommands(HtDatabaseClient dbClient); /** - * + * * @param dbClient * @return if succeeded or not */ diff --git a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/Release.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/Release.java index b2442df6b..4f55f4cd7 100644 --- a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/Release.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/Release.java @@ -26,15 +26,12 @@ import org.onap.ccsdk.features.sdnr.wt.common.database.data.EsVersion; public enum Release { - EL_ALTO("el alto", "_v1", new EsVersion(2, 2, 0), new EsVersion(2, 2, 0)), FRANKFURT_R1("frankfurt-R1", "-v2", - new EsVersion(6, 4, 3), new EsVersion(6, 8, 6)), FRANKFURT_R2("frankfurt-R2", "-v3", new EsVersion(7, 0, 1), - new EsVersion(7, 6, 1)), - //FRANKFURT_R3("frankfurt-R3","",new EsVersion(6,4,3),new EsVersion(6,8,6)), + EL_ALTO("el alto", "_v1", new EsVersion(2, 2, 0), new EsVersion(2, 2, 0)), + FRANKFURT_R1("frankfurt-R1", "-v2", new EsVersion(6, 4, 3), new EsVersion(6, 8, 6)), + FRANKFURT_R2("frankfurt-R2", "-v3", new EsVersion(7, 0, 1), new EsVersion(7, 6, 1)), + GUILIN_R1("guilin-R1", "-v4", new EsVersion(7,1,1), new EsVersion(7,6,1)); - GUILIN_R1("guilin-R1", "-v4", new EsVersion(6, 4, 3), new EsVersion(6, 8, 6)), GUILIN_R2("guilin-R2", "-v5", - new EsVersion(7, 0, 1), new EsVersion(7, 6, 1)); - - public static final Release CURRENT_RELEASE = Release.FRANKFURT_R1; + public static final Release CURRENT_RELEASE = Release.GUILIN_R1; private final String value; private final String dbSuffix; diff --git a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/ReleaseGroup.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/ReleaseGroup.java index c7d26dbed..993d0261f 100644 --- a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/ReleaseGroup.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/ReleaseGroup.java @@ -23,7 +23,6 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data; import java.util.ArrayList; import java.util.List; - import org.onap.ccsdk.features.sdnr.wt.common.database.data.EsVersion; /** @@ -32,10 +31,9 @@ import org.onap.ccsdk.features.sdnr.wt.common.database.data.EsVersion; */ public enum ReleaseGroup { - EL_ALTO(Release.EL_ALTO), FRANKFURT(Release.FRANKFURT_R1, Release.FRANKFURT_R2), GUILIN(Release.GUILIN_R1, - Release.GUILIN_R2); + EL_ALTO(Release.EL_ALTO), FRANKFURT(Release.FRANKFURT_R1, Release.FRANKFURT_R2), GUILIN(Release.GUILIN_R1); - public static final ReleaseGroup CURRENT_RELEASE = FRANKFURT; + public static final ReleaseGroup CURRENT_RELEASE = GUILIN; private final List<Release> releases; diff --git a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/frankfurt/FrankfurtReleaseInformationR2.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/frankfurt/FrankfurtReleaseInformationR2.java index e842b5c7b..f972777b9 100644 --- a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/frankfurt/FrankfurtReleaseInformationR2.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/frankfurt/FrankfurtReleaseInformationR2.java @@ -24,6 +24,10 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.frankfurt; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; +import org.onap.ccsdk.features.sdnr.wt.common.database.requests.ClusterSettingsRequest; +import org.onap.ccsdk.features.sdnr.wt.common.database.responses.ClusterSettingsResponse; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.ReleaseInformation; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.ComponentName; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.DatabaseInfo; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.DatabaseInfo7; @@ -31,10 +35,6 @@ import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.Release; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.SearchHitConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; -import org.onap.ccsdk.features.sdnr.wt.common.database.requests.ClusterSettingsRequest; -import org.onap.ccsdk.features.sdnr.wt.common.database.responses.ClusterSettingsResponse; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.ReleaseInformation; public class FrankfurtReleaseInformationR2 extends ReleaseInformation { @@ -45,7 +45,7 @@ public class FrankfurtReleaseInformationR2 extends ReleaseInformation { super(Release.FRANKFURT_R2, createDBMap()); } - private static Map<ComponentName, DatabaseInfo> createDBMap() { + public static Map<ComponentName, DatabaseInfo> createDBMap() { Map<ComponentName, DatabaseInfo> map = new HashMap<>(); map.put(ComponentName.CONNECTIONLOG, new DatabaseInfo7("connectionlog", "connectionlog", "{\"node-id\": {\"type\": \"keyword\"},\"timestamp\": {\"type\": \"date\"},\"status\": {\"type\": \"keyword\"}}")); diff --git a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/guilin/GuilinReleaseInformation.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/guilin/GuilinReleaseInformation.java index 2c2ac25a9..e057d82f2 100644 --- a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/guilin/GuilinReleaseInformation.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/guilin/GuilinReleaseInformation.java @@ -21,43 +21,25 @@ */ package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.guilin; -import java.util.HashMap; -import java.util.Map; - +import java.io.IOException; import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; +import org.onap.ccsdk.features.sdnr.wt.common.database.requests.ClusterSettingsRequest; +import org.onap.ccsdk.features.sdnr.wt.common.database.responses.ClusterSettingsResponse; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.ReleaseInformation; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.ComponentName; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.DatabaseInfo; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.KeepDataSearchHitConverter; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.Release; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.SearchHitConverter; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.frankfurt.FrankfurtReleaseInformationR2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class GuilinReleaseInformation extends ReleaseInformation { - /** - * @param r - * @param dbMap - */ + private final Logger LOG = LoggerFactory.getLogger(GuilinReleaseInformation.class); public GuilinReleaseInformation() { - super(Release.GUILIN_R1, createDBMap()); - - } + super(Release.GUILIN_R1, FrankfurtReleaseInformationR2.createDBMap()); - private static Map<ComponentName, DatabaseInfo> createDBMap() { - Map<ComponentName, DatabaseInfo> map = new HashMap<>(); - map.put(ComponentName.EVENTLOG, new DatabaseInfo("eventlog", "eventlog", "")); - map.put(ComponentName.FAULTCURRENT, new DatabaseInfo("faultcurrent", "faultcurrent", "")); - map.put(ComponentName.FAULTLOG, new DatabaseInfo("faultlog", "faultlog", "")); - map.put(ComponentName.INVENTORY, new DatabaseInfo("inventoryequipment", "inventoryequipment", "")); - map.put(ComponentName.HISTORICAL_PERFORMANCE_15M, - new DatabaseInfo("historicalperformance15min", "historicalperformance15min", "")); - map.put(ComponentName.HISTORICAL_PERFORMANCE_24H, - new DatabaseInfo("historicalperformance24h", "historicalperformance24h", "")); - map.put(ComponentName.REQUIRED_NETWORKELEMENT, - new DatabaseInfo("networkelement-connection", "networkelement-connection", "")); - map.put(ComponentName.MEDIATOR_SERVER, new DatabaseInfo("mediator-server", "mediator-server", "")); - map.put(ComponentName.MAINTENANCE, new DatabaseInfo("maintenancemode", "maintenancemode", "")); - return map; } @Override @@ -70,7 +52,13 @@ public class GuilinReleaseInformation extends ReleaseInformation { @Override protected boolean runPreInitCommands(HtDatabaseClient dbClient) { - return true; + ClusterSettingsResponse response = null; + try { + response = dbClient.setupClusterSettings(new ClusterSettingsRequest(false).maxCompilationsPerMinute(400)); + } catch (IOException e) { + LOG.warn("problem setting up cluster: {}", e); + } + return response == null ? false : response.isAcknowledged(); } @Override diff --git a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/guilin/GuilinReleaseInformationR2.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/guilin/GuilinReleaseInformationR2.java deleted file mode 100644 index 29c79f3da..000000000 --- a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/guilin/GuilinReleaseInformationR2.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP : ccsdk features - * ================================================================================ - * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. - * All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - * - */ -package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.guilin; - -import java.util.HashMap; -import java.util.Map; - -import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.ReleaseInformation; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.ComponentName; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.DatabaseInfo; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.KeepDataSearchHitConverter; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.Release; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.SearchHitConverter; - -public class GuilinReleaseInformationR2 extends ReleaseInformation { - - /** - * @param r - * @param dbMap - */ - public GuilinReleaseInformationR2() { - super(Release.GUILIN_R2, createDBMap()); - - } - - private static Map<ComponentName, DatabaseInfo> createDBMap() { - Map<ComponentName, DatabaseInfo> map = new HashMap<>(); - map.put(ComponentName.EVENTLOG, new DatabaseInfo("eventlog", "eventlog", "")); - map.put(ComponentName.FAULTCURRENT, new DatabaseInfo("faultcurrent", "faultcurrent", "")); - map.put(ComponentName.FAULTLOG, new DatabaseInfo("faultlog", "faultlog", "")); - map.put(ComponentName.INVENTORY, new DatabaseInfo("inventoryequipment", "inventoryequipment", "")); - map.put(ComponentName.HISTORICAL_PERFORMANCE_15M, - new DatabaseInfo("historicalperformance15min", "historicalperformance15min", "")); - map.put(ComponentName.HISTORICAL_PERFORMANCE_24H, - new DatabaseInfo("historicalperformance24h", "historicalperformance24h", "")); - map.put(ComponentName.REQUIRED_NETWORKELEMENT, - new DatabaseInfo("networkelement-connection", "networkelement-connection", "")); - map.put(ComponentName.MEDIATOR_SERVER, new DatabaseInfo("mediator-server", "mediator-server", "")); - map.put(ComponentName.MAINTENANCE, new DatabaseInfo("maintenancemode", "maintenancemode", "")); - return map; - } - - @Override - public SearchHitConverter getConverter(Release dst, ComponentName comp) { - if (dst == Release.GUILIN_R2) { - return new KeepDataSearchHitConverter(comp); - } - return null; - } - - @Override - protected boolean runPreInitCommands(HtDatabaseClient dbClient) { - return true; - } - - @Override - protected boolean runPostInitCommands(HtDatabaseClient dbClient) { - return true; - } - -} diff --git a/sdnr/wt/data-provider/setup/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/TestMigrationProvider.java b/sdnr/wt/data-provider/setup/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/TestMigrationProvider.java index 32438410f..aaa33839f 100644 --- a/sdnr/wt/data-provider/setup/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/TestMigrationProvider.java +++ b/sdnr/wt/data-provider/setup/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/TestMigrationProvider.java @@ -24,7 +24,6 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; - import org.junit.Test; import org.onap.ccsdk.features.sdnr.wt.common.database.config.HostInfo; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.DataMigrationReport; @@ -54,7 +53,7 @@ public class TestMigrationProvider { //import data into database DataMigrationReport report = provider.importData(FRANKFURT_BACKUP_FILE, false, Release.FRANKFURT_R2); assertTrue(report.completed()); - assertEquals(Release.FRANKFURT_R2, provider.autoDetectRelease()); + assertEquals(Release.CURRENT_RELEASE, provider.autoDetectRelease()); } catch (Exception e) { fail(e.getMessage()); } diff --git a/sdnr/wt/devicemanager-openroadm/installer/pom.xml b/sdnr/wt/devicemanager-openroadm/installer/pom.xml index fb3131c6d..2750d6094 100755 --- a/sdnr/wt/devicemanager-openroadm/installer/pom.xml +++ b/sdnr/wt/devicemanager-openroadm/installer/pom.xml @@ -20,7 +20,7 @@ ~ ============LICENSE_END======================================================= ~ --> - + <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> diff --git a/sdnr/wt/devicemanager-openroadm/provider/pom.xml b/sdnr/wt/devicemanager-openroadm/provider/pom.xml index 5eeae51e0..a8f2c91be 100644 --- a/sdnr/wt/devicemanager-openroadm/provider/pom.xml +++ b/sdnr/wt/devicemanager-openroadm/provider/pom.xml @@ -65,6 +65,7 @@ <version>1.9.10</version> <scope>test</scope> </dependency> + <!-- end for testing --> <dependency> <groupId>${project.groupId}</groupId> diff --git a/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/DeviceManagerOpenroadmImpl.java b/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/DeviceManagerOpenroadmImpl.java index efda889b9..fc5aabaa7 100644 --- a/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/DeviceManagerOpenroadmImpl.java +++ b/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/DeviceManagerOpenroadmImpl.java @@ -81,13 +81,13 @@ public class DeviceManagerOpenroadmImpl implements AutoCloseable { } // end of public methods + // private methods /** * Used to close all Services, that should support AutoCloseable Pattern * * @param toClose * @throws Exception */ - // private methods private void close(AutoCloseable... toCloseList) { for (AutoCloseable element : toCloseList) { if (element != null) { diff --git a/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/OpenroadmDeviceChangeNotificationListener.java b/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/OpenroadmDeviceChangeNotificationListener.java index 32f8cb0cb..f055c598a 100644 --- a/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/OpenroadmDeviceChangeNotificationListener.java +++ b/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/OpenroadmDeviceChangeNotificationListener.java @@ -78,9 +78,7 @@ public class OpenroadmDeviceChangeNotificationListener implements OrgOpenroadmDe sb.append(", "); } sb.append(edit); - EventlogBuilder eventlogBuilder = new EventlogBuilder(); - InstanceIdentifier<?> target = edit.getTarget(); if (target != null) { eventlogBuilder.setObjectId(target.getPathArguments().toString()); @@ -91,13 +89,11 @@ public class OpenroadmDeviceChangeNotificationListener implements OrgOpenroadmDe eventlogBuilder.setAttributeName(target.getTargetType().getName()); } eventlogBuilder.setNodeId(netconfAccessor.getNodeId().getValue()); - eventlogBuilder.setNewValue(String.valueOf(edit.getOperation())); eventlogBuilder.setTimestamp(notification.getChangeTime()); eventlogBuilder.setCounter(counter); eventlogBuilder.setSourceType(SourceType.Netconf); databaseProvider.writeEventLog(eventlogBuilder.build()); - log.info("onDeviceConfigChange (2) {}", sb); counter++; } @@ -107,7 +103,6 @@ public class OpenroadmDeviceChangeNotificationListener implements OrgOpenroadmDe public void onCreateTechInfoNotification(CreateTechInfoNotification notification) { // TODO Auto-generated method stub log.info("onCreateTechInfoNotification(1){}", notification); - EventlogBuilder eventlogBuilder = new EventlogBuilder(); eventlogBuilder.setId(notification.getShelfId()).setAttributeName(notification.getShelfId()) .setObjectId(notification.getShelfId()).setNodeId(this.netconfAccessor.getNodeId().getValue()) @@ -115,7 +110,6 @@ public class OpenroadmDeviceChangeNotificationListener implements OrgOpenroadmDe databaseProvider.writeEventLog(eventlogBuilder.build()); log.info("Create-techInfo Notification written "); counter++; - } // end of public methods diff --git a/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/OpenroadmInventoryInput.java b/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/OpenroadmInventoryInput.java index be79c7ba7..d67db8a03 100644 --- a/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/OpenroadmInventoryInput.java +++ b/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/OpenroadmInventoryInput.java @@ -45,11 +45,6 @@ public class OpenroadmInventoryInput { private final NetconfAccessor accessor; // end of variables - /** - * @param netconfAccessor - * @param readDevice - */ - // constructors public OpenroadmInventoryInput(NetconfAccessor netconfAccessor, OrgOpenroadmDevice readDevice) { this.openRoadmDevice = readDevice; diff --git a/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/OpenroadmNetworkElement.java b/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/OpenroadmNetworkElement.java index 98e5e4659..5fa438497 100644 --- a/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/OpenroadmNetworkElement.java +++ b/sdnr/wt/devicemanager-openroadm/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/openroadm/impl/OpenroadmNetworkElement.java @@ -110,11 +110,6 @@ public class OpenroadmNetworkElement implements NetworkElement { readInterfaceData(device); // Writing initial alarms at the time of device registration initialAlarmReader.faultService(); - // faultEventListener.initCurrentProblemStatus(this.netconfAccessor.getNodeId(), - // oScaFaultListener.writeFaultData(this.sequenceNumber)); - // oScaFaultListener.writeAlarmLog(oScaFaultListener.writeFaultData(this.sequenceNumber)); - // this.sequenceNumber = this.sequenceNumber + 1; - pmDataEntity = this.openRoadmPmData.buildPmDataEntity(this.openRoadmPmData.getPmData(this.netconfAccessor)); if (!pmDataEntity.isEmpty()) { this.databaseService.doWritePerformanceData(pmDataEntity); diff --git a/sdnr/wt/helpserver/provider/pom.xml b/sdnr/wt/helpserver/provider/pom.xml index 8c64c47a4..487e08806 100644 --- a/sdnr/wt/helpserver/provider/pom.xml +++ b/sdnr/wt/helpserver/provider/pom.xml @@ -41,6 +41,7 @@ <name>ccsdk-features :: ${project.artifactId}</name> <properties> + <maven.javadoc.skip>true</maven.javadoc.skip> <checkstyle.skip>true</checkstyle.skip> </properties> @@ -70,6 +71,7 @@ <artifactId>mockito-core</artifactId> <scope>test</scope> </dependency> + </dependencies> <build> diff --git a/sdnr/wt/helpserver/provider/src/main/resources/help/meta.json b/sdnr/wt/helpserver/provider/src/main/resources/help/meta.json index 29a678728..208bee032 100644 --- a/sdnr/wt/helpserver/provider/src/main/resources/help/meta.json +++ b/sdnr/wt/helpserver/provider/src/main/resources/help/meta.json @@ -120,6 +120,36 @@ } }, "label": "EventLog" + }, + "networkApp": { + "versions": { + "0.4.0": { + "date": "2018-02-24", + "path": "sdnr/networkMap/README.md", + "label": "NetworkMap" + }, + "current": { + "date": "2018-02-24", + "path": "sdnr/networkMap/README.md", + "label": "NetworkMap" + } + }, + "label": "NetworkMap" + }, + "linkCalculationApp": { + "versions": { + "0.4.0": { + "date": "2018-02-24", + "path": "sdnr/linkCalculator/README.md", + "label": "LinkCalculator" + }, + "current": { + "date": "2018-02-24", + "path": "sdnr/linkCalculator/README.md", + "label": "LinkCalculator" + } + }, + "label": "LinkCalculator" } }, "versions": { diff --git a/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/general.md b/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/general.md index d908d1221..a91b48545 100644 --- a/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/general.md +++ b/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/general.md @@ -19,7 +19,7 @@ The following filters are supported by all tables based on the data type of the |Data type | Possible Filter | Example | | ---------|---------------|---------| -| Text | Any characters or numbers, matches exactly unless a * is used. The * acts as a wildcard and can be used for contains, ends with and begins with queries. |Test, Tes*, *t | +| Text | Any characters or numbers, matches exactly unless a * or a ? are used. Both special characters act as wildcards, which can be used for contains, ends with and begins with queries. The * matches any number of characters whereas the ? matches exactly one character. Both wildcards can be used in the same query. |Test, T*, *st, Te?t, ?est | | Numeric | < or <= or > or >= or exact number |>5000, 20, <=82 | | Boolean |None (no filter set), true or false |true, false | diff --git a/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/linkCalculator/README.md b/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/linkCalculator/README.md new file mode 100644 index 000000000..0c7e20245 --- /dev/null +++ b/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/linkCalculator/README.md @@ -0,0 +1,51 @@ +# Link Calculator + +The 'Link calculator' analyzes the microwave propagation measurements of the wireless links. It can be accessed through the Network Map by clicking on the 'link calculation' button available in microwave links. + +## View + +The app includes two view possibilities. If it is accessed via the menu, the view provides a form table and a blank information table. The form table offers inputs for latitude and longitude values of the two points of a link. By entering this geographical information the data in the information table gets updated. + +The information table contains the calculation inputs and outputs. If the Link Calculator is accessed through the 'calculate link' button, only this table with pre-filled geographical locations is shown. Currently, input variables of the link calculation include Polarization, Frequency, Rain Model, and Rainfall Rate. Outputs of the calculation are Free Space Loss and Rain Loss. The results will be visible upon clicking the 'Calculate' button at the bottom of the table. + +### Average Mean Sea Level + +Denotes the ground elevation of the sites on each end. + +### Antenna Height Above Ground + +Is the height at which the antenna is mounted from the ground. + +### Distance + +The distance in the information table is auto-filled when the microwave link is selected and the calculator is accessed through the 'calculate link' button in the Network Map. If the points are entered manually, the distance is calculated after clicking the 'Calculate' button. + +### Polarization + +A selection of Vertical and Horizontal polarization is possible. + +### Frequency + +A selection of known and regulated microwave bands is possible. + +### Rainfall Rate + +Rainfall rate can be entered in the field, however if the local information is not available, the digital map and rainfall values of ITU-R P.837-7 [^1] is used. The latitude grid is from -90 North degrees to +90 North degrees and the longitude grid is from -180 degrees East to +180 East. For this calculation, the pre-computed R_0.01 map is used. A selection is possible through the Rain Model drop-down list. When the ITU model is selected, the rainfall rate will be shown in the rainfall rate field after clicking the 'Calculate' button. + +## Calculations + +Wireless signal attenuation is calculated based on ITU Recommendations for Propagation. At the moment these calculations include the free space loss and rain loss. + +### Free Space Loss + +Calculates the Free Space Path Loss for a point-to-point non-terrestrial link using the recommended formula in ITU-R P.525-4 [^2]. The output is shown in dB hence the distance is attributed in the calculation. + +### Rain Loss + +Calculates the rain induced attenuation on microwave signal. The calculation is based on the recommended formula in ITU-R P.838-3 [^3], taking into account the polarization of the signal, rainfall rate, and distance. The manual calculation is also possible if 'Specific Rain' is selected as rain model. After selecting the inputs, rain loss will be calculated by clicking the 'Calculate' button. + +------------------------------------------------ + +[^1]: Radiocommunication Sector of International Telecommunication Union. ITU-R P.837-7: Characteristics of precipitation for propagation modelling 2017. +[^2]: Radiocommunication Sector of International Telecommunication Union. ITU-R P.525-4: Calculation of free-space attenuation 2019. +[^3]: Radiocommunication Sector of International Telecommunication Union. ITU-R P.838-3: Specific attenuation model for rain for use in prediction methods 2005.
\ No newline at end of file diff --git a/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/networkMap/README.md b/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/networkMap/README.md new file mode 100644 index 000000000..98d413529 --- /dev/null +++ b/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/networkMap/README.md @@ -0,0 +1,46 @@ +# Network Map + +The 'Network Map' visualizes a network by showing the location of a site and its connections (links) to other sites in a geographical context. + +## Views + +The 'Network Map' consists of two side-by-side views: The map and the details-panel. + +### Map + +The geographical map visualizes sites and links of a network. Sites are usually displayed as blue circles and links are shown as lines connecting sites. + +If a link or site is clicked, its information is presented in the details panel. If more than one site or link is clicked, or if links or sites are too close together to determine which element should be selected, a selection popup appears to select one of the elements. + +The map offers statistics information to visualize the number of links and sites in the currently shown map area. The statistics information gets updated when the map stops moving. + +Additionally, the map offers a search field. The user can enter the name of a site or link. If an element was found, the map will center on the given element and its information is loaded by the details panel. + +If the zoom level is bigger than 11 and the loaded sites have a type of high-rise building, datacenter, factory, or street-lamp, the blue circles are swapped against icons, which visualizes the type of site. + +The swapping of icons can be activated or deactivated via a switch on the left-hand site of the map. The switch only becomes visible, if the zoom level is bigger than 9. + +The map supports zoom levels between 0 (furthest zoomed out, the entire world is visible) and 18 (most detailed). + +Whenever the map stops moving, it updates the URL with its current latitude, longitude, and zoom values. If the 'Network Map' application is opened with those URL parameters present, it will display the given area. That way, the map can be bookmarked or shared and will always display the same result. + + +### Details + +The details panel shows information specific to the selected element. + +Sites offer information about itself, such as name, address and owner, and a short overview of its links and nodes data. The nodes are physical network elements, comparable to the elements of the 'connect' application, and offer an interface to other apps via buttons, such as connect, configure, and fault. Currently, those buttons are disabled. By clicking on a link, the given link is loaded into details. + +If a link of type 'microwave' is selected, the 'calculate link' button is available, which opens the [Link Calculator](../linkCalculator/README.md) in a new tab or page. + +Just like the map, the details panel updates the URL if data is loaded. Once again, the 'Network Map' application will try to load the element specified in the URL, if one is present. + +## Connection Error + +If no tile or network data is available, an error popup is shown. + +## Load Network- and Tile-Data + +On startup of the sdnc-web container, a topology URL for the network data and a tile URL for the tiles can be specified. + +A ready-to-use topology server offering pre-defined network data is available here. There is no way to import generic network data as of now.
\ No newline at end of file diff --git a/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/pnfInventory/README.md b/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/pnfInventory/README.md index f09a492d7..1f2dd88e5 100644 --- a/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/pnfInventory/README.md +++ b/sdnr/wt/helpserver/provider/src/main/resources/help/sdnr/pnfInventory/README.md @@ -2,7 +2,17 @@ The application offers basic inventory management of devices supporting ONF-TR-512 and ietf-hardware. -The view displays the inventory data of the network element – for example, serial-numbers and part-numbers according to the containment of the equipment. +## Views + +The inventory application offers two different ways to visualize inventory data. + +### Tableview + +The view displays the inventory data of the network element – for example, serial-numbers and part-numbers according to the containment of the equipment – as a table. By right-clicking on an entry, the element can be viewed in the treeview. + +### Treeview + +The treeview visualizes relations between the inventory data of a network element. To load all relations, a '*' can be entered in the search-field. ##### Inventory Export: diff --git a/sdnr/wt/odlux/apps/app-feature/pom.xml b/sdnr/wt/odlux/apps/app-feature/pom.xml index 2aaf573d1..e5575a537 100644 --- a/sdnr/wt/odlux/apps/app-feature/pom.xml +++ b/sdnr/wt/odlux/apps/app-feature/pom.xml @@ -97,10 +97,18 @@ <artifactId>sdnr-wt-odlux-app-configurationApp</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>sdnr-wt-odlux-app-networkMapApp</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>sdnr-wt-odlux-app-linkCalculationApp</artifactId> <version>${project.version}</version> - </dependency> + </dependency> + + + </dependencies> </project> diff --git a/sdnr/wt/odlux/apps/app-installer/pom.xml b/sdnr/wt/odlux/apps/app-installer/pom.xml index 1bf55ed30..dc919f01f 100755 --- a/sdnr/wt/odlux/apps/app-installer/pom.xml +++ b/sdnr/wt/odlux/apps/app-installer/pom.xml @@ -124,6 +124,11 @@ </dependency> <dependency> <groupId>${project.groupId}</groupId> + <artifactId>sdnr-wt-odlux-app-networkMapApp</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> <artifactId>sdnr-wt-odlux-app-linkCalculationApp</artifactId> <version>${project.version}</version> </dependency> diff --git a/sdnr/wt/odlux/apps/connectApp/src/models/topologyNetconf.ts b/sdnr/wt/odlux/apps/connectApp/src/models/topologyNetconf.ts index 694009d1b..ef22aab43 100644 --- a/sdnr/wt/odlux/apps/connectApp/src/models/topologyNetconf.ts +++ b/sdnr/wt/odlux/apps/connectApp/src/models/topologyNetconf.ts @@ -32,5 +32,5 @@ export interface TopologyNode { export interface Topology { "topology-id": string; - node: TopologyNode[]; + "network-topology:node": TopologyNode[]; } diff --git a/sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts b/sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts index 2aa9e3958..fbbfa68d9 100644 --- a/sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts +++ b/sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts @@ -126,11 +126,11 @@ class ConnectService { /** Yang capabilities of the selected network elements. */ public async infoNetworkElement(nodeId: string): Promise<TopologyNode | null> { - const path = '/rests/operational/network-topology:network-topology/topology=topology-netconf/node=' + nodeId; + const path = '/rests/data/network-topology:network-topology/topology=topology-netconf/node=' + nodeId; const topologyRequestPomise = requestRest<Topology>(path, { method: "GET" }); return topologyRequestPomise && topologyRequestPomise.then(result => { - return result && result.node && result.node[0] || null; + return result && result["network-topology:node"] && result["network-topology:node"][0] || null; }); } @@ -157,25 +157,6 @@ class ConnectService { })) || null; } - public async getWebUriExtensionForNetworkElementAsync(ne: string) { - const path = '/rests/data/network-topology:network-topology/topology=topology-netconf/node=' + ne + '/yang-ext:mount/core-model:network-element'; - try { - const result = await requestRest<any>(path, { method: "GET" }); - - if (result['network-element'].extension) { - const webUri = result['network-element'].extension.find((item: any) => item['value-name'] === "webUri") - if (webUri) { - return webUri.value as string; - } - } - } catch (error) { - console.log(ne + ' unrechable: ' + error) - } - - return undefined; - - } - public getAllWebUriExtensionsForNetworkElementListAsync(ne: string[]) { let promises: any[] = []; @@ -187,9 +168,8 @@ class ConnectService { // add search request to array promises.push(requestRest<any>(path, { method: "GET" }) .then(result => { - - if (result != null && result['network-element'] && result['network-element'].extension) { - const webUri = result['network-element'].extension.find((item: any) => item['value-name'] === "webUri") + if (result != null && result['core-model:network-element'] && result['core-model:network-element'].extension) { + const webUri = result['core-model:network-element'].extension.find((item: any) => item['value-name'] === "webUri") if (webUri) { webUris.push({ webUri: webUri.value, nodeId: nodeId }); } else { diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/actions/commonLinkCalculationActions.ts b/sdnr/wt/odlux/apps/linkCalculationApp/src/actions/commonLinkCalculationActions.ts index 555954d15..09887f27f 100644 --- a/sdnr/wt/odlux/apps/linkCalculationApp/src/actions/commonLinkCalculationActions.ts +++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/actions/commonLinkCalculationActions.ts @@ -81,24 +81,24 @@ export class UpdateLatLonAction extends Action{ } } +export class UpdatePolAction extends Action{ + constructor(public polarization: string){ + super(); + } +} export class isCalculationServerReachableAction extends Action{ constructor(public reachable: boolean){ super(); } } +export class updateAltitudeAction extends Action{ + constructor( + public amslA:number, + public aglA:number, + public amslB:number, + public aglB:number + ){ + super(); + } +} -// export const checkCalculationsServerConnectivityAction = (callback: Promise<any>) => (dispatcher: Dispatch, getState: () => IApplicationStoreState)=>{ -// callback -// .then(res =>{ -// const {linkCalculation:{calculations: {isCalculationServerAvailable}}} = getState(); -// if(!isToplogyServerAvailable){ -// dispatcher(new IsTopologyServerReachableAction(true)) -// } -// }) -// .catch(error=>{ -// const {network:{connectivity: {isToplogyServerAvailable}}} = getState(); -// if(isToplogyServerAvailable){ -// dispatcher(new IsTopologyServerReachableAction(false)) -// } -// }) -// } diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/components/connectionInfo.tsx b/sdnr/wt/odlux/apps/linkCalculationApp/src/components/connectionInfo.tsx index c798e481f..cae6fbd9e 100644 --- a/sdnr/wt/odlux/apps/linkCalculationApp/src/components/connectionInfo.tsx +++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/components/connectionInfo.tsx @@ -30,7 +30,7 @@ type props = Connect<typeof mapStateToProps, typeof mapDispatchToProps>; const ConnectionInfo: React.FunctionComponent<props> = (props) => { return ( - (props.isCalculationServerReachable === false)? <Paper style={{padding:5, position: 'absolute', top: 160, width: 230, left:"40%"}}> + (props.isCalculationServerReachable === false)? <Paper style={{padding:5, width: 230, position:"absolute", top:"40%", left:"40%"}}> <div style={{display: 'flex', flexDirection: 'column'}}> <div style={{'alignSelf': 'center', marginBottom:5}}> <Typography> <FontAwesomeIcon icon={faExclamationTriangle} /> Connection Error</Typography></div> {props.isCalculationServerReachable === false && <Typography> Calculation data can't be loaded.</Typography>} diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/handlers/linkCalculationAppRootHandler.ts b/sdnr/wt/odlux/apps/linkCalculationApp/src/handlers/linkCalculationAppRootHandler.ts index 00dd48d45..85c013572 100644 --- a/sdnr/wt/odlux/apps/linkCalculationApp/src/handlers/linkCalculationAppRootHandler.ts +++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/handlers/linkCalculationAppRootHandler.ts @@ -15,14 +15,13 @@ * the License. * ============LICENSE_END========================================================================== */ -// main state handler import { combineActionHandler } from '../../../../framework/src/flux/middleware'; // ** do not remove ** import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; import { IActionHandler } from '../../../../framework/src/flux/action';; -import { UpdateLinkIdAction, UpdateFrequencyAction , UpdateLatLonAction, UpdateRainAttAction, UpdateRainValAction, updateHideForm, UpdateFslCalculation, UpdateSiteAction, UpdateDistanceAction, isCalculationServerReachableAction} from '../actions/commonLinkCalculationActions'; +import { UpdateLinkIdAction, UpdateFrequencyAction , UpdateLatLonAction, UpdateRainAttAction, UpdateRainValAction, updateHideForm, UpdateFslCalculation, UpdateSiteAction, UpdateDistanceAction, isCalculationServerReachableAction, UpdatePolAction, updateAltitudeAction} from '../actions/commonLinkCalculationActions'; declare module '../../../../framework/src/store/applicationStore' { interface IApplicationStoreState { @@ -48,7 +47,12 @@ export type ILinkCalculationAppStateState= { rainAtt : number, siteA: any, siteB: any, - reachable: boolean + reachable: boolean, + polarization : string | null, + amslA: number, + amslB:number, + aglA: number, + aglB:number } const initialState: ILinkCalculationAppStateState ={ @@ -65,7 +69,12 @@ const initialState: ILinkCalculationAppStateState ={ siteB: '', rainVal : 0, rainAtt: 0, - reachable : true + reachable : true, + polarization : 'Horizontal', + amslA: 0, + amslB:0, + aglA: 0, + aglB:0 } @@ -102,7 +111,12 @@ export const LinkCalculationHandler: IActionHandler<ILinkCalculationAppStateStat } else if(action instanceof isCalculationServerReachableAction){ state = Object.assign({}, state, { reachable: action.reachable }); -} + } + else if (action instanceof UpdatePolAction){ + state = Object.assign({}, state, {polarization: action.polarization}) + }else if (action instanceof updateAltitudeAction){ + state = Object.assign({}, state, {amslA:action.amslA, amslB:action.amslA, aglA:action.aglA, aglB:action.aglB}) + } return state } diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/pluginLinkCalculation.tsx b/sdnr/wt/odlux/apps/linkCalculationApp/src/pluginLinkCalculation.tsx index fc72f5ab3..f86b22a5c 100644 --- a/sdnr/wt/odlux/apps/linkCalculationApp/src/pluginLinkCalculation.tsx +++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/pluginLinkCalculation.tsx @@ -15,6 +15,7 @@ * the License. * ============LICENSE_END========================================================================== */ + // app configuration and main entry point for the app import * as React from "react"; @@ -27,13 +28,14 @@ import LinkCalculation from './views/linkCalculationComponent'; import LinkCalculationAppRootHandler from './handlers/linkCalculationAppRootHandler'; import connect, { Connect, IDispatcher } from '../../../framework/src/flux/connect'; import { IApplicationStoreState } from "../../../framework/src/store/applicationStore"; -import { UpdateLinkIdAction, UpdateLatLonAction, updateHideForm, UpdateSiteAction, UpdateDistanceAction } from "./actions/commonLinkCalculationActions"; +import { UpdateLinkIdAction, UpdateLatLonAction, updateHideForm, UpdateSiteAction, UpdateDistanceAction, isCalculationServerReachableAction, updateAltitudeAction } from "./actions/commonLinkCalculationActions"; let currentLinkId: string | null = null; let lastUrl: string = "/linkCalculation"; const mapProps = (state: IApplicationStoreState) => ({ + reachable: state.linkCalculation.calculations.reachable }); const mapDisp = (dispatcher: IDispatcher) => ({ @@ -50,6 +52,12 @@ const mapDisp = (dispatcher: IDispatcher) => ({ dispatcher.dispatch(new UpdateLatLonAction(Lat1, Lon1, Lat2, Lon2)) dispatcher.dispatch(new updateHideForm (true)) }, + updateAltitude : (amslA:number, aglA:number, amslB:number, aglB:number) => { + dispatcher.dispatch(new updateAltitudeAction(amslA,aglA,amslB,aglB)) + } + // UpdateConectivity : (reachable:boolean) => { + // dispatcher.dispatch (new isCalculationServerReachableAction (reachable)) + // } }); @@ -69,7 +77,6 @@ const LinkCalculationRouteAdapter = connect(mapProps, mapDisp)((props: RouteComp if (data !== undefined && data.length>0){ - const lat1 = data.split('&')[0].split('=')[1] const lon1 = data.split('&')[1].split('=')[1] const lat2 = data.split('&')[2].split('=')[1] @@ -80,12 +87,20 @@ const LinkCalculationRouteAdapter = connect(mapProps, mapDisp)((props: RouteComp const distance = data.split('&')[8].split('=')[1] + const amslA = data.split('&')[9].split('=')[1] + const aglA = data.split('&')[10].split('=')[1] + + const amslB = data.split('&')[11].split('=')[1] + const aglB = data.split('&')[12].split('=')[1] + props.updateSiteName(String(siteNameA), String(siteNameB)) - props.updateDistance(Number(distance)) + props.updateDistance(Number(distance)) props.updateLatLon(Number(lat1),Number(lon1),Number(lat2),Number(lon2)) + + props.updateAltitude (Number(amslA), Number(aglA), Number(amslB), Number(aglB)) } diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/views/linkCalculationComponent.tsx b/sdnr/wt/odlux/apps/linkCalculationApp/src/views/linkCalculationComponent.tsx index 97219b6d8..9cbc771f4 100644 --- a/sdnr/wt/odlux/apps/linkCalculationApp/src/views/linkCalculationComponent.tsx +++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/views/linkCalculationComponent.tsx @@ -15,16 +15,18 @@ * the License. * ============LICENSE_END========================================================================== */ + import * as React from "react"; import { Connect, connect, IDispatcher } from '../../../../framework/src/flux/connect'; import { MaterialTable, MaterialTableCtorType } from '../../../../framework/src/components/material-table'; -import { TextField, Tabs, Tab, Typography, AppBar, Button, Tooltip } from '@material-ui/core'; +import { TextField, Tabs, Tab, Typography, AppBar, Button, Tooltip, Checkbox, Table, TableCell, TableHead, TableRow, TableBody, Paper } from '@material-ui/core'; import DenseTable from '../components/denseTable' import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore"; -import { UpdateFrequencyAction, UpdateLatLonAction, UpdateRainAttAction, UpdateRainValAction, UpdateFslCalculation, isCalculationServerReachableAction } from "../actions/commonLinkCalculationActions"; +import { UpdateFrequencyAction, UpdateLatLonAction, UpdateRainAttAction, UpdateRainValAction, UpdateFslCalculation, isCalculationServerReachableAction, UpdatePolAction, UpdateDistanceAction, updateAltitudeAction } from "../actions/commonLinkCalculationActions"; import { faPlaneArrival } from "@fortawesome/free-solid-svg-icons"; +import ConnectionInfo from '../components/connectionInfo' const mapProps = (state: IApplicationStoreState) => ({ linkId: state.linkCalculation.calculations.linkId, @@ -40,7 +42,12 @@ const mapProps = (state: IApplicationStoreState) => ({ siteA: state.linkCalculation.calculations.siteA, siteB: state.linkCalculation.calculations.siteB, distance: state.linkCalculation.calculations.distance, - reachable :state.linkCalculation.calculations.reachable + reachable :state.linkCalculation.calculations.reachable, + polarization:state.linkCalculation.calculations.polarization, + amslA:state.linkCalculation.calculations.amslA, + amslB:state.linkCalculation.calculations.amslB, + aglA:state.linkCalculation.calculations.aglA, + aglB:state.linkCalculation.calculations.aglB }); const BASE_URL="/topology/services" @@ -52,9 +59,7 @@ const mapDispatch = (dispatcher: IDispatcher) => ({ }, updateLatLon: (Lat1: number, Lon1: number, Lat2: number, Lon2: number) => { - dispatcher.dispatch(new UpdateLatLonAction(Lat1, Lon1, Lat2, Lon2)) - }, updateRainValue: (rainVal: number) => { @@ -76,18 +81,31 @@ const mapDispatch = (dispatcher: IDispatcher) => ({ UpdateConectivity : (reachable:boolean) => { dispatcher.dispatch (new isCalculationServerReachableAction (reachable)) + }, + + updatePolarization :(polarization:any)=>{ + dispatcher.dispatch (new UpdatePolAction(polarization)) + }, + + updateAutoDistance : (distance:number)=>{ + dispatcher.dispatch (new UpdateDistanceAction(distance)) } }); -class LinkCalculation extends React.Component<Connect<typeof mapProps, typeof mapDispatch>, { rainMethodDisplay: boolean }> { +type linkCalculationProps = Connect<typeof mapProps, typeof mapDispatch>; + +class LinkCalculation extends React.Component<linkCalculationProps, {rainMethodDisplay: boolean, horizontalBoxChecked: boolean}> { constructor(props: any) { super(props) - this.state = { rainMethodDisplay: true } - } - - handleChange = (e: number) => { - this.props.updateFrequency(e) - } + this.state = { rainMethodDisplay: false, + horizontalBoxChecked: true + } + } + updateAutoDistance = async (lat1: number, lon1: number, lat2: number, lon2: number)=>{ + const result = await fetch(BASE_URL+'/calculations/distance/' + lat1 + '/' + lon1 + '/' + lat2 + '/' + lon2) + const json = await result.json() + return json.distanceInKm + } updateLatLon = (e: any) => { @@ -98,6 +116,13 @@ class LinkCalculation extends React.Component<Connect<typeof mapProps, typeof ma } + updatePoli = (val: string) =>{ + + this.setState({horizontalBoxChecked: !this.state.horizontalBoxChecked}); + this.props.updatePolarization(val); + //this.forceUpdate(); + } + LatLonToDMS = (value: number, isLon: boolean = false) => { const absoluteValue = Math.abs(value); const d = Math.floor(absoluteValue); @@ -114,43 +139,47 @@ class LinkCalculation extends React.Component<Connect<typeof mapProps, typeof ma } } - calRain = (lat1: any, lon1: any, lat2: any, lon2: any, frequency: any) => { - fetch(BASE_URL+'/calculations/rain/' + lat1 + '/' + lon1 + '/' + lat2 + '/' + lon2 + '/' + frequency) + rainAttCal = (lat1: any, lon1: any, lat2: any, lon2: any, frequency: any, distance: number, polarization : any) => { + fetch(BASE_URL+'/calculations/rain/' + lat1 + '/' + lon1 + '/' + lat2 + '/' + lon2 + '/' + frequency+ '/'+ distance + '/' + polarization) .then(res => res.json()) .then(result => { this.props.UpdateRainAtt(result.RainAtt) }) } - updateRainValue = (lat1: any, lon1: any, lat2: any, lon2: any) => { - fetch(BASE_URL+'/calculations/rain/' + lat1 + '/' + lon1 + '/' + lat2 + '/' + lon2) - .then(res => res.json()) - .then(result => { this.props.updateRainValue(result.RainAtt) }) - } - - - specificRain = (rainfall: number, frequency: number) => { - fetch(BASE_URL+'/calculations/rain/' + rainfall + '/' + frequency) + manualRain = (rainfall: number, frequency: number, distance:number, polarization : any) => { + fetch(BASE_URL+'/calculations/rain/' + rainfall + '/' + frequency + '/' + distance+ '/' + polarization) .then(res => res.json()) .then(result => { this.props.specificRain(result.RainAtt) }) } + updateRainValue = (lat1: any, lon1: any, lat2: any, lon2: any) => { + fetch(BASE_URL+'/calculations/rainval/' + lat1 + '/' + lon1 + '/' + lat2 + '/' + lon2) + .then(res => res.json()) + .then(result => {this.props.updateRainValue(result.rainFall) }) + } + FSL = (distance:number, frequency:number) => { fetch(BASE_URL+'/calculations/FSL/' + distance + '/' + frequency) .then(res=>res.json()) .then (result => {this.props.FSL(result.free)}) } - buttonHandler =() => { + + + buttonHandler = async () => { + this.props.updateAutoDistance(await this.updateAutoDistance(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2)) + this.FSL(this.props.distance, this.props.frequency) if (this.state.rainMethodDisplay === true){ - this.specificRain(this.props.rainVal, this.props.frequency); + this.manualRain(this.props.rainVal, this.props.frequency, this.props.distance, this.props.polarization); } else { - this.calRain(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2, this.props.frequency); this.updateRainValue(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2) + this.rainAttCal(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2, this.props.frequency, this.props.distance, this.props.polarization); } + } componentDidMount = () => { @@ -158,53 +187,27 @@ class LinkCalculation extends React.Component<Connect<typeof mapProps, typeof ma .then(res => {if (res.ok) {this.props.reachable===false && this.props.UpdateConectivity(true)}else {this.props.reachable===true && this.props.UpdateConectivity(false)} }) .catch (res => {this.props.reachable===true && this.props.UpdateConectivity(false)} ) } - + + handleChange =(e:any) => { + this.props.updatePolarization(e.target.value) + } + + // AbsorptionAttW = () => { + // fetch(BASE_URL+'/calculations/FSL/' + distance + '/' + frequency) + // .then(res=>res.json()) + // .then (result => {this.props.FSL(result.free)}) + // } + + // AbsorptionAttOx =() => { + // fetch(BASE_URL+'/calculations/FSL/' + distance + '/' + frequency) + // .then(res=>res.json()) + // .then (result => {this.props.FSL(result.free)}) + // } + + render() { - console.log(this.props); - const data = [ - - { name: "Site Name", val1: this.props.siteA, val2: '', val3: this.props.siteB}, - { name: "Latitude", val1: this.props.lat1 && this.LatLonToDMS(this.props.lat1), val2:'', val3: this.props.lat2 && this.LatLonToDMS(this.props.lat2) }, - { name: "Longitude", val1: this.props.lon1 && this.LatLonToDMS(this.props.lon1, true), val2:'', val3: this.props.lon2 && this.LatLonToDMS(this.props.lon2, true) }, - { name: "Azimuth in °", val1: '', val2: '' , val3:''}, - { name: "", val1: '', val2: '' , val3:''}, - { name: "Distance (km)", val1: '', val2: (this.props.distance).toFixed(3) ,val3:'' }, - {name: 'Polarization', val1:'', val2: <div><input type='checkbox' id='Horizontal' value ="Horizontal"></input>Horizontal<br /> - <input type='checkbox' id='Vertical' value ="Vertical"></input>Vertical - </div>, val3:''}, - {name : 'Frequency (GHz)', val1: '', val2: <div> - <select onChange={(e) => this.handleChange(Number(e.target.value))}> - <option value='' >Select Freq</option> - <option value='7' >7 GHz</option> - <option value='11' >11 GHz</option> - <option value='15' >15 GHz</option> - <option value='23' >23 GHz</option> - <option value='26' >26 GHz</option> - <option value='28' >28 GHz</option> - <option value='38' >38 GHz</option> - <option value='42' >42 GHz</option> - <option value='80' >80 GHz</option> - </select></div>,val3: ''}, - {name: 'Free Space Loss (dB)' ,val1: '', val2: this.props.fsl,val3: ''}, - {name:'Rain Model', val1:'', val2: <div> - <select onChange={e => { this.setState({ rainMethodDisplay: !this.state.rainMethodDisplay }) }} > - <option value='' >Select Rain Method</option> - <option value='itu' onSelect={e => { this.setState({ rainMethodDisplay: false }) }}>ITU-R P.837-7</option> - <option value='manual' onSelect={(e) => { this.updateRainValue(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2) }} >Specific Rain</option> - </select> </div>, val3:''}, - {name: 'Rainfall Rate (mm/h)', val1: '', val2:<label> - <input type="number" style={{ width: 70, height: 15, fontSize: 14 }} onChange={(e) => { this.props.updateRainValue(Number(e.target.value)) }} - value={this.props.rainVal} disabled={this.state.rainMethodDisplay === false ? true : false}> - </input></label>, val3:''}, - {name: 'Rain Loss (dB/km)', val1: '', val2: this.props.rainAtt, val3: ''}, - {name: '', val1:'', val2:<button style={{color: '#222', fontFamily:'Arial', boxAlign: 'center', display:'inline-block', insetInlineStart: '20' }} - onClick = {(e) => this.buttonHandler()} >Calculate</button>, val3:'' } - - ]; - - - return <div> - Link Calculation app. LinkId: {this.props.linkId} <br /> + + return <div style={{position: 'relative'}}> {!this.props.formView && <form> <div> @@ -230,17 +233,133 @@ class LinkCalculation extends React.Component<Connect<typeof mapProps, typeof ma </div> </form> } - - <DenseTable height={600} width={1300} hover={true} headers={["", "Site A","", "Site B"]} data={data}> </DenseTable> - - - - - </div> - - } - +<Paper style={{borderRadius:"0px"}}> + <div style={{ height:600, overflow:"auto"}}> + <Table stickyHeader size="small" aria-label="a dense table" > + <TableHead> + <TableRow> + <TableCell >{""} </TableCell> + <TableCell >{"Site A"}</TableCell> + <TableCell > {""} </TableCell> + <TableCell >{"Site B"} </TableCell> + </TableRow> + </TableHead> + <TableBody> + <TableRow> + <TableCell >{"Site Name"} </TableCell> + <TableCell >{this.props.siteA}</TableCell> + <TableCell > {""} </TableCell> + <TableCell >{this.props.siteB} </TableCell> + </TableRow> + <TableRow> + <TableCell >{"Latitude"} </TableCell> + <TableCell >{this.props.lat1 && this.LatLonToDMS(this.props.lat1)} </TableCell> + <TableCell > {""} </TableCell> + <TableCell >{this.props.lat2 && this.LatLonToDMS(this.props.lat2)} </TableCell> + </TableRow> + <TableRow> + <TableCell >{"Longitude"} </TableCell> + <TableCell >{this.props.lon1 && this.LatLonToDMS(this.props.lon1)}</TableCell> + <TableCell > {""} </TableCell> + <TableCell >{this.props.lon2 && this.LatLonToDMS(this.props.lon2)} </TableCell> + </TableRow> + <TableRow> + <TableCell >{"Azimuth"} </TableCell> + <TableCell >{""}</TableCell> + <TableCell > {""} </TableCell> + <TableCell >{""} </TableCell> + </TableRow> + <TableRow> + <TableCell >{"Average Mean Sea Level"} </TableCell> + <TableCell >{this.props.amslA + ' m'}</TableCell> + <TableCell > {""} </TableCell> + <TableCell >{this.props.amslB+ ' m'} </TableCell> + </TableRow> + <TableRow> + <TableCell >{"Antenna Height Above Ground"} </TableCell> + <TableCell >{this.props.aglA+ ' m'}</TableCell> + <TableCell > {""} </TableCell> + <TableCell >{this.props.aglB+ ' m'} </TableCell> + </TableRow> + <TableRow> + <TableCell >{"Distance"} </TableCell> + <TableCell >{""}</TableCell> + <TableCell > {this.props.distance.toFixed(3)+ ' km'} </TableCell> + <TableCell >{""} </TableCell> + </TableRow> + <TableRow> + <TableCell >{"Polarization"} </TableCell> + <TableCell >{""}</TableCell> + <TableCell > {<form><input type='checkbox' id='Horizontal' value ="Horizontal" checked= {this.props.polarization==='Horizontal'} onClick= {(e: any) => this.props.updatePolarization(e.target.value)}></input>Horizontal<br /> + <input type='checkbox' id='Vertical' value ="Vertical" checked= {this.props.polarization==='Vertical'} onClick= {(e:any)=>{this.props.updatePolarization(e.target.value)}}></input>Vertical</form>} </TableCell> + <TableCell >{""} </TableCell> + </TableRow> + <TableRow> + <TableCell >{"Frequency"} </TableCell> + <TableCell >{""}</TableCell> + <TableCell > {<select onChange={(e) => this.props.updateFrequency(Number(e.target.value))}> + <option value='' >Select Freq</option> + <option value='7' >7 GHz</option> + <option value='11' >11 GHz</option> + <option value='15' >15 GHz</option> + <option value='23' >23 GHz</option> + <option value='26' >26 GHz</option> + <option value='28' >28 GHz</option> + <option value='38' >38 GHz</option> + <option value='42' >42 GHz</option> + <option value='80' >80 GHz</option> + </select>} + </TableCell> + <TableCell >{""} </TableCell> + </TableRow> + <TableRow> + <TableCell >{"Free Space Loss"} </TableCell> + <TableCell >{""}</TableCell> + <TableCell > {this.props.fsl + ' dB'} </TableCell> + <TableCell >{""} </TableCell> + </TableRow> + <TableRow> + <TableCell >{"Rain Model"} </TableCell> + <TableCell >{""}</TableCell> + <TableCell > {<select onChange = {(e) => {e.target.value === 'itu' ? this.setState({ rainMethodDisplay: false}):this.setState({ rainMethodDisplay: true}) }}> + <option >Select Rain Method</option> + <option value='itu' >ITU-R P.837-7</option> + <option value='manual' >Specific Rain</option> + </select>} </TableCell> + <TableCell >{""} </TableCell> + </TableRow> + <TableRow> + <TableCell >{"Rainfall Rate"} </TableCell> + <TableCell >{""}</TableCell> + <TableCell > {<form><input type="number" style={{ width: 70, height: 15, fontSize: 14 }} onChange={(e) => { this.props.updateRainValue(Number(e.target.value)) }} + value={this.props.rainVal} disabled={this.state.rainMethodDisplay === false ? true : false}> + </input> mm/hr</form> } </TableCell> + <TableCell >{""} </TableCell> + </TableRow> + <TableRow> + <TableCell >{"Rain Loss"} </TableCell> + <TableCell >{""}</TableCell> + <TableCell > {this.props.rainAtt + ' dB'} </TableCell> + <TableCell >{""} </TableCell> + </TableRow> + <TableRow> + <TableCell >{""} </TableCell> + <TableCell >{""}</TableCell> + <TableCell > {<button style={{color: '#222', fontFamily:'Arial', boxAlign: 'center', display:'inline-block', insetInlineStart: '20' }} + onClick = {(e) => this.buttonHandler()} >Calculate</button>} </TableCell> + <TableCell >{""} </TableCell> + </TableRow> + + </TableBody> + </Table> + </div> + </Paper> + <ConnectionInfo /> + + + </div> + } } export default connect(mapProps, mapDispatch)(LinkCalculation); diff --git a/sdnr/wt/odlux/apps/networkMapApp/.babelrc b/sdnr/wt/odlux/apps/networkMapApp/.babelrc new file mode 100644 index 000000000..3d8cd1260 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/.babelrc @@ -0,0 +1,17 @@ +{ + "presets": [ + ["@babel/preset-react"], + ["@babel/preset-env", { + "targets": { + "chrome": "66" + }, + "spec": true, + "loose": false, + "modules": false, + "debug": false, + "useBuiltIns": "usage", + "forceAllTransforms": true + }] + ], + "plugins": [] +} diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/README.md b/sdnr/wt/odlux/apps/networkMapApp/icons/README.md new file mode 100644 index 000000000..acfbcf823 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/README.md @@ -0,0 +1,29 @@ +Copyright of icons is as followes: + +<!-- + * ============LICENSE_START======================================================================== + * apartment.png - Material Icons + * ================================================================================================= + * Copyright (C) 2020 Google. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + --> + +datacenter.png, lamp.png, factory.png, datacenterred.png, lampred.png, factoryred.png, + +Taken from MS Word + +According to https://support.microsoft.com/en-us/office/insert-icons-in-microsoft-office-e2459f17-3996-4795-996e-b9a13486fa79 (date: October 9th, 2019) +"These icons are free to use; there's no royalty or copyright." + +
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/apartment.png b/sdnr/wt/odlux/apps/networkMapApp/icons/apartment.png Binary files differnew file mode 100644 index 000000000..d4a1c5e7c --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/apartment.png diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/apartment.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/apartment.png.d.ts new file mode 100644 index 000000000..bf398f5a4 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/apartment.png.d.ts @@ -0,0 +1,2 @@ +declare const apartment: string; +export default apartment;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/datacenter.png b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenter.png Binary files differnew file mode 100644 index 000000000..eb2a6278d --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenter.png diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/datacenter.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenter.png.d.ts new file mode 100644 index 000000000..a58a9f5af --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenter.png.d.ts @@ -0,0 +1,2 @@ +declare const datacenter: string; +export default datacenter;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png Binary files differnew file mode 100644 index 000000000..5d5a6c523 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png.d.ts new file mode 100644 index 000000000..33f3061e2 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/datacenterred.png.d.ts @@ -0,0 +1,2 @@ +declare const datacenterred: string; +export default datacenterred;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png b/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png Binary files differnew file mode 100644 index 000000000..a38781baa --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png.d.ts new file mode 100644 index 000000000..b5c4f19d9 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/factory.png.d.ts @@ -0,0 +1,2 @@ +declare const factory: string; +export default factory;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png b/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png Binary files differnew file mode 100644 index 000000000..959603ab1 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png.d.ts new file mode 100644 index 000000000..1fac0a943 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/factoryred.png.d.ts @@ -0,0 +1,2 @@ +declare const factoryRed: string; +export default factoryRed;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/lamp.png b/sdnr/wt/odlux/apps/networkMapApp/icons/lamp.png Binary files differnew file mode 100644 index 000000000..f5ea00138 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/lamp.png diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/lamp.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/lamp.png.d.ts new file mode 100644 index 000000000..9634b1275 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/lamp.png.d.ts @@ -0,0 +1,2 @@ +declare const lamp: string; +export default lamp;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png b/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png Binary files differnew file mode 100644 index 000000000..4678ce91c --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png diff --git a/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png.d.ts b/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png.d.ts new file mode 100644 index 000000000..12a8f91cb --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/icons/lampred.png.d.ts @@ -0,0 +1,2 @@ +declare const lampred: string; +export default lampred;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/package.json b/sdnr/wt/odlux/apps/networkMapApp/package.json new file mode 100644 index 000000000..0f05ffb6c --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/package.json @@ -0,0 +1,44 @@ +{ + "name": "@odlux/networkmap-app", + "version": "0.1.0", + "description": "A react based modular UI to display event log from a database.", + "main": "index.js", + "scripts": { + "start": "webpack-dev-server --env debug", + "build": "webpack --env release --config webpack.config.js", + "build:dev": "webpack --env debug --config webpack.config.js" + }, + "repository": { + "type": "git", + "url": "https://git.mfico.de/highstreet-technologies/odlux.git" + }, + "keywords": [ + "reactjs", + "redux", + "ui", + "framework" + ], + "author": "Aijana Schumann", + "license": "Apache-2.0", + "dependencies": { + "@odlux/framework": "*", + "@types/mapbox-gl": "^1.10.2", + "mapbox-gl": "^1.11.0", + "object.values": "^1.1.1" + }, + "peerDependencies": { + "@types/react": "16.9.19", + "@types/react-dom": "16.9.5", + "@types/react-router-dom": "4.3.1", + "@material-ui/core": "4.9.0", + "@material-ui/icons": "4.5.1", + "@types/classnames": "2.2.6", + "@types/flux": "3.1.8", + "@types/jquery": "3.3.10", + "jquery": "3.3.1", + "react": "16.12.0", + "react-dom": "16.12.0", + "react-router-dom": "4.3.1" + + } +} diff --git a/sdnr/wt/odlux/apps/networkMapApp/pom.xml b/sdnr/wt/odlux/apps/networkMapApp/pom.xml new file mode 100644 index 000000000..285bb7057 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/pom.xml @@ -0,0 +1,176 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ ============LICENSE_START======================================================= + ~ ONAP : ccsdk features + ~ ================================================================================ + ~ Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + ~ ================================================================================ + ~ 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. + ~ ============LICENSE_END======================================================= + ~ + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>odlparent</artifactId> + <version>2.0.1-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.features.sdnr.wt</groupId> + <artifactId>sdnr-wt-odlux-app-networkMapApp</artifactId> + <version>1.0.1-SNAPSHOT</version> + <packaging>bundle</packaging> + + <name>ccsdk-features :: ${project.artifactId}</name> + <licenses> + <license> + <name>Apache License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0</url> + </license> + </licenses> + + <properties> + <maven.javadoc.skip>true</maven.javadoc.skip> + <checkstyle.skip>true</checkstyle.skip> + </properties> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>sdnr-wt-odlux-core-model</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>sdnr-wt-odlux-core-provider</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <sourceDirectory>src2/main/java</sourceDirectory> + <resources> + <resource> + <directory>dist</directory> + <targetPath>odlux</targetPath> + </resource> + <resource> + <directory>src2/main/resources</directory> + </resource> + <resource> + <directory>src2/test/resources</directory> + </resource> + </resources> + <plugins> + <plugin> + <artifactId>maven-clean-plugin</artifactId> + <configuration> + <filesets> + <fileset> + <directory>dist</directory> + <followSymlinks>false</followSymlinks> + </fileset> + <fileset> + <directory>node</directory> + <followSymlinks>false</followSymlinks> + </fileset> + <fileset> + <directory>node_modules</directory> + <followSymlinks>false</followSymlinks> + </fileset> + <fileset> + <directory>../node_modules</directory> + <followSymlinks>false</followSymlinks> + </fileset> + <!-- eclipse bug build bin folder in basedir --> + <fileset> + <directory>bin</directory> + <followSymlinks>false</followSymlinks> + </fileset> + </filesets> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <id>add-test-source</id> + <phase>generate-test-sources</phase> + <goals> + <goal>add-test-source</goal> + </goals> + <configuration> + <sources> + <source>src2/test/java</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>de.jacks-it-lab</groupId> + <artifactId>frontend-maven-plugin</artifactId> + <version>1.7.2</version> + <executions> + <execution> + <id>install node and yarn</id> + <goals> + <goal>install-node-and-yarn</goal> + </goals> + <!-- optional: default phase is "generate-resources" --> + <phase>initialize</phase> + <configuration> + <nodeVersion>v10.16.3</nodeVersion> + <yarnVersion>v1.19.0</yarnVersion> + </configuration> + </execution> + <execution> + <id>yarn build</id> + <goals> + <goal>yarn</goal> + </goals> + <configuration> + <arguments>run build</arguments> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Import-Package>org.onap.ccsdk.features.sdnr.wt.odlux.model.*,com.opensymphony.*</Import-Package> + <Private-Package/> + </instructions> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/App.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/App.tsx new file mode 100644 index 000000000..6caab5147 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/App.tsx @@ -0,0 +1,32 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import * as React from 'react'; +import Map from './components/map' +import Details from './components/details/details' + +function MainView() { + return ( + <div className="App" style={{display: 'flex', flexDirection:'row', flexGrow:1, height:"100%"}}> + <Map /> + <Details /> + </div> + ); +} + +export default MainView; diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/actions/connectivityAction.ts b/sdnr/wt/odlux/apps/networkMapApp/src/actions/connectivityAction.ts new file mode 100644 index 000000000..448ae8386 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/actions/connectivityAction.ts @@ -0,0 +1,50 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { Action } from "../../../../framework/src/flux/action"; +import { Dispatch } from "../../../../framework/src/flux/store"; +import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore"; + + +export class IsTopologyServerReachableAction extends Action{ + constructor(public reachable: boolean){ + super(); + } +} + +export class IsTileServerReachableAction extends Action{ + constructor(public reachable: boolean){ + super(); + } +} + +export const verifyResponse = (response: Response) =>{ + + if(response.ok){ + return response + }else{ + throw Error(`Connection Error: ${response.status} | ${response.statusText} | ${response.url}`) + } +} + +export const handleConnectionError = (error: Error) => (dispatcher: Dispatch, getState: () => IApplicationStoreState)=>{ + const {network:{connectivity: {isToplogyServerAvailable}}} = getState(); + if(isToplogyServerAvailable){ + dispatcher(new IsTopologyServerReachableAction(false)) + } +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/actions/detailsAction.ts b/sdnr/wt/odlux/apps/networkMapApp/src/actions/detailsAction.ts new file mode 100644 index 000000000..5288f61d9 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/actions/detailsAction.ts @@ -0,0 +1,138 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { Action } from '../../../../framework/src/flux/action'; +import { requestRest } from '../../../../framework/src/services/restService'; + + +import { site, Device } from "../model/site"; +import { link } from '../model/link'; +import { HistoryEntry } from "../model/historyEntry"; +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; +import { Dispatch } from '../../../../framework/src/flux/store'; + +export class SelectSiteAction extends Action { + constructor(public site: site){ + super() + } +} + +export class SelectLinkAction extends Action { + constructor(public link: link){ + super(); + } +} + +export class ClearDetailsAction extends Action{ + constructor(){ + super(); + } +} + +export class AddToHistoryAction extends Action { + constructor(public entry: HistoryEntry){ + super(); + } +} + +export class ClearHistoryAction extends Action { + constructor(){ + super(); + } +} + +export class IsBusyCheckingDeviceListAction extends Action{ + constructor(public isBusy: boolean){ + super(); + } +} + +export class FinishedLoadingDeviceListAction extends Action{ + constructor(public devices: Device[]){ + super(); + } +} + +export class ClearLoadedDevicesAction extends Action{ + constructor(){ + super(); + } +} + +let running=false; + +export const UpdateDetailsView = (nodeId: string) =>(dispatcher: Dispatch, getState: () => IApplicationStoreState) =>{ + const {network:{details:{checkedDevices}}} = getState(); + if(checkedDevices!==null){ + const index = checkedDevices.findIndex(item=>item.name===nodeId) + if(index!==-1) + requestRest<any>("/rests/operational/network-topology:network-topology/topology/topology-netconf/node/"+nodeId, { method: "GET" }) + .then(result =>{ + if(result!==null){ + checkedDevices[index].status = result.node[0]["netconf-node-topology:connection-status"]; + + }else{ + checkedDevices[index].status = "Not connected"; + } + dispatcher(new FinishedLoadingDeviceListAction(checkedDevices)); + + }); + + } +} + +export const CheckDeviceList = (list: Device[]) => async (dispatcher: Dispatch, getState: () => IApplicationStoreState) =>{ +if(running) return; +running=true; + dispatcher(new IsBusyCheckingDeviceListAction(true)); + + const promises = list.map((device)=>{ + if(device.simulatorId){ + return requestRest<any>("/rests/operational/network-topology:network-topology/topology/topology-netconf/node/"+device.simulatorId, { method: "GET" }) + + }else{ + return requestRest<any>("/rests/operational/network-topology:network-topology/topology/topology-netconf/node/"+device.name, { method: "GET" }) + + } + + }) + + Promise.all(promises).then((result)=>{ + running=false; + + + result.forEach((res: any, index)=>{ + if(res !==null && res.node!==null){ + + list[index].status = res.node[0]["netconf-node-topology:connection-status"]; + }else{ + list[index].status = "Not connected"; + } + }); + + dispatcher(new FinishedLoadingDeviceListAction(list)); + dispatcher(new IsBusyCheckingDeviceListAction(false)); + + }) + .catch(err=>{ + console.error(err); + + dispatcher(new IsBusyCheckingDeviceListAction(false)); + + }); +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/actions/mapActions.ts b/sdnr/wt/odlux/apps/networkMapApp/src/actions/mapActions.ts new file mode 100644 index 000000000..b8af40b0c --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/actions/mapActions.ts @@ -0,0 +1,83 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { Action } from '../../../../framework/src/flux/action'; +import { Dispatch } from '../../../../framework/src/flux/store'; + + +import { link } from "../model/link"; +import { site } from "../model/site"; +import { Feature } from '../model/Feature'; +import { URL_API } from '../config'; + + +export class HighlightLinkAction extends Action{ + constructor(public link: link){ + super(); + } +} + +export class HighlightSiteAction extends Action{ + constructor(public site: site){ + super(); + } +} + +export class RemoveHighlightingAction extends Action { + constructor(){ + super(); + } +} + +export class ZoomToSearchResultAction extends Action{ + constructor(public lat: number, public lon: number){ + super(); + } +} + +export class AddAlarmAction extends Action{ + constructor(public element: Feature){ + super(); + } +} + +export class SetCoordinatesAction extends Action{ + constructor(public lat: number, public lon: number, public zoom: number){ + super(); + } +} + +export class SetStatistics extends Action{ + constructor(public siteCount: string, public linkCount: string){ + super(); + } +} + +export class SetIconSwitchAction extends Action{ + constructor(public enable:boolean){ + super(); + } +} + +export const findSiteToAlarm = (alarmedNodeId: string) => (dispatcher: Dispatch) =>{ + fetch(URL_API+"/site/geojson/device/"+alarmedNodeId) + .then(res => res.json()) + .then(result=>{ + dispatcher(new AddAlarmAction(result)); + }); +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/actions/popupActions.ts b/sdnr/wt/odlux/apps/networkMapApp/src/actions/popupActions.ts new file mode 100644 index 000000000..ff8d07921 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/actions/popupActions.ts @@ -0,0 +1,39 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { Action } from '../../../../framework/src/flux/action'; + +export class SetPopupPositionAction extends Action { + constructor(public top: number, public left: number){ + super() + } +} + +export class SelectMultipleLinksAction extends Action { + constructor(public ids: string[]) { + super(); + } +} + + + +export class SelectMultipleSitesAction extends Action { + constructor(public ids: string[]) { + super(); + } +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/actions/searchAction.ts b/sdnr/wt/odlux/apps/networkMapApp/src/actions/searchAction.ts new file mode 100644 index 000000000..a553319da --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/actions/searchAction.ts @@ -0,0 +1,25 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { Action } from '../../../../framework/src/flux/action'; + +export class SetSearchValueAction extends Action{ + constructor(public value: string){ + super(); + } +} diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/connectionInfo.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/connectionInfo.tsx new file mode 100644 index 000000000..d1e2d978f --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/connectionInfo.tsx @@ -0,0 +1,59 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import * as React from 'react' + +import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore"; +import connect, { IDispatcher, Connect } from "../../../../framework/src/flux/connect"; +import { Paper, Typography } from "@material-ui/core"; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; + + +type props = Connect<typeof mapStateToProps, typeof mapDispatchToProps>; + +const ConnectionInfo: React.FunctionComponent<props> = (props) => { + + return ((props.isTopoServerReachable === false || props.isTileServerReachable === false )? <Paper style={{padding:5, position: 'absolute', top: 160, width: 230, left:"40%"}}> + <div style={{display: 'flex', flexDirection: 'column'}}> + <div style={{'alignSelf': 'center', marginBottom:5}}> <Typography> <FontAwesomeIcon icon={faExclamationTriangle} /> Connection Error</Typography></div> + {props.isTileServerReachable === false && <Typography> Tile data can't be loaded.</Typography>} + {props.isTopoServerReachable === false && <Typography > Network data can't be loaded.</Typography>} + </div> + </Paper> : null +) + +} + +const mapStateToProps = (state: IApplicationStoreState) => ({ + isTopoServerReachable: state.network.connectivity.isToplogyServerAvailable, + isTileServerReachable: state.network.connectivity.isTileServerAvailable + +}); + + + +const mapDispatchToProps = (dispatcher: IDispatcher) => ({ + + //zoomToSearchResult: (lat: number, lon: number) => dispatcher.dispatch(new ZoomToSearchResultAction(lat, lon)) + +});; + + +export default connect(mapStateToProps,mapDispatchToProps)(ConnectionInfo) + diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/denseTable.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/denseTable.tsx new file mode 100644 index 000000000..1506df5ab --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/denseTable.tsx @@ -0,0 +1,124 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import * as React from 'react'; +import Table from '@material-ui/core/Table'; +import TableBody from '@material-ui/core/TableBody'; +import TableCell from '@material-ui/core/TableCell'; +import TableContainer from '@material-ui/core/TableContainer'; +import TableHead from '@material-ui/core/TableHead'; +import TableRow from '@material-ui/core/TableRow'; +import Paper from '@material-ui/core/Paper'; +import { makeStyles, Button, Tooltip } from '@material-ui/core'; + +type props = { headers: string[], height:number, navigate?(applicationName: string, path?: string):void, onLinkClick?(id: string): void, data: any[], hover: boolean, ariaLabel: string, onClick?(id: string): void, actions?:boolean }; + + +const styles = makeStyles({ + container: { + overflow:"auto" + }, + button: { + margin: 0, + padding: "6px 6px", + minWidth: 'unset' + } + + }); + + +const DenseTable: React.FunctionComponent<props> = (props) => { + + const classes = styles(); + + const handleClick = (event: any, id: string) =>{ + event.preventDefault(); + props.onClick !== undefined && props.onClick(id); + + } + + const handleHover = (event: any, id: string) =>{ + event.preventDefault(); + + } + + return ( + <Paper style={{borderRadius:"0px"}}> + <div style={{ height:props.height, overflow:"auto"}}> + <Table stickyHeader size="small" aria-label="a dense table" > + <TableHead> + <TableRow> + { + props.headers.map((data) => { + return <TableCell>{data}</TableCell> + }) + } + </TableRow> + </TableHead> + <TableBody> + {props.data.map((row, index) => { + + + var filteredRows = Object.keys(row).filter(function(e) { if(e!=="simulatorId") return row }); + + //var filteredRows = Object.keys(row).filter(function(e) { if(e!=="simulatorId") return row[e] }); + var values = Object.keys(row).map(function(e) { if(e!=="simulatorId"){ return row[e];} else return undefined }); + + + return ( + <TableRow aria-label={props.ariaLabel} key={index} hover={props.hover} onMouseOver={e => handleHover(e,row.name)} onClick={ e => handleClick(e, row.name)}> + + { + values.map((data:any) => { + + if(data!== undefined) + return <TableCell> {data} </TableCell> + else + return null; + }) + } + { + + props.actions && <TableCell > +<div style={{display:"flex"}}> + <Tooltip title="Connect"> + <Button className={classes.button} disabled={true} onClick={(e: any) =>{ e.preventDefault(); e.stopPropagation(); props.navigate && props.navigate("connect", row.simulatorId ? row.simulatorId : row.name)}}>C</Button> + </Tooltip> + <Tooltip title="Configure"> + <Button className={classes.button} disabled={true} onClick={(e: any) =>{ e.preventDefault(); e.stopPropagation(); props.navigate && props.navigate("configuration", row.simulatorId ? row.simulatorId : row.name)}}>C</Button> + </Tooltip> + <Tooltip title="Fault"> + <Button className={classes.button} disabled={true} onClick={(e: any) =>{ e.preventDefault(); e.stopPropagation(); props.navigate && props.navigate("fault", row.simulatorId ? row.simulatorId : row.name)}}>F</Button> + </Tooltip> + </div> + </TableCell> + + } + </TableRow>) + }) + } + + </TableBody> + </Table> + </div> + </Paper> + ); + +} + +export default DenseTable;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/details/details.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/details.tsx new file mode 100644 index 000000000..081276b5c --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/details.tsx @@ -0,0 +1,205 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import * as React from 'react' + +import connect, { IDispatcher, Connect } from '../../../../../framework/src/flux/connect'; + +import { site, Device } from '../../model/site'; +import Typography from '@material-ui/core/Typography'; +import { link } from '../../model/link'; +import { Breadcrumbs, Link, Paper } from '@material-ui/core'; +import SiteDetails from './siteDetails'; +import LinkDetails from './linkDetails'; +import { URL_API, URL_BASEPATH } from '../../config'; +import { SelectSiteAction, SelectLinkAction, AddToHistoryAction, ClearHistoryAction, CheckDeviceList, ClearDetailsAction } from '../../actions/detailsAction'; +import { HistoryEntry } from '../../model/historyEntry'; +import { HighlightLinkAction, HighlightSiteAction, RemoveHighlightingAction } from '../../actions/mapActions'; +import { isSite } from '../../utils/utils'; +import { IApplicationStoreState } from '../../../../../framework/src/store/applicationStore'; +import { NavigateToApplication } from '../../../../../framework/src/actions/navigationActions'; +import { RouteComponentProps, withRouter } from 'react-router-dom'; + + +const Details: React.FunctionComponent<porps> = (props) => { + + const [message, setMessage] = React.useState("No data selected."); + + + //on mount + React.useEffect(() => { + const detailsId = getDetailsIdFromUrl(); + if (detailsId !== null && props.data?.name !== detailsId) { + loadDetailsData(detailsId) + } + + }, []); + + // if url changed, load details data + React.useEffect(() => { + const detailsId = getDetailsIdFromUrl(); + if (detailsId !== null && props.data?.name !== detailsId) { + loadDetailsData(detailsId) + } + else if(detailsId===null){ + setMessage("No data selected."); + props.clearDetails(); + props.undoMapSelection(); + } + + }, [props.location.pathname]); + + //update url if new element loaded + React.useEffect(() => { + if (props.data !== null) { + const currentUrl = window.location.href; + const parts = currentUrl.split(URL_BASEPATH); + const detailsPath = parts[1].split("/details/"); + props.history.replace(`/${URL_BASEPATH}${detailsPath[0]}/details/${props.data.name}`) + } + + }, [props.data]) + + const onLinkClick = async (id: string) => { + const result = await fetch(`${URL_API}/link/${id}`); + if(result.ok){ + const resultAsJson = await result.json(); + const link = resultAsJson as link; + props.selectLink(link); + props.addHistory({ id: props.data!.name, data: props.data! }); + props.highlightLink(link); + + } + } + + const backClick = (e: any) => { + if (isSite(props.breadcrumbs[0].data)) { + props.selectSite(props.breadcrumbs[0].data) + props.highlightSite(props.breadcrumbs[0].data); + + } else { + props.selectLink(props.breadcrumbs[0].data); + props.highlightLink(props.breadcrumbs[0].data); + + } + + props.clearHistory(); + e.preventDefault(); + } + + const createDetailPanel = (data: site | link) => { + + if (isSite(data)) { + return <SiteDetails navigate={props.navigateToApplication} updatedDevices={props.updatedDevices} loadDevices={props.loadDevices} site={data} onLinkClick={onLinkClick} /> + } else { + return <LinkDetails link={data} /> + } + } + + const getDetailsIdFromUrl = () =>{ + const currentUrl = window.location.href; + const parts = currentUrl.split(URL_BASEPATH); + const detailsPath = parts[1].split("/details/") + return detailsPath[1] ? detailsPath[1] : null; + } + + const loadDetailsData = (id: string) =>{ + + fetch(`${URL_API}/link/${id}`) + .then(res => { + if (res.ok) + return res.json() + else + return Promise.reject() + + }) + .then(result => { + props.selectLink(result) + props.highlightLink(result); + + }) + .catch(error => { + + fetch(`${URL_API}/site/${id}`) + .then(res => { + if (res.ok) + return res.json() + else return Promise.reject(); + }) + .then(result => { + props.selectSite(result); + props.highlightSite(result); + }) + .catch(error =>{ + setMessage("No element with name " + id + " found"); + props.clearDetails(); + props.undoMapSelection(); + }); + }) + } + + const panelId = props.data!== null ? (isSite(props.data) ? 'site-details-panel' : 'link-details-panel' ): 'details-panel'; + + return (<div style={{ width: '30%', background: "#bbbdbf", padding: "20px", alignSelf:"stretch" }}> + <Paper style={{ height:"100%"}} id={panelId} aria-label={panelId} > + { + props.breadcrumbs.length > 0 && + <Breadcrumbs style={{ marginLeft: "15px", marginTop: "5px" }} aria-label="breadcrumbs-navigation"> + <Link aria-label="parent-element" color="inherit" href="/" onClick={backClick}> + {props.breadcrumbs[0].id} + </Link> + <Link aria-label="child-element" color="textSecondary"> + {props.data?.name} + </Link> + </Breadcrumbs> + } + { + props.data !== null ? + createDetailPanel(props.data) + : <Typography aria-label="details-panel-alt-message" style={{ marginTop: "5px" }} align="center" variant="body1">{message}</Typography> + + } + </Paper> + </div>) +} + +type porps = RouteComponentProps & Connect<typeof mapStateToProps, typeof mapDispatchToProps>; + +//select always via details? +const mapStateToProps = (state: IApplicationStoreState) => ({ + data: state.network.details?.data, + breadcrumbs: state.network.details.history, + updatedDevices: state.network.details.checkedDevices +}); + +const mapDispatchToProps = (dispatcher: IDispatcher) => ({ + selectSite: (site: site) => dispatcher.dispatch(new SelectSiteAction(site)), + selectLink: (link: link) => dispatcher.dispatch(new SelectLinkAction(link)), + clearDetails: () => dispatcher.dispatch(new ClearDetailsAction()), + addHistory: (newEntry: HistoryEntry) => dispatcher.dispatch(new AddToHistoryAction(newEntry)), + clearHistory: () => dispatcher.dispatch(new ClearHistoryAction()), + highlightLink: (link: link) => dispatcher.dispatch(new HighlightLinkAction(link)), + highlightSite: (site: site) => dispatcher.dispatch(new HighlightSiteAction(site)), + loadDevices: async (networkElements: Device[]) => { await dispatcher.dispatch(CheckDeviceList(networkElements)) }, + navigateToApplication: (applicationName: string, path?: string) => dispatcher.dispatch(new NavigateToApplication(applicationName, path, "test3")), + undoMapSelection: () => dispatcher.dispatch(new RemoveHighlightingAction()) + +}) + + +export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Details));
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/details/linkDetails.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/linkDetails.tsx new file mode 100644 index 000000000..0c9f6034f --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/linkDetails.tsx @@ -0,0 +1,100 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import * as React from 'react'; + +import { link } from '../../model/link'; +import { TextField, Tabs, Tab, Typography, AppBar, Button, Link } from '@material-ui/core'; +import DenseTable from '../denseTable'; +import { LatLonToDMS } from '../../utils/mapUtils'; + +type panelId = "siteA" | "siteB"; +type props = { link: link }; + +const LinkDetails: React.FunctionComponent<props> = (props) => { + + const [value, setValue] = React.useState<panelId>("siteA"); + const [height, setHeight] = React.useState(330); + + const handleResize = () =>{ + const el = document.getElementById('link-details-panel')?.getBoundingClientRect(); + const el2 = document.getElementById('site-tabs')?.getBoundingClientRect(); + + if(el && el2){ + if(props.link.type==="microwave") + setHeight(el!.height - el2!.y -30); + else + setHeight(el!.height - el2!.y +20); + + } + } + + //on mount + React.useEffect(()=>{ + handleResize(); + + //window.addEventListener("resize", handleResize); + },[]); + + React.useEffect(()=>{ + handleResize(); + }, [props.link]) + + const onHandleTabChange = (event: React.ChangeEvent<{}>, newValue: panelId) => { + setValue(newValue); + } + + const onCalculateLinkClick = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) =>{ + e.preventDefault(); + const siteA= props.link.locationA; + const siteB =props.link.locationB; + const nameA = props.link.siteA; + const nameB = props.link.siteB; + const distance = props.link.length > 0 ? props.link.length : props.link.calculatedLength; + const azimuthA = props.link.azimuthA; + const azimuthB = props.link.azimuthB; + window.open(`/#/linkCalculation?lat1=${siteA.lat}&lon1=${siteA.lon}&lat2=${siteB.lat}&lon2=${siteB.lon}&siteA=${nameA}&siteB=${nameB}&azimuthA=${azimuthA}&azimuthB=${azimuthB}&distance=${distance}&amslSiteA=${siteA.amsl}&AGLsiteA=${siteA.antennaHeight}&amslSiteB=${siteB.amsl}&AGLsiteB=${siteB.antennaHeight}`) + + } + + const data = [ + + {name:"Site Name", val1: props.link.siteA, val2: props.link.siteB}, + {name:"Latitude", val1: LatLonToDMS(props.link.locationA.lat), val2: LatLonToDMS(props.link.locationB.lat)}, + {name:"Longitude", val1: LatLonToDMS(props.link.locationA.lon, true), val2: LatLonToDMS(props.link.locationB.lon, true)}, + {name:"Azimuth in °", val1: props.link.azimuthA.toFixed(2), val2: props.link.azimuthB.toFixed(2)} +]; + + return (<div style={{ paddingLeft: "15px", paddingRight: "15px", paddingTop: "0px", display: 'flex', flexDirection: 'column' }}> + <h2>{props.link.name}</h2> + <TextField aria-label="operator" disabled style={{ marginTop: "5px" }} value="Unkown" label="Operator" /> + <TextField aria-label="type" disabled style={{ marginTop: "5px" }} value={props.link.type} label="Type" /> + <TextField aria-label="planned-distance-in-km" disabled style={{ marginTop: "5px" }} value={props.link.length.toFixed(2)} label="Distance planned in km" /> + <TextField aria-label="calculated-distance-in-km" disabled style={{ marginTop: "5px" }} value={props.link.calculatedLength.toFixed(2)} label="Distance calculated in km" /> + + <AppBar position="static" id="site-tabs" style={{ marginTop: "20px", background: '#2E3B55' }}> + <Typography aria-label="details-of-link-sites" style={{ margin:"5px"}}>SITE DETAILS</Typography> + </AppBar> + <DenseTable ariaLabel="site-information-table-entry" height={height} hover={false} headers={["", "Site A", "Site B"]} data={data} /> + { + props.link.type==="microwave" && <Button style={{marginTop:20}} fullWidth variant="contained" color="primary" onClick={onCalculateLinkClick}>Calculate link</Button> + } + </div>) +} + +export default LinkDetails;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/details/siteDetails.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/siteDetails.tsx new file mode 100644 index 000000000..92643d0c4 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/details/siteDetails.tsx @@ -0,0 +1,153 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import * as React from 'react'; +import { TextField, Tabs, Tab, Typography, AppBar, Button, Tooltip } from '@material-ui/core'; + + +import MaterialTable, { ColumnModel, ColumnType, MaterialTableCtorType } from "../../../../../framework/src/components/material-table"; + + +import { site, Device } from '../../model/site'; +import DenseTable from '../denseTable'; +import { LatLonToDMS } from '../../utils/mapUtils'; + +type minLinks = { name: string, azimuth: string} + +const FaultAlarmNotificationTable = MaterialTable as MaterialTableCtorType<minLinks>; + + +type panelId="links" | "nodes"; +type props = { site: site, updatedDevices: Device[]|null, navigate(applicationName: string, path?: string):void, onLinkClick(id: string): void, loadDevices(devices:Device[]): void }; + +const SiteDetails: React.FunctionComponent<props> = (props) => { + + const [value, setValue] = React.useState<panelId>("links"); + const [height, setHeight] = React.useState(330); + + const handleResize = () =>{ + //console.log("resize") + const el = document.getElementById('site-details-panel')?.getBoundingClientRect(); + const el2 = document.getElementById('site-tabs')?.getBoundingClientRect(); + + if(el && el2){ + setHeight(el!.height - el2!.y +20); + } + + } + + //on mount + React.useEffect(()=>{ + handleResize(); + + window.addEventListener("resize", ()=>{console.log("really got resized.")}); + },[]); + + // on update + React.useEffect(()=>{ + + props.loadDevices(props.site.devices); + handleResize(); + + }, [props.site]) + + const onHandleTabChange = (event: React.ChangeEvent<{}>, newValue: panelId) => { + setValue(newValue); + } + + const linkRows: minLinks[] = props.site.links.map(link=> + { + return {name: link.name, azimuth: link.azimuthB.toFixed(2) } + }); + + + + return (<div style={{ padding: '15px', display: "flex", flexDirection:"column", minWidth:0, minHeight:0 }}> + <h2 >{props.site.name}</h2> + { + props.site.operator !== '' && props.site.operator !== null ? + <TextField aria-label="operator" disabled={true} value={props.site.operator} label="Operator" /> : + <TextField aria-label="operator" disabled={true} value="Unkown" label="Operator" style={{ marginTop: "5px" }} /> + } + { + props.site.type !== undefined && props.site.type.length > 0 && + <TextField aria-label="type" disabled={true} value={props.site.type} label="Type" style={{ marginTop: "5px" }} /> + } + { + props.site.address !== undefined && props.site.address.length > 0 && + <TextField aria-label="adress" disabled={true} value={props.site.address} label="Adress" style={{ marginTop: "5px" }} /> + } + { + props.site.heighAGLInMeters !== undefined && props.site.heighAGLInMeters > 0 && + <TextField aria-label="amsl-in-meters" disabled={true} value={props.site.heighAGLInMeters} label="AMSL in meters" style={{ marginTop: "5px" }} /> + } + { + props.site.antennaHeightAGLInMeters !== undefined && props.site.antennaHeightAGLInMeters > 0 && + <TextField aria-label="antenna-above-ground-in-meters" disabled={true} value={props.site.antennaHeightAGLInMeters} label="Atenna above ground in meters" style={{ marginTop: "5px" }} /> + } + + <TextField aria-label="latitude" style={{ marginTop: "5px" }} disabled={true} value={LatLonToDMS(props.site.geoLocation.lat)} label="Latitude" /> + <TextField aria-label="longitude" style={{ marginTop: "5px" }} disabled={true} value={LatLonToDMS(props.site.geoLocation.lon, true)} label="Longitude" /> + + <AppBar position="static" style={{ marginTop: "5px", background: '#2E3B55' }}> + <Tabs id="site-tabs" value={value} onChange={onHandleTabChange} aria-label="simple tabs example"> + <Tab label="Links" value="links" /> + <Tab label="Nodes" value="nodes" /> + </Tabs> + </AppBar> + { + value === "links" && + <> + { + props.site.links.length === 0 && + <Typography aria-label="no-links-available" variant="body1" style={{ marginTop: '10px' }}>No links available.</Typography> + } + + { + props.site.links.length > 0 && + <DenseTable ariaLabel="available-links-table-entry" height={height} hover={true} headers={["Link Name", "Azimuth in °"]} data={linkRows} onClick={props.onLinkClick} ></DenseTable> + /** + * + * */ + + + } + + </> + + } + { + value === "nodes" && + <> + { + props.site.devices.length === 0 && + <Typography aria-label="no-nodes-avilable" variant="body1" style={{ marginTop: '10px' }}>No nodes available.</Typography> + } + + { + props.site.devices.length>0 && props.updatedDevices !== null && + <DenseTable ariaLabel="available-nodes-table-entry" navigate={props.navigate} height={height} hover={false} headers={["ID","Name","Type", "Manufacturer","Owner","Status", "Ports", "Actions"]} actions={true} data={props.updatedDevices!} /> + } + </> + } + </div> + ) + +} + +export default SiteDetails;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/iconSwitch.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/iconSwitch.tsx new file mode 100644 index 000000000..8df1385d0 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/iconSwitch.tsx @@ -0,0 +1,53 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import * as React from 'react'; +import { FormControlLabel, Switch, Paper } from "@material-ui/core"; +import connect, { Connect, IDispatcher } from '../../../../framework/src/flux/connect'; +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; +import { SetIconSwitchAction } from '../actions/mapActions'; + +type props = Connect<typeof mapStateToProps, typeof mapDispatchToProps> & {visible: boolean} + +const IconSwitch: React.FunctionComponent<props> = (props) =>{ + + const toggleChecked = () => { + props.toogle(!props.areIconsEnabled) + }; + + return ( + props.visible ? + <FormControlLabel style={{ padding:5, position: 'absolute',top: 190}} + value="end" + control={<Switch color="secondary" checked={props.areIconsEnabled} onChange={toggleChecked} />} + label="Show icons" + labelPlacement="end" + />: null) +} + +const mapStateToProps = (state: IApplicationStoreState) => ({ + areIconsEnabled: state.network.map.allowIconSwitch +}); + + +const mapDispatchToProps = (dispatcher: IDispatcher) => ({ + toogle : (enable:boolean) => dispatcher.dispatch(new SetIconSwitchAction(enable)) + +});; + +export default (connect(mapStateToProps,mapDispatchToProps)(IconSwitch)) diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx new file mode 100644 index 000000000..ceb51d41a --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/map.tsx @@ -0,0 +1,611 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import * as React from 'react' +import * as mapboxgl from 'mapbox-gl'; +import { RouteComponentProps, withRouter } from 'react-router-dom'; + + +import { site } from '../model/site'; +import { SelectSiteAction, ClearHistoryAction, SelectLinkAction } from '../actions/detailsAction'; +import { OSM_STYLE, URL_API, URL_BASEPATH, URL_TILE_API } from '../config'; +import { link } from '../model/link'; +import MapPopup from './mapPopup'; +import { SetPopupPositionAction, SelectMultipleLinksAction, SelectMultipleSitesAction } from '../actions/popupActions'; +import { Feature } from '../model/Feature'; +import { HighlightLinkAction, HighlightSiteAction, SetCoordinatesAction, SetStatistics } from '../actions/mapActions'; +import { addDistance, getUniqueFeatures } from '../utils/mapUtils'; +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; +import connect, { IDispatcher, Connect } from '../../../../framework/src/flux/connect'; +import SearchBar from './searchBar'; +import { verifyResponse, IsTileServerReachableAction, handleConnectionError } from '../actions/connectivityAction'; +import ConnectionInfo from './connectionInfo' +import { showIconLayers, addBaseLayers } from '../utils/mapLayers'; +import lamp from '../../icons/lamp.png'; +import apartment from '../../icons/apartment.png'; +import datacenter from '../../icons/datacenter.png'; +import factory from '../../icons/factory.png'; +import Statistics from './statistics'; +import IconSwitch from './iconSwitch'; + +type coordinates = { lat: number, lon: number, zoom: number } + +let alarmElements: Feature[] = []; +let map: mapboxgl.Map; +let isLoadingInProgress = false; +let notLoadedBoundingBoxes: mapboxgl.LngLatBounds[] = []; + +let lastBoundingBox: mapboxgl.LngLatBounds | null = null; +let myRef = React.createRef<HTMLDivElement>(); + + +class Map extends React.Component<mapProps, { isPopupOpen: boolean }> { + + constructor(props: mapProps) { + super(props); + //any state stuff + this.state = { isPopupOpen: false } + + } + + componentDidMount() { + + // resize the map, if menu gets collapsed + window.addEventListener("menu-resized", this.handleResize); + + // try if connection to tile + topologyserver is available + + fetch(URL_TILE_API + '/10/0/0.png') + .then(res => { + if (res.ok) { + this.setupMap(); + } else { + this.props.setTileServerLoaded(false); + console.error("tileserver " + URL_TILE_API + "can't be reached.") + } + }) + .catch(err => { + this.props.setTileServerLoaded(false); + console.error("tileserver " + URL_TILE_API + "can't be reached.") + }); + + fetch(URL_API + "/info") + .then(result => verifyResponse(result)) + .catch(error => this.props.handleConnectionError(error)); + } + + setupMap = () => { + + let lat = this.props.lat; + let lon = this.props.lon; + let zoom = this.props.zoom; + + const coordinates = this.extractCoordinatesFromUrl(); + // override lat/lon/zoom with coordinates from url, if available + if (this.areCoordinatesValid(coordinates)) { + lat = coordinates.lat; + lon = coordinates.lon; + zoom = !Number.isNaN(coordinates.zoom) ? coordinates.zoom : zoom; + } + + map = new mapboxgl.Map({ + container: myRef.current!, + style: OSM_STYLE as any, + center: [lon, lat], + zoom: zoom, + accessToken: '' + }); + + map.on('load', (ev) => { + + addBaseLayers(map, this.props.selectedSite, this.props.selectedLink); + map.loadImage( + lamp, + function (error: any, image: any) { + if (error) throw error; + map.addImage('lamp', image); + }); + + map.loadImage( + datacenter, + function (error: any, image: any) { + if (error) throw error; + map.addImage('data-center', image); + }); + + map.loadImage( + apartment, + function (error: any, image: any) { + if (error) throw error; + map.addImage('house', image); + }); + + map.loadImage( + factory, + function (error: any, image: any) { + if (error) throw error; + map.addImage('factory', image); + }); + + const boundingBox = map.getBounds(); + + + fetch(`${URL_API}/links/geoJson/${boundingBox.getWest()},${boundingBox.getSouth()},${boundingBox.getEast()},${boundingBox.getNorth()}`) + .then(result => verifyResponse(result)) + .then(result => result.json()) + .then(features => { + if (map.getLayer('fibre-lines')) { + (map.getSource('lines') as mapboxgl.GeoJSONSource).setData(features); + } + }) + .catch(error => this.props.handleConnectionError(error)); + + + fetch(`${URL_API}/sites/geoJson/${boundingBox.getWest()},${boundingBox.getSouth()},${boundingBox.getEast()},${boundingBox.getNorth()}`) + .then(result => verifyResponse(result)) + .then(result => result.json()) + .then(features => { + if (map.getLayer('points')) { + (map.getSource('points') as mapboxgl.GeoJSONSource).setData(features); + } + }) + .catch(error => this.props.handleConnectionError(error)); + }); + + map.on('click', (e: any) => { + + if (map.getLayer('points')) { // data is shown as points + + var clickedLines = getUniqueFeatures(map.queryRenderedFeatures([[e.point.x - 5, e.point.y - 5], + [e.point.x + 5, e.point.y + 5]], { + layers: ['microwave-lines', 'fibre-lines'] + }), "id"); + + const clickedPoints = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['points'] }), "id"); + const alarmedSites = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['alarmedPoints'] }), "id"); + + if (clickedPoints.length != 0) { + + + if (alarmedSites.length > 0) { + alarmedSites.forEach(alarm => { + const index = clickedPoints.findIndex(item => item.properties!.id === alarm.properties!.id); + + if (index !== -1) { + clickedPoints[index].properties!.alarmed = true; + clickedPoints[index].properties!.type = "alarmed"; + } + }); + } + + this.showSitePopup(clickedPoints, e.point.x, e.point.y); + } else if (clickedLines.length != 0) { + this.showLinkPopup(clickedLines, e.point.x, e.point.y); + } + + + } else { // data is shown as icons + + const clickedLamps = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['point-lamps'] }), "id"); + const buildings = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['point-building'] }), "id"); + const houses = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['point-data-center'] }), "id"); + const factories = getUniqueFeatures(map.queryRenderedFeatures(e.point, { layers: ['point-factory'] }), "id"); + + const combinedFeatures = [...clickedLamps, ...buildings, ...houses, ...factories]; + + const clickedLines = getUniqueFeatures(map.queryRenderedFeatures([[e.point.x - 5, e.point.y - 5], + [e.point.x + 5, e.point.y + 5]], { + layers: ['microwave-lines', 'fibre-lines'] + }), "id"); + + if (combinedFeatures.length > 0) + this.showSitePopup(combinedFeatures, e.point.x, e.point.y); + else if (clickedLines.length != 0) { + this.showLinkPopup(clickedLines, e.point.x, e.point.y); + } + } + + }); + + map.on('moveend', () => { + + const mapZoom = Number(map.getZoom().toFixed(2)); + const lat = Number(map.getCenter().lat.toFixed(4)); + const lon = Number(map.getCenter().lng.toFixed(4)); + + + if (this.props.lat !== lat || this.props.lon !== lon || this.props.zoom !== mapZoom) { + this.props.updateMapPosition(lat, lon, mapZoom) + } + + // update the url to current lat,lon,zoom values + + const currentUrl = window.location.href; + const parts = currentUrl.split(URL_BASEPATH); + const detailsPath = parts[1].split("/details/"); + + if (detailsPath[1] !== undefined && detailsPath[1].length > 0) { + this.props.history.replace(`/${URL_BASEPATH}/${map.getCenter().lat.toFixed(4)},${map.getCenter().lng.toFixed(4)},${mapZoom.toFixed(2)}/details/${detailsPath[1]}`) + } + else { + this.props.history.replace(`/${URL_BASEPATH}/${map.getCenter().lat.toFixed(4)},${map.getCenter().lng.toFixed(4)},${mapZoom.toFixed(2)}`) + } + + //switch icon layers if applicable + showIconLayers(map, this.props.showIcons, this.props.selectedSite?.properties.id); + + //update statistics + const boundingBox = map.getBounds(); + + fetch(`${URL_API}/info/count/${boundingBox.getWest()},${boundingBox.getSouth()},${boundingBox.getEast()},${boundingBox.getNorth()}`) + .then(result => verifyResponse(result)) + .then(res => res.json()) + .then(result => { + if (result.links !== this.props.linkCount || result.sites !== this.props.siteCount) { + this.props.setStatistics(result.links, result.sites); + } + }) + .catch(error => this.props.handleConnectionError(error));; + }) + + map.on('move', () => { + const mapZoom = map.getZoom(); + + const boundingBox = map.getBounds(); + + this.loadNetworkData(boundingBox); + if (mapZoom > 9) { + + if (map.getLayer('points')) { + map.setLayoutProperty('selectedPoints', 'visibility', 'visible'); + map.setPaintProperty('points', 'circle-radius', 7); + } + } else { + + // reduce size of points / lines if zoomed out + map.setPaintProperty('points', 'circle-radius', 2); + map.setLayoutProperty('selectedPoints', 'visibility', 'none'); + + if (mapZoom <= 4) { + map.setPaintProperty('fibre-lines', 'line-width', 1); + map.setPaintProperty('microwave-lines', 'line-width', 1); + + } else { + map.setPaintProperty('fibre-lines', 'line-width', 2); + map.setPaintProperty('microwave-lines', 'line-width', 2); + } + } + }); + } + + componentDidUpdate(prevProps: mapProps, prevState: {}) { + + if (map !== undefined) { + if (prevProps.selectedSite?.properties.id !== this.props.selectedSite?.properties.id) { + + if (this.props.selectedSite != null) { + if (map.getSource("selectedLine") !== undefined) { + (map.getSource("selectedLine") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: [] }); + (map.getSource("selectedPoints") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: [this.props.selectedSite] }); + } + + + if (map.getLayer('point-lamps') !== undefined) { + + map.setFilter('point-lamps', ['==', 'type', 'street lamp']); + map.setFilter('point-data-center', ['==', 'type', 'data center']); + map.setFilter('point-building', ['==', 'type', 'high rise building']); + map.setFilter('point-factory', ['==', 'type', 'factory']) + + if (this.props.selectedSite?.properties.type !== undefined) { + switch (this.props.selectedSite?.properties.type) { + case 'street lamp': + map.setFilter('point-lamps', ["all", ['==', 'type', 'street lamp'], ['!=', 'id', this.props.selectedSite.properties.id]]); + break; + case 'data center': + map.setFilter('point-data-center', ["all", ['==', 'type', 'data center'], ['!=', 'id', this.props.selectedSite.properties.id]]); + break; + case 'high rise building': + map.setFilter('point-building', ["all", ['==', 'type', 'high rise building'], ['!=', 'id', this.props.selectedSite.properties.id]]) + break; + case 'factory': + map.setFilter('point-factory', ["all", ['==', 'type', 'factory'], ['!=', 'id', this.props.selectedSite.properties.id]]); + break; + } + } + } + + + } + else + { + if (map.getSource("selectedPoints") !== undefined) + (map.getSource("selectedPoints") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: [] }); + + } + } + + if (prevProps.selectedLink !== this.props.selectedLink) { + if (this.props.selectedLink != null) { + + if (map.getLayer('point-lamps') !== undefined) { + map.setFilter('point-lamps', ['==', 'type', 'street lamp']); + map.setFilter('point-data-center', ['==', 'type', 'data center']); + map.setFilter('point-building', ['==', 'type', 'high rise building']); + map.setFilter('point-factory', ['==', 'type', 'factory']); + } + + if (map.getSource("selectedLine") !== undefined) { + (map.getSource("selectedPoints") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: [] }); + (map.getSource("selectedLine") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: [this.props.selectedLink] }); + } + } + else + { + if (map.getSource("selectedLine") !== undefined) + (map.getSource("selectedLine") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: [] }); + } + } + + if (prevProps.location.pathname !== this.props.location.pathname) { + if (map) { + const coordinates = this.extractCoordinatesFromUrl(); + this.moveMapToCoordinates(coordinates); + } + } + + if (prevProps.alarmlement !== this.props.alarmlement) { + if (this.props.alarmlement !== null && !alarmElements.includes(this.props.alarmlement)) { + if (map.getSource("alarmedPoints")) + (map.getSource("alarmedPoints") as mapboxgl.GeoJSONSource).setData({ type: "FeatureCollection", features: alarmElements }); + alarmElements.push(this.props.alarmlement) + } + } + + if (prevProps.showIcons !== this.props.showIcons) { + if (map && map.getZoom() > 11) { + showIconLayers(map, this.props.showIcons, this.props.selectedSite?.properties.id); + } + } + + if (prevProps.zoomToElement !== this.props.zoomToElement) { + if (this.props.zoomToElement !== null) { + const currentZoom = map?.getZoom(); + + map.flyTo({ + center: [ + this.props.zoomToElement.lon, + this.props.zoomToElement.lat + ], zoom: currentZoom < 10 ? 10 : currentZoom, + essential: true + }); + } + } + } + } + + componentWillUnmount(){ + window.removeEventListener("menu-resized", this.handleResize); + } + + handleResize = () => { + if (map) { + // wait a moment until resizing actually happened + window.setTimeout(() => map.resize(), 500); + } + } + + extractCoordinatesFromUrl = (): coordinates => { + const currentUrl = window.location.href; + const mainPathParts = currentUrl.split(URL_BASEPATH); + const coordinatePathPart = mainPathParts[1].split("/details/"); // split by details if present + const allCoordinates = coordinatePathPart[0].replace("/", ""); + const coordinates = allCoordinates.split(","); + return { lat: Number(coordinates[0]), lon: Number(coordinates[1]), zoom: Number(coordinates[2]) } + } + + areCoordinatesValid = (coordinates: coordinates) => { + + if ((!Number.isNaN(coordinates.lat)) && (!Number.isNaN(coordinates.lon))) { + return true; + } else { + return false; + } + } + + moveMapToCoordinates = (coordinates: coordinates) => { + + if (this.areCoordinatesValid(coordinates)) { + let zoom = -1; + + if (!Number.isNaN(coordinates.zoom)) { + zoom = coordinates.zoom; + } + + map.flyTo({ + center: [ + coordinates.lon, + coordinates.lat + ], zoom: zoom !== -1 ? zoom : this.props.zoom, + essential: true + }) + } + } + + loadNetworkData = async (bbox: mapboxgl.LngLatBounds) => { + if (!isLoadingInProgress) { // only load data if loading not in progress + isLoadingInProgress = true; + + if (lastBoundingBox == null) { + lastBoundingBox = bbox; + await this.draw('lines', `${URL_API}/links/geoJson/${lastBoundingBox.getWest()},${lastBoundingBox.getSouth()},${lastBoundingBox.getEast()},${lastBoundingBox.getNorth()}`); + await this.draw('points', `${URL_API}/sites/geoJson/${lastBoundingBox.getWest()},${lastBoundingBox.getSouth()},${lastBoundingBox.getEast()},${lastBoundingBox.getNorth()}`); + } else { + + // new bbox is bigger than old one + if (bbox.contains(lastBoundingBox.getNorthEast()) && bbox.contains(lastBoundingBox.getSouthWest()) && lastBoundingBox !== bbox) { //if new bb is bigger than old one + + lastBoundingBox = bbox; + + const distance = map.getCenter().distanceTo(bbox.getNorthEast()); // radius of visible area (center -> corner) (in meters) + + //calculate new boundingBox + const increasedBoundingBox = addDistance(bbox.getSouth(), bbox.getWest(), bbox.getNorth(), bbox.getEast(), (distance / 1000) / 2) + + await this.draw('lines', `${URL_API}/links/geoJson/${increasedBoundingBox.west},${increasedBoundingBox.south},${increasedBoundingBox.east},${increasedBoundingBox.north}`); + await this.draw('points', `${URL_API}/sites/geoJson/${increasedBoundingBox.west},${increasedBoundingBox.south},${increasedBoundingBox.east},${increasedBoundingBox.north}`); + + } else if (lastBoundingBox.contains(bbox.getNorthEast()) && lastBoundingBox.contains(bbox.getSouthWest())) { // last one contains new one + // bbox is contained in last one, do nothing + isLoadingInProgress = false; + + } else { // bbox is not fully contained in old one, extend + + lastBoundingBox.extend(bbox); + + await this.draw('lines', `${URL_API}/links/geoJson/${lastBoundingBox.getWest()},${lastBoundingBox.getSouth()},${lastBoundingBox.getEast()},${lastBoundingBox.getNorth()}`); + await this.draw('points', `${URL_API}/sites/geoJson/${lastBoundingBox.getWest()},${lastBoundingBox.getSouth()},${lastBoundingBox.getEast()},${lastBoundingBox.getNorth()}`); + } + + } + + + if (notLoadedBoundingBoxes.length > 0) { // load last not loaded boundingbox + this.loadNetworkData(notLoadedBoundingBoxes.pop()!) + notLoadedBoundingBoxes = []; + } + + } else { + notLoadedBoundingBoxes.push(bbox); + } + } + + showSitePopup = (sites: mapboxgl.MapboxGeoJSONFeature[], top: number, left: number) => { + if (sites.length > 1) { + const ids = sites.map(feature => feature.properties!.id); + + this.props.setPopupPosition(top, left); + this.props.selectMultipleSites(ids); + this.setState({ isPopupOpen: true }); + + } else { + const id = sites[0].properties!.id; + + fetch(`${URL_API}/site/${id}`) + .then(result => verifyResponse(result)) + .then(res => res.json() as Promise<site>) + .then(result => { + this.props.selectSite(result); + this.props.highlightSite(result); + this.props.clearDetailsHistory(); + }) + .catch(error => this.props.handleConnectionError(error));; + } + } + + showLinkPopup = (links: mapboxgl.MapboxGeoJSONFeature[], top: number, left: number) => { + + if (links.length > 1) { + + const ids = links.map(feature => feature.properties!.id as string); + this.props.setPopupPosition(top, left); + this.props.selectMultipleLinks(ids); + this.setState({ isPopupOpen: true }); + + } else { + var id = links[0].properties!.id; + + fetch(`${URL_API}/link/${id}`) + .then(result => verifyResponse(result)) + .then(res => res.json() as Promise<link>) + .then(result => { + this.props.selectLink(result); + this.props.highlightLink(result); + + this.props.clearDetailsHistory(); + }) + .catch(error => this.props.handleConnectionError(error));; + } + } + + draw = async (layer: string, url: string) => { + + fetch(url) + .then(result => verifyResponse(result)) + .then(res => res.json()) + .then(result => { + isLoadingInProgress = false; + if (map.getSource(layer)) { + (map.getSource(layer) as mapboxgl.GeoJSONSource).setData(result); + } + }) + .catch(error => this.props.handleConnectionError(error));; + } + + render() { + + return <> + + <div id="map" style={{ width: "70%", position: 'relative' }} ref={myRef} > + { + this.state.isPopupOpen && + <MapPopup onClose={() => { this.setState({ isPopupOpen: false }); }} /> + } + <SearchBar /> + <Statistics /> + <IconSwitch visible={this.props.zoom>11} /> + <ConnectionInfo /> + </div> + </> + } + +} + +type mapProps = RouteComponentProps & Connect<typeof mapStateToProps, typeof mapDispatchToProps>; + +const mapStateToProps = (state: IApplicationStoreState) => ({ + selectedLink: state.network.map.selectedLink, + selectedSite: state.network.map.selectedSite, + zoomToElement: state.network.map.zoomToElement, + alarmlement: state.network.map.alarmlement, + lat: state.network.map.lat, + lon: state.network.map.lon, + zoom: state.network.map.zoom, + linkCount: state.network.map.statistics.links, + siteCount: state.network.map.statistics.sites, + isTopoServerReachable: state.network.connectivity.isToplogyServerAvailable, + isTileServerReachable: state.network.connectivity.isTileServerAvailable, + showIcons: state.network.map.allowIconSwitch +}); + +const mapDispatchToProps = (dispatcher: IDispatcher) => ({ + selectSite: (site: site) => dispatcher.dispatch(new SelectSiteAction(site)), + selectLink: (link: link) => dispatcher.dispatch(new SelectLinkAction(link)), + clearDetailsHistory: () => dispatcher.dispatch(new ClearHistoryAction()), + selectMultipleLinks: (ids: string[]) => dispatcher.dispatch(new SelectMultipleLinksAction(ids)), + selectMultipleSites: (ids: string[]) => dispatcher.dispatch(new SelectMultipleSitesAction(ids)), + setPopupPosition: (x: number, y: number) => dispatcher.dispatch(new SetPopupPositionAction(x, y)), + highlightLink: (link: link) => dispatcher.dispatch(new HighlightLinkAction(link)), + highlightSite: (site: site) => dispatcher.dispatch(new HighlightSiteAction(site)), + updateMapPosition: (lat: number, lon: number, zoom: number) => dispatcher.dispatch(new SetCoordinatesAction(lat, lon, zoom)), + setStatistics: (linkCount: string, siteCount: string) => dispatcher.dispatch(new SetStatistics(siteCount, linkCount)), + setTileServerLoaded: (reachable: boolean) => dispatcher.dispatch(new IsTileServerReachableAction(reachable)), + handleConnectionError: (error: Error) => dispatcher.dispatch(handleConnectionError(error)) +}) + +export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Map));
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/mapPopup.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/mapPopup.tsx new file mode 100644 index 000000000..040024760 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/mapPopup.tsx @@ -0,0 +1,94 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import * as React from 'react'; +import { Typography, Select, MenuItem, ClickAwayListener, Popper, Paper, FormGroup, Portal, Popover } from '@material-ui/core'; +import { SelectSiteAction, ClearHistoryAction, ClearDetailsAction } from '../actions/detailsAction'; +import { site } from '../model/site'; +import { link } from '../model/link'; +import { URL_API } from '../config'; +import { HighlightLinkAction, HighlightSiteAction } from '../actions/mapActions'; +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; +import connect, { IDispatcher, Connect } from '../../../../framework/src/flux/connect'; +import { verifyResponse, handleConnectionError } from '../actions/connectivityAction'; + + + + +const MapPopup: React.FunctionComponent<props> = (props) => { + + const [value, setValue] = React.useState(""); + + const handleChange = (event: any) => { + setValue(event.target.value); + + const id = event.target.value; + + + fetch(`${URL_API}/${props.type}/${id}`) + .then(result => verifyResponse(result)) + .then(res => res.json()) + .then(result => { + props.clearDetailsHistory(); + props.selectElement(result); + props.type === "link" ? props.highlightLink(result) : props.highlightSite(result) + props.onClose(); + }) + .catch(error => { + props.handleConnectionError(error); + props.onClose(); + // props.clearDetails(); + }); + }; + + return <> + <Popover open={true} anchorEl={undefined} onClose={props.onClose} anchorReference="anchorPosition" anchorPosition={{ top: props.position.left, left: props.position.top }}> + <Paper style={{ padding: "15px" }}> + <Typography variant="h5">{`Multiple ${props.type.toLowerCase()}s were selected`}</Typography> + <Typography variant="body1">Please select one.</Typography> + <Select style={{ width: 300 }} onChange={handleChange} value={value} native> + <option value={""} disabled>{props.type} ids</option> + { + props.ids.map(id => <option key={id} value={id}>{id}</option>) + } + </Select> + </Paper> + </Popover> + </> +} + +type props = Connect<typeof mapStateToProps, typeof mapDispatchToProps>& { onClose(): void } + +const mapStateToProps = (state: IApplicationStoreState) => ({ + ids: state.network.popup.selectionPendingForIds, + type: state.network.popup.pendingDataType, + position: state.network.popup.position + +}); + +const mapDispatchToProps = (dispatcher: IDispatcher) => ({ + selectElement: (site: site) => dispatcher.dispatch(new SelectSiteAction(site)), + clearDetailsHistory:()=> dispatcher.dispatch(new ClearHistoryAction()), + highlightLink: (link: link) => dispatcher.dispatch(new HighlightLinkAction(link)), + highlightSite: (site: site) => dispatcher.dispatch(new HighlightSiteAction(site)), + handleConnectionError: (error:Error) => dispatcher.dispatch(handleConnectionError(error)), + clearDetails: () => dispatcher.dispatch(new ClearDetailsAction()), + +}); + +export default (connect(mapStateToProps, mapDispatchToProps))(MapPopup);
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/searchBar.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/searchBar.tsx new file mode 100644 index 000000000..c825e5ae0 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/searchBar.tsx @@ -0,0 +1,160 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import * as React from 'react'; +import { makeStyles, Paper, InputBase, IconButton, Divider, Popover, Typography } from '@material-ui/core'; +import SearchIcon from '@material-ui/icons/Search'; + +import { URL_API } from '../config'; +import { isSite } from '../utils/utils'; +import { site } from '../model/site'; +import { link } from '../model/link'; +import { SelectSiteAction, SelectLinkAction } from '../actions/detailsAction'; +import { HighlightLinkAction, HighlightSiteAction, ZoomToSearchResultAction } from '../actions/mapActions'; +import { calculateMidPoint } from '../utils/mapUtils'; +import { SetSearchValueAction } from '../actions/searchAction'; +import connect,{ Connect, IDispatcher } from '../../../../framework/src/flux/connect'; +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; + + + + + + +const styles = makeStyles({ + root: { + //{ padding:5, position: 'absolute', display:'flex', flexDirection:"column",top: 150, width: 200} + padding: '2px 4px', + position: 'absolute', + display:'flex', + alignItems: 'center', + top: 15, + marginLeft: 5, + width: 400, + }, + input: { + flex: 1, + marginLeft: 5 + }, + iconButton: { + padding: 10, + }, + divider: { + height: 28, + margin: 4, + }, + }); + + +const SearchBar: React.FunctionComponent<searchBarProps> = (props) =>{ + + const classes = styles(); + const [anchorEl, setAnchorEl] = React.useState<any>(null); + const [errorMessage, setErrorMessage] = React.useState(""); + + const divRef = React.useRef(); + + const handleClick = (e: any) =>{ + + setAnchorEl(null); + if(props.searchterm.length>0){ + + const siteResult = fetch(`${URL_API}/site/${props.searchterm}`) + + const linkResult = fetch(`${URL_API}/link/${props.searchterm}`); + + Promise.all([ siteResult, linkResult]).then((result)=>{ + const suceededResults = result.filter(el=> el.ok); + + if(suceededResults.length==0){ + setAnchorEl(divRef.current); + setErrorMessage("No element found.") + // hide message after 3 sec + window.setTimeout(()=>{setAnchorEl(null)}, 3000); + + }else{ + suceededResults[0].json().then(result =>{ + if(isSite(result)){ + props.selectSite(result); + props.highlightSite(result); + props.zoomToSearchResult(result.geoLocation.lat, result.geoLocation.lon); + }else{ + props.selectLink(result); + props.highlightLink(result); + const midPoint = calculateMidPoint(result.locationA.lat, result.locationA.lon, result.locationB.lat, result.locationB.lon); + props.zoomToSearchResult(midPoint[1], midPoint[0]) + } + }); + } + }); + } + e.preventDefault(); +} + + const open = Boolean(anchorEl); + + const reachabe = props.isTopoServerReachable && props.isTileServerReachable; + + return ( + <> + <Paper ref={divRef} component="form" className={classes.root}> + <InputBase + disabled={!reachabe} + className={classes.input} + placeholder="Find sites or links by name" + inputProps={{ 'aria-label': 'networkmap-searchbar' }} + value={props.searchterm} + onChange={e=> props.setSearchTerm(e.currentTarget.value)} + /> + <Divider className={classes.divider} orientation="vertical" /> + <IconButton type="submit" className={classes.iconButton} aria-label="search" onClick={handleClick}> + <SearchIcon /> + </IconButton> + </Paper> + <Popover open={open} onClose={e=> setAnchorEl(null)} anchorEl={anchorEl} anchorOrigin={{ + vertical: "bottom", + horizontal: "left" + }}> + <Paper style={{width: 380, padding:10}}> + <Typography variant="body1">{errorMessage}</Typography> + </Paper> + </Popover> + </> + ); +} + +const mapStateToProps = (state: IApplicationStoreState) => ({ + searchterm: state.network.search.value, + isTopoServerReachable: state.network.connectivity.isToplogyServerAvailable, + isTileServerReachable: state.network.connectivity.isTileServerAvailable + +}); + +type searchBarProps = Connect<typeof mapStateToProps, typeof mapDispatchToProps>; + + +const mapDispatchToProps = (dispatcher: IDispatcher) => ({ + selectSite:(site: site)=> dispatcher.dispatch(new SelectSiteAction(site)), + selectLink:(link: link) => dispatcher.dispatch(new SelectLinkAction(link)), + highlightLink:(link: link)=> dispatcher.dispatch(new HighlightLinkAction(link)), + highlightSite: (site: site) => dispatcher.dispatch(new HighlightSiteAction(site)), + setSearchTerm: (value: string) => dispatcher.dispatch(new SetSearchValueAction(value)), + zoomToSearchResult: (lat: number, lon: number) => dispatcher.dispatch(new ZoomToSearchResultAction(lat, lon)), +});; + +export default (connect(mapStateToProps,mapDispatchToProps)(SearchBar))
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/components/statistics.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/components/statistics.tsx new file mode 100644 index 000000000..4103d64f1 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/components/statistics.tsx @@ -0,0 +1,57 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import * as React from 'react'; +import { Paper, Typography, Tooltip } from '@material-ui/core'; +import InfoIcon from '@material-ui/icons/Info'; + +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; +import connect, { IDispatcher, Connect } from '../../../../framework/src/flux/connect'; + +type props = Connect<typeof mapStateToProps, typeof mapDispatchToProps>; + +const mapStateToProps = (state: IApplicationStoreState) => ({ + linkCount: state.network.map.statistics.links, + siteCount: state.network.map.statistics.sites, + isTopoServerReachable: state.network.connectivity.isToplogyServerAvailable, + isTileServerReachable: state.network.connectivity.isTileServerAvailable, + +}); + +const mapDispatchToProps = (dispatcher: IDispatcher) => ({ +}); + +const Statistics: React.FunctionComponent<props> = (props: props) =>{ + + const reachabe = props.isTopoServerReachable && props.isTileServerReachable; + + + return (<Paper style={{ padding: 5, position: 'absolute', display: 'flex', flexDirection: "column", top: 70, width: 200, marginLeft: 5 }}> + <div style={{ display: 'flex', flexDirection: "row" }}> + <Typography style={{ fontWeight: "bold", flex: "1", color: reachabe ? "black" : "lightgrey" }} >Statistics</Typography> + <Tooltip style={{ alignSelf: "flex-end" }} title="Gets updated when the map stops moving."> + <InfoIcon fontSize="small" /> + </Tooltip> + </div> + + <Typography style={{ color: reachabe ? "black" : "lightgrey" }}>Sites: {props.siteCount}</Typography> + <Typography style={{ color: reachabe ? "black" : "lightgrey" }}>Links: {props.linkCount}</Typography> +</Paper>) +} + +export default connect(mapStateToProps, mapDispatchToProps)(Statistics); diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/config.ts b/sdnr/wt/odlux/apps/networkMapApp/src/config.ts new file mode 100644 index 000000000..e2e5718d5 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/config.ts @@ -0,0 +1,49 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +export const URL_API="/topology" +export const URL_TILE_API = '/tiles'; + + +export const OSM_STYLE = { + 'version': 8, + 'sources': { + 'raster-tiles': { + 'type': 'raster', + 'tiles': [ + URL_TILE_API+'/{z}/{x}/{y}.png' + ], + 'tileSize': 256, + 'attribution': + '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' + } + }, + 'layers': [ + { + 'id': 'simple-tiles', + 'type': 'raster', + 'source': 'raster-tiles', + 'minzoom': 0, + 'maxzoom': 18 + } + ] +}; + +export const URL_BASEPATH = "network"; + + diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/handlers/connectivityReducer.ts b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/connectivityReducer.ts new file mode 100644 index 000000000..7214705e1 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/connectivityReducer.ts @@ -0,0 +1,38 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { IActionHandler } from "../../../../framework/src/flux/action"; +import { IsTopologyServerReachableAction, IsTileServerReachableAction } from "../actions/connectivityAction"; + + +export type connectivityState = {isToplogyServerAvailable: boolean, isTileServerAvailable: boolean }; + +const initialState: connectivityState = {isToplogyServerAvailable: true, isTileServerAvailable: true}; + +export const ConnectivityReducer: IActionHandler<connectivityState> =(state=initialState, action)=> { + + if(action instanceof IsTopologyServerReachableAction){ + state = Object.assign({}, state, { isToplogyServerAvailable: action.reachable }); + } + else if (action instanceof IsTileServerReachableAction){ + state = Object.assign({}, state, { isTileServerAvailable: action.reachable }); + + } + + return state; +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/handlers/detailsReducer.ts b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/detailsReducer.ts new file mode 100644 index 000000000..f573009bd --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/detailsReducer.ts @@ -0,0 +1,70 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { IActionHandler } from '../../../../framework/src/flux/action'; +import { link } from "../model/link"; +import { site, Device } from "../model/site"; +import { HistoryEntry } from "../model/historyEntry"; +import { SelectSiteAction, SelectLinkAction, AddToHistoryAction, ClearHistoryAction, IsBusyCheckingDeviceListAction, FinishedLoadingDeviceListAction, ClearLoadedDevicesAction, ClearDetailsAction } from '../actions/detailsAction'; + +export type DetailsStoreState={ + data: site | link | null, + history: HistoryEntry[], + isBusyCheckingDeviceList: boolean, + checkedDevices: Device[] | null + +} + +const initialState: DetailsStoreState = { + data: null, + history:[], + isBusyCheckingDeviceList: false, + checkedDevices: null +} + +export const DetailsReducer:IActionHandler<DetailsStoreState>=(state = initialState, action)=>{ + + if(action instanceof SelectSiteAction){ + state= Object.assign({}, state, {data: action.site}); + } + else if(action instanceof SelectLinkAction){ + state = Object.assign({}, state, {data: action.link}); + }else if(action instanceof ClearDetailsAction){ + state = Object.assign({}, state, {data: null}); + } + else if(action instanceof AddToHistoryAction){ + state = Object.assign({}, state, {history: [...state.history, action.entry]}) + + }else if(action instanceof ClearHistoryAction){ + state = Object.assign({}, state, {history: []}); + + }else if(action instanceof IsBusyCheckingDeviceListAction){ + state = Object.assign({}, state, {isBusyCheckingDeviceList: action.isBusy}); + }else if (action instanceof FinishedLoadingDeviceListAction){ + state = Object.assign({}, state, {checkedDevices: action.devices}); + + }else if(action instanceof ClearLoadedDevicesAction){ + state = Object.assign({}, state, {checkedDevices: null}); + + } + + + return state; + +} + diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/handlers/mapReducer.ts b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/mapReducer.ts new file mode 100644 index 000000000..6f6277347 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/mapReducer.ts @@ -0,0 +1,81 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { IActionHandler } from '../../../../framework/src/flux/action'; +import { Feature } from "../model/Feature"; +import { HighlightLinkAction, HighlightSiteAction, ZoomToSearchResultAction, AddAlarmAction, SetCoordinatesAction, SetStatistics, SetIconSwitchAction, RemoveHighlightingAction } from '../actions/mapActions'; + +export type location = {lat: number, lon:number} + +export type mapState = { + selectedLink: Feature | null, + selectedSite: Feature | null, + zoomToElement: location | null, + alarmlement: Feature|null, + lat: number, + lon: number, + zoom: number, + statistics:{links: string, sites: string}, + allowIconSwitch: boolean +} + +const initialState: mapState ={ + selectedLink: null, + selectedSite: null, + zoomToElement: null, + alarmlement: null, + lat: 52, + lon: 13, + zoom: 10, + statistics:{links:"Not counted yet.", sites: "Not counted yet."}, + allowIconSwitch: true +} + +export const MapReducer: IActionHandler<mapState> = (state=initialState, action: any) => { + + if(action instanceof HighlightLinkAction){ + + state = Object.assign({}, state, {selectedSite: null, selectedLink:{type: "Feature", properties:{id:action.link.id, type: action.link.type}, geometry:{type:"LineString", coordinates:[[action.link.locationA.lon,action.link.locationA.lat ],[action.link.locationB.lon,action.link.locationB.lat ]]}}}) + + + } + else if(action instanceof HighlightSiteAction){ + + state = Object.assign({}, state, {selectedLink: null, selectedSite:{type: "Feature", properties: {id: action.site.name, type:action.site.type}, geometry:{type:"Point", coordinates:[action.site.geoLocation.lon,action.site.geoLocation.lat ]}}}) + + }else if (action instanceof ZoomToSearchResultAction){ + state = Object.assign({}, state, {zoomToElement:{lat: action.lat, lon: action.lon}}); + }else if (action instanceof AddAlarmAction){ + state = Object.assign({}, state, {alarmlement:action.element}); + + }else if(action instanceof SetCoordinatesAction){ + state = Object.assign({}, state, {lat:action.lat, lon: action.lon, zoom:action.zoom}); + + }else if(action instanceof SetStatistics){ + state = Object.assign({}, state, {statistics:{sites: action.siteCount, links: action.linkCount}}); + + }else if (action instanceof SetIconSwitchAction){ + state = Object.assign({}, state, {allowIconSwitch: action.enable}); + + }else if(action instanceof RemoveHighlightingAction){ + state = Object.assign({}, state, {selectedLink: null, selectedSite:null}) + + } + + return state; +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/handlers/popupReducer.ts b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/popupReducer.ts new file mode 100644 index 000000000..dcac9c9c2 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/popupReducer.ts @@ -0,0 +1,50 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { IActionHandler } from '../../../../framework/src/flux/action'; +import { SelectMultipleLinksAction, SelectMultipleSitesAction, SetPopupPositionAction } from "../actions/popupActions"; + +export type popupStoreState = { + selectionPendingForIds: string[], + pendingDataType: "link"|"site"| "", + position: { top: number, left: number } +}; + +const initialState: popupStoreState = { + selectionPendingForIds: [], + pendingDataType: "", + position: { top: 0, left: 0 } +}; + +export const PopupsReducer: IActionHandler<popupStoreState> = (state = initialState, action) => { + + if(action instanceof SelectMultipleLinksAction){ + state = Object.assign({}, state, { selectionPendingForIds: action.ids, pendingDataType: "link", isSelectionNeeded: true }); + + }else if(action instanceof SelectMultipleSitesAction){ + state = Object.assign({}, state, { selectionPendingForIds: action.ids, pendingDataType: "site", isSelectionNeeded: true }); + + }else if(action instanceof SetPopupPositionAction){ + state= Object.assign({}, state, {position:{top:action.top, left: action.left}}) + + } + + + return state; + +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/handlers/rootReducer.ts b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/rootReducer.ts new file mode 100644 index 000000000..c9c475411 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/rootReducer.ts @@ -0,0 +1,50 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { combineActionHandler } from '../../../../framework/src/flux/middleware'; + +import { DetailsReducer, DetailsStoreState } from "./detailsReducer"; +import { PopupsReducer, popupStoreState } from "./popupReducer"; +import { MapReducer, mapState } from "./mapReducer"; +import { SearchReducer, searchState } from "./searchReducer"; +import { connectivityState, ConnectivityReducer } from './connectivityReducer'; + +export interface INetworkAppStoreState{ + details: DetailsStoreState, + popup: popupStoreState, + map: mapState, + search: searchState, + connectivity: connectivityState +} + +declare module '../../../../framework/src/store/applicationStore' { + interface IApplicationStoreState { + network: INetworkAppStoreState + } + } + +const appHandler = { + details: DetailsReducer, + popup: PopupsReducer, + map: MapReducer, + search: SearchReducer, + connectivity: ConnectivityReducer}; + +export const networkmapRootHandler = combineActionHandler<INetworkAppStoreState>(appHandler) + +export default networkmapRootHandler;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/handlers/searchReducer.ts b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/searchReducer.ts new file mode 100644 index 000000000..68aade477 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/handlers/searchReducer.ts @@ -0,0 +1,33 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { IActionHandler } from '../../../../framework/src/flux/action'; +import { SetSearchValueAction } from "../actions/searchAction"; + +export type searchState = {value: string}; + +const initialState: searchState = {value: ''}; + +export const SearchReducer: IActionHandler<searchState> =(state=initialState, action)=> { + + if(action instanceof SetSearchValueAction){ + state = Object.assign({}, state, { value: action.value }); + } + + return state; +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/index.html b/sdnr/wt/odlux/apps/networkMapApp/src/index.html new file mode 100644 index 000000000..9a7f77a29 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/index.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta http-equiv="X-UA-Compatible" content="ie=edge"> + <!-- <link rel="stylesheet" href="./vendor.css" > --> + <title>Networkmap App</title> +</head> + +<body> + <div id="app"></div> + <script type="text/javascript" src="./require.js"></script> + <script type="text/javascript" src="./config.js"></script> + <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.8.1/mapbox-gl.css' rel='stylesheet' /> + + <script> + // run the application + require(["app","connectApp","faultApp", "networkMapApp", "configurationApp", "linkCalculationApp"], function (app, connectApp, faultApp, networkMapApp, configurationApp, linkCalculationApp) { + connectApp.register(); + //faultApp.register(); + configurationApp.register(); + linkCalculationApp.register(); + networkMapApp.register(); + app("./app.tsx").runApplication(); + }); + </script> +</body> + +</html>
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/model/Feature.ts b/sdnr/wt/odlux/apps/networkMapApp/src/model/Feature.ts new file mode 100644 index 000000000..c4f9ad1cb --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/model/Feature.ts @@ -0,0 +1,25 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +export type Feature = {type: "Feature", properties: {id: string, type?: string}, geometry: Geometry} + +export type Geometry = Point | LineString; + +type Point = {type: "Point", coordinates: number[]} + +type LineString ={type: "LineString", coordinates: number[][]}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/model/count.ts b/sdnr/wt/odlux/apps/networkMapApp/src/model/count.ts new file mode 100644 index 000000000..726e2ff76 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/model/count.ts @@ -0,0 +1,19 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +export type elementCount ={sites: string, links: string}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/model/historyEntry.ts b/sdnr/wt/odlux/apps/networkMapApp/src/model/historyEntry.ts new file mode 100644 index 000000000..707ff3d2a --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/model/historyEntry.ts @@ -0,0 +1,22 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { site } from "./site"; +import { link } from "./link"; + +export type HistoryEntry={id: string, data: site|link};
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/model/link.ts b/sdnr/wt/odlux/apps/networkMapApp/src/model/link.ts new file mode 100644 index 000000000..e11be1a68 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/model/link.ts @@ -0,0 +1,30 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +export type link = {id: string, + name: string, + length: number, + calculatedLength: number, + type: string, + siteA: string, + siteB: string, + azimuthA: number, + azimuthB: number, + locationA: { lon: number, lat: number, amsl?:number, antennaHeight?: number }, + locationB: { lon: number, lat: number, amsl?:number, antennaHeight?: number }, + };
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/model/site.ts b/sdnr/wt/odlux/apps/networkMapApp/src/model/site.ts new file mode 100644 index 000000000..79af65377 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/model/site.ts @@ -0,0 +1,43 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { link } from "./link"; + +export type site = { + id: string, + name: string, + address?: string, + heighAGLInMeters?: number, //AboveGroundLevel + antennaHeightAGLInMeters?: number, + type?: string, + operator: string, + geoLocation:{lon: number, lat: number}, + devices: Device[], + links: link[] +} + +export type Device = { + id: string, + type: string, + name: string, + manufacture: string, + owner: string, + status?: string, + port: number[], + simulatorId?: string, +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/pluginTransport.tsx b/sdnr/wt/odlux/apps/networkMapApp/src/pluginTransport.tsx new file mode 100644 index 000000000..67c75cecf --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/pluginTransport.tsx @@ -0,0 +1,85 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +// app configuration and main entry point for the app + +import * as React from "react"; +import { faMapMarked } from '@fortawesome/free-solid-svg-icons'; // select app icon +import applicationManager from '../../../framework/src/services/applicationManager'; + + +import { networkmapRootHandler } from './handlers/rootReducer'; +import MainView from "./App"; +import { subscribe, IFormatedMessage } from "../../../framework/src/services/notificationService"; +import applicationApi from "../../../framework/src/services/applicationApi"; +import { UpdateDetailsView } from "./actions/detailsAction"; +import { findSiteToAlarm } from "./actions/mapActions"; +import { URL_BASEPATH } from "./config"; + +const App : React.SFC = (props) => { + return <MainView /> +}; + +export function register() { + applicationManager.registerApplication({ + name: URL_BASEPATH, // used as name of state as well + icon: faMapMarked, + rootActionHandler: networkmapRootHandler, + rootComponent: App, + menuEntry: "Network Map" + }); +} + +type ObjectNotification = { + counter: string; + nodeName: string; + objectId: string; + timeStamp: string; +} + +type FaultAlarmNotification = { + id: string; + nodeName: string; + counter: number; + timeStamp: string; + objectId: string; + problem: string; + severity: null | 'Warning' | 'Minor' | 'Major' | 'Critical'; + type: string; + sourceType: string; +} +/* +// subscribe to the websocket notifications from connect +subscribe<ObjectNotification & IFormatedMessage>(["ObjectCreationNotification", "ObjectDeletionNotification", "AttributeValueChangedNotification"], (msg => { + const store = applicationApi.applicationStore; + + //store && store.dispatch(UpdateDetailsView(msg.nodeName)) + +})); + + +subscribe<FaultAlarmNotification & IFormatedMessage>("ProblemNotification", (fault => { + const store = applicationApi && applicationApi.applicationStore; + if (fault && store) { + // store.dispatch(findSiteToAlarm(fault.nodeName)); + + + } +})); + +*/
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/styles/index.css b/sdnr/wt/odlux/apps/networkMapApp/src/styles/index.css new file mode 100644 index 000000000..ec2585e8c --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/styles/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/styles/mapbox-gl.css b/sdnr/wt/odlux/apps/networkMapApp/src/styles/mapbox-gl.css new file mode 100644 index 000000000..03c479af9 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/styles/mapbox-gl.css @@ -0,0 +1 @@ +.mapboxgl-map{font:12px/20px Helvetica Neue,Arial,Helvetica,sans-serif;overflow:hidden;position:relative;-webkit-tap-highlight-color:rgba(0,0,0,0);text-align:left}.mapboxgl-map:-webkit-full-screen{width:100%;height:100%}.mapboxgl-canary{background-color:salmon}.mapboxgl-canvas-container.mapboxgl-interactive,.mapboxgl-ctrl-group button.mapboxgl-ctrl-compass{cursor:-webkit-grab;cursor:-moz-grab;cursor:grab;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.mapboxgl-canvas-container.mapboxgl-interactive.mapboxgl-track-pointer{cursor:pointer}.mapboxgl-canvas-container.mapboxgl-interactive:active,.mapboxgl-ctrl-group button.mapboxgl-ctrl-compass:active{cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate,.mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate .mapboxgl-canvas{touch-action:pan-x pan-y}.mapboxgl-canvas-container.mapboxgl-touch-drag-pan,.mapboxgl-canvas-container.mapboxgl-touch-drag-pan .mapboxgl-canvas{touch-action:pinch-zoom}.mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate.mapboxgl-touch-drag-pan,.mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate.mapboxgl-touch-drag-pan .mapboxgl-canvas{touch-action:none}.mapboxgl-ctrl-bottom-left,.mapboxgl-ctrl-bottom-right,.mapboxgl-ctrl-top-left,.mapboxgl-ctrl-top-right{position:absolute;pointer-events:none;z-index:2}.mapboxgl-ctrl-top-left{top:0;left:0}.mapboxgl-ctrl-top-right{top:0;right:0}.mapboxgl-ctrl-bottom-left{bottom:0;left:0}.mapboxgl-ctrl-bottom-right{right:0;bottom:0}.mapboxgl-ctrl{clear:both;pointer-events:auto;transform:translate(0)}.mapboxgl-ctrl-top-left .mapboxgl-ctrl{margin:10px 0 0 10px;float:left}.mapboxgl-ctrl-top-right .mapboxgl-ctrl{margin:10px 10px 0 0;float:right}.mapboxgl-ctrl-bottom-left .mapboxgl-ctrl{margin:0 0 10px 10px;float:left}.mapboxgl-ctrl-bottom-right .mapboxgl-ctrl{margin:0 10px 10px 0;float:right}.mapboxgl-ctrl-group{border-radius:4px;background:#fff}.mapboxgl-ctrl-group:not(:empty){-moz-box-shadow:0 0 2px rgba(0,0,0,.1);-webkit-box-shadow:0 0 2px rgba(0,0,0,.1);box-shadow:0 0 0 2px rgba(0,0,0,.1)}@media (-ms-high-contrast:active){.mapboxgl-ctrl-group:not(:empty){box-shadow:0 0 0 2px ButtonText}}.mapboxgl-ctrl-group button{width:29px;height:29px;display:block;padding:0;outline:none;border:0;box-sizing:border-box;background-color:transparent;cursor:pointer}.mapboxgl-ctrl-group button+button{border-top:1px solid #ddd}.mapboxgl-ctrl button .mapboxgl-ctrl-icon{display:block;width:100%;height:100%;background-repeat:no-repeat;background-position:50%}@media (-ms-high-contrast:active){.mapboxgl-ctrl-icon{background-color:transparent}.mapboxgl-ctrl-group button+button{border-top:1px solid ButtonText}}.mapboxgl-ctrl button::-moz-focus-inner{border:0;padding:0}.mapboxgl-ctrl-group button:focus{box-shadow:0 0 2px 2px #0096ff}.mapboxgl-ctrl button:disabled{cursor:not-allowed}.mapboxgl-ctrl button:disabled .mapboxgl-ctrl-icon{opacity:.25}.mapboxgl-ctrl button:not(:disabled):hover{background-color:rgba(0,0,0,.05)}.mapboxgl-ctrl-group button:focus:focus-visible{box-shadow:0 0 2px 2px #0096ff}.mapboxgl-ctrl-group button:focus:not(:focus-visible){box-shadow:none}.mapboxgl-ctrl-group button:focus:first-child{border-radius:4px 4px 0 0}.mapboxgl-ctrl-group button:focus:last-child{border-radius:0 0 4px 4px}.mapboxgl-ctrl-group button:focus:only-child{border-radius:inherit}.mapboxgl-ctrl button.mapboxgl-ctrl-zoom-out .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M10 13c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h9c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-9z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M14.5 8.5c-.75 0-1.5.75-1.5 1.5v3h-3c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h3v3c0 .75.75 1.5 1.5 1.5S16 19.75 16 19v-3h3c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-3v-3c0-.75-.75-1.5-1.5-1.5z'/%3E%3C/svg%3E")}@media (-ms-high-contrast:active){.mapboxgl-ctrl button.mapboxgl-ctrl-zoom-out .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23fff'%3E%3Cpath d='M10 13c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h9c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-9z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23fff'%3E%3Cpath d='M14.5 8.5c-.75 0-1.5.75-1.5 1.5v3h-3c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h3v3c0 .75.75 1.5 1.5 1.5S16 19.75 16 19v-3h3c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-3v-3c0-.75-.75-1.5-1.5-1.5z'/%3E%3C/svg%3E")}}@media (-ms-high-contrast:black-on-white){.mapboxgl-ctrl button.mapboxgl-ctrl-zoom-out .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10 13c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h9c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-9z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M14.5 8.5c-.75 0-1.5.75-1.5 1.5v3h-3c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h3v3c0 .75.75 1.5 1.5 1.5S16 19.75 16 19v-3h3c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-3v-3c0-.75-.75-1.5-1.5-1.5z'/%3E%3C/svg%3E")}}.mapboxgl-ctrl button.mapboxgl-ctrl-fullscreen .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M24 16v5.5c0 1.75-.75 2.5-2.5 2.5H16v-1l3-1.5-4-5.5 1-1 5.5 4 1.5-3h1zM6 16l1.5 3 5.5-4 1 1-4 5.5 3 1.5v1H7.5C5.75 24 5 23.25 5 21.5V16h1zm7-11v1l-3 1.5 4 5.5-1 1-5.5-4L6 13H5V7.5C5 5.75 5.75 5 7.5 5H13zm11 2.5c0-1.75-.75-2.5-2.5-2.5H16v1l3 1.5-4 5.5 1 1 5.5-4 1.5 3h1V7.5z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-shrink .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M18.5 16c-1.75 0-2.5.75-2.5 2.5V24h1l1.5-3 5.5 4 1-1-4-5.5 3-1.5v-1h-5.5zM13 18.5c0-1.75-.75-2.5-2.5-2.5H5v1l3 1.5L4 24l1 1 5.5-4 1.5 3h1v-5.5zm3-8c0 1.75.75 2.5 2.5 2.5H24v-1l-3-1.5L25 5l-1-1-5.5 4L17 5h-1v5.5zM10.5 13c1.75 0 2.5-.75 2.5-2.5V5h-1l-1.5 3L5 4 4 5l4 5.5L5 12v1h5.5z'/%3E%3C/svg%3E")}@media (-ms-high-contrast:active){.mapboxgl-ctrl button.mapboxgl-ctrl-fullscreen .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23fff'%3E%3Cpath d='M24 16v5.5c0 1.75-.75 2.5-2.5 2.5H16v-1l3-1.5-4-5.5 1-1 5.5 4 1.5-3h1zM6 16l1.5 3 5.5-4 1 1-4 5.5 3 1.5v1H7.5C5.75 24 5 23.25 5 21.5V16h1zm7-11v1l-3 1.5 4 5.5-1 1-5.5-4L6 13H5V7.5C5 5.75 5.75 5 7.5 5H13zm11 2.5c0-1.75-.75-2.5-2.5-2.5H16v1l3 1.5-4 5.5 1 1 5.5-4 1.5 3h1V7.5z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-shrink .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23fff'%3E%3Cpath d='M18.5 16c-1.75 0-2.5.75-2.5 2.5V24h1l1.5-3 5.5 4 1-1-4-5.5 3-1.5v-1h-5.5zM13 18.5c0-1.75-.75-2.5-2.5-2.5H5v1l3 1.5L4 24l1 1 5.5-4 1.5 3h1v-5.5zm3-8c0 1.75.75 2.5 2.5 2.5H24v-1l-3-1.5L25 5l-1-1-5.5 4L17 5h-1v5.5zM10.5 13c1.75 0 2.5-.75 2.5-2.5V5h-1l-1.5 3L5 4 4 5l4 5.5L5 12v1h5.5z'/%3E%3C/svg%3E")}}@media (-ms-high-contrast:black-on-white){.mapboxgl-ctrl button.mapboxgl-ctrl-fullscreen .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M24 16v5.5c0 1.75-.75 2.5-2.5 2.5H16v-1l3-1.5-4-5.5 1-1 5.5 4 1.5-3h1zM6 16l1.5 3 5.5-4 1 1-4 5.5 3 1.5v1H7.5C5.75 24 5 23.25 5 21.5V16h1zm7-11v1l-3 1.5 4 5.5-1 1-5.5-4L6 13H5V7.5C5 5.75 5.75 5 7.5 5H13zm11 2.5c0-1.75-.75-2.5-2.5-2.5H16v1l3 1.5-4 5.5 1 1 5.5-4 1.5 3h1V7.5z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-shrink .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M18.5 16c-1.75 0-2.5.75-2.5 2.5V24h1l1.5-3 5.5 4 1-1-4-5.5 3-1.5v-1h-5.5zM13 18.5c0-1.75-.75-2.5-2.5-2.5H5v1l3 1.5L4 24l1 1 5.5-4 1.5 3h1v-5.5zm3-8c0 1.75.75 2.5 2.5 2.5H24v-1l-3-1.5L25 5l-1-1-5.5 4L17 5h-1v5.5zM10.5 13c1.75 0 2.5-.75 2.5-2.5V5h-1l-1.5 3L5 4 4 5l4 5.5L5 12v1h5.5z'/%3E%3C/svg%3E")}}.mapboxgl-ctrl button.mapboxgl-ctrl-compass .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M10.5 14l4-8 4 8h-8z'/%3E%3Cpath d='M10.5 16l4 8 4-8h-8z' fill='%23ccc'/%3E%3C/svg%3E")}@media (-ms-high-contrast:active){.mapboxgl-ctrl button.mapboxgl-ctrl-compass .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23fff'%3E%3Cpath d='M10.5 14l4-8 4 8h-8z'/%3E%3Cpath d='M10.5 16l4 8 4-8h-8z' fill='%23999'/%3E%3C/svg%3E")}}@media (-ms-high-contrast:black-on-white){.mapboxgl-ctrl button.mapboxgl-ctrl-compass .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10.5 14l4-8 4 8h-8z'/%3E%3Cpath d='M10.5 16l4 8 4-8h-8z' fill='%23ccc'/%3E%3C/svg%3E")}}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate:disabled .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23aaa'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3Cpath d='M14 5l1 1-9 9-1-1 9-9z' fill='red'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-active .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%2333b5e5'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-active-error .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23e58978'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-background .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%2333b5e5'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-background-error .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23e54e33'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-waiting .mapboxgl-ctrl-icon{-webkit-animation:mapboxgl-spin 2s linear infinite;-moz-animation:mapboxgl-spin 2s infinite linear;-o-animation:mapboxgl-spin 2s infinite linear;-ms-animation:mapboxgl-spin 2s infinite linear;animation:mapboxgl-spin 2s linear infinite}@media (-ms-high-contrast:active){.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23fff'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate:disabled .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23999'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3Cpath d='M14 5l1 1-9 9-1-1 9-9z' fill='red'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-active .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%2333b5e5'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-active-error .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23e58978'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-background .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%2333b5e5'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-background-error .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23e54e33'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3C/svg%3E")}}@media (-ms-high-contrast:black-on-white){.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate:disabled .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23666'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3Cpath d='M14 5l1 1-9 9-1-1 9-9z' fill='red'/%3E%3C/svg%3E")}}@-webkit-keyframes mapboxgl-spin{0%{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(1turn)}}@-moz-keyframes mapboxgl-spin{0%{-moz-transform:rotate(0deg)}to{-moz-transform:rotate(1turn)}}@-o-keyframes mapboxgl-spin{0%{-o-transform:rotate(0deg)}to{-o-transform:rotate(1turn)}}@-ms-keyframes mapboxgl-spin{0%{-ms-transform:rotate(0deg)}to{-ms-transform:rotate(1turn)}}@keyframes mapboxgl-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}a.mapboxgl-ctrl-logo{width:88px;height:23px;margin:0 0 -4px -4px;display:block;background-repeat:no-repeat;cursor:pointer;overflow:hidden;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='88' height='23' viewBox='0 0 88 23' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' fill-rule='evenodd'%3E%3Cdefs%3E%3Cpath id='a' d='M11.5 2.25c5.105 0 9.25 4.145 9.25 9.25s-4.145 9.25-9.25 9.25-9.25-4.145-9.25-9.25 4.145-9.25 9.25-9.25zM6.997 15.983c-.051-.338-.828-5.802 2.233-8.873a4.395 4.395 0 013.13-1.28c1.27 0 2.49.51 3.39 1.42.91.9 1.42 2.12 1.42 3.39 0 1.18-.449 2.301-1.28 3.13C12.72 16.93 7 16 7 16l-.003-.017zM15.3 10.5l-2 .8-.8 2-.8-2-2-.8 2-.8.8-2 .8 2 2 .8z'/%3E%3Cpath id='b' d='M50.63 8c.13 0 .23.1.23.23V9c.7-.76 1.7-1.18 2.73-1.18 2.17 0 3.95 1.85 3.95 4.17s-1.77 4.19-3.94 4.19c-1.04 0-2.03-.43-2.74-1.18v3.77c0 .13-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V8.23c0-.12.1-.23.23-.23h1.4zm-3.86.01c.01 0 .01 0 .01-.01.13 0 .22.1.22.22v7.55c0 .12-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V15c-.7.76-1.69 1.19-2.73 1.19-2.17 0-3.94-1.87-3.94-4.19 0-2.32 1.77-4.19 3.94-4.19 1.03 0 2.02.43 2.73 1.18v-.75c0-.12.1-.23.23-.23h1.4zm26.375-.19a4.24 4.24 0 00-4.16 3.29c-.13.59-.13 1.19 0 1.77a4.233 4.233 0 004.17 3.3c2.35 0 4.26-1.87 4.26-4.19 0-2.32-1.9-4.17-4.27-4.17zM60.63 5c.13 0 .23.1.23.23v3.76c.7-.76 1.7-1.18 2.73-1.18 1.88 0 3.45 1.4 3.84 3.28.13.59.13 1.2 0 1.8-.39 1.88-1.96 3.29-3.84 3.29-1.03 0-2.02-.43-2.73-1.18v.77c0 .12-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V5.23c0-.12.1-.23.23-.23h1.4zm-34 11h-1.4c-.13 0-.23-.11-.23-.23V8.22c.01-.13.1-.22.23-.22h1.4c.13 0 .22.11.23.22v.68c.5-.68 1.3-1.09 2.16-1.1h.03c1.09 0 2.09.6 2.6 1.55.45-.95 1.4-1.55 2.44-1.56 1.62 0 2.93 1.25 2.9 2.78l.03 5.2c0 .13-.1.23-.23.23h-1.41c-.13 0-.23-.11-.23-.23v-4.59c0-.98-.74-1.71-1.62-1.71-.8 0-1.46.7-1.59 1.62l.01 4.68c0 .13-.11.23-.23.23h-1.41c-.13 0-.23-.11-.23-.23v-4.59c0-.98-.74-1.71-1.62-1.71-.85 0-1.54.79-1.6 1.8v4.5c0 .13-.1.23-.23.23zm53.615 0h-1.61c-.04 0-.08-.01-.12-.03-.09-.06-.13-.19-.06-.28l2.43-3.71-2.39-3.65a.213.213 0 01-.03-.12c0-.12.09-.21.21-.21h1.61c.13 0 .24.06.3.17l1.41 2.37 1.4-2.37a.34.34 0 01.3-.17h1.6c.04 0 .08.01.12.03.09.06.13.19.06.28l-2.37 3.65 2.43 3.7c0 .05.01.09.01.13 0 .12-.09.21-.21.21h-1.61c-.13 0-.24-.06-.3-.17l-1.44-2.42-1.44 2.42a.34.34 0 01-.3.17zm-7.12-1.49c-1.33 0-2.42-1.12-2.42-2.51 0-1.39 1.08-2.52 2.42-2.52 1.33 0 2.42 1.12 2.42 2.51 0 1.39-1.08 2.51-2.42 2.52zm-19.865 0c-1.32 0-2.39-1.11-2.42-2.48v-.07c.02-1.38 1.09-2.49 2.4-2.49 1.32 0 2.41 1.12 2.41 2.51 0 1.39-1.07 2.52-2.39 2.53zm-8.11-2.48c-.01 1.37-1.09 2.47-2.41 2.47s-2.42-1.12-2.42-2.51c0-1.39 1.08-2.52 2.4-2.52 1.33 0 2.39 1.11 2.41 2.48l.02.08zm18.12 2.47c-1.32 0-2.39-1.11-2.41-2.48v-.06c.02-1.38 1.09-2.48 2.41-2.48s2.42 1.12 2.42 2.51c0 1.39-1.09 2.51-2.42 2.51z'/%3E%3C/defs%3E%3Cmask id='c'%3E%3Crect width='100%25' height='100%25' fill='%23fff'/%3E%3Cuse xlink:href='%23a'/%3E%3Cuse xlink:href='%23b'/%3E%3C/mask%3E%3Cg opacity='.3' stroke='%23000' stroke-width='3'%3E%3Ccircle mask='url(%23c)' cx='11.5' cy='11.5' r='9.25'/%3E%3Cuse xlink:href='%23b' mask='url(%23c)'/%3E%3C/g%3E%3Cg opacity='.9' fill='%23fff'%3E%3Cuse xlink:href='%23a'/%3E%3Cuse xlink:href='%23b'/%3E%3C/g%3E%3C/svg%3E")}a.mapboxgl-ctrl-logo.mapboxgl-compact{width:23px}@media (-ms-high-contrast:active){a.mapboxgl-ctrl-logo{background-color:transparent;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='88' height='23' viewBox='0 0 88 23' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' fill-rule='evenodd'%3E%3Cdefs%3E%3Cpath id='a' d='M11.5 2.25c5.105 0 9.25 4.145 9.25 9.25s-4.145 9.25-9.25 9.25-9.25-4.145-9.25-9.25 4.145-9.25 9.25-9.25zM6.997 15.983c-.051-.338-.828-5.802 2.233-8.873a4.395 4.395 0 013.13-1.28c1.27 0 2.49.51 3.39 1.42.91.9 1.42 2.12 1.42 3.39 0 1.18-.449 2.301-1.28 3.13C12.72 16.93 7 16 7 16l-.003-.017zM15.3 10.5l-2 .8-.8 2-.8-2-2-.8 2-.8.8-2 .8 2 2 .8z'/%3E%3Cpath id='b' d='M50.63 8c.13 0 .23.1.23.23V9c.7-.76 1.7-1.18 2.73-1.18 2.17 0 3.95 1.85 3.95 4.17s-1.77 4.19-3.94 4.19c-1.04 0-2.03-.43-2.74-1.18v3.77c0 .13-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V8.23c0-.12.1-.23.23-.23h1.4zm-3.86.01c.01 0 .01 0 .01-.01.13 0 .22.1.22.22v7.55c0 .12-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V15c-.7.76-1.69 1.19-2.73 1.19-2.17 0-3.94-1.87-3.94-4.19 0-2.32 1.77-4.19 3.94-4.19 1.03 0 2.02.43 2.73 1.18v-.75c0-.12.1-.23.23-.23h1.4zm26.375-.19a4.24 4.24 0 00-4.16 3.29c-.13.59-.13 1.19 0 1.77a4.233 4.233 0 004.17 3.3c2.35 0 4.26-1.87 4.26-4.19 0-2.32-1.9-4.17-4.27-4.17zM60.63 5c.13 0 .23.1.23.23v3.76c.7-.76 1.7-1.18 2.73-1.18 1.88 0 3.45 1.4 3.84 3.28.13.59.13 1.2 0 1.8-.39 1.88-1.96 3.29-3.84 3.29-1.03 0-2.02-.43-2.73-1.18v.77c0 .12-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V5.23c0-.12.1-.23.23-.23h1.4zm-34 11h-1.4c-.13 0-.23-.11-.23-.23V8.22c.01-.13.1-.22.23-.22h1.4c.13 0 .22.11.23.22v.68c.5-.68 1.3-1.09 2.16-1.1h.03c1.09 0 2.09.6 2.6 1.55.45-.95 1.4-1.55 2.44-1.56 1.62 0 2.93 1.25 2.9 2.78l.03 5.2c0 .13-.1.23-.23.23h-1.41c-.13 0-.23-.11-.23-.23v-4.59c0-.98-.74-1.71-1.62-1.71-.8 0-1.46.7-1.59 1.62l.01 4.68c0 .13-.11.23-.23.23h-1.41c-.13 0-.23-.11-.23-.23v-4.59c0-.98-.74-1.71-1.62-1.71-.85 0-1.54.79-1.6 1.8v4.5c0 .13-.1.23-.23.23zm53.615 0h-1.61c-.04 0-.08-.01-.12-.03-.09-.06-.13-.19-.06-.28l2.43-3.71-2.39-3.65a.213.213 0 01-.03-.12c0-.12.09-.21.21-.21h1.61c.13 0 .24.06.3.17l1.41 2.37 1.4-2.37a.34.34 0 01.3-.17h1.6c.04 0 .08.01.12.03.09.06.13.19.06.28l-2.37 3.65 2.43 3.7c0 .05.01.09.01.13 0 .12-.09.21-.21.21h-1.61c-.13 0-.24-.06-.3-.17l-1.44-2.42-1.44 2.42a.34.34 0 01-.3.17zm-7.12-1.49c-1.33 0-2.42-1.12-2.42-2.51 0-1.39 1.08-2.52 2.42-2.52 1.33 0 2.42 1.12 2.42 2.51 0 1.39-1.08 2.51-2.42 2.52zm-19.865 0c-1.32 0-2.39-1.11-2.42-2.48v-.07c.02-1.38 1.09-2.49 2.4-2.49 1.32 0 2.41 1.12 2.41 2.51 0 1.39-1.07 2.52-2.39 2.53zm-8.11-2.48c-.01 1.37-1.09 2.47-2.41 2.47s-2.42-1.12-2.42-2.51c0-1.39 1.08-2.52 2.4-2.52 1.33 0 2.39 1.11 2.41 2.48l.02.08zm18.12 2.47c-1.32 0-2.39-1.11-2.41-2.48v-.06c.02-1.38 1.09-2.48 2.41-2.48s2.42 1.12 2.42 2.51c0 1.39-1.09 2.51-2.42 2.51z'/%3E%3C/defs%3E%3Cmask id='c'%3E%3Crect width='100%25' height='100%25' fill='%23fff'/%3E%3Cuse xlink:href='%23a'/%3E%3Cuse xlink:href='%23b'/%3E%3C/mask%3E%3Cg stroke='%23000' stroke-width='3'%3E%3Ccircle mask='url(%23c)' cx='11.5' cy='11.5' r='9.25'/%3E%3Cuse xlink:href='%23b' mask='url(%23c)'/%3E%3C/g%3E%3Cg fill='%23fff'%3E%3Cuse xlink:href='%23a'/%3E%3Cuse xlink:href='%23b'/%3E%3C/g%3E%3C/svg%3E")}}@media (-ms-high-contrast:black-on-white){a.mapboxgl-ctrl-logo{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='88' height='23' viewBox='0 0 88 23' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' fill-rule='evenodd'%3E%3Cdefs%3E%3Cpath id='a' d='M11.5 2.25c5.105 0 9.25 4.145 9.25 9.25s-4.145 9.25-9.25 9.25-9.25-4.145-9.25-9.25 4.145-9.25 9.25-9.25zM6.997 15.983c-.051-.338-.828-5.802 2.233-8.873a4.395 4.395 0 013.13-1.28c1.27 0 2.49.51 3.39 1.42.91.9 1.42 2.12 1.42 3.39 0 1.18-.449 2.301-1.28 3.13C12.72 16.93 7 16 7 16l-.003-.017zM15.3 10.5l-2 .8-.8 2-.8-2-2-.8 2-.8.8-2 .8 2 2 .8z'/%3E%3Cpath id='b' d='M50.63 8c.13 0 .23.1.23.23V9c.7-.76 1.7-1.18 2.73-1.18 2.17 0 3.95 1.85 3.95 4.17s-1.77 4.19-3.94 4.19c-1.04 0-2.03-.43-2.74-1.18v3.77c0 .13-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V8.23c0-.12.1-.23.23-.23h1.4zm-3.86.01c.01 0 .01 0 .01-.01.13 0 .22.1.22.22v7.55c0 .12-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V15c-.7.76-1.69 1.19-2.73 1.19-2.17 0-3.94-1.87-3.94-4.19 0-2.32 1.77-4.19 3.94-4.19 1.03 0 2.02.43 2.73 1.18v-.75c0-.12.1-.23.23-.23h1.4zm26.375-.19a4.24 4.24 0 00-4.16 3.29c-.13.59-.13 1.19 0 1.77a4.233 4.233 0 004.17 3.3c2.35 0 4.26-1.87 4.26-4.19 0-2.32-1.9-4.17-4.27-4.17zM60.63 5c.13 0 .23.1.23.23v3.76c.7-.76 1.7-1.18 2.73-1.18 1.88 0 3.45 1.4 3.84 3.28.13.59.13 1.2 0 1.8-.39 1.88-1.96 3.29-3.84 3.29-1.03 0-2.02-.43-2.73-1.18v.77c0 .12-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V5.23c0-.12.1-.23.23-.23h1.4zm-34 11h-1.4c-.13 0-.23-.11-.23-.23V8.22c.01-.13.1-.22.23-.22h1.4c.13 0 .22.11.23.22v.68c.5-.68 1.3-1.09 2.16-1.1h.03c1.09 0 2.09.6 2.6 1.55.45-.95 1.4-1.55 2.44-1.56 1.62 0 2.93 1.25 2.9 2.78l.03 5.2c0 .13-.1.23-.23.23h-1.41c-.13 0-.23-.11-.23-.23v-4.59c0-.98-.74-1.71-1.62-1.71-.8 0-1.46.7-1.59 1.62l.01 4.68c0 .13-.11.23-.23.23h-1.41c-.13 0-.23-.11-.23-.23v-4.59c0-.98-.74-1.71-1.62-1.71-.85 0-1.54.79-1.6 1.8v4.5c0 .13-.1.23-.23.23zm53.615 0h-1.61c-.04 0-.08-.01-.12-.03-.09-.06-.13-.19-.06-.28l2.43-3.71-2.39-3.65a.213.213 0 01-.03-.12c0-.12.09-.21.21-.21h1.61c.13 0 .24.06.3.17l1.41 2.37 1.4-2.37a.34.34 0 01.3-.17h1.6c.04 0 .08.01.12.03.09.06.13.19.06.28l-2.37 3.65 2.43 3.7c0 .05.01.09.01.13 0 .12-.09.21-.21.21h-1.61c-.13 0-.24-.06-.3-.17l-1.44-2.42-1.44 2.42a.34.34 0 01-.3.17zm-7.12-1.49c-1.33 0-2.42-1.12-2.42-2.51 0-1.39 1.08-2.52 2.42-2.52 1.33 0 2.42 1.12 2.42 2.51 0 1.39-1.08 2.51-2.42 2.52zm-19.865 0c-1.32 0-2.39-1.11-2.42-2.48v-.07c.02-1.38 1.09-2.49 2.4-2.49 1.32 0 2.41 1.12 2.41 2.51 0 1.39-1.07 2.52-2.39 2.53zm-8.11-2.48c-.01 1.37-1.09 2.47-2.41 2.47s-2.42-1.12-2.42-2.51c0-1.39 1.08-2.52 2.4-2.52 1.33 0 2.39 1.11 2.41 2.48l.02.08zm18.12 2.47c-1.32 0-2.39-1.11-2.41-2.48v-.06c.02-1.38 1.09-2.48 2.41-2.48s2.42 1.12 2.42 2.51c0 1.39-1.09 2.51-2.42 2.51z'/%3E%3C/defs%3E%3Cmask id='c'%3E%3Crect width='100%25' height='100%25' fill='%23fff'/%3E%3Cuse xlink:href='%23a'/%3E%3Cuse xlink:href='%23b'/%3E%3C/mask%3E%3Cg stroke='%23fff' stroke-width='3' fill='%23fff'%3E%3Ccircle mask='url(%23c)' cx='11.5' cy='11.5' r='9.25'/%3E%3Cuse xlink:href='%23b' mask='url(%23c)'/%3E%3C/g%3E%3Cuse xlink:href='%23a'/%3E%3Cuse xlink:href='%23b'/%3E%3C/svg%3E")}}.mapboxgl-ctrl.mapboxgl-ctrl-attrib{padding:0 5px;background-color:hsla(0,0%,100%,.5);margin:0}@media screen{.mapboxgl-ctrl-attrib.mapboxgl-compact{min-height:20px;padding:0;margin:10px;position:relative;background-color:#fff;border-radius:3px 12px 12px 3px}.mapboxgl-ctrl-attrib.mapboxgl-compact:hover{padding:2px 24px 2px 4px;visibility:visible;margin-top:6px}.mapboxgl-ctrl-bottom-left>.mapboxgl-ctrl-attrib.mapboxgl-compact:hover,.mapboxgl-ctrl-top-left>.mapboxgl-ctrl-attrib.mapboxgl-compact:hover{padding:2px 4px 2px 24px;border-radius:12px 3px 3px 12px}.mapboxgl-ctrl-attrib.mapboxgl-compact .mapboxgl-ctrl-attrib-inner{display:none}.mapboxgl-ctrl-attrib.mapboxgl-compact:hover .mapboxgl-ctrl-attrib-inner{display:block}.mapboxgl-ctrl-attrib.mapboxgl-compact:after{content:"";cursor:pointer;position:absolute;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='24' height='24' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd'%3E%3Cpath d='M4 10a6 6 0 1012 0 6 6 0 10-12 0m5-3a1 1 0 102 0 1 1 0 10-2 0m0 3a1 1 0 112 0v3a1 1 0 11-2 0'/%3E%3C/svg%3E");background-color:hsla(0,0%,100%,.5);width:24px;height:24px;box-sizing:border-box;border-radius:12px}.mapboxgl-ctrl-bottom-right>.mapboxgl-ctrl-attrib.mapboxgl-compact:after{bottom:0;right:0}.mapboxgl-ctrl-top-right>.mapboxgl-ctrl-attrib.mapboxgl-compact:after{top:0;right:0}.mapboxgl-ctrl-top-left>.mapboxgl-ctrl-attrib.mapboxgl-compact:after{top:0;left:0}.mapboxgl-ctrl-bottom-left>.mapboxgl-ctrl-attrib.mapboxgl-compact:after{bottom:0;left:0}}@media screen and (-ms-high-contrast:active){.mapboxgl-ctrl-attrib.mapboxgl-compact:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='24' height='24' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd' fill='%23fff'%3E%3Cpath d='M4 10a6 6 0 1012 0 6 6 0 10-12 0m5-3a1 1 0 102 0 1 1 0 10-2 0m0 3a1 1 0 112 0v3a1 1 0 11-2 0'/%3E%3C/svg%3E")}}@media screen and (-ms-high-contrast:black-on-white){.mapboxgl-ctrl-attrib.mapboxgl-compact:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='24' height='24' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd'%3E%3Cpath d='M4 10a6 6 0 1012 0 6 6 0 10-12 0m5-3a1 1 0 102 0 1 1 0 10-2 0m0 3a1 1 0 112 0v3a1 1 0 11-2 0'/%3E%3C/svg%3E")}}.mapboxgl-ctrl-attrib a{color:rgba(0,0,0,.75);text-decoration:none}.mapboxgl-ctrl-attrib a:hover{color:inherit;text-decoration:underline}.mapboxgl-ctrl-attrib .mapbox-improve-map{font-weight:700;margin-left:2px}.mapboxgl-attrib-empty{display:none}.mapboxgl-ctrl-scale{background-color:hsla(0,0%,100%,.75);font-size:10px;border:2px solid #333;border-top:#333;padding:0 5px;color:#333;box-sizing:border-box}.mapboxgl-popup{position:absolute;top:0;left:0;display:-webkit-flex;display:flex;will-change:transform;pointer-events:none}.mapboxgl-popup-anchor-top,.mapboxgl-popup-anchor-top-left,.mapboxgl-popup-anchor-top-right{-webkit-flex-direction:column;flex-direction:column}.mapboxgl-popup-anchor-bottom,.mapboxgl-popup-anchor-bottom-left,.mapboxgl-popup-anchor-bottom-right{-webkit-flex-direction:column-reverse;flex-direction:column-reverse}.mapboxgl-popup-anchor-left{-webkit-flex-direction:row;flex-direction:row}.mapboxgl-popup-anchor-right{-webkit-flex-direction:row-reverse;flex-direction:row-reverse}.mapboxgl-popup-tip{width:0;height:0;border:10px solid transparent;z-index:1}.mapboxgl-popup-anchor-top .mapboxgl-popup-tip{-webkit-align-self:center;align-self:center;border-top:none;border-bottom-color:#fff}.mapboxgl-popup-anchor-top-left .mapboxgl-popup-tip{-webkit-align-self:flex-start;align-self:flex-start;border-top:none;border-left:none;border-bottom-color:#fff}.mapboxgl-popup-anchor-top-right .mapboxgl-popup-tip{-webkit-align-self:flex-end;align-self:flex-end;border-top:none;border-right:none;border-bottom-color:#fff}.mapboxgl-popup-anchor-bottom .mapboxgl-popup-tip{-webkit-align-self:center;align-self:center;border-bottom:none;border-top-color:#fff}.mapboxgl-popup-anchor-bottom-left .mapboxgl-popup-tip{-webkit-align-self:flex-start;align-self:flex-start;border-bottom:none;border-left:none;border-top-color:#fff}.mapboxgl-popup-anchor-bottom-right .mapboxgl-popup-tip{-webkit-align-self:flex-end;align-self:flex-end;border-bottom:none;border-right:none;border-top-color:#fff}.mapboxgl-popup-anchor-left .mapboxgl-popup-tip{-webkit-align-self:center;align-self:center;border-left:none;border-right-color:#fff}.mapboxgl-popup-anchor-right .mapboxgl-popup-tip{-webkit-align-self:center;align-self:center;border-right:none;border-left-color:#fff}.mapboxgl-popup-close-button{position:absolute;right:0;top:0;border:0;border-radius:0 3px 0 0;cursor:pointer;background-color:transparent}.mapboxgl-popup-close-button:hover{background-color:rgba(0,0,0,.05)}.mapboxgl-popup-content{position:relative;background:#fff;border-radius:3px;box-shadow:0 1px 2px rgba(0,0,0,.1);padding:10px 10px 15px;pointer-events:auto}.mapboxgl-popup-anchor-top-left .mapboxgl-popup-content{border-top-left-radius:0}.mapboxgl-popup-anchor-top-right .mapboxgl-popup-content{border-top-right-radius:0}.mapboxgl-popup-anchor-bottom-left .mapboxgl-popup-content{border-bottom-left-radius:0}.mapboxgl-popup-anchor-bottom-right .mapboxgl-popup-content{border-bottom-right-radius:0}.mapboxgl-popup-track-pointer{display:none}.mapboxgl-popup-track-pointer *{pointer-events:none;user-select:none}.mapboxgl-map:hover .mapboxgl-popup-track-pointer{display:flex}.mapboxgl-map:active .mapboxgl-popup-track-pointer{display:none}.mapboxgl-marker{position:absolute;top:0;left:0;will-change:transform}.mapboxgl-user-location-dot,.mapboxgl-user-location-dot:before{background-color:#1da1f2;width:15px;height:15px;border-radius:50%}.mapboxgl-user-location-dot:before{content:"";position:absolute;-webkit-animation:mapboxgl-user-location-dot-pulse 2s infinite;-moz-animation:mapboxgl-user-location-dot-pulse 2s infinite;-ms-animation:mapboxgl-user-location-dot-pulse 2s infinite;animation:mapboxgl-user-location-dot-pulse 2s infinite}.mapboxgl-user-location-dot:after{border-radius:50%;border:2px solid #fff;content:"";height:19px;left:-2px;position:absolute;top:-2px;width:19px;box-sizing:border-box;box-shadow:0 0 3px rgba(0,0,0,.35)}@-webkit-keyframes mapboxgl-user-location-dot-pulse{0%{-webkit-transform:scale(1);opacity:1}70%{-webkit-transform:scale(3);opacity:0}to{-webkit-transform:scale(1);opacity:0}}@-ms-keyframes mapboxgl-user-location-dot-pulse{0%{-ms-transform:scale(1);opacity:1}70%{-ms-transform:scale(3);opacity:0}to{-ms-transform:scale(1);opacity:0}}@keyframes mapboxgl-user-location-dot-pulse{0%{transform:scale(1);opacity:1}70%{transform:scale(3);opacity:0}to{transform:scale(1);opacity:0}}.mapboxgl-user-location-dot-stale{background-color:#aaa}.mapboxgl-user-location-dot-stale:after{display:none}.mapboxgl-user-location-accuracy-circle{background-color:rgba(29,161,242,.2);width:1px;height:1px;border-radius:100%}.mapboxgl-crosshair,.mapboxgl-crosshair .mapboxgl-interactive,.mapboxgl-crosshair .mapboxgl-interactive:active{cursor:crosshair}.mapboxgl-boxzoom{position:absolute;top:0;left:0;width:0;height:0;background:#fff;border:2px dotted #202020;opacity:.5}@media print{.mapbox-improve-map{display:none}}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapLayers.ts b/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapLayers.ts new file mode 100644 index 000000000..f2cabf501 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapLayers.ts @@ -0,0 +1,518 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import * as mapboxgl from 'mapbox-gl'; +import { Feature } from 'model/Feature'; + +const fibreLinkColor = "#1154d9"; +const microwaveLinkColor="#039903"; + + +export const addBaseLayers = (map: mapboxgl.Map, selectedPoint: Feature|null, selectedLine: Feature|null) => { + + const boundingBox = map.getBounds(); + map.addSource('lines', { + type: 'geojson', + data: { type: "FeatureCollection", features: [] } + }); + + const features = selectedLine !== null ? [selectedLine] : []; + + map.addSource('selectedLine', { + type: 'geojson', + data: { type: "FeatureCollection", features: features } + }); + + map.addSource('points', { + type: 'geojson', + data: { type: "FeatureCollection", features: [] } + }); + + const selectedPointFeature = selectedPoint !== null ? [selectedPoint] : []; + + + map.addSource('selectedPoints', { + type: 'geojson', + data: { type: "FeatureCollection", features: selectedPointFeature } + + }); + + map.addLayer({ + 'id': 'microwave-lines', + 'type': 'line', + 'source': 'lines', + 'layout': { + 'line-join': 'round', + 'line-cap': 'round' + }, + 'paint': { + 'line-color': microwaveLinkColor, + 'line-width': 2 + }, + 'filter': ['==', 'type', 'microwave'] + }); + + map.addLayer({ + 'id': 'fibre-lines', + 'type': 'line', + 'source': 'lines', + 'layout': { + 'line-join': 'round', + 'line-cap': 'round' + }, + 'paint': { + 'line-color': fibreLinkColor, + 'line-width': 2 + }, + 'filter': ['==', 'type', 'fibre'] + }); + + map.addLayer({ + 'id': 'selectedLineMicrowave', + 'type': 'line', + 'source': 'selectedLine', + 'layout': { + 'line-join': 'round', + 'line-cap': 'round' + }, + 'paint': { + 'line-color': microwaveLinkColor, + 'line-width': 4 + }, + 'filter': ['==', 'type', 'microwave'] + }); + + map.addLayer({ + 'id': 'selectedLineFibre', + 'type': 'line', + 'source': 'selectedLine', + 'layout': { + 'line-join': 'round', + 'line-cap': 'round' + }, + 'paint': { + 'line-color': fibreLinkColor, + 'line-width': 4 + }, + 'filter': ['==', 'type', 'fibre'] + }); + + + + map.addLayer({ + id: 'points', + source: 'points', + type: 'circle', + paint: { + 'circle-color': '#11b4da', + 'circle-radius': 7, + 'circle-stroke-width': 1, + 'circle-stroke-color': '#fff' + } + }); + + map.addLayer({ + id: 'selectedPoints', + source: 'selectedPoints', + type: 'circle', + paint: { + 'circle-color': '#116bda', + 'circle-radius': 9, + 'circle-stroke-width': 1, + 'circle-stroke-color': '#fff' + } + }); + + map.addSource("alarmedPoints", { + type: 'geojson', + data: {type:"FeatureCollection", features:[]} + }) + + map.addLayer({ + id: 'alarmedPoints', + source: 'alarmedPoints', + type: 'circle', + paint: { + 'circle-color': '#CC0000', + 'circle-radius': 9, + 'circle-stroke-width': 1, + 'circle-stroke-color': '#fff' + } + }); +} + +export const removeBaseLayers = (map: mapboxgl.Map) => { + + map.removeLayer("points"); + map.removeLayer("lines"); + map.removeLayer('selectedPoints'); + map.removeLayer('selectedLine'); + + map.removeSource("points"); + map.removeSource("lines"); + map.removeSource('selectedPoints'); + map.removeSource('selectedLine'); +} + +let checkedLayers = false; + +const createFilter = (type:'street lamp'|'high rise building'|'data center'|'factory', selectedSiteId?:string) =>{ + + return selectedSiteId === undefined ? ['==', 'type', type] : ["all", ['==', 'type', type], ['!=', 'id', selectedSiteId]] +} + +export const showIconLayers = (map: mapboxgl.Map, show: boolean, selectedSiteId?: string) => { + + const zoom = map.getZoom(); + + if(show){ + + if (zoom > 11) { + + const bounds = map.getBounds(); + + if(map.getLayer('points')!== undefined && map.getLayer('point-lamps')===undefined && !checkedLayers){ + + // if sites don't have a type don't change layers to icons + const elements = map.queryRenderedFeatures( undefined,{ + layers: ['points'], filter:['has', 'type'] + }); + checkedLayers=true; + + if(elements.length>0 && elements.length<1000){ + + if (map.getLayer('point-lamps') === undefined) { + map.removeLayer('points'); + map.setLayoutProperty('alarmedPoints', 'visibility', 'none'); + map.setLayoutProperty('selectedPoints', 'visibility', 'none'); + + map.addLayer({ + 'id': 'point-lamps', + 'type': 'symbol', + 'source': 'points', + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'lamp', + 'icon-size': 0.1 + + }, + 'filter': createFilter("street lamp", selectedSiteId), + }); + + map.addLayer({ + 'id': 'point-building', + 'type': 'symbol', + 'source': 'points', + 'filter': createFilter("high rise building", selectedSiteId), + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'house', + 'icon-size': 0.1 + } + }); + + map.addLayer({ + 'id': 'point-data-center', + 'type': 'symbol', + 'source': 'points', + 'filter': createFilter("data center", selectedSiteId), + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'data-center', + 'icon-size': 0.1 + } }); + + map.addLayer({ + 'id': 'point-factory', + 'type': 'symbol', + 'source': 'points', + 'filter': createFilter("factory", selectedSiteId), + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'factory', + 'icon-size': 0.2 + } + }); + + //alarm layers + + map.addLayer({ + 'id': 'point-lamps-alarm', + 'type': 'symbol', + 'source': 'alarmedPoints', + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'lamp-red', + 'icon-size': 0.1 + + }, + 'filter': createFilter("street lamp"), + }); + + map.addLayer({ + 'id': 'point-building-alarm', + 'type': 'symbol', + 'source': 'alarmedPoints', + 'filter': createFilter("high rise building"), + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'house-red', + 'icon-size': 0.1 + } + }); + + map.addLayer({ + 'id': 'point-data-center-alarm', + 'type': 'symbol', + 'source': 'alarmedPoints', + 'filter': createFilter("data center"), + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'data-center_red', + 'icon-size': 0.1 + } }); + + map.addLayer({ + 'id': 'point-factory-alarm', + 'type': 'symbol', + 'source': 'alarmedPoints', + 'filter': createFilter("factory"), + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'factory-red', + 'icon-size': 0.2 + } + }); + + + + map.addLayer({ + id: 'point-remaining', + source: 'points', + type: 'circle', + 'filter': ['==', 'type', ''], + paint: { + 'circle-color': '#11b4da', + 'circle-radius': 7, + 'circle-stroke-width': 1, + 'circle-stroke-color': '#fff' + } + }); + + map.addLayer({ + 'id': 'select-point-lamps', + 'type': 'symbol', + 'source': 'selectedPoints', + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'lamp', + 'icon-size': 0.15 + + }, + 'filter': ['==', 'type', 'street lamp'], + }); + + map.addLayer({ + 'id': 'select-point-buildings', + 'type': 'symbol', + 'source': 'selectedPoints', + 'filter': ['==', 'type', 'high rise building'], + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'house', + 'icon-size': 0.15 + } + }); + + map.addLayer({ + 'id': 'select-point-data-center', + 'type': 'symbol', + 'source': 'selectedPoints', + 'filter': ['==', 'type', 'data center'], + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'data-center', + 'icon-size': 0.15 + } + }); + + + map.addLayer({ + 'id': 'select-point-factory', + 'type': 'symbol', + 'source': 'selectedPoints', + 'filter': ['==', 'type', 'factory'], + 'layout': { + 'icon-allow-overlap': true, + 'icon-image': 'factory', + 'icon-size': 0.3 + } + }); + } + } + } + + } else { + swapLayersBack(map); + } +}else{ + swapLayersBack(map); + +} + +} + +export const swapLayersBack = (map: mapboxgl.Map) =>{ + checkedLayers=false; + if (map.getLayer('points') === undefined) { + + map.setLayoutProperty('selectedPoints', 'visibility', 'visible'); + map.setLayoutProperty('alarmedPoints', 'visibility', 'visible'); + + + map.removeLayer('point-building'); + map.removeLayer('point-lamps'); + map.removeLayer('point-data-center'); + map.removeLayer('point-factory'); + map.removeLayer('point-remaining'); + map.removeLayer('select-point-data-center'); + map.removeLayer('select-point-buildings'); + map.removeLayer('select-point-lamps'); + map.removeLayer('select-point-factory'); + map.removeLayer('point-building-alarm'); + map.removeLayer('point-lamps-alarm'); + map.removeLayer('point-data-center-alarm'); + map.removeLayer('point-factory-alarm'); + + + + map.addLayer({ + id: 'points', + source: 'points', + type: 'circle', + paint: { + 'circle-color': '#11b4da', + 'circle-radius': 7, + 'circle-stroke-width': 1, + 'circle-stroke-color': '#fff' + } + }); + + map.moveLayer('points', map.getLayer('selectedPoints').id) + + + } +} + +const addClusterLayers = (map: mapboxgl.Map, data: any) => { + map.addSource('clusters', { + type: 'geojson', + data: data + }); + + map.addSource('selectedLine', { + type: 'geojson', + data: { type: "FeatureCollection", features: [] } + }); + + map.addSource('selectedPoints', { + type: 'geojson', + data: { type: "FeatureCollection", features: [] } + + }); + + map.addLayer({ + id: 'clusters', + type: 'circle', + source: 'clusters', + filter: ['has', 'count'], + paint: { + 'circle-color': [ + 'step', + ['get', 'count'], + '#51bbd6', + 100, + '#f1f075', + 750, + '#f28cb1' + ], + 'circle-radius': [ + 'step', + ['get', 'count'], + 20, + 100, + 30, + 750, + 40 + ] + } + }); + + + map.addLayer({ + id: 'cluster-count', + type: 'symbol', + source: 'clusters', + filter: ['has', 'count'], + layout: { + 'text-field': '{count}', + 'text-font': ['Roboto Bold'], + 'text-size': 12 + } + }); + + map.addLayer({ + 'id': 'selectedLine', + 'type': 'line', + 'source': 'selectedLine', + 'layout': { + 'line-join': 'round', + 'line-cap': 'round' + }, + 'paint': { + 'line-color': '#888', + 'line-width': 4 + } + }); + + map.addLayer({ + id: 'unclustered-points', + source: 'clusters', + filter: ['!', ['has', 'count'],], + type: 'circle', + paint: { + 'circle-color': '#11b4da', + 'circle-radius': 7, + 'circle-stroke-width': 1, + 'circle-stroke-color': '#fff' + } + }); + + map.addLayer({ + id: 'selectedPoints', + source: 'selectedPoints', + type: 'circle', + paint: { + 'circle-color': '#116bda', + 'circle-radius': 9, + 'circle-stroke-width': 1, + 'circle-stroke-color': '#fff' + } + }); + +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapUtils.ts b/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapUtils.ts new file mode 100644 index 000000000..34cdc0638 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/utils/mapUtils.ts @@ -0,0 +1,135 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +const EARTHRADIUSM = 6378137; + +type updatedCoordinates = { south: number, west: number, north: number, east: number }; + + + + +export const addDistance = (south: number, west: number, north: number, east: number, distanceKm: number): updatedCoordinates => { + + const distanceInM = distanceKm * 1000; + + const dLat = distanceInM / EARTHRADIUSM; + const dLon = distanceInM / (EARTHRADIUSM * Math.cos(Math.PI * (north + south) / 360)); + + const latOffset = dLat * 180 / Math.PI; + const lonOffset = dLon * 180 / Math.PI; + + const newEast = checkLongitude(east + lonOffset); + const newWest = checkLongitude(west - lonOffset); + const newNorth = checkLatitude(north + latOffset); + const newSouth = checkLatitude(south - latOffset); + + return { east: newEast, north: newNorth, south: newSouth, west: newWest }; + +} + + +//taken from https://www.movable-type.co.uk/scripts/latlong.html +export const calculateMidPoint = (lat1: number, lon1: number, lat2: number, lon2: number) =>{ + + const dLon = degrees_to_radians(lon2 - lon1); + + //convert to radians + lat1 = degrees_to_radians(lat1); + lat2 = degrees_to_radians(lat2); + lon1 = degrees_to_radians(lon1); + + const Bx = Math.cos(lat2) * Math.cos(dLon); + const By = Math.cos(lat2) * Math.sin(dLon); + const lat3 = Math.atan2(Math.sin(lat1) + Math.sin(lat2), Math.sqrt((Math.cos(lat1) + Bx) * (Math.cos(lat1) + Bx) + By * By)); + const lon3 = lon1 + Math.atan2(By, Math.cos(lat1) + Bx); + + return [radians_to_degrees(lon3), radians_to_degrees(lat3)]; +} + + +export const LatLonToDMS = (value:number, isLon:boolean=false) =>{ + const absoluteValue = Math.abs(value); + const d = Math.floor(absoluteValue); + const m = Math.floor((absoluteValue -d)* 60); + const s = (absoluteValue - d - m / 60 ) * 3600; + const dms=`${d}° ${m}' ${s.toFixed(2)}"` + + const sign = Math.sign(value); + + if(isLon){ + return (sign === -1 || sign === -0 ) ? dms + " W" : dms + " E"; + }else{ + return (sign === -1 || sign === -0 ) ? dms + " S" : dms + " N"; + } +} + +// Because features come from tiled vector data, feature geometries may be split +// or duplicated across tile boundaries and, as a result, features may appear +// multiple times in query results. + +//taken from https://docs.mapbox.com/mapbox-gl-js/example/filter-features-within-map-view/ + +export const getUniqueFeatures = (array: mapboxgl.MapboxGeoJSONFeature[], comparatorProperty:string) =>{ + var existingFeatureKeys: any = {}; + + var uniqueFeatures = array.filter(function(el) { + if (existingFeatureKeys[el.properties![comparatorProperty]]) { + return false; + } else { + existingFeatureKeys[el.properties![comparatorProperty]] = true; + return true; + } + }); + + return uniqueFeatures; + } + +const radians_to_degrees = (radians:number) =>{ + + var pi = Math.PI; + return radians * (180/pi); +} + + const degrees_to_radians = (degrees: number) => + { + return degrees * (Math.PI/180); + } + + +const checkLatitude = (lat: number) => { + + if (lat > 90) + return 90; + else if (lat < -90) + return -90; + else + return lat; + +} + +const checkLongitude = (lon: number) => { + if (lon > 180) + return 180; + else if (lon < -180) + return -180; + else + return lon; +} + + + diff --git a/sdnr/wt/odlux/apps/networkMapApp/src/utils/utils.ts b/sdnr/wt/odlux/apps/networkMapApp/src/utils/utils.ts new file mode 100644 index 000000000..20c4e5aad --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src/utils/utils.ts @@ -0,0 +1,25 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ + +import { link } from "../model/link"; +import { site } from "../model/site"; + + +export function isSite(data: link | site): data is site { + return (data as site).geoLocation !== undefined; +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java b/sdnr/wt/odlux/apps/networkMapApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java new file mode 100644 index 000000000..43b072c4b --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java @@ -0,0 +1,68 @@ +/* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ +package org.onap.ccsdk.features.sdnr.wt.odlux.bundles; + +import org.onap.ccsdk.features.sdnr.wt.odlux.model.bundles.OdluxBundle; +import org.onap.ccsdk.features.sdnr.wt.odlux.model.bundles.OdluxBundleLoader; + +public class MyOdluxBundle extends OdluxBundle { + + @Override + public void initialize() { + super.initialize(); + } + + @Override + public void clean() { + super.clean(); + } + + @Override + public String getResourceFileContent(String filename) { + return super.getResourceFileContent(filename); + } + + @Override + public boolean hasResource(String filename) { + return super.hasResource(filename); + } + + @Override + public void setBundleName(String bundleName) { + super.setBundleName(bundleName); + } + + @Override + public void setLoader(OdluxBundleLoader loader) { + super.setLoader(loader); + } + + @Override + public String getBundleName() { + return super.getBundleName(); + } + + @Override + public OdluxBundleLoader getLoader() { + return super.getLoader(); + } + + public MyOdluxBundle() { + super(); + } +} diff --git a/sdnr/wt/odlux/apps/networkMapApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml b/sdnr/wt/odlux/apps/networkMapApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml new file mode 100644 index 000000000..4ede94477 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -0,0 +1,9 @@ +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> + <reference id="loadersvc" availability="mandatory" activation="eager" interface="org.onap.ccsdk.features.sdnr.wt.odlux.model.bundles.OdluxBundleLoader"/> + + <bean id="bundle" init-method="initialize" destroy-method="clean" class="org.onap.ccsdk.features.sdnr.wt.odlux.bundles.MyOdluxBundle"> + <property name="loader" ref="loadersvc"/> + <property name="bundleName" value="networkMapApp"/> + <property name="index" value="110"/> + </bean> +</blueprint>
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java b/sdnr/wt/odlux/apps/networkMapApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java new file mode 100644 index 000000000..c319bb189 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java @@ -0,0 +1,46 @@ +/* + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt + * ================================================================================================= + * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved. + * ================================================================================================= + * 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. + * ============LICENSE_END========================================================================== + */ +package org.onap.ccsdk.features.sdnr.wt.odlux.bundles.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import org.junit.Test; +import org.onap.ccsdk.features.sdnr.wt.odlux.OdluxBundleLoaderImpl; +import org.onap.ccsdk.features.sdnr.wt.odlux.bundles.MyOdluxBundle; + +public class TestBundleRes { + + @Test + public void test() { + OdluxBundleLoaderImpl loader = OdluxBundleLoaderImpl.getInstance(); + MyOdluxBundle b = new MyOdluxBundle(); + b.setLoader(loader); + b.setIndex(0); + b.setBundleName("abc"); + b.initialize(); + assertTrue(loader.getNumberOfBundles()==1); + assertNotNull(b.getLoader()); + assertEquals("abc",b.getBundleName()); + assertTrue(b.hasResource("test.js")); + assertNotNull(b.getResourceFileContent("test.js")); + b.clean(); + assertTrue(loader.getNumberOfBundles()==0); + } + +} diff --git a/sdnr/wt/odlux/apps/networkMapApp/src2/test/resources/test.js b/sdnr/wt/odlux/apps/networkMapApp/src2/test/resources/test.js new file mode 100644 index 000000000..b47fdc39f --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/src2/test/resources/test.js @@ -0,0 +1,5 @@ +asdac sad +as +d +sad + sadfa
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/networkMapApp/tsconfig.json b/sdnr/wt/odlux/apps/networkMapApp/tsconfig.json new file mode 100644 index 000000000..a66b5d828 --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/tsconfig.json @@ -0,0 +1,37 @@ +{ + "compilerOptions": { + "baseUrl": "./src", + "outDir": "./dist", + "sourceMap": true, + "forceConsistentCasingInFileNames": true, + "allowSyntheticDefaultImports": false, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "strictNullChecks": true, + "pretty": true, + "newLine": "LF", + "module": "es2015", + "target": "es2016", + "moduleResolution": "node", + "experimentalDecorators": true, + "jsx": "preserve", + "lib": [ + "dom", + "es2015", + "es2016" + ], + "types": [ + "prop-types", + "react", + "react-dom" + ] + }, + "exclude": [ + "dist", + "node_modules" + ] +} diff --git a/sdnr/wt/odlux/apps/networkMapApp/webpack.config.js b/sdnr/wt/odlux/apps/networkMapApp/webpack.config.js new file mode 100644 index 000000000..5fc67e3ec --- /dev/null +++ b/sdnr/wt/odlux/apps/networkMapApp/webpack.config.js @@ -0,0 +1,177 @@ +/** + * Webpack 4 configuration file + * see https://webpack.js.org/configuration/ + * see https://webpack.js.org/configuration/dev-server/ + */ + +"use strict"; + +const path = require("path"); +const webpack = require("webpack"); +const CopyWebpackPlugin = require("copy-webpack-plugin"); +const TerserPlugin = require('terser-webpack-plugin'); + +// const __dirname = (path => path.replace(/^([a-z]\:)/, c => c.toUpperCase()))(process.__dirname()); + +module.exports = (env) => { + const distPath = path.resolve(__dirname, env === "release" ? "." : "../..", "dist"); + const frameworkPath = path.resolve(__dirname, env === "release" ? "../../framework" : "../..", "dist"); + return [{ + name: "App", + + mode: "none", //disable default behavior + + target: "web", + + context: path.resolve(__dirname, "src"), + + entry: { + networkMapApp: ["./pluginTransport.tsx"] + }, + + devtool: env === "release" ? false : "source-map", + + resolve: { + extensions: [".ts", ".tsx", ".js", ".jsx"] + }, + + output: { + path: distPath, + filename: "[name].js", + library: "[name]", + libraryTarget: "umd2", + chunkFilename: "[name].js" + }, + module: { + rules: [{ + test: /\.tsx?$/, + exclude: /node_modules/, + use: [{ + loader: "babel-loader" + }, { + loader: "ts-loader" + }] + }, { + test: /\.jsx?$/, + exclude: /node_modules/, + use: [{ + loader: "babel-loader" + }] + }, + { + test: /\.(png|gif|jpg|svg)$/, + use: [{ + loader: 'url-loader', + options: { + limit: 10000, + name: './icons/[hash].[ext]' + } + }] + }] + }, + + optimization: { + noEmitOnErrors: true, + namedModules: env !== "release", + minimize: env === "release", + minimizer: env !== "release" ? [] : [new TerserPlugin({ + terserOptions: { + warnings: false, // false, true, "verbose" + compress: { + drop_console: true, + drop_debugger: true, + } + } + })], + }, + + plugins: [ + new webpack.DllReferencePlugin({ + context: path.resolve(__dirname, "../../framework/src"), + manifest: require(path.resolve(frameworkPath, "vendor-manifest.json")), + sourceType: "umd2" + }), + new webpack.DllReferencePlugin({ + context: path.resolve(__dirname, "../../framework/src"), + manifest: require(path.resolve(frameworkPath, "app-manifest.json")), + sourceType: "umd2" + }), + ...(env === "release") ? [ + new webpack.DefinePlugin({ + "process.env": { + NODE_ENV: "'production'", + VERSION: JSON.stringify(require("./package.json").version) + } + }), + ] : [ + new webpack.DefinePlugin({ + "process.env": { + NODE_ENV: "'development'", + VERSION: JSON.stringify(require("./package.json").version) + } + }), + new CopyWebpackPlugin([{ + from: 'index.html', + to: distPath + }]), + ] + ], + + devServer: { + public: "http://localhost:3100", + contentBase: frameworkPath, + + compress: true, + headers: { + "Access-Control-Allow-Origin": "*" + }, + host: "0.0.0.0", + port: 3100, + disableHostCheck: true, + historyApiFallback: true, + inline: true, + hot: false, + quiet: false, + stats: { + colors: true + }, + proxy: { + "/yang-schema/": { + target: "http://10.20.6.29:8181", + secure: false + }, + "/oauth2/": { + target: "http://10.20.6.29:8181", + secure: false + }, + "/database/": { + target: "http://10.20.6.29:8181", + secure: false + }, + "/restconf/": { + target: "http://10.20.6.29:8181", + secure: false + }, + "/rests/": { + target: "http://10.20.6.29:8181", + secure: false + }, + "/topology/": { + target: "http://localhost:3001", + secure: false + }, + "/help/": { + target: "http://10.20.6.29:8181", + secure: false + }, + "/websocket": { + target: "http://10.20.6.29:8181", + ws: true, + changeOrigin: true, + secure: false + } + } + + } + }]; +} diff --git a/sdnr/wt/odlux/framework/pom.xml b/sdnr/wt/odlux/framework/pom.xml index a7c81ebb1..5239b2bf4 100644 --- a/sdnr/wt/odlux/framework/pom.xml +++ b/sdnr/wt/odlux/framework/pom.xml @@ -46,7 +46,7 @@ <properties> <buildtime>${maven.build.timestamp}</buildtime> <distversion>ONAP Frankfurt (Neon, mdsal ${odl.mdsal.version})</distversion> - <buildno>62.ad364be(20/08/21)</buildno> + <buildno>68.d7886ce(20/09/04)</buildno> <odlux.version>ONAP SDN-R | ONF Wireless for ${distversion} - Build: ${buildtime} ${buildno} ${project.version}</odlux.version> </properties> diff --git a/sdnr/wt/odlux/framework/src/assets/version.json b/sdnr/wt/odlux/framework/src/assets/version.json new file mode 100644 index 000000000..6311e1094 --- /dev/null +++ b/sdnr/wt/odlux/framework/src/assets/version.json @@ -0,0 +1,4 @@ +{ + "version":"68.d7886ce(20/09/04)", + "build":"2020-09-04T12:31:19Z" +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/framework/src/components/material-ui/listItemLink.tsx b/sdnr/wt/odlux/framework/src/components/material-ui/listItemLink.tsx index 23bad66ea..8c4b740a0 100644 --- a/sdnr/wt/odlux/framework/src/components/material-ui/listItemLink.tsx +++ b/sdnr/wt/odlux/framework/src/components/material-ui/listItemLink.tsx @@ -42,15 +42,16 @@ export const ListItemLink = withStyles(styles)((props: IListItemLinkProps) => { const { icon, primary: Primary, secondary: Secondary, classes, to, exact = false } = props;
const renderLink = (itemProps: any): JSX.Element => (<NavLink exact={ exact } to={ to } activeClassName={ classes.active } { ...itemProps } />);
+ const ariaLabel = typeof Primary === 'string' ? "link-to-"+Primary.toLowerCase().replace(/\s/g, "-") : "link-to-"+Primary.displayName?.toLowerCase();
return (
<>
- <ListItem button component={ renderLink }>
+ <ListItem button component={ renderLink } aria-label={ariaLabel}>
{ icon
? <ListItemIcon>{ icon }</ListItemIcon>
: null
}
{ typeof Primary === 'string'
- ? <ListItemText aria-label={"link-to-"+Primary.toLowerCase()} primary={ Primary } style={{ padding: 0 }} />
+ ? <ListItemText primary={ Primary } style={{ padding: 0 }} />
: <Primary />
}
</ListItem>
diff --git a/sdnr/wt/odlux/installer/pom.xml b/sdnr/wt/odlux/installer/pom.xml index 5ff2791c2..7559b25d7 100644 --- a/sdnr/wt/odlux/installer/pom.xml +++ b/sdnr/wt/odlux/installer/pom.xml @@ -156,6 +156,14 @@ <type>jar</type> <overWrite>false</overWrite> </artifactItem> + <!-- networkMapApp--> + <artifactItem> + <groupId>${project.groupId}</groupId> + <artifactId>sdnr-wt-odlux-app-networkMapApp</artifactId> + <version>${project.version}</version> + <type>jar</type> + <overWrite>false</overWrite> + </artifactItem> <!-- linkCalculationApp--> <artifactItem> <groupId>${project.groupId}</groupId> diff --git a/sdnr/wt/odlux/pom.xml b/sdnr/wt/odlux/pom.xml index a822d3d08..c4e1615d6 100644 --- a/sdnr/wt/odlux/pom.xml +++ b/sdnr/wt/odlux/pom.xml @@ -52,6 +52,7 @@ <module>apps/performanceHistoryApp</module> <module>apps/eventLogApp</module> <module>apps/configurationApp</module> + <module>apps/networkMapApp</module> <module>apps/linkCalculationApp</module> <module>apps/app-feature</module> <module>apps/app-installer</module> |