diff options
128 files changed, 4880 insertions, 2125 deletions
diff --git a/sdnr/wt/data-provider/installer/pom.xml b/sdnr/wt/data-provider/installer/pom.xml index 5b3a5df13..dcb688468 100755 --- a/sdnr/wt/data-provider/installer/pom.xml +++ b/sdnr/wt/data-provider/installer/pom.xml @@ -69,7 +69,7 @@ <artifactId>${application.name}-setup</artifactId> <version>${project.version}</version> </dependency> - + </dependencies> <build> 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 a9e334668..f4578d5dc 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 @@ -1,4 +1,4 @@ -/** +/* * ============LICENSE_START======================================================================== * ONAP : ccsdk feature sdnr wt * ================================================================================================= @@ -19,7 +19,6 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.model; import java.util.Date; import java.util.List; - import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.ConnectionlogEntity; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.EventlogEntity; @@ -67,7 +66,7 @@ public interface DataProvider extends ArchiveCleanProvider { /** * write internal equipment to database - * + * * @param internalEquipment with mandatory fields. */ void writeInventory(Inventory internalEquipment); @@ -76,17 +75,19 @@ public interface DataProvider extends ArchiveCleanProvider { * * @param networkElementConnectionEntitiy to wirte to DB * @param nodeId Id for this DB element + * @return if succeeded */ - void updateNetworkConnectionDeviceType(NetworkElementConnectionEntity networkElementConnectionEntitiy, + boolean updateNetworkConnectionDeviceType(NetworkElementConnectionEntity networkElementConnectionEntitiy, String nodeId); /** * Update after new mountpoint registration - * + * * @param networkElementConnectionEntitiy data * @param nodeId of device (mountpoint name) + * @return if succeeded */ - void updateNetworkConnection22(NetworkElementConnectionEntity networkElementConnectionEntitiy, String nodeId); + boolean updateNetworkConnection22(NetworkElementConnectionEntity networkElementConnectionEntitiy, String nodeId); void removeNetworkConnection(String nodeId); diff --git a/sdnr/wt/data-provider/model/src/main/yang/data-provider.yang b/sdnr/wt/data-provider/model/src/main/yang/data-provider@2019-08-01.yang index ef65104e5..46505cd8f 100644 --- a/sdnr/wt/data-provider/model/src/main/yang/data-provider.yang +++ b/sdnr/wt/data-provider/model/src/main/yang/data-provider@2019-08-01.yang @@ -1,5 +1,5 @@ module data-provider { - + yang-version 1.1; namespace "urn:opendaylight:params:xml:ns:yang:data-provider"; prefix odluxprovider; @@ -191,7 +191,7 @@ module data-provider { } enum NtsManager { description - "Simulation of device"; + "Manage adapter to simulate devices"; } enum Nonsupported { description @@ -201,6 +201,18 @@ module data-provider { description "Device type at this point of time unknown"; } + enum O-RAN-FH { + description + "implements RAN according to o-ran*.yang fro for fronthaule"; + } + enum O-ROADM { + description + "implements Open ROADM"; + } + enum O1-TR069 { + description + "implements O1 RAN interface according to TR069"; + } } description "An enumeration as identification of the device."; @@ -272,7 +284,7 @@ module data-provider { } } description - "The enumeration with the options for granularity period of the + "The enumeration with the options for granularity period of the performance data similar to g.874.1-model"; } @@ -466,7 +478,7 @@ module data-provider { type string; mandatory true; description - "Key to get/set configuration entry in database. Normally Mountpoint + "Key to get/set configuration entry in database. Normally Mountpoint name is used as key id of node."; } leaf node-id { @@ -559,7 +571,7 @@ module data-provider { grouping pmdata-microwave { description - "Consolidated performance information of all microwave model interface + "Consolidated performance information of all microwave model interface PACs"; leaf es { type int32; @@ -855,7 +867,7 @@ module data-provider { default "-99"; config false; description - "Lowest temperature (in degree Celsius) of the radio module inside the + "Lowest temperature (in degree Celsius) of the radio module inside the outdoor unit."; } leaf rf-temp-max { @@ -864,7 +876,7 @@ module data-provider { default "-99"; config false; description - "Highest temperature (in degree Celsius) of the radio module inside the + "Highest temperature (in degree Celsius) of the radio module inside the outdoor unit."; } leaf rf-temp-avg { @@ -873,7 +885,7 @@ module data-provider { default "-99"; config false; description - "Averaged temperature (in degree Celsius) of the radio module inside + "Averaged temperature (in degree Celsius) of the radio module inside the outdoor unit."; } leaf defect-blocks-sum { @@ -882,7 +894,7 @@ module data-provider { default "-1"; config false; description - "Total number of blocks that were defect after receiving and could not + "Total number of blocks that were defect after receiving and could not be corrected by the FEC."; } leaf time-period { @@ -904,9 +916,9 @@ module data-provider { default "-1"; config false; description - "Counts the number of Bytes of Ethernet traffic (before header - compression) transmitted within a second and keeps the highest value - within the measurement period. Field to be left blank for all types of + "Counts the number of Bytes of Ethernet traffic (before header + compression) transmitted within a second and keeps the highest value + within the measurement period. Field to be left blank for all types of TDM containers."; } leaf tx-ethernet-bytes-max-m { @@ -915,9 +927,9 @@ module data-provider { default "-1"; config false; description - "Counts the number of Bytes of Ethernet traffic (before header - compression) transmitted within a minute and keeps the highest value - with in the measurement period. Field to be left blank for all types + "Counts the number of Bytes of Ethernet traffic (before header + compression) transmitted within a minute and keeps the highest value + with in the measurement period. Field to be left blank for all types of TDM containers."; } leaf tx-ethernet-bytes-sum { @@ -926,8 +938,8 @@ module data-provider { default "-1"; config false; description - "Total number of Bytes of Ethernet traffic (before header compression) - transmitted (in direction out of the device) during the measurement + "Total number of Bytes of Ethernet traffic (before header compression) + transmitted (in direction out of the device) during the measurement period. Field to be left blank for all types of TDM containers."; } } @@ -970,7 +982,7 @@ module data-provider { grouping inventory-entity { description - "One equipment entity in a list of a network element that could be rack, + "One equipment entity in a list of a network element that could be rack, card, backplane, module"; leaf id { type string; @@ -996,7 +1008,7 @@ module data-provider { leaf uuid { type string; description - "Unique inventory id of this node for this equipment, provided by + "Unique inventory id of this node for this equipment, provided by network element"; } leaf-list contained-holder { @@ -1022,7 +1034,7 @@ module data-provider { leaf date { type string; description - "manufactured-thing/equipment-instance/manufacture-date: Date + "manufactured-thing/equipment-instance/manufacture-date: Date information provided by manufacturer. No specific format. ()"; } leaf version { diff --git a/sdnr/wt/data-provider/provider/pom.xml b/sdnr/wt/data-provider/provider/pom.xml index 0d133f8d4..9e158abf1 100644 --- a/sdnr/wt/data-provider/provider/pom.xml +++ b/sdnr/wt/data-provider/provider/pom.xml @@ -47,12 +47,11 @@ </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}</buildtime> <databaseport>49402</databaseport> - <odlux.buildno>52.3b24c2d(20/04/08)</odlux.buildno> + <odlux.buildno>56.139cd6d(20/07/08)</odlux.buildno> </properties> <dependencies> @@ -91,6 +90,11 @@ <artifactId>org.apache.karaf.shell.core</artifactId> <scope>provided</scope> </dependency> +<!-- <dependency> --> +<!-- <groupId>org.apache.karaf.bundle</groupId> --> +<!-- <artifactId>org.apache.karaf.bundle.core</artifactId> --> +<!-- <scope>provided</scope> --> +<!-- </dependency> --> <dependency> <groupId>org.opendaylight.netconf</groupId> <artifactId>sal-netconf-connector</artifactId> @@ -146,9 +150,11 @@ <executable>java</executable> <arguments> <argument>-jar</argument> - <argument>${basedir}/../setup/target/sdnr-dmt.jar</argument> + <argument>${basedir}/../../data-provider/setup/target/sdnr-dmt.jar</argument> <argument>-c</argument> <argument>pluginfile</argument> + <argument>-v</argument> + <argument>v3</argument> <argument>-of</argument> <argument>${project.build.directory}/EsInit.script</argument> </arguments> @@ -165,7 +171,7 @@ <clusterName>testCluster</clusterName> <transportPort>9500</transportPort> <httpPort>${databaseport}</httpPort> - <version>6.5.0</version> + <version>7.1.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/DataObjectAcessor.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessor.java index 3fe2a62af..c3c63a963 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessor.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessor.java @@ -24,38 +24,35 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.data; import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; import org.onap.ccsdk.features.sdnr.wt.common.database.SearchResult; import org.onap.ccsdk.features.sdnr.wt.common.database.queries.QueryBuilder; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.database.EsDataObjectReaderWriter; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.database.EsDataObjectReaderWriter2; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.Entity; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.EntityInput; import org.opendaylight.yangtools.yang.binding.DataObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class DataObjectAcessor<T extends DataObject> extends EsDataObjectReaderWriter<T> { +public class DataObjectAcessor<T extends DataObject> extends EsDataObjectReaderWriter2<T> { private static final Logger LOG = LoggerFactory.getLogger(DataObjectAcessor.class); - public DataObjectAcessor(HtDatabaseClient dbClient, Entity entity, Class<T> clazz) throws ClassNotFoundException { - this(dbClient, entity, clazz, true); + DataObjectAcessor(HtDatabaseClient dbClient, Entity entity, Class<T> clazz) throws ClassNotFoundException { + super(dbClient, entity, clazz); LOG.info("Create {}", this.getClass().getName()); } - public DataObjectAcessor(HtDatabaseClient dbClient, Entity entity, Class<T> clazz, boolean idSupported) - throws ClassNotFoundException { - super(dbClient, entity, clazz); - if (idSupported) { - setEsIdAttributeName("_id"); - } - } + public QueryResult<T> getData(EntityInput input) { - QueryResult<T> getData(EntityInput input) { - long page = QueryByFilter.getPage(input); - long pageSize = QueryByFilter.getPageSize(input); - LOG.info("Request: {}", this.getDataTypeName()); - QueryBuilder query = QueryByFilter.fromFilter(input.getFilter()).from((page - 1) * pageSize).size(pageSize); - QueryByFilter.setSortOrder(query, input.getSortorder()); - SearchResult<T> result = doReadAll(query, query.contains("range")); - return new QueryResult<>(page, pageSize, result); + QueryByFilter queryByFilter = new QueryByFilter(input); + QueryBuilder queryBuilder = queryByFilter.getQueryBuilderByFilter(); + // Exception handling during user input for invalid filter input. + // This wrong filter by user is allowed an results into empty data. + boolean ignoreException = queryBuilder.contains("range"); + + LOG.info("Request: {} filter {} ignoreException{}:", this.getDataTypeName(), queryByFilter, ignoreException); + + SearchResult<T> result = doReadAll(queryBuilder, ignoreException); + return new QueryResult<>(queryByFilter, result); } + } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessorPm.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessorPm.java index 8eb51b6aa..83017366d 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessorPm.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessorPm.java @@ -26,16 +26,11 @@ import java.io.IOException; import org.onap.ccsdk.features.sdnr.wt.common.database.ExtRestClient; import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; import org.onap.ccsdk.features.sdnr.wt.common.database.SearchResult; -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.requests.SearchRequest; import org.onap.ccsdk.features.sdnr.wt.common.database.responses.AggregationEntries; import org.onap.ccsdk.features.sdnr.wt.common.database.responses.SearchResponse; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.Entity; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.EntityInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.SortOrder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Filter; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Sortorder; import org.opendaylight.yangtools.yang.binding.DataObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +44,7 @@ public class DataObjectAcessorPm<T extends DataObject> extends DataObjectAcessor private static final String KEY = "node-name"; - enum Intervall { + public enum Intervall { PMDATA15M("historicalperformance15min", "historicalperformance15min"), PMDATA24H("historicalperformance24h", "historicalperformance24h"); @@ -75,7 +70,8 @@ public class DataObjectAcessorPm<T extends DataObject> extends DataObjectAcessor public DataObjectAcessorPm(HtDatabaseClient dbClient, Intervall mode, Entity entity, Class<T> clazz) throws ClassNotFoundException { - super(dbClient, entity, clazz, false); + super(dbClient, entity, clazz); + LOG.info("DataObjectAcessorPm"); this.dbClient = dbClient; this.mode = mode; } @@ -87,47 +83,24 @@ public class DataObjectAcessorPm<T extends DataObject> extends DataObjectAcessor * @return * @throws IOException */ - QueryResult<String> getDataLtpList(EntityInput input) throws IOException { - long page = QueryByFilter.getPage(input); - long pageSize = QueryByFilter.getPageSize(input); - Filter nodeFilter = QueryByFilter.getFilter(input.getFilter(), NODE_KEY); - if (nodeFilter != null) { - SearchRequest request = new SearchRequest(mode.getIndex(), mode.getType()); - request.setQuery( - QueryBuilders.matchQuery(NODE_KEY, nodeFilter.getFiltervalue()).aggregations(UUID_KEY).size(0)); - try { - SearchResponse response = this.dbClient.search(request); - AggregationEntries aggs = response.getAggregations(UUID_KEY); - String[] uuids = aggs.getKeysAsPagedStringList(pageSize, pageSize * (page - 1)); - long totalSize = aggs.size(); - return new QueryResult<String>(page, pageSize, new SearchResult<String>(uuids, totalSize)); - } catch (IOException e) { - throw new IOException("problem reading ltps for req=" + request, e); - } - } else { - String msg = "no nodename in filter found "; - LOG.debug(msg); - throw new IllegalArgumentException(msg); + public QueryResult<String> getDataLtpList(EntityInput input) throws IOException { + + QueryByFilter queryByFilter = new QueryByFilter(input); + SearchRequest request = + queryByFilter.getSearchRequestByFilter(NODE_KEY, UUID_KEY, mode.getIndex(), mode.getType()); + try { + SearchResponse response = this.dbClient.search(request); + AggregationEntries aggs = response.getAggregations(UUID_KEY); + String[] uuids = + aggs.getKeysAsPagedStringList(queryByFilter.getPageSize(), queryByFilter.getPageStartIndex()); + long totalSize = aggs.size(); + return new QueryResult<String>(queryByFilter.getPage(), queryByFilter.getPageSize(), + new SearchResult<String>(uuids, totalSize)); + } catch (IOException e) { + throw new IOException("problem reading ltps for req=" + request, e); } } - // QueryResult<String> getDataDeviceList(EntityInput input) throws IOException { - // - // long page = QueryByFilter.getPage(input); - // long pageSize = QueryByFilter.getPageSize(input); - // - // SearchRequest request = new SearchRequest(mode.getIndex(), mode.getType()); - // request.setQuery(QueryBuilders.matchAllQuery().aggregations(KEY).size(0)); - //// try { - // SearchResponse response = this.dbClient.search(request); - // AggregationEntries aggs = response.getAggregations(KEY); - // String[] uuids = aggs.getKeysAsPagedStringList(pageSize, pageSize * (page - 1)); - // long totalSize = aggs.size(); - // return new QueryResult<String>(page, pageSize, new SearchResult<String>(uuids, totalSize)); - //// } catch (IOException e) { - //// throw new IOException("problem reading nodes for req="+request, e); - //// } - // } /** * get aggregated devices list * @@ -135,31 +108,19 @@ public class DataObjectAcessorPm<T extends DataObject> extends DataObjectAcessor * @return * @throws IOException */ - QueryResult<String> getDataDeviceList(EntityInput input) throws IOException { - - long page = QueryByFilter.getPage(input); - long pageSize = QueryByFilter.getPageSize(input); - - Sortorder soNode = QueryByFilter.getSortOrder(input.getSortorder(), KEY); - SearchRequest request = new SearchRequest(mode.getIndex(), mode.getType()); - QueryBuilder query = null; - if (soNode != null) { - query = QueryBuilders.matchAllQuery() - .aggregations(KEY, - soNode.getSortorder() == SortOrder.Ascending - ? org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.ASCENDING - : org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.DESCENDING) - .size(0); - } else { - query = QueryBuilders.matchAllQuery().aggregations(KEY).size(0); - } - request.setQuery(query); + public QueryResult<String> getDataDeviceList(EntityInput input) throws IOException { + + QueryByFilter queryByFilter = new QueryByFilter(input); + SearchRequest request = + queryByFilter.getSearchRequestBySortOrder(NODE_KEY, UUID_KEY, mode.getIndex(), mode.getType()); try { SearchResponse response = this.dbClient.search(request); AggregationEntries aggs = response.getAggregations(KEY); - String[] uuids = aggs.getKeysAsPagedStringList(pageSize, pageSize * (page - 1)); + String[] uuids = + aggs.getKeysAsPagedStringList(queryByFilter.getPageSize(), queryByFilter.getPageStartIndex()); long totalSize = aggs.size(); - return new QueryResult<String>(page, pageSize, new SearchResult<String>(uuids, totalSize)); + return new QueryResult<String>(queryByFilter.getPage(), queryByFilter.getPageSize(), + new SearchResult<String>(uuids, totalSize)); } catch (IOException e) { throw new IOException("problem reading nodes for req=" + request, e); } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessorStatus.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessorStatus.java index 4dd52f43a..1fa6de37d 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessorStatus.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessorStatus.java @@ -43,12 +43,12 @@ public class DataObjectAcessorStatus extends DataObjectAcessor<Data> { private final Entity entity; public DataObjectAcessorStatus(HtDatabaseClient dbClient, Entity entity) throws ClassNotFoundException { - super(dbClient, entity, Data.class, false); + super(dbClient, entity, Data.class); this.dbClient = dbClient; this.entity = entity; } - QueryResult<Data> getDataStatus() throws IOException { + public QueryResult<Data> getDataStatus() throws IOException { SearchRequest request = getNewInstanceOfSearchRequest(entity); request.setQuery(QueryBuilders.matchAllQuery().aggregations(ESDATATYPE_FAULTCURRENT_SEVERITY_KEY).size(0)); SearchResponse response = this.dbClient.search(request); diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataTreeChildObject.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessorWithId.java index a92265a84..10dd7792c 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataTreeChildObject.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataObjectAcessorWithId.java @@ -21,26 +21,21 @@ */ package org.onap.ccsdk.features.sdnr.wt.dataprovider.data; -import java.util.Map; +import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.Entity; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -/** - * @author Michael Dürre - * - */ -public class DataTreeChildObject { +public class DataObjectAcessorWithId<T extends DataObject> extends DataObjectAcessor<T> { - private final String label; - private final String ownSeverity; - private final String childrenSeveritySummary; - private final boolean isMatch; - private final Map<String, DataTreeChildObject> children; + private static final Logger LOG = LoggerFactory.getLogger(DataObjectAcessorWithId.class); - public DataTreeChildObject(String label, boolean isMatch, Map<String, DataTreeChildObject> children, - String ownSeverity, String childrenSeveritySummary) { - this.label = label; - this.isMatch = isMatch; - this.children = children; - this.ownSeverity = ownSeverity; - this.childrenSeveritySummary = childrenSeveritySummary; + public DataObjectAcessorWithId(HtDatabaseClient dbClient, Entity entity, Class<T> clazz) + throws ClassNotFoundException { + super(dbClient, entity, clazz); + setEsIdAttributeName("_id"); + LOG.info("Create {}", this.getClass().getName()); } + } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/ElasticSearchDataProvider.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/ElasticSearchDataProvider.java index 76d47e3e0..30e617ab6 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/ElasticSearchDataProvider.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/ElasticSearchDataProvider.java @@ -77,17 +77,15 @@ public class ElasticSearchDataProvider /*extends BaseStatusProvider /* implement private static final String EXCEPTION_UNABLE_TO_UPDATE_IN_DATABASE = "unable to update data in database"; private static final String EXCEPTION_UNABLE_TO_REMOVE_FROM_DATABASE = "unable to remove data from database"; - private static final boolean DEFAULT_TRUSTALLCERTS = false; - private final HtDatabaseClient dbClient; - private final DataObjectAcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.faultcurrent.list.output.Data> eventRWFaultCurrent; - private final DataObjectAcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.faultlog.list.output.Data> eventRWFaultLog; - private final DataObjectAcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.mediator.server.list.output.Data> mediatorserverRW; - private final DataObjectAcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.maintenance.list.output.Data> maintenanceRW; - private final DataObjectAcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.Data> equipmentRW; - private final DataObjectAcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.connectionlog.list.output.Data> connnectionlogRW; - private final DataObjectAcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.eventlog.list.output.Data> eventlogRW; - private final DataObjectAcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.network.element.connection.list.output.Data> networkelementConnectionRW; + private final DataObjectAcessorWithId<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.faultcurrent.list.output.Data> eventRWFaultCurrent; + private final DataObjectAcessorWithId<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.faultlog.list.output.Data> eventRWFaultLog; + private final DataObjectAcessorWithId<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.mediator.server.list.output.Data> mediatorserverRW; + private final DataObjectAcessorWithId<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.maintenance.list.output.Data> maintenanceRW; + private final DataObjectAcessorWithId<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.Data> equipmentRW; + private final DataObjectAcessorWithId<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.connectionlog.list.output.Data> connnectionlogRW; + private final DataObjectAcessorWithId<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.eventlog.list.output.Data> eventlogRW; + private final DataObjectAcessorWithId<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.network.element.connection.list.output.Data> networkelementConnectionRW; private final DataObjectAcessorPm<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.Data> pm15mRW; private final DataObjectAcessorPm<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._24h.list.output.Data> pm24hRW; @@ -100,7 +98,7 @@ public class ElasticSearchDataProvider /*extends BaseStatusProvider /* implement } public ElasticSearchDataProvider(HostInfo[] hosts) throws Exception { - this(hosts, null, null, DEFAULT_TRUSTALLCERTS); + this(hosts, null, null, HtDatabaseClient.TRUSTALL_DEFAULT); } public ElasticSearchDataProvider(HostInfo[] hosts, String authUsername, String authPassword, boolean trustAllCerts) @@ -108,31 +106,32 @@ public class ElasticSearchDataProvider /*extends BaseStatusProvider /* implement super(); LOG.info("Start {}", this.getClass().getName()); + this.dbClient = HtDatabaseClient.getClient(hosts, authUsername, authPassword, trustAllCerts); - this.mediatorserverRW = new DataObjectAcessor<>(dbClient, Entity.MediatorServer, + this.mediatorserverRW = new DataObjectAcessorWithId<>(dbClient, Entity.MediatorServer, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.mediator.server.list.output.Data.class); this.mediatorserverRW.setWriteInterface(MediatorServerEntity.class); - this.maintenanceRW = new DataObjectAcessor<>(dbClient, Entity.Maintenancemode, + this.maintenanceRW = new DataObjectAcessorWithId<>(dbClient, Entity.Maintenancemode, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.maintenance.list.output.Data.class); this.maintenanceRW.setWriteInterface(MaintenanceEntity.class); - this.equipmentRW = new DataObjectAcessor<>(dbClient, Entity.Inventoryequipment, + this.equipmentRW = new DataObjectAcessorWithId<>(dbClient, Entity.Inventoryequipment, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.Data.class); - this.eventRWFaultCurrent = new DataObjectAcessor<>(dbClient, Entity.Faultcurrent, + this.eventRWFaultCurrent = new DataObjectAcessorWithId<>(dbClient, Entity.Faultcurrent, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.faultcurrent.list.output.Data.class); - this.eventRWFaultLog = new DataObjectAcessor<>(dbClient, Entity.Faultlog, + this.eventRWFaultLog = new DataObjectAcessorWithId<>(dbClient, Entity.Faultlog, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.faultlog.list.output.Data.class); - this.connnectionlogRW = new DataObjectAcessor<>(dbClient, Entity.Connectionlog, + this.connnectionlogRW = new DataObjectAcessorWithId<>(dbClient, Entity.Connectionlog, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.connectionlog.list.output.Data.class); - this.eventlogRW = new DataObjectAcessor<>(dbClient, Entity.Eventlog, + this.eventlogRW = new DataObjectAcessorWithId<>(dbClient, Entity.Eventlog, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.eventlog.list.output.Data.class); - this.networkelementConnectionRW = new DataObjectAcessor<>(dbClient, Entity.NetworkelementConnection, + this.networkelementConnectionRW = new DataObjectAcessorWithId<>(dbClient, Entity.NetworkelementConnection, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.network.element.connection.list.output.Data.class); this.networkelementConnectionRW.setWriteInterface(NetworkElementConnectionEntity.class); diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/HtDatabaseEventsService.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/HtDatabaseEventsService.java index d255cadcd..4efbf6e28 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/HtDatabaseEventsService.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/HtDatabaseEventsService.java @@ -27,6 +27,7 @@ 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; @@ -113,7 +114,7 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid ConnectionlogEntity.class, ConnectionlogBuilder.class); networkelementConnectionDB = new EsDataObjectReaderWriter2<>(client, Entity.NetworkelementConnection, - NetworkElementConnectionEntity.class, NetworkElementConnectionBuilder.class) + NetworkElementConnectionEntity.class, NetworkElementConnectionBuilder.class, true) .setEsIdAttributeName("_id"); pmData15mDB = new EsDataObjectReaderWriter2<>(client, Entity.Historicalperformance15min, PmdataEntity.class, @@ -271,15 +272,64 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid // -- Networkelement + + /** + * 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 + */ + @SuppressWarnings("unused") + private NetworkElementConnectionEntity joinNe(NetworkElementConnectionEntity base, + NetworkElementConnectionEntity toJoin) { + if (base == null) { + return toJoin; + } + NetworkElementConnectionBuilder builder = new NetworkElementConnectionBuilder(base); + if (toJoin != null) { + if (toJoin.isIsRequired() != null) { + builder.setIsRequired(toJoin.isIsRequired()); + } + if (toJoin.getCoreModelCapability() != null) { + builder.setCoreModelCapability(toJoin.getCoreModelCapability()); + } + if (toJoin.getDeviceType() != null) { + builder.setDeviceType(toJoin.getDeviceType()); + } + if (toJoin.getHost() != null) { + builder.setHost(toJoin.getHost()); + } + if (toJoin.getNodeDetails() != null) { + builder.setNodeDetails(toJoin.getNodeDetails()); + } + if (toJoin.getPassword() != null) { + builder.setPassword(toJoin.getPassword()); + } + if (toJoin.getPort() != null) { + builder.setPort(toJoin.getPort()); + } + if (toJoin.getStatus() != null) { + builder.setStatus(toJoin.getStatus()); + } + if (toJoin.getUsername() != null) { + builder.setUsername(toJoin.getUsername()); + } + } + return builder.build(); + } + /** * * @param networkElementConnectionEntitiy to wirte to DB * @param nodeId Id for this DB element */ @Override - public void updateNetworkConnectionDeviceType(NetworkElementConnectionEntity networkElementConnectionEntitiy, + public boolean updateNetworkConnectionDeviceType(NetworkElementConnectionEntity networkElementConnectionEntitiy, String nodeId) { - this.networkelementConnectionDB.update(networkElementConnectionEntitiy, nodeId); + return this.networkelementConnectionDB.update(networkElementConnectionEntitiy, nodeId) != null; + // NetworkElementConnectionEntity e = this.networkelementConnectionDB.read(nodeId); + // this.networkelementConnectionDB.write(this.joinNe(e, networkElementConnectionEntitiy), nodeId); } /** @@ -289,10 +339,14 @@ public class HtDatabaseEventsService implements ArchiveCleanProvider, DataProvid * @param nodeId of device (mountpoint name) */ @Override - public void updateNetworkConnection22(NetworkElementConnectionEntity networkElementConnectionEntitiy, + public boolean updateNetworkConnection22(NetworkElementConnectionEntity networkElementConnectionEntitiy, String nodeId) { - this.networkelementConnectionDB.updateOrCreate(networkElementConnectionEntitiy, nodeId, - Arrays.asList("is-required", "username", "password")); + LOG.info("update networkelement-connection for {} with data {}", nodeId, networkElementConnectionEntitiy); + return this.networkelementConnectionDB.updateOrCreate(networkElementConnectionEntitiy, nodeId, + Arrays.asList("is-required", "username", "password")) != null; + // NetworkElementConnectionEntity e = this.networkelementConnectionDB.read(nodeId); + // this.networkelementConnectionDB.write(this.joinNe(e, networkElementConnectionEntitiy), nodeId); + } /* please do not remove */ diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/HtDatabaseMaintenanceService.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/HtDatabaseMaintenanceService.java index a675f6876..3e9a93902 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/HtDatabaseMaintenanceService.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/HtDatabaseMaintenanceService.java @@ -46,15 +46,15 @@ public class HtDatabaseMaintenanceService implements HtDatabaseMaintenance { private final EsDataObjectReaderWriter2<MaintenanceEntity> maintenanceRW; private final EsDataObjectReaderWriter2<NetworkElementConnectionEntity> requiredNeRW; - HtDatabaseMaintenanceService(@NonNull HtDatabaseClient client) throws ClassNotFoundException { + public HtDatabaseMaintenanceService(@NonNull HtDatabaseClient client) throws ClassNotFoundException { HtAssert.nonnull(client); // Create control structure maintenanceRW = new EsDataObjectReaderWriter2<>(client, Entity.Maintenancemode, MaintenanceEntity.class, - MaintenanceBuilder.class).setEsIdAttributeName("_id"); + MaintenanceBuilder.class, true).setEsIdAttributeName("_id"); requiredNeRW = new EsDataObjectReaderWriter2<>(client, Entity.NetworkelementConnection, - NetworkElementConnectionEntity.class, NetworkElementConnectionBuilder.class) + NetworkElementConnectionEntity.class, NetworkElementConnectionBuilder.class, true) .setEsIdAttributeName("_id"); } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/MediatorServerDataProvider.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/MediatorServerDataProvider.java index 258104db4..c229006ff 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/MediatorServerDataProvider.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/MediatorServerDataProvider.java @@ -40,7 +40,7 @@ public class MediatorServerDataProvider implements AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(MediatorServerDataProvider.class); private final HtDatabaseClient dbClient; - private final DataObjectAcessor<Data> mediatorserverRW; + private final DataObjectAcessorWithId<Data> mediatorserverRW; private final int REFRESH_INTERVAL = 60; private final Map<String, Data> entries; private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); @@ -55,7 +55,7 @@ public class MediatorServerDataProvider implements AutoCloseable { LOG.info("Start {}", this.getClass().getName()); this.entries = new HashMap<>(); this.dbClient = HtDatabaseClient.getClient(hosts, authUsername, authPassword); - this.mediatorserverRW = new DataObjectAcessor<>(dbClient, Entity.MediatorServer, Data.class); + this.mediatorserverRW = new DataObjectAcessorWithId<>(dbClient, Entity.MediatorServer, Data.class); this.scheduler.scheduleAtFixedRate(onTick, this.REFRESH_INTERVAL, this.REFRESH_INTERVAL, TimeUnit.SECONDS); } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/QueryByFilter.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/QueryByFilter.java index b6a502071..4e7bee9d0 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/QueryByFilter.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/QueryByFilter.java @@ -21,6 +21,8 @@ */ package org.onap.ccsdk.features.sdnr.wt.dataprovider.data; +import java.math.BigInteger; +import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -33,11 +35,13 @@ 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.RangeQueryBuilder; +import org.onap.ccsdk.features.sdnr.wt.common.database.requests.SearchRequest; import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.NetconfTimeStamp; import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.EntityInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.SortOrder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Filter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Pagination; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Sortorder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,48 +51,130 @@ public class QueryByFilter { private static final Logger LOG = LoggerFactory.getLogger(DataObjectAcessorPm.class); private static final List<String> timestampValueNames = Arrays.asList("timestamp", "start", "end"); - private QueryByFilter() { - //Hide + private static List<Sortorder> emptySortOrderList = new ArrayList<>(); + private static List<Filter> emptyFilterList = new ArrayList<>(); + + // Derived from input + private long page; + private long pageSize; + private long fromPage; + private List<Filter> filterList; + private List<Sortorder> sortOrder; + + /** + * Process input from RPC into Queries to database + * + * @param input Input from RPC, for test it could be null + */ + public QueryByFilter(EntityInput input) { + page = -1; + pageSize = -1; + if (input != null) { + @Nullable + Pagination pagination = input.getPagination(); + if (pagination != null) { + BigInteger pageOrNull = pagination.getPage(); + if (pageOrNull != null) { + page = pageOrNull.longValue(); + } + Long pageSizeOrNull = pagination.getSize(); + if (pageSizeOrNull != null) { + pageSize = pageSizeOrNull; + } + } + } + if (page < 0) + page = 1; + if (pageSize < 0) + pageSize = 1; + + fromPage = (page - 1) * pageSize; + if (fromPage < 0 || pageSize > 10000) + throw new IllegalArgumentException("mismatching input parameters. From:" + fromPage + " size:" + pageSize); + + filterList = input.getFilter(); + if (filterList == null) + filterList = emptyFilterList; + sortOrder = input.getSortorder(); + if (sortOrder == null) + sortOrder = emptySortOrderList; + + } + + public QueryBuilder getQueryBuilderByFilter() { + return getQueryBuilderByFilter(""); } - static long getPage(EntityInput input) { - return getPage(input, 1); + public QueryBuilder getQueryBuilderByFilter(String prefix) { + QueryBuilder queryBuilder = fromFilter(filterList, prefix).from(fromPage).size(pageSize); + setSortOrder(queryBuilder, sortOrder, prefix); + return queryBuilder; } - @SuppressWarnings("null") - private static long getPage(EntityInput input, long defaultValue) { - return input.getPagination() != null ? input.getPagination().getPage().longValue() : defaultValue; + public SearchRequest getSearchRequestByFilter(String nodeKey, String uuidKey, String index, String dataType) { + Filter nodeFilter = getFilter(filterList, nodeKey); + if (nodeFilter != null) { + SearchRequest request = new SearchRequest(index, dataType); + request.setQuery( + QueryBuilders.matchQuery(nodeKey, nodeFilter.getFiltervalue()).aggregations(uuidKey).size(0)); + return request; + } else { + String msg = "no nodename in filter found "; + LOG.debug(msg); + throw new IllegalArgumentException(msg); + } } - static long getPageSize(EntityInput input) { - return getPageSize(input, 1); + public SearchRequest getSearchRequestBySortOrder(String nodeKey, String uuidKey, String index, String dataType) { + Sortorder soNode = getSortOrder(sortOrder, nodeKey); + SearchRequest request = new SearchRequest(index, dataType); + QueryBuilder query = null; + if (soNode != null) { + query = QueryBuilders.matchAllQuery().aggregations(nodeKey, convert(soNode.getSortorder())).size(0); + } else { + query = QueryBuilders.matchAllQuery().aggregations(nodeKey).size(0); + } + request.setQuery(query); + return request; } - @SuppressWarnings("null") - private static long getPageSize(EntityInput input, long defaultValue) { - return input.getPagination() != null ? input.getPagination().getSize().longValue() : defaultValue; + public long getPage() { + return page; } + public long getPageSize() { + return pageSize; + } + + public long getPageStartIndex() { + return fromPage; + } - public static QueryBuilder setSortOrder(QueryBuilder query, @Nullable List<Sortorder> sortorder) { - return setSortOrder(query, sortorder, ""); + @Override + public String toString() { + return "QueryByFilter [page=" + page + ", pageSize=" + pageSize + ", fromPage=" + fromPage + ", filterList=" + + filterList + ", sortOrder=" + sortOrder + "]"; } + /* + * Private and static implementations + */ private static QueryBuilder setSortOrder(QueryBuilder query, @Nullable List<Sortorder> sortorder, String prefix) { if (sortorder != null && sortorder.size() > 0) { for (Sortorder so : sortorder) { - query.sort((prefix != null ? prefix : "") + so.getProperty(), - so.getSortorder() == SortOrder.Ascending - ? org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.ASCENDING - : org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.DESCENDING); + query.sort(handlePrefix(prefix, so.getProperty()), convert(so.getSortorder())); } } return query; - } + private static org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder convert(SortOrder sortOrder) { + return sortOrder == SortOrder.Ascending + ? org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.ASCENDING + : org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.DESCENDING; + }; - public static Sortorder getSortOrder(@Nullable List<Sortorder> list, String prop) { + private static Sortorder getSortOrder(@Nullable List<Sortorder> list, String prop) { if (list == null) { return null; } @@ -100,7 +186,7 @@ public class QueryByFilter { return null; } - public static Filter getFilter(@Nullable List<Filter> list, String prop) { + private static Filter getFilter(@Nullable List<Filter> list, String prop) { if (list == null) { return null; } @@ -112,10 +198,6 @@ public class QueryByFilter { return null; } - public static QueryBuilder fromFilter(@Nullable List<Filter> filters) { - return fromFilter(filters, ""); - } - private static String fillTimeStamp(String value) { int idx = value.lastIndexOf("*"); final String REPLACE = "0000-00-00T00:00:00.0Z"; @@ -176,7 +258,7 @@ public class QueryByFilter { c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1); upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); break; - case 6: //switch 10 months (2000-0* or 2000-1*) + case 6: // switch 10 months (2000-0* or 2000-1*) tmpvalue = c.get(Calendar.MONTH); if (tmpvalue < 9) { c.set(Calendar.MONTH, 9); @@ -187,7 +269,7 @@ public class QueryByFilter { upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); break; - case 7: //switch one month (2018-01* or 2018-01-*) + case 7: // switch one month (2018-01* or 2018-01-*) case 8: c.add(Calendar.MONTH, 1); upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); @@ -287,14 +369,14 @@ public class QueryByFilter { } else if (DbFilter.isComparisonValid(v)) { - RangeQueryBuilder q = DbFilter.getRangeQuery((prefix != null ? prefix : "") + p, v); + RangeQueryBuilder q = DbFilter.getRangeQuery(handlePrefix(prefix, p), v); if (q != null) { return q; } else { - return QueryBuilders.matchQuery((prefix != null ? prefix : "") + p, v); + return QueryBuilders.matchQuery(handlePrefix(prefix, p), v); } } else { - return QueryBuilders.matchQuery((prefix != null ? prefix : "") + p, v); + return QueryBuilders.matchQuery(handlePrefix(prefix, p), v); } } else { BoolQueryBuilder query = new BoolQueryBuilder(); @@ -313,22 +395,20 @@ public class QueryByFilter { if (tmpQuery != null) { query.must(tmpQuery); } else { - query.must(QueryBuilders.regex((prefix != null ? prefix : "") + p, - DbFilter.createDatabaseRegex(v))); + query.must(QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v))); } } else { - query.must(QueryBuilders.regex((prefix != null ? prefix : "") + p, - DbFilter.createDatabaseRegex(v))); + query.must(QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v))); } } else if (DbFilter.isComparisonValid(v)) { - RangeQueryBuilder q = DbFilter.getRangeQuery((prefix != null ? prefix : "") + p, v); + RangeQueryBuilder q = DbFilter.getRangeQuery(handlePrefix(prefix, p), v); if (q != null) { query.must(q); } else { - query.must(QueryBuilders.matchQuery((prefix != null ? prefix : "") + p, v)); + query.must(QueryBuilders.matchQuery(handlePrefix(prefix, p), v)); } } else { - query.must(QueryBuilders.matchQuery((prefix != null ? prefix : "") + p, v)); + query.must(QueryBuilders.matchQuery(handlePrefix(prefix, p), v)); } } LOG.trace("Query result. {}", query.toJSON()); @@ -336,4 +416,8 @@ public class QueryByFilter { } } + private static String handlePrefix(String prefix, String p) { + return (prefix != null ? prefix : "") + p; + } + } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/QueryByFilterStatic.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/QueryByFilterStatic.java new file mode 100644 index 000000000..4abe65856 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/QueryByFilterStatic.java @@ -0,0 +1,336 @@ +/* + * ============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.data; + +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; +import org.eclipse.jdt.annotation.Nullable; +import org.onap.ccsdk.features.sdnr.wt.common.database.data.DbFilter; +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.RangeQueryBuilder; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.NetconfTimeStamp; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.EntityInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.SortOrder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Filter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Sortorder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class QueryByFilterStatic { + + private static final Logger LOG = LoggerFactory.getLogger(DataObjectAcessorPm.class); + private static final List<String> timestampValueNames = Arrays.asList("timestamp", "start", "end"); + + private QueryByFilterStatic() { + //Hide + } + + static long getPage(EntityInput input) { + return getPage(input, 1); + } + + private static long getPage(EntityInput input, long defaultValue) { + return input.getPagination() != null ? input.getPagination().getPage().longValue() : defaultValue; + } + + static long getPageSize(EntityInput input) { + return getPageSize(input, 1); + } + + private static long getPageSize(EntityInput input, long defaultValue) { + return input.getPagination() != null ? input.getPagination().getSize().longValue() : defaultValue; + } + + + public static QueryBuilder setSortOrder(QueryBuilder query, @Nullable List<Sortorder> sortorder) { + return setSortOrder(query, sortorder, ""); + } + + private static QueryBuilder setSortOrder(QueryBuilder query, @Nullable List<Sortorder> sortorder, String prefix) { + if (sortorder != null && sortorder.size() > 0) { + for (Sortorder so : sortorder) { + query.sort((prefix != null ? prefix : "") + so.getProperty(), + so.getSortorder() == SortOrder.Ascending + ? org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.ASCENDING + : org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.DESCENDING); + } + } + return query; + + } + + + public static Sortorder getSortOrder(@Nullable List<Sortorder> list, String prop) { + if (list == null) { + return null; + } + for (Sortorder o : list) { + if (prop.equals(o.getProperty())) { + return o; + } + } + return null; + } + + public static Filter getFilter(@Nullable List<Filter> list, String prop) { + if (list == null) { + return null; + } + for (Filter f : list) { + if (prop.equals(f.getProperty())) { + return f; + } + } + return null; + } + + public static QueryBuilder fromFilter(@Nullable List<Filter> filters) { + return fromFilter(filters, ""); + } + + private static String fillTimeStamp(String value) { + int idx = value.lastIndexOf("*"); + final String REPLACE = "0000-00-00T00:00:00.0Z"; + String s = value.substring(0, idx) + REPLACE.substring(idx); + if (Integer.parseInt(s.substring(5, 7)) == 0) { + s = s.substring(0, 5) + "01-" + s.substring(8); + } + if (Integer.parseInt(s.substring(8, 10)) == 0) { + s = s.substring(0, 8) + "01" + s.substring(10); + } + + return s; + } + + /** + * convert timestamp with ending placeholder in filter to elasticsearch filter e.g. 2017* => gte: + * 2017-01-01T00:00:00Z, lt:2018-01-01T00:00:00Z + * + * 201* => 2010-01... 2020 .. 2018-* => 2018-01... <=> 2019-01 + * + */ + private static @Nullable QueryBuilder fromTimestampSearchFilter(String property, String value) { + if (!value.endsWith("*")) { + return null; + } + int idx = value.lastIndexOf("*"); + String lowerEnd = fillTimeStamp(value); + String upperEnd = null; + NetconfTimeStamp converter = NetconfTimeStampImpl.getConverter(); + Date dt = null; + try { + dt = converter.getDateFromNetconf(lowerEnd); + } catch (Exception e) { + + } + if (dt == null) { + return null; + } + // property.substring(0,idx)+REPLACE.substring(idx+1); + Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + c.setTime(dt); + int tmpvalue; + switch (idx) { + case 1: // (2*) + c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1000); + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + case 2: // (20*) + c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 100); + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + case 3: // (200*) + c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 10); + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + case 4: // (2000*) + case 5: // (2000-*) + c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1); + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + case 6: //switch 10 months (2000-0* or 2000-1*) + tmpvalue = c.get(Calendar.MONTH); + if (tmpvalue < 9) { + c.set(Calendar.MONTH, 9); + } else { + c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1); + c.set(Calendar.MONTH, 0); + } + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + + break; + case 7: //switch one month (2018-01* or 2018-01-*) + case 8: + c.add(Calendar.MONTH, 1); + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + case 9: // (2018-01-0*) + tmpvalue = c.get(Calendar.DAY_OF_MONTH); + if (tmpvalue == 1) { + c.set(Calendar.DAY_OF_MONTH, 10); + } else if (tmpvalue == 10) { + c.set(Calendar.DAY_OF_MONTH, 20); + } else if (tmpvalue == 20) { + if (c.getActualMaximum(Calendar.DAY_OF_MONTH) < 30) { + c.set(Calendar.DAY_OF_MONTH, 1); + c.add(Calendar.MONTH, 1); + } else { + c.set(Calendar.DAY_OF_MONTH, 30); + } + } else if (tmpvalue == 30) { + c.set(Calendar.DAY_OF_MONTH, 1); + c.add(Calendar.MONTH, 1); + } else { + break; + } + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + case 10: // (2018-01-01*) + case 11: // (2018-01-01T*) + c.add(Calendar.DAY_OF_MONTH, 1); + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + case 12: // (2018-01-01T1*) + tmpvalue = c.get(Calendar.HOUR_OF_DAY); + if (tmpvalue == 20) { + c.set(Calendar.HOUR_OF_DAY, 0); + c.add(Calendar.DAY_OF_MONTH, 1); + } else { + c.add(Calendar.HOUR_OF_DAY, 10); + } + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + case 13: // (2018-01-01T11*) + case 14: // (2018-01-01T11-*) + c.add(Calendar.HOUR_OF_DAY, 1); + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + case 15: // (2018-01-01T11-3*) + c.add(Calendar.MINUTE, 10); + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + case 16: // (2018-01-01T11-32*) + case 17: // (2018-01-01T11-32-*) + c.add(Calendar.MINUTE, 1); + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + case 18: // (2018-01-01T11-32-1*) + c.add(Calendar.SECOND, 10); + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + case 19: // (2018-01-01T11-32-11*) + case 20: // (2018-01-01T11-32-11.*) + c.add(Calendar.SECOND, 1); + upperEnd = converter.getTimeStampAsNetconfString(c.getTime()); + break; + + default: + break; + } + + if (upperEnd == null) { + return null; + } + return QueryBuilders.rangeQuery(property).gte(lowerEnd).lt(upperEnd); + + } + + private static QueryBuilder fromFilter(@Nullable List<Filter> filters, String prefix) { + if (filters == null || filters.size() == 0) { + return QueryBuilders.matchAllQuery(); + + } else if (filters.size() == 1) { + QueryBuilder query; + String p = filters.get(0).getProperty(); + String v = filters.get(0).getFiltervalue(); + if ("id".equals(p)) { + p = "_id"; + } else { + // v=v.toLowerCase(); + } + if (DbFilter.hasSearchParams(v)) { + if (p != null && timestampValueNames.contains(p.toLowerCase())) { + query = fromTimestampSearchFilter(p, v); + if (query != null) { + return query; + } + } + return QueryBuilders.regex(p, DbFilter.createDatabaseRegex(v)); + + + } else if (DbFilter.isComparisonValid(v)) { + RangeQueryBuilder q = DbFilter.getRangeQuery((prefix != null ? prefix : "") + p, v); + if (q != null) { + return q; + } else { + return QueryBuilders.matchQuery((prefix != null ? prefix : "") + p, v); + } + } else { + return QueryBuilders.matchQuery((prefix != null ? prefix : "") + p, v); + } + } else { + BoolQueryBuilder query = new BoolQueryBuilder(); + QueryBuilder tmpQuery; + for (Filter fi : filters) { + String p = fi.getProperty(); + String v = fi.getFiltervalue(); + if ("id".equals(p)) { + p = "_id"; + } else { + // v=v.toLowerCase(); + } + if (DbFilter.hasSearchParams(v)) { + if (p != null && timestampValueNames.contains(p.toLowerCase())) { + tmpQuery = fromTimestampSearchFilter(p, v); + if (tmpQuery != null) { + query.must(tmpQuery); + } else { + query.must(QueryBuilders.regex((prefix != null ? prefix : "") + p, + DbFilter.createDatabaseRegex(v))); + } + } else { + query.must(QueryBuilders.regex((prefix != null ? prefix : "") + p, + DbFilter.createDatabaseRegex(v))); + } + } else if (DbFilter.isComparisonValid(v)) { + RangeQueryBuilder q = DbFilter.getRangeQuery((prefix != null ? prefix : "") + p, v); + if (q != null) { + query.must(q); + } else { + query.must(QueryBuilders.matchQuery((prefix != null ? prefix : "") + p, v)); + } + } else { + query.must(QueryBuilders.matchQuery((prefix != null ? prefix : "") + p, v)); + } + } + LOG.trace("Query result. {}", query.toJSON()); + return query; + } + } + +} diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/QueryResult.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/QueryResult.java index 61e524192..7570523cd 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/QueryResult.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/QueryResult.java @@ -42,11 +42,22 @@ public class QueryResult<T> { pagination = x.build(); } + public QueryResult(QueryByFilter queryByFilter, SearchResult<T> result) { + this.result = result; + + PaginationBuilder x = new PaginationBuilder(); + x.setPage(BigInteger.valueOf(queryByFilter.getPage())); + x.setSize(queryByFilter.getPageSize()); + x.setTotal(BigInteger.valueOf(result.getTotal())); + pagination = x.build(); + } + + public SearchResult<T> getResult() { return result; } - PaginationOutputG getPagination() { + public PaginationOutputG getPagination() { return pagination; } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/database/EsDataObjectReaderWriter.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/database/EsDataObjectReaderWriter.java deleted file mode 100644 index c0518c664..000000000 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/database/EsDataObjectReaderWriter.java +++ /dev/null @@ -1,357 +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.database; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.util.List; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import org.onap.ccsdk.features.sdnr.wt.common.database.DatabaseClient; -import org.onap.ccsdk.features.sdnr.wt.common.database.SearchHit; -import org.onap.ccsdk.features.sdnr.wt.common.database.SearchResult; -import org.onap.ccsdk.features.sdnr.wt.common.database.queries.QueryBuilder; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.yangtools.YangToolsMapper; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.Entity; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.core.JsonProcessingException; - -/** - * Class to rw yang-tool generated objects into elasticsearch database. For "ES _id" exchange the esIdAddAtributteName - * is used. This attribute mast be of type String and contains for read and write operations the object id. The function - * can be used without id handling. If id handling is required the parameter needs to be specified by class definition - * in yang and setting the name by using setAttributeName() - * - * @param <T> Yang tools generated class object. - */ -public class EsDataObjectReaderWriter<T extends DataObject> { - - private final Logger LOG = LoggerFactory.getLogger(EsDataObjectReaderWriter.class); - - /** Typename for elastic search data schema **/ - private String dataTypeName; - - /** Elasticsearch Database client to be used **/ - private DatabaseClient db; - - /** Mapper with configuration to use opendaylight yang-tools builder pattern for object creation **/ - private YangToolsMapper yangtoolsMapper; - - /** Class of T as attribute to allow JSON to Class object mapping **/ - private Class<T> clazz; - - /** Field is used to write id. If null no id handling **/ - private @Nullable Field field; - - /** Attribute that is used as id field for the database object **/ - private @Nullable String esIdAddAtributteName; - - /** Interface to be used for write operations. Rule for write: T extends S and **/ - private Class<? extends DataObject> writeInterfaceClazz; // == "S" - - /** - * Elasticsearch database read and write for specific class, defined by opendaylight yang-tools. - * - * @param db Database access client - * @param dataTypeName typename in database schema - * @param clazz class of type to be handled - * @throws ClassNotFoundException - */ - public EsDataObjectReaderWriter(DatabaseClient db, Entity dataTypeName, Class<T> clazz) - throws ClassNotFoundException { - this(db, dataTypeName.getName(), clazz); - } - - public EsDataObjectReaderWriter(DatabaseClient db, String dataTypeName, Class<T> clazz) - throws ClassNotFoundException { - LOG.info("Create {} for datatype {} class {}", this.getClass().getName(), dataTypeName, clazz.getName()); - - this.esIdAddAtributteName = null; - this.field = null; - this.writeInterfaceClazz = clazz; - this.db = db; - this.dataTypeName = dataTypeName; - this.yangtoolsMapper = new YangToolsMapper(); - //this.yangtoolsMapper.assertBuilderClass(clazz); - this.clazz = clazz; - // - // if (! db.isExistsIndex(dataTypeName)) { - // throw new IllegalArgumentException("Index "+dataTypeName+" not existing."); - // } - } - - public String getDataTypeName() { - return dataTypeName; - } - - public Class<T> getClazz() { - return clazz; - } - - /** - * Simlar to {@link #setEsIdAttributeName()}, but adapts the parameter to yangtools attribute naming schema - * - * @param esIdAttributeName is converted to UnderscoreCamelCase - * @return this for further operations. - */ - public EsDataObjectReaderWriter<T> setEsIdAttributeNameCamelized(String esIdAttributeName) { - return setEsIdAttributeName(YangToolsMapper.toCamelCaseAttributeName(esIdAttributeName)); - } - - /** - * Attribute name of class that is containing the object id - * - * @param esIdAttributeName of the implementation class for the yangtools interface. Expected attribute name format - * is CamelCase with leading underline. @ - * @return this for further operations. - * @throws SecurityException if no access or IllegalArgumentException if wrong type or no attribute with this name. - */ - public EsDataObjectReaderWriter<T> setEsIdAttributeName(String esIdAttributeName) { - LOG.debug("Set attribute '{}'", esIdAttributeName); - this.esIdAddAtributteName = null; // Reset status - this.field = null; - - Field attributeField; - try { - Builder<T> builder = yangtoolsMapper.getBuilder(clazz); - T object = builder.build(); - attributeField = object.getClass().getDeclaredField(esIdAttributeName); - if (attributeField.getType().equals(String.class)) { - attributeField.setAccessible(true); - this.esIdAddAtributteName = esIdAttributeName; //Set new status if everything OK - this.field = attributeField; - } else { - String msg = "Wrong field type " + attributeField.getType().getName() + " of " + esIdAttributeName; - LOG.debug(msg); - throw new IllegalArgumentException(msg); - } - } catch (NoSuchFieldException e) { - // Convert to run-time exception - String msg = "NoSuchFieldException for '" + esIdAttributeName + "' in class " + clazz.getName(); - LOG.debug(msg); - throw new IllegalArgumentException(msg); - } catch (SecurityException e) { - LOG.debug("Access problem " + esIdAttributeName, e); - throw e; - } - return this; - } - - /** - * Specify subclass of T for write operations. - * - * @param writeInterfaceClazz - */ - public EsDataObjectReaderWriter<T> setWriteInterface(@Nonnull Class<? extends DataObject> writeInterfaceClazz) { - LOG.debug("Set write interface to {}", writeInterfaceClazz); - if (writeInterfaceClazz == null) - throw new IllegalArgumentException("Null not allowed here."); - - this.writeInterfaceClazz = writeInterfaceClazz; - return this; - } - - /** - * Write child object to database with specific id - * - * @param object - * @param @Nullable esId use the id or if null generate unique id - * @return String with id or null - */ - public @Nullable <S extends DataObject> String write(S object, @Nullable String esId) { - if (writeInterfaceClazz.isInstance(object)) { - try { - String json = yangtoolsMapper.writeValueAsString(object); - return db.doWriteRaw(dataTypeName, esId, json); - } catch (JsonProcessingException e) { - LOG.error("Write problem: ", e); - } - } else { - LOG.error("Type {} does not provide interface {}", object != null ? object.getClass().getName() : "null", - writeInterfaceClazz.getName()); - } - return null; - } - - /** - * Update partial child object to database with match/term query - * - * @param object - * @param esId - * @return String with esId or null - */ - public @Nullable <S extends DataObject> boolean update(S object, QueryBuilder query) { - if (writeInterfaceClazz.isInstance(object)) { - try { - String json = yangtoolsMapper.writeValueAsString(object); - return db.doUpdate(this.dataTypeName, json, query); - } catch (JsonProcessingException e) { - LOG.error("Update problem: ", e); - } - } else { - LOG.error("Type {} does not provide interface {}", object != null ? object.getClass().getName() : "null", - writeInterfaceClazz.getName()); - } - return false; - } - - /** - * Write/ update partial child object to database with specific id Write if not exists, else update - * - * @param object - * @param esId - * @return String with esId or null - */ - public @Nullable <S extends DataObject> String update(S object, String esId) { - return this.update(object, esId, null); - } - - public @Nullable <S extends DataObject> String update(S object, String esId, List<String> onylForInsert) { - if (writeInterfaceClazz.isInstance(object)) { - try { - String json = yangtoolsMapper.writeValueAsString(object); - return db.doUpdateOrCreate(dataTypeName, esId, json, onylForInsert); - } catch (JsonProcessingException e) { - LOG.error("Update problem: ", e); - } - } else { - LOG.error("Type {} does not provide interface {}", object != null ? object.getClass().getName() : "null", - writeInterfaceClazz.getName()); - } - return null; - } - - /** - * Read object from database, by using the id field - * - * @param object - * @return - */ - public @Nullable T read(String esId) { - @Nullable - T res = (T) null; - if (esId != null) { - String json = db.doReadJsonData(dataTypeName, esId); - try { - res = yangtoolsMapper.readValue(json.getBytes(), clazz); - } catch (IOException e) { - LOG.error("Problem: ", e); - } - } - return res; - } - - /** - * Remove object - * - * @param esId to identify the object. - * @return success - */ - public boolean remove(String esId) { - return db.doRemove(this.dataTypeName, esId); - } - - public int remove(QueryBuilder query) { - return this.db.doRemove(this.dataTypeName, query); - } - - /** - * Get all elements of related type - * - * @return all Elements - */ - public SearchResult<T> doReadAll() { - return doReadAll(null); - } - - public SearchResult<T> doReadAll(QueryBuilder query) { - return this.doReadAll(query, false); - } - - /** - * Read all existing objects of a type - * - * @param query for the elements - * @return the list of all objects - */ - - public SearchResult<T> doReadAll(QueryBuilder query, boolean ignoreException) { - - SearchResult<T> res = new SearchResult<T>(); - SearchResult<SearchHit> result; - List<SearchHit> hits; - if (query != null) { - LOG.debug("read data in {} with query {}", dataTypeName, query.toJSON()); - result = db.doReadByQueryJsonData(dataTypeName, query, ignoreException); - } else { - result = db.doReadAllJsonData(dataTypeName, ignoreException); - } - hits = result.getHits(); - LOG.debug("Read: {} elements: {} Failures: {}", dataTypeName, hits.size(), - yangtoolsMapper.getMappingFailures()); - - T object; - for (SearchHit hit : hits) { - object = getT(hit.getSourceAsString()); - LOG.debug("Mapp Object: {}\nSource: '{}'\nResult: '{}'\n Failures: {}", hit.getId(), - hit.getSourceAsString(), object, yangtoolsMapper.getMappingFailures()); - if (object != null) { - setEsId(object, hit.getId()); - res.add(object); - } else { - LOG.warn("Mapp result null Object: {}\n Source: '{}'\n : '", hit.getId(), hit.getSourceAsString()); - } - } - res.setTotal(result.getTotal()); - return res; - } - - /* --------------------------------------------- - * Private functions - */ - - private void setEsId(T object, String esId) { - if (field != null) { - try { - field.set(object, esId); - } catch (IllegalArgumentException | IllegalAccessException e) { - LOG.debug("Field set problem.", e); - } - } - } - - private @Nullable T getT(String jsonString) { - try { - return yangtoolsMapper.readValue(jsonString, clazz); - } catch (IOException e) { - LOG.info("Mapping problem", e); - return (T) null; - } - } - -} diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/database/EsDataObjectReaderWriter2.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/database/EsDataObjectReaderWriter2.java index e0f6e4aea..658826986 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/database/EsDataObjectReaderWriter2.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/database/EsDataObjectReaderWriter2.java @@ -21,13 +21,12 @@ */ package org.onap.ccsdk.features.sdnr.wt.dataprovider.database; +import com.fasterxml.jackson.core.JsonProcessingException; import java.io.IOException; import java.lang.reflect.Field; import java.util.List; - import javax.annotation.Nonnull; import javax.annotation.Nullable; - import org.eclipse.jdt.annotation.NonNull; import org.onap.ccsdk.features.sdnr.wt.common.database.DatabaseClient; import org.onap.ccsdk.features.sdnr.wt.common.database.SearchHit; @@ -41,8 +40,6 @@ import org.opendaylight.yangtools.yang.binding.DataObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.core.JsonProcessingException; - /** * Class to rw yang-tool generated objects into elasticsearch database. For "ES _id" exchange the esIdAddAtributteName * is used. This attribute mast be of type String and contains for read and write operations the object id. The function @@ -78,28 +75,23 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { /** Interface to be used for write operations. Rule for write: T extends S and **/ private Class<? extends DataObject> writeInterfaceClazz; // == "S" + /** Flag true to sync this attribute during write always, what is slow and false do not sync */ + private final boolean syncAfterWrite; /** * Elasticsearch database read and write for specific class, defined by opendaylight yang-tools. * + * @param <X> + * @param <B> * @param db Database access client * @param dataTypeName typename in database schema * @param clazz class of type to be handled + * @param builderClazz class to build related object if builder pattern should be used. + * @param syncAfterWrite * @throws ClassNotFoundException */ public <X extends T, @NonNull B extends Builder<X>> EsDataObjectReaderWriter2(DatabaseClient db, - Entity dataTypeName, @Nonnull Class<T> clazz, @Nullable Class<B> builderClazz) - throws ClassNotFoundException { - this(db, dataTypeName.getName(), clazz, builderClazz); - } - - public <X extends T, @NonNull B extends Builder<X>> EsDataObjectReaderWriter2(DatabaseClient db, - Entity dataTypeName, @Nonnull Class<T> clazz) throws ClassNotFoundException { - this(db, dataTypeName.getName(), clazz, null); - } - - public <X extends T, @NonNull B extends Builder<X>> EsDataObjectReaderWriter2(DatabaseClient db, - String dataTypeName, @Nonnull Class<T> clazz, @Nullable Class<B> builderClazz) + String dataTypeName, @Nonnull Class<T> clazz, @Nullable Class<B> builderClazz, boolean syncAfterWrite) throws ClassNotFoundException { LOG.info("Create {} for datatype {} class {}", this.getClass().getName(), dataTypeName, clazz.getName()); @@ -110,11 +102,43 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { this.dataTypeName = dataTypeName; this.yangtoolsMapper = new YangToolsMapper2<>(clazz, builderClazz); this.clazz = clazz; + this.syncAfterWrite = syncAfterWrite; + } + + public <X extends T, @NonNull B extends Builder<X>> EsDataObjectReaderWriter2(DatabaseClient db, + Entity dataTypeName, @Nonnull Class<T> clazz, @Nullable Class<B> builderClazz) + throws ClassNotFoundException { + this(db, dataTypeName.getName(), clazz, builderClazz, false); + } + + public <X extends T, @NonNull B extends Builder<X>> EsDataObjectReaderWriter2(DatabaseClient db, + Entity dataTypeName, @Nonnull Class<T> clazz, @Nullable Class<B> builderClazz, boolean syncAfterWrite) + throws ClassNotFoundException { + this(db, dataTypeName.getName(), clazz, builderClazz, syncAfterWrite); + } + + public EsDataObjectReaderWriter2(DatabaseClient db, Entity dataTypeName, @Nonnull Class<T> clazz, + boolean syncAfterWrite) throws ClassNotFoundException { + this(db, dataTypeName.getName(), clazz, null, syncAfterWrite); + } + + public EsDataObjectReaderWriter2(DatabaseClient db, Entity dataTypeName, Class<T> clazz) + throws ClassNotFoundException { + this(db, dataTypeName.getName(), clazz, null, false); + } + + /** + * Get Datatype name + * + * @return string with dataTypeName + */ + public String getDataTypeName() { + return dataTypeName; } /** * Simlar to {@link #setEsIdAttributeName()}, but adapts the parameter to yangtools attribute naming schema - * + * * @param esIdAttributeName is converted to UnderscoreCamelCase * @return this for further operations. */ @@ -124,7 +148,7 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { /** * Attribute name of class that is containing the object id - * + * * @param esIdAttributeName of the implementation class for the yangtools interface. Expected attribute name format * is CamelCase with leading underline. @ * @return this for further operations. @@ -137,7 +161,7 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { Field attributeField; try { - Builder<T> builder = yangtoolsMapper.getBuilder(clazz); + Builder<? extends T> builder = yangtoolsMapper.getBuilder(clazz); if (builder == null) { String msg = "No builder for " + clazz; LOG.debug(msg); @@ -169,7 +193,7 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { /** * Specify subclass of T for write operations. - * + * * @param writeInterfaceClazz */ public EsDataObjectReaderWriter2<T> setWriteInterface(@Nonnull Class<? extends DataObject> writeInterfaceClazz) { @@ -194,7 +218,7 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { /** * Write child object to database with specific id - * + * * @param object to be written * @param esId use the id or if null generate unique id * @return String with id or null @@ -203,7 +227,7 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { if (object != null && writeInterfaceClazz.isInstance(object)) { try { String json = yangtoolsMapper.writeValueAsString(object); - return db.doWriteRaw(dataTypeName, esId, json); + return db.doWriteRaw(dataTypeName, esId, json, this.syncAfterWrite); } catch (JsonProcessingException e) { LOG.error("Write problem: ", e); } @@ -216,7 +240,7 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { /** * Update partial child object to database with match/term query - * + * * @param <S> of object * @param object to write * @param query for write of specific attributes @@ -239,7 +263,7 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { /** * Write/ update partial child object to database with specific id Write if not exists, else update - * + * * @param object * @param esId * @return String with esId or null @@ -268,7 +292,7 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { /** * Read object from database, by using the id field - * + * * @param object * @return */ @@ -292,7 +316,7 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { /** * Remove object - * + * * @param esId to identify the object. * @return success */ @@ -306,7 +330,7 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { /** * Get all elements of related type - * + * * @return all Elements */ public SearchResult<T> doReadAll() { @@ -319,46 +343,39 @@ public class EsDataObjectReaderWriter2<T extends DataObject> { /** * Read all existing objects of a type - * + * * @param query for the elements * @return the list of all objects */ public SearchResult<T> doReadAll(QueryBuilder query, boolean ignoreException) { - SearchResult<T> res = new SearchResult<>(); - int idx = 0; //Idx for getAll - int iterateLength = 100; //Step width for iterate + SearchResult<T> res = new SearchResult<T>(); SearchResult<SearchHit> result; List<SearchHit> hits; - do { - if (query != null) { - LOG.debug("read data in {} with query {}", dataTypeName, query.toJSON()); - result = db.doReadByQueryJsonData(dataTypeName, query, ignoreException); + if (query != null) { + LOG.debug("read data in {} with query {}", dataTypeName, query.toJSON()); + result = db.doReadByQueryJsonData(dataTypeName, query, ignoreException); + } else { + result = db.doReadAllJsonData(dataTypeName, ignoreException); + } + hits = result.getHits(); + LOG.debug("Read: {} elements: {} Failures: {}", dataTypeName, hits.size(), + yangtoolsMapper.getMappingFailures()); + + T object; + for (SearchHit hit : hits) { + object = getT(hit.getSourceAsString()); + LOG.debug("Mapp Object: {}\nSource: '{}'\nResult: '{}'\n Failures: {}", hit.getId(), + hit.getSourceAsString(), object, yangtoolsMapper.getMappingFailures()); + if (object != null) { + setEsId(object, hit.getId()); + res.add(object); } else { - result = db.doReadAllJsonData(dataTypeName, ignoreException); - } - hits = result.getHits(); - LOG.debug("Read: {} elements: {} Failures: {}", dataTypeName, hits.size(), - yangtoolsMapper.getMappingFailures()); - - T object; - idx += result.getHits().size(); - for (SearchHit hit : hits) { - object = getT(hit.getSourceAsString()); - LOG.debug("Mapp Object: {}\nSource: '{}'\nResult: '{}'\n Failures: {}", hit.getId(), - hit.getSourceAsString(), object, yangtoolsMapper.getMappingFailures()); - if (object != null) { - setEsId(object, hit.getId()); - res.add(object); - } else { - LOG.warn("Mapp result null Object: {}\n Source: '{}'\n : '", hit.getId(), hit.getSourceAsString()); - } + LOG.warn("Mapp result null Object: {}\n Source: '{}'\n : '", hit.getId(), hit.getSourceAsString()); } - - } while (hits.size() == iterateLength); // Do it until end indicated, because less hits than iterateLength - // allows. + } res.setTotal(result.getTotal()); return res; } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/AboutHttpServlet.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/AboutHttpServlet.java index 120684298..fdac1c10a 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/AboutHttpServlet.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/AboutHttpServlet.java @@ -23,7 +23,9 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.http; import java.io.IOException; import java.net.URL; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.jar.Attributes; @@ -35,11 +37,14 @@ 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.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.onap.ccsdk.features.sdnr.wt.dataprovider.data.ODLVersionLUT; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.data.SystemInfo; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,6 +74,7 @@ public class AboutHttpServlet extends HttpServlet { private static final String PLACEHOLDER_MDSAL_VERSION = "{mdsal-version}"; private static final String PLACEHOLDER_YANGTOOLS_VERSION = "{yangtools-version}"; 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 final String groupId = "org.onap.ccsdk.features.sdnr.wt"; @@ -76,14 +82,22 @@ public class AboutHttpServlet extends HttpServlet { private final Map<String, String> data; private final String readmeContent; + // private BundleService bundleService; + public AboutHttpServlet() { this.data = new HashMap<>(); this.collectStaticData(); this.readmeContent = this.render(this.getResourceFileContent(README_FILE)); + //BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); + } + // public void setBundleService(BundleService bundleService) { + // this.bundleService = bundleService; + // } + /** * collect static versioning data */ @@ -96,7 +110,7 @@ public class AboutHttpServlet extends HttpServlet { this.data.put(PLACEHOLDER_ODLUX_REVISION, this.getPomProperty("odlux.buildno")); this.data.put(PLACEHOLDER_PACAKGE_VERSION, this.getManifestValue("Bundle-Version")); this.data.put(PLACEHOLDER_CCSDK_VERSION, ccsdkVersion); - this.data.put(PLACEHOLDER_ONAP_RELEASEVERSION, "1.8.1-SNAPSHOT"); + this.data.put(PLACEHOLDER_ONAP_RELEASEVERSION, "2.0.0-SNAPSHOT"); this.data.put(PLACEHOLDER_MDSAL_VERSION, SystemInfo.getMdSalVersion(UNKNOWN)); this.data.put(PLACEHOLDER_YANGTOOLS_VERSION, SystemInfo.getYangToolsVersion(UNKNOWN)); this.data.put(PLACEHOLDER_PACKAGE_GITHASH, this.getGitHash(UNKNOWN)); @@ -170,6 +184,7 @@ public class AboutHttpServlet extends HttpServlet { LOG.info("collecting dynamic data"); try { this.data.put(PLACEHOLDER_KARAF_INFO, SystemInfo.get()); + this.data.put(PLACEHOLDER_DEVICEMANAGER_TABLE, this.getDevicemanagerBundles()); } catch (Exception e) { LOG.warn("problem collecting system data: {}", e); } @@ -264,6 +279,28 @@ public class AboutHttpServlet extends HttpServlet { return null; } + 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 ""; + } + /** * get file by uri from resources and write out to response stream * diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/DataTreeChildObject.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/DataTreeChildObject.java new file mode 100644 index 000000000..e34988b4b --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/DataTreeChildObject.java @@ -0,0 +1,192 @@ +/* + * ============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.http; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.json.JSONObject; + +public class DataTreeChildObject { + + private final String label; + private final String ownSeverity; + private final String childrenSeveritySummary; + private final boolean isMatch; + private final Map<String, DataTreeChildObject> children; + private final Map<String, Object> properties; + + public boolean isMatch() { + return this.isMatch; + } + + public DataTreeChildObject(String label, boolean isMatch, Map<String, DataTreeChildObject> children, + String ownSeverity, String childrenSeveritySummary) { + this.label = label; + this.isMatch = isMatch; + this.children = children; + this.ownSeverity = ownSeverity; + this.childrenSeveritySummary = childrenSeveritySummary; + this.properties = new HashMap<>(); + } + + public DataTreeChildObject setProperty(String key, Object value) { + this.properties.put(key, value); + return this; + } + + public Object getProperty(String key, Object defaultValue) { + return this.properties.getOrDefault(key, defaultValue); + } + + /** + * @param string + * @param b + */ + public DataTreeChildObject(String label, boolean isMatch) { + this(label, isMatch, new HashMap<>(), null, null); + } + + /** + * @param treeLevel + * @param id + * @param data + * @param childKey + * @param parentKey + * @return + */ + public boolean putChild(long treeLevel, String id, DataTreeChildObject data, String parentKey, String childKey) { + Object itemValue; + Object itemValueToMatch = data.getProperty(parentKey, null); + if (itemValueToMatch == null) { + return false; + } + if (treeLevel > 0) { + if (this.children != null) { + for (DataTreeChildObject child : this.children.values()) { + if (child.putChild(treeLevel - 1, id, data, parentKey, childKey)) { + return true; + } + } + } + } else { + // if(this.children!=null) { + // for(DataTreeChildObject child:this.children.values()) { + // itemValue=(String) child.getProperty(childKey, null); + // if(itemValue!=null && itemValue.equals(itemValueToMatch)) { + // child.children.put(id, data); + // return true; + // } + // } + // } + itemValue = this.getProperty(childKey, null); + if (itemValue != null && itemValue.equals(itemValueToMatch)) { + this.children.put(id, data); + } + } + return false; + } + + /** + * @param treeLevel + * @param id + * @param data + * @param parentKey + * @param childKey + * @return + */ + public boolean putChildIfNotExists(long treeLevel, String id, DataTreeChildObject data, String parentKey, + String childKey) { + Object itemValue; + Object itemValueToMatch = data.getProperty(parentKey, null); + if (itemValueToMatch == null) { + return false; + } + if (treeLevel > 0) { + if (this.children != null) { + for (DataTreeChildObject child : this.children.values()) { + if (child.putChildIfNotExists(treeLevel - 1, id, data, parentKey, childKey)) { + return true; + } + } + } + } else { + itemValue = this.getProperty(childKey, null); + if (itemValue != null && itemValue.equals(itemValueToMatch)) { + if (!this.children.containsKey(id)) { + this.children.put(id, data); + } + } + } + return false; + } + + /** + * @return + */ + public JSONObject toJSONObject() { + JSONObject o = new JSONObject(); + o.put("label", this.label); + o.put("isMatch", this.isMatch); + JSONObject c = new JSONObject(); + if (this.children != null) { + for (Entry<String, DataTreeChildObject> entry : this.children.entrySet()) { + c.put(entry.getKey(), entry.getValue().toJSONObject()); + } + } + o.put("children", c); + // o.put("ownSeverity", null); + // o.put("childrenSeveritySummary", null); + return o; + } + + public boolean hasChildMatching() { + boolean match = false; + for (DataTreeChildObject child : this.children.values()) { + match = match || child.hasChildMatching() || this.isMatch; + if (match) { + break; + } + } + return match; + } + + /** + * + */ + public void removeUnmatchedPaths() { + List<String> toRemove = new ArrayList<>(); + for (Entry<String, DataTreeChildObject> entry : this.children.entrySet()) { + if (!(entry.getValue().hasChildMatching() || entry.getValue().isMatch)) { + toRemove.add(entry.getKey()); + } else { + entry.getValue().removeUnmatchedPaths(); + } + } + for (String key : toRemove) { + this.children.remove(key); + } + } +} diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/DataTreeHttpServlet.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/DataTreeHttpServlet.java index 490f3cac8..245ac1cf6 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/DataTreeHttpServlet.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/DataTreeHttpServlet.java @@ -21,14 +21,29 @@ */ package org.onap.ccsdk.features.sdnr.wt.dataprovider.http; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.json.JSONObject; import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.impl.DataTreeProviderImpl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.Entity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Michael Dürre @@ -36,24 +51,190 @@ import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; */ public class DataTreeHttpServlet extends HttpServlet { + public enum FilterMode { + Strict, //show only filtered items and their parents + Lazy //show root items (and all their children) which have matches inside + } + /** - * @param rawClient + * */ - public void setDatabaseClient(HtDatabaseClient rawClient) { + private static final long serialVersionUID = 1L; + private final DataTreeProviderImpl dataTreeProvider; + private static final Logger LOG = LoggerFactory.getLogger(DataTreeHttpServlet.class); + public DataTreeHttpServlet() { + super(); + this.dataTreeProvider = new DataTreeProviderImpl(); + } + + /** + * @param client + */ + public void setDatabaseClient(HtDatabaseClient client) { + this.dataTreeProvider.setDatabaseClient(client); } + public static String readPayload(HttpServletRequest request) throws IOException { + + String body = null; + StringBuilder stringBuilder = new StringBuilder(); + BufferedReader bufferedReader = null; + + try { + InputStream inputStream = request.getInputStream(); + if (inputStream != null) { + bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + char[] charBuffer = new char[128]; + int bytesRead = -1; + while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { + stringBuilder.append(charBuffer, 0, bytesRead); + } + } else { + stringBuilder.append(""); + } + } catch (IOException ex) { + throw ex; + } finally { + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (IOException ex) { + throw ex; + } + } + } + + body = stringBuilder.toString(); + return body; + } + @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { final String uri = req.getRequestURI(); + LOG.debug("GET request for {}", uri); + final EntityWithTree e = getEntity(uri); + if (e != null) { + LOG.info("GET request for {} to e={} with tree={}", uri, e.entity, e.tree); + switch (e.entity) { + case Inventoryequipment: + DataTreeObject o = this.dataTreeProvider.readInventoryTree(e.tree, null, FilterMode.Lazy); + this.doJsonResponse(resp, o); + break; + default: + this.notAvailble(resp); + break; + } + } else { + LOG.debug("unable to find entity for uri {}", uri); + } } - private void readInventoryTree(String filter) { + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + final String uri = req.getRequestURI(); + String filter = null; + FilterMode mode = FilterMode.Lazy; + try { + final String body = readPayload(req); + JSONObject data = new JSONObject(body); + if (data.has("query")) { + filter = data.getString("query"); + } + if (data.has("mode")) { + mode = data.getString("mode").equals("lazy") ? FilterMode.Lazy : FilterMode.Strict; + } + + } catch (Exception e) { + LOG.warn("problem reading payload: {}", e); + } + LOG.debug("POST request for {}", uri); + final EntityWithTree e = getEntity(uri); + if (e != null) { + switch (e.entity) { + case Inventoryequipment: + DataTreeObject o = this.dataTreeProvider.readInventoryTree(e.tree, filter, mode); + this.doJsonResponse(resp, o); + break; + default: + this.notAvailble(resp); + break; + } + } + } + + /** + * @param resp + */ + private void notAvailble(HttpServletResponse resp) { + try { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + } catch (IOException e) { + + } } - private void doJsonResponse(HttpServletResponse resp, Object data) { + public static EntityWithTree getEntity(String uri) { + final String regex = "^\\/tree\\/read-(.*)-tree\\/?(.*)$"; + final Pattern pattern = Pattern.compile(regex); + final Matcher matcher = pattern.matcher(uri); + Entity e = null; + if (matcher.find() && matcher.groupCount() > 0) { + try { + e = Entity.forName(matcher.group(1)).get(); + return new EntityWithTree(e, matcher.groupCount() > 1 ? matcher.group(2) : null); + } catch (Exception e2) { + LOG.warn("unable to parse {} into entity: {}", matcher.group(2), e2); + } + } + return null; + + } + + private void doJsonResponse(HttpServletResponse resp, DataTreeObject data) { + resp.setHeader("Content-Type", "application/json"); + try { + resp.getWriter().write(data.toJSON()); + } catch (IOException e) { + LOG.warn("problem sending response: {}", e); + } + } + + public static class EntityWithTree { + public final Entity entity; + public final List<String> tree; + + @Override + public String toString() { + return "EntityWithTree [entity=" + entity + ", tree=" + tree + "]"; + } + public EntityWithTree(Entity e, String tree) { + this.entity = e; + if (tree != null) { + if (tree.startsWith("/")) { + tree = tree.substring(1); + } + if (tree.endsWith("/")) { + tree = tree.substring(0, tree.length() - 1); + } + String[] tmp = tree.split("\\/"); + this.tree = new ArrayList<>(); + for (int i = 0; i < tmp.length; i++) { + try { + String s = URLDecoder.decode(tmp[i], "utf-8"); + if (s != null && s.length() > 0) { + this.tree.add(s); + } + } catch (UnsupportedEncodingException e1) { + LOG.warn("problem urldecode {}: {}", tmp[i], e); + } + } + } else { + this.tree = null; + } + } } } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/DataTreeObject.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/DataTreeObject.java new file mode 100644 index 000000000..d6c8bd7bb --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/DataTreeObject.java @@ -0,0 +1,140 @@ +/* + * ============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.http; + +import java.util.HashMap; + +import org.json.JSONObject; + +public class DataTreeObject extends HashMap<String, DataTreeChildObject> { + + private static final long serialVersionUID = 1L; + private final String parentKey; + private final String childKey; + + public DataTreeObject createTreeByPath(String[] pathFilter) { + + if (pathFilter != null && pathFilter.length > 0) { + for (String key : this.keySet()) { + if (key.equals(pathFilter[0])) { + DataTreeChildObject o = this.getChildElemByPath(this.get(key), slice(pathFilter, 1)); + DataTreeObject r = new DataTreeObject(this.parentKey, this.childKey); + r.put(key, o); + return r; + } + } + } + + return null; + + } + + private DataTreeChildObject getChildElemByPath(DataTreeChildObject source, String[] pathFilter) { + + if (pathFilter != null && pathFilter.length > 0) { + // for(String key:source..keySet()) { + // if(key.equals(pathFilter[0])){ + // DataTreeChildObject o= this.getChildElemByPath(this.get(key),slice(pathFilter,1)); + // } + // } + } + + return null; + } + + public DataTreeObject(String parentKey, String childKey) { + this.parentKey = parentKey; + this.childKey = childKey; + } + + /** + * @param treeLevel + * @param id + * @param data + */ + public void put(long treeLevel, String id, DataTreeChildObject data) { + for (DataTreeChildObject entry : this.values()) { + if (entry.putChild(treeLevel, id, data, this.parentKey, this.childKey)) { + break; + } + } + + } + + /** + * + */ + public String toJSON() { + JSONObject o = new JSONObject(); + for (Entry<String, DataTreeChildObject> entry : this.entrySet()) { + o.put(entry.getKey(), entry.getValue().toJSONObject()); + } + return o.toString(); + } + + /** + * + */ + public void removeUnmatchedPaths() { + for (DataTreeChildObject entry : this.values()) { + entry.removeUnmatchedPaths(); + } + + } + + /** + * @param treeLevel + * @param id + * @param setProperty + */ + public void putIfNotExists(long treeLevel, String id, DataTreeChildObject data) { + for (DataTreeChildObject entry : this.values()) { + if (entry.putChildIfNotExists(treeLevel, id, data, this.parentKey, this.childKey)) { + break; + } + } + } + + /** + * @param id + * @param data + */ + public void putIfNotExists(String id, DataTreeChildObject data) { + if (!this.containsKey(id)) { + this.put(id, data); + } + } + + /** + * @param source + * @param i + * @return + */ + public static String[] slice(String[] source, int start) { + String[] r = new String[source.length - start]; + for (int i = 0; i < r.length; i++) { + r[i] = source[i + start]; + } + return r; + + } +} diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/MarkdownTable.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/MarkdownTable.java new file mode 100644 index 000000000..52eda0cd8 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/MarkdownTable.java @@ -0,0 +1,75 @@ +/* + * ============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.http; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Michael Dürre + * + */ +public class MarkdownTable { + + private String[] columns; + private final List<String[]> rows; + + public MarkdownTable() { + this.rows = new ArrayList<>(); + } + + public void setHeader(String[] cols) { + this.columns = cols; + } + + public void addRow(String[] values) { + this.rows.add(values); + } + + public String toMarkDown() { + StringBuilder sb = new StringBuilder(); + final int cols = + this.columns != null ? this.columns.length : this.rows.size() > 0 ? this.rows.get(0).length : 0; + if (cols > 0) { + sb.append("|"); + for (int i = 0; i < cols; i++) { + sb.append(String.format(" %s |", this.columns != null ? this.columns[i] : "")); + } + sb.append("\n"); + sb.append("|"); + for (int i = 0; i < cols; i++) { + sb.append(" --- |"); + } + sb.append("\n"); + sb.append("|"); + for (String[] row : this.rows) { + for (int i = 0; i < cols; i++) { + sb.append(String.format(" %s |", row[i])); + } + sb.append("\n"); + } + + + } + return sb.toString(); + } +} diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/ODLVersionLUT.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/ODLVersionLUT.java index 8027fb2c5..3ea3e3d02 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/ODLVersionLUT.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/ODLVersionLUT.java @@ -19,7 +19,7 @@ * ============LICENSE_END========================================================= * */ -package org.onap.ccsdk.features.sdnr.wt.dataprovider.data; +package org.onap.ccsdk.features.sdnr.wt.dataprovider.http; public class ODLVersionLUT { @@ -27,8 +27,8 @@ public class ODLVersionLUT { if (onapCCSDKVersion == null) { return def; } - if (onapCCSDKVersion.startsWith("1.6.")) { - return "ONAP Guillin"; + if (onapCCSDKVersion.startsWith("2.0.")) { + return "ONAP Guilin"; } if (onapCCSDKVersion.startsWith("1.5.")) { return "ONAP Frankfurt"; @@ -39,6 +39,9 @@ public class ODLVersionLUT { if (onapCCSDKVersion.startsWith("1.3.")) { return "ONAP El Alto"; } + if (onapCCSDKVersion.startsWith("1.2.")) { + return "ONAP Guilin"; + } return def; } @@ -47,8 +50,8 @@ public class ODLVersionLUT { if (onapCCSDKVersion == null) { return def; } - if (onapCCSDKVersion.startsWith("1.6.")) { - return "sodium-SRX (0.11.X)"; + if (onapCCSDKVersion.startsWith("2.")) { + return "sodium-SR3 (0.11.3)"; } if (onapCCSDKVersion.startsWith("1.5.")) { return "neon-SR1 (0.10.1)"; @@ -59,6 +62,9 @@ public class ODLVersionLUT { if (onapCCSDKVersion.startsWith("1.3.")) { return "fluorine-SR2 (0.9.2)"; } + if (onapCCSDKVersion.startsWith("1.2.")) { + return "sodium-SR3 (0.11.3)"; + } return def; } } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/SystemInfo.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/SystemInfo.java index 9b8806ab8..12b03ffe6 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/SystemInfo.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/SystemInfo.java @@ -19,7 +19,7 @@ * ============LICENSE_END========================================================= * */ -package org.onap.ccsdk.features.sdnr.wt.dataprovider.data; +package org.onap.ccsdk.features.sdnr.wt.dataprovider.http; import java.io.File; import java.io.IOException; diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/YangSchemaHttpServlet.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/YangSchemaHttpServlet.java index 075f4f766..48862a6a5 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/YangSchemaHttpServlet.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/http/YangSchemaHttpServlet.java @@ -28,7 +28,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - import org.onap.ccsdk.features.sdnr.wt.dataprovider.data.YangFileProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/impl/DataProviderImpl.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/impl/DataProviderImpl.java index 286af7aa3..f9e0fcbc2 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/impl/DataProviderImpl.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/impl/DataProviderImpl.java @@ -46,6 +46,7 @@ public class DataProviderImpl implements IEntityDataProvider, AutoCloseable { private MsServlet mediatorServerServlet; private DataProviderServiceImpl rpcApiService; private AboutHttpServlet aboutServlet; + private DataTreeHttpServlet treeServlet; private HtDatabaseClient dbClient; // Blueprint 1 @@ -66,12 +67,17 @@ public class DataProviderImpl implements IEntityDataProvider, AutoCloseable { this.aboutServlet = aboutServlet; } + public void setTreeServlet(DataTreeHttpServlet treeServlet) { + this.treeServlet = treeServlet; + } + public void init() throws Exception { LOG.info("Session Initiated start {}", APPLICATION_NAME); // Start RPC Service this.rpcApiService = new DataProviderServiceImpl(rpcProviderService, this.mediatorServerServlet); + this.treeServlet.setDatabaseClient(this.rpcApiService.getRawClient()); LOG.info("Session Initiated end. Initialization done"); } diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/impl/DataTreeProviderImpl.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/impl/DataTreeProviderImpl.java new file mode 100644 index 000000000..2af354bcc --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/impl/DataTreeProviderImpl.java @@ -0,0 +1,321 @@ +/* + * ============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.impl; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.json.JSONObject; +import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; +import org.onap.ccsdk.features.sdnr.wt.common.database.SearchHit; +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.database.requests.Search7Request; +import org.onap.ccsdk.features.sdnr.wt.common.database.requests.SearchRequest; +import org.onap.ccsdk.features.sdnr.wt.common.database.responses.AggregationEntries; +import org.onap.ccsdk.features.sdnr.wt.common.database.responses.SearchResponse; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.DataTreeChildObject; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.DataTreeHttpServlet.FilterMode; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.DataTreeObject; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.Entity; + +/** + * @author Michael Dürre + * + */ +public class DataTreeProviderImpl { + + private static final long MAXSIZE_PERSEARCH = 10; + private HtDatabaseClient dbClient; + final String INVENTORY_PROPERTY_TREELEVEL = "tree-level"; + final String INVENTORY_PROPERTY_NODEID = "node-id"; + final String INVENTORY_PROPERTY_UUID = "uuid"; + final String INVENTORY_PROPERTY_PARENTUUID = "parent-uuid"; + final String INVENTORY_PROPERTY_FOR_LABEL_CHILD = "uuid"; + final String INVENTORY_PROPERTY_FOR_LABEL = "uuid"; + + private List<SearchHit> search(Entity e, String filter, String propTreeLevel) throws IOException { + return this.search(e, filter, null, null, null, null, null, null, propTreeLevel); + } + + private List<SearchHit> search(Entity e, String filter, String nodeKey, String nodeId, String parentKey, + String parentValue, String childKey, String childValue, String propTreeLevel) throws IOException { + QueryBuilder query = + filter == null ? QueryBuilders.matchAllQuery() : QueryBuilders.searchAllFieldsQuery(filter); + if ((nodeId != null && nodeKey != null) || (parentKey != null && parentValue != null)) { + BoolQueryBuilder bquery = new BoolQueryBuilder(); + if (filter != null) { + bquery.must(query); + } + if (nodeId != null) { + bquery.must(QueryBuilders.matchQuery(nodeKey, nodeId)); + } + // if (parentKey != null && parentValue != null) { + // bquery.must(QueryBuilders.matchQuery(parentKey, parentValue)); + // } + // if (childKey != null && childValue != null) { + // bquery.must(QueryBuilders.matchQuery(childKey, childValue)); + // } + query = bquery; + + } + return this.search(e, query, propTreeLevel); + } + + private List<SearchHit> search(Entity e, QueryBuilder query, String propTreeLevel) throws IOException { + List<SearchHit> list = new ArrayList<SearchHit>(); + query.sort(propTreeLevel, SortOrder.ASCENDING); + SearchRequest request = new Search7Request(Entity.Inventoryequipment.getName()); + query.size(MAXSIZE_PERSEARCH); + request.setQuery(query); + SearchResponse response = this.dbClient.search(request); + SearchHit[] matches = response.getHits(); + for (SearchHit hit : matches) { + list.add(hit); + } + if (response.getTotal() > MAXSIZE_PERSEARCH) { + long todo = response.getTotal(); + long from = MAXSIZE_PERSEARCH; + while (todo > from) { + request.setQuery(query.from(from)); + from += MAXSIZE_PERSEARCH; + //merge into list + response = this.dbClient.search(request); + matches = response.getHits(); + for (SearchHit hit : matches) { + list.add(hit); + } + } + } + return list; + } + + /** + * @param iNVENTORY_PROPERTY_NODEID2 + * @return + * @throws IOException + */ + private AggregationEntries searchAggregated(Entity e, String key) throws IOException { + QueryBuilder query = QueryBuilders.matchAllQuery().aggregations(key).size(MAXSIZE_PERSEARCH); + SearchRequest request = new Search7Request(e.getName()); + request.setQuery(query); + SearchResponse response = this.dbClient.search(request); + return response.getAggregations(key); + } + + /** + * + * @param tree + * @param filter + * @param + * @return + * @throws IOException + */ + public DataTreeObject readInventoryTree(List<String> tree, String filter, FilterMode mode) throws IOException { + + //root nodes will be node-information -> below inventory + if (tree == null || tree.size() <= 0) { + return this.readInventoryTreeWithNode(filter, mode); + } + //root node will be inventory on tree-level if sliced treePath + else { + return this.readInventoryTreeForNode(tree.get(0), tree.subList(0, tree.size() - 1), filter, mode); + } + + } + + /** + * @param string + * @param slice + * @param filter + * @param mode + * @return + */ + private DataTreeObject readInventoryTreeForNode(String nodeId, List<String> list, String filter, FilterMode mode) + throws IOException { + DataTreeObject tree = new DataTreeObject(INVENTORY_PROPERTY_PARENTUUID, INVENTORY_PROPERTY_UUID); + final String parentUuid = list.size() > 1 ? list.get(list.size() - 2) : null; + final String uuid = list.size() > 0 ? list.get(list.size() - 1) : null; + List<SearchHit> matches = this.search(Entity.Inventoryequipment, filter, INVENTORY_PROPERTY_NODEID, nodeId, + INVENTORY_PROPERTY_PARENTUUID, parentUuid, INVENTORY_PROPERTY_UUID, uuid, INVENTORY_PROPERTY_TREELEVEL); + + //tree.a(subtreePath); + List<SearchHit> others = this.search(Entity.Inventoryequipment, (String) null, INVENTORY_PROPERTY_TREELEVEL); + if (matches.size() > 0) { + int treeLevelToStart = (list == null || list.size() <= 0) ? 0 : list.size() - 1; + //build tree + JSONObject hitData; + //fill root elems + for (SearchHit hit : matches) { + hitData = hit.getSource(); + if (hitData.getLong("tree-level") == treeLevelToStart) { + tree.put(hit.getId(), + new DataTreeChildObject(hitData.getString(INVENTORY_PROPERTY_FOR_LABEL), true) + .setProperty(INVENTORY_PROPERTY_UUID, hitData.getString(INVENTORY_PROPERTY_UUID)) + .setProperty(INVENTORY_PROPERTY_PARENTUUID, + hitData.getString(INVENTORY_PROPERTY_PARENTUUID))); + } + } + for (SearchHit hit : others) { + hitData = hit.getSource(); + if (hitData.getLong("tree-level") == treeLevelToStart) { + tree.putIfNotExists(hit.getId(), + new DataTreeChildObject(hitData.getString(INVENTORY_PROPERTY_FOR_LABEL), false) + .setProperty(INVENTORY_PROPERTY_UUID, hitData.getString(INVENTORY_PROPERTY_UUID)) + .setProperty(INVENTORY_PROPERTY_PARENTUUID, + hitData.getString(INVENTORY_PROPERTY_PARENTUUID))); + } + } + //fill child elems + for (SearchHit hit : matches) { + hitData = hit.getSource(); + if (hitData.getLong("tree-level") > treeLevelToStart) { + tree.put(hitData.getLong("tree-level") - treeLevelToStart - 1, hit.getId(), + new DataTreeChildObject(hitData.getString(INVENTORY_PROPERTY_FOR_LABEL), true) + .setProperty(INVENTORY_PROPERTY_UUID, hitData.getString(INVENTORY_PROPERTY_UUID)) + .setProperty(INVENTORY_PROPERTY_PARENTUUID, + hitData.getString(INVENTORY_PROPERTY_PARENTUUID))); + } + } + for (SearchHit hit : others) { + hitData = hit.getSource(); + if (hitData.getLong("tree-level") > treeLevelToStart) { + tree.putIfNotExists(hitData.getLong("tree-level") - treeLevelToStart - 1, hit.getId(), + new DataTreeChildObject(hitData.getString(INVENTORY_PROPERTY_FOR_LABEL), false) + .setProperty(INVENTORY_PROPERTY_UUID, hitData.getString(INVENTORY_PROPERTY_UUID)) + .setProperty(INVENTORY_PROPERTY_PARENTUUID, + hitData.getString(INVENTORY_PROPERTY_PARENTUUID))); + } + } + } + return tree; + } + + /** + * node will be root elements inventory information below from level-1 + * + * @param filter + * @param mode + * @return + * @throws IOException + */ + private DataTreeObject readInventoryTreeWithNode(String filter, FilterMode mode) throws IOException { + DataTreeObject tree = new DataTreeObject(INVENTORY_PROPERTY_PARENTUUID, INVENTORY_PROPERTY_UUID); + + List<SearchHit> matches = this.search(Entity.Inventoryequipment, filter, INVENTORY_PROPERTY_TREELEVEL); + List<SearchHit> others = null; + if (matches.size() > 0) { + if (filter != null) { + //find all parents up to tree-level 0 + String nodeId = ""; + List<String> alreadyInList = new ArrayList<>(); + BoolQueryBuilder query2 = QueryBuilders.boolQuery(); + for (SearchHit hit : matches) { + nodeId = hit.getSource().getString(INVENTORY_PROPERTY_NODEID); + if (alreadyInList.contains(nodeId)) { + continue; + } + query2.should(QueryBuilders.matchQuery(INVENTORY_PROPERTY_NODEID, nodeId)); + alreadyInList.add(nodeId); + tree.put(nodeId, + new DataTreeChildObject(nodeId, false).setProperty(INVENTORY_PROPERTY_UUID, nodeId)); + + } + others = this.search(Entity.Inventoryequipment, query2, INVENTORY_PROPERTY_TREELEVEL); + } else { + AggregationEntries nodes = this.searchAggregated(Entity.Inventoryequipment, INVENTORY_PROPERTY_NODEID); + for (String node : nodes.keySet()) { + tree.put(node, new DataTreeChildObject(node, false).setProperty(INVENTORY_PROPERTY_UUID, node)); + } + } + + //build tree + JSONObject hitData; + //fill root elems + for (SearchHit hit : matches) { + hitData = hit.getSource(); + if (hitData.getLong("tree-level") == 0) { + tree.put(0, hit.getId(), + new DataTreeChildObject(hitData.getString(INVENTORY_PROPERTY_FOR_LABEL), true) + .setProperty(INVENTORY_PROPERTY_UUID, hitData.getString(INVENTORY_PROPERTY_UUID)) + .setProperty(INVENTORY_PROPERTY_PARENTUUID, + hitData.getString(INVENTORY_PROPERTY_NODEID))); + } + } + if (others != null) { + for (SearchHit hit : others) { + hitData = hit.getSource(); + if (hitData.getLong("tree-level") == 0) { + tree.putIfNotExists(0, hit.getId(), + new DataTreeChildObject(hitData.getString(INVENTORY_PROPERTY_FOR_LABEL), false) + .setProperty(INVENTORY_PROPERTY_UUID, + hitData.getString(INVENTORY_PROPERTY_UUID)) + .setProperty(INVENTORY_PROPERTY_PARENTUUID, + hitData.getString(INVENTORY_PROPERTY_NODEID))); + } + } + } + //fill child elements + for (SearchHit hit : matches) { + hitData = hit.getSource(); + long treeLevel = hitData.getLong("tree-level"); + if (treeLevel > 0) { + tree.put(treeLevel, hit.getId(), + new DataTreeChildObject(hitData.getString(INVENTORY_PROPERTY_FOR_LABEL_CHILD), true) + .setProperty(INVENTORY_PROPERTY_UUID, hitData.getString(INVENTORY_PROPERTY_UUID)) + .setProperty(INVENTORY_PROPERTY_PARENTUUID, + hitData.getString(INVENTORY_PROPERTY_PARENTUUID))); + } + } + if (others != null) { + for (SearchHit hit : others) { + hitData = hit.getSource(); + long treeLevel = hitData.getLong("tree-level"); + if (hitData.getLong("tree-level") > 0) { + tree.putIfNotExists(treeLevel, hit.getId(), + new DataTreeChildObject(hitData.getString(INVENTORY_PROPERTY_FOR_LABEL_CHILD), false) + .setProperty(INVENTORY_PROPERTY_UUID, + hitData.getString(INVENTORY_PROPERTY_UUID)) + .setProperty(INVENTORY_PROPERTY_PARENTUUID, + hitData.getString(INVENTORY_PROPERTY_PARENTUUID))); + } + } + } + if (mode == FilterMode.Strict) { + tree.removeUnmatchedPaths(); + } + } + return tree; + } + + + + /** + * @param client + */ + public void setDatabaseClient(HtDatabaseClient client) { + this.dbClient = client; + + } +} diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/impl/EsConfig.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/impl/EsConfig.java index 001437771..44751ffd0 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/impl/EsConfig.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/impl/EsConfig.java @@ -26,7 +26,6 @@ import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.List; - import org.onap.ccsdk.features.sdnr.wt.common.configuration.Configuration; import org.onap.ccsdk.features.sdnr.wt.common.configuration.ConfigurationFileRepresentation; import org.onap.ccsdk.features.sdnr.wt.common.configuration.filechange.IConfigChangedListener; @@ -52,13 +51,12 @@ public class EsConfig implements Configuration, IEsConfig { private static final String PROPERTY_KEY_AUTH_PASSWORD = "esAuthPassword"; - private static String defaultHostinfo = "${SDNRDBURL}";//printHosts(new HostInfo[] { new HostInfo("sdnrdb", 9200, Protocol.HTTP) }); + private static String defaultHostinfo = "${SDNRDBURL}"; private static final String DEFAULT_VALUE_CLUSTER = ""; /** check db data in this interval [in seconds] 0 deactivated */ private static final String DEFAULT_ARCHIVE_INTERVAL_SEC = "0"; /** keep data for this time [in seconds] 30 days */ private static final String DEFAULT_ARCHIVE_LIMIT_SEC = String.valueOf(60L * 60L * 24L * 30L); - //private static final String DEFAULT_KEY_NODE = "elasticsearchnode"; private static final String DEFAULT_VALUE_NODE = "elasticsearchnode"; private static final String DEFAULT_VALUE_DBUSERNAME = "${SDNRDBUSERNAME}"; private static final String DEFAULT_VALUE_DBPASSWORD = "${SDNRDBPASSWORD}"; diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/yangtools/YangToolsMapper2.java b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/yangtools/YangToolsMapper2.java index ce67c39dd..814bfd745 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/yangtools/YangToolsMapper2.java +++ b/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/yangtools/YangToolsMapper2.java @@ -59,16 +59,25 @@ public class YangToolsMapper2<T extends DataObject> extends ObjectMapper { private final Logger LOG = LoggerFactory.getLogger(YangToolsMapper2.class); private static final long serialVersionUID = 1L; - private static String ENTITY = "Entity"; private static String BUILDER = "Builder"; - private @Nullable Class<T> clazz; - private @Nullable Class<? extends Builder<? extends T>> builderClazz; + private @Nullable final Class<T> clazz; + private @Nullable final Class<? extends Builder<? extends T>> builderClazz; private BundleContext context; - public <X extends T, B extends Builder<X>> YangToolsMapper2(Class<T> clazz, Class<B> builderClazz) - throws ClassNotFoundException { + /** + * Generic Object creation of yangtools java class builder pattern. + * + * @param <X> Class of DataObject + * @param <B> Builder for the class. + * @param clazz specifies class to be mapped + * @param builderClazz is the builder for class with name pattern "clazzBuilder".<br> + * If null the clazz is expected to support normal jackson build pattern. + * @throws ClassNotFoundException if builderClazz not available in bundle + */ + public <X extends T, B extends Builder<X>> YangToolsMapper2(@NonNull Class<T> clazz, + @Nullable Class<B> builderClazz) throws ClassNotFoundException { super(); configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); setPropertyNamingStrategy(PropertyNamingStrategy.KEBAB_CASE); @@ -84,11 +93,6 @@ public class YangToolsMapper2<T extends DataObject> extends ObjectMapper { context = bundle != null ? bundle.getBundleContext() : null; } - public YangToolsMapper2() throws ClassNotFoundException { - this(null, null); - } - - @Override public String writeValueAsString(Object value) throws JsonProcessingException { return super.writeValueAsString(value); @@ -101,11 +105,12 @@ public class YangToolsMapper2<T extends DataObject> extends ObjectMapper { * @param clazz class with interface. * @return builder for interface or null if not existing */ - @SuppressWarnings("unchecked") - public @Nullable <T extends DataObject> Builder<T> getBuilder(Class<T> clazz) { + public @Nullable Builder<? extends T> getBuilder(Class<T> clazz) { try { - //Class<?> clazzBuilder = getBuilderClass(getBuilderClassName(clazz)); - return (Builder<T>) builderClazz.newInstance(); + if (builderClazz != null) + return (Builder<? extends T>) builderClazz.newInstance(); + else + return null; } catch (InstantiationException | IllegalAccessException e) { LOG.debug("Problem ", e); return null; @@ -169,12 +174,6 @@ public class YangToolsMapper2<T extends DataObject> extends ObjectMapper { */ private static String getBuilderClassName(Class<?> clazz) { return clazz.getName() + BUILDER; - // String clazzName = clazz.getName(); - // if (clazzName.endsWith(ENTITY)) { - // return clazzName.replace(ENTITY, BUILDER); - // } else { - // return clazzName + BUILDER; - // } } /** diff --git a/sdnr/wt/data-provider/provider/src/main/resources/about/README.md b/sdnr/wt/data-provider/provider/src/main/resources/about/README.md index 81c8c6c1e..58091d5da 100644 --- a/sdnr/wt/data-provider/provider/src/main/resources/about/README.md +++ b/sdnr/wt/data-provider/provider/src/main/resources/about/README.md @@ -1,4 +1,4 @@ - +## Version Info | | | | --- | ----- | | ONAP release | {release-name} | @@ -12,6 +12,11 @@ | ODLUX version | {odlux-revision} | | Cluster size | {cluster-size} | +## Device manager + +{devicemanagers} + +## System Info ``` {karaf-info} ```
\ No newline at end of file diff --git a/sdnr/wt/data-provider/provider/src/main/resources/es-init.sh b/sdnr/wt/data-provider/provider/src/main/resources/es-init.sh deleted file mode 100755 index 67d495aa0..000000000 --- a/sdnr/wt/data-provider/provider/src/main/resources/es-init.sh +++ /dev/null @@ -1,446 +0,0 @@ -#!/bin/bash -# ============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========================================================================== -# -# Version 2 -# Usage .. see help below - -SDNRNAME=sdnrdb -REPLICAS=1 -SHARDS=5 -PREFIX="" -VERSION="-v1" -VERBOSE=0 -INITFILENAME="Init.script" - -#declare -a ALIAS -#declare -a MAPPING - -# ------------------------------------------------------------ -# Function with definition of mappings -# $1: alias name for index -# $2: mapping properties and additonal parameter for this section - -set_definition() { - def "connectionlog" '{"node-id": {"type": "keyword"},"timestamp": {"type": "date"},"status": {"type": "keyword"}}' - def "maintenancemode" '{"node-id": {"type": "keyword"},"start": {"type": "date"},"end": {"type": "date"},"description": {"type": "keyword"},"active": {"type": "boolean"}},"date_detection":false}}' - def "faultlog" '{"node-id": {"type": "keyword"},"severity": {"type": "keyword"},"timestamp": {"type": "date"},"problem": {"type": "keyword"},"counter": {"type": "long"},"object-id":{"type": "keyword"},"source-type":{"type": "keyword"}}' - def "faultcurrent" '{"node-id": {"type": "keyword"},"severity": {"type": "keyword"},"timestamp": {"type": "date"},"problem": {"type": "keyword"},"counter": {"type": "long"},"object-id":{"type": "keyword"}}' - def "eventlog" '{"node-id": {"type": "keyword"},"source-type": {"type": "keyword"},"timestamp": {"type": "date"},"new-value": {"type": "keyword"},"attribute-name": {"type": "keyword"},"counter": {"type": "long"},"object-id": {"type": "keyword"}}' - def "inventoryequipment" '{"date": {"type": "keyword"},"model-identifier": {"type": "keyword"},"manufacturer-identifier": {"type": "keyword"},"type-name": {"type": "keyword"},"description": {"type": "keyword"},"uuid": {"type": "keyword"},"version": {"type": "keyword"},"parent-uuid": {"type": "keyword"},"contained-holder": {"type": "keyword"},"node-id": {"type": "keyword"},"tree-level": {"type": "long"},"part-type-id": {"type": "keyword"},"serial": {"type": "keyword"}}' - def "historicalperformance24h" '{"node-name":{"type": "keyword"},"timestamp":{"type": "date"},"suspect-interval-flag":{"type":"boolean"},"scanner-id":{"type": "keyword"},"uuid-interface":{"type": "keyword"},"layer-protocol-name":{"type": "keyword"},"granularity-period":{"type": "keyword"},"radio-signal-id":{"type": "keyword"}}' - def "historicalperformance15min" '{"node-name":{"type": "keyword"},"timestamp":{"type": "date"},"suspect-interval-flag":{"type":"boolean"},"scanner-id":{"type": "keyword"},"uuid-interface":{"type": "keyword"},"layer-protocol-name":{"type": "keyword"},"granularity-period":{"type": "keyword"},"radio-signal-id":{"type": "keyword"}}' - def "mediator-server" '{"url":{"type": "keyword"},"name":{"type": "keyword"}}' - def "networkelement-connection" '{"node-id": {"type": "keyword"},"host": {"type": "keyword"},"port": {"type": "long"},"username": {"type": "keyword"},"password": {"type": "keyword"},"core-model-capability": {"type": "keyword"},"device-type": {"type": "keyword"},"is-required": {"type": "boolean"},"status": {"type": "keyword"}},"date_detection":false' -} - -# ------------------------------------------------------------ -# Functions - -# Get ip of container with database -getsdnrurl() { - if [ ! -z "$DBURL" ]; then - return - fi - cmd=$(which docker) - if [ ! -z "$cmd" ]; then - SDNRIP=$($cmd inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$SDNRNAME") - if [ "$?" = "1" ] ; then - echo "WARN: Container $SDNRNAME not running. Start the sdnrdb container or enter a database url." - echo "continuing with localhost" - SDNRIP="localhost" - fi - else - # if no docker and no db url given - if [ -z "$DBURL" ]; then - echo "WARN: Please enter a database url." - echo "continuing with localhost" - SDNRIP="localhost" - fi - fi - DBURL="http://$SDNRIP:9200" -} - -# Add elements to the array ALIAS and MAPPING -# $1 alias -# $2 mapping properties -def() { - ALIAS=("${ALIAS[@]}" "$1") - MAPPING=("${MAPPING[@]}" "$2") -} - -# $1 Response -print_response() { - response="$1" - body=$(echo $response | sed -E 's/HTTPSTATUS\:[0-9]{3}$//') - code=$(echo $response | tr -d '\n' | sed -E 's/.*HTTPSTATUS:([0-9]{3})$/\1/') - if [ "$VERBOSE" = "0" -a "$code" -ne "200" ] ; then - echo "Error response $code $body" - fi - if [ "$VERBOSE" -ge 1 ] ; then - echo "response $code" - fi - if [ "$VERBOSE" -ge 2 ] ; then - echo "content: $body" - fi -} - -#Write ini file for elasticsearch -# $1 index -# $1 data -file_append() { - echo "PUT:"$1"/:"$2 >> $INITFILENAME -} - -# Send get request to database -# USes DBURL -# $1 url path -# $2 data -http_get_request() { - url="$DBURL/$1" - if [ "$VERBOSE" -ge 2 ] ; then - echo "PUT to $url data $data" - fi - response=$(curl --silent --write-out "HTTPSTATUS:%{http_code}" -X GET -H "Content-Type: application/json" "$url") - print_response "$response" -} - -# Send put request to database -# USes DBURL -# $1 url path -# $2 data -http_put_request() { - url="$DBURL/$1" - if [ "$VERBOSE" -ge 2 ] ; then - echo "PUT to $url data $data" - fi - response=$(curl --silent --write-out "HTTPSTATUS:%{http_code}" -X PUT -H "Content-Type: application/json" -d "$2" "$url") - print_response "$response" -} - -# Send delete request to database -# $1 url -http_delete_request() { - url="$DBURL/$1" - if [ "$VERBOSE" -ge 2 ] ; then - echo "DELETE to $url" - fi - echo "DELETE to $url" - response=$(curl --silent --write-out "HTTPSTATUS:%{http_code}" -X DELETE -H "Content-Type: application/json" $url) - print_response "$response" -} - -# Delete index and alias -# $1 alias -delete_index_alias() { - - echo "deleting alias $alias" - # Delete alias - alias="$PREFIX$1" - index="$PREFIX$1$VERSION" - - url="$index/_alias/$alias" - http_delete_request "$url" - - # Delete index - echo "deleting index $index" - url="$index" - http_delete_request "$url" - - # Delete alias that was falsely autocreated as index - echo "deleting index $index" - url="$alias" - http_delete_request "$url" -} - -# Write mappings -# Uses version, SHARDS and REPLICAS parameters -# $1 alias and datatype "mydatatype" -# $2 mapping properties -# $3 filename or empty for WEB -create_index_alias() { - # Create index - alias="$PREFIX$1" - index="$PREFIX$1$VERSION" - mappings='"mappings":{"'$1'":{"properties":'$2'}}' - settings='"settings":{"index":{"number_of_shards":'$SHARDS',"number_of_replicas":'$REPLICAS'},"analysis":{"analyzer":{"content":{"type":"custom","tokenizer":"whitespace"}}}}' - - if [ -z "$mappings" ]; then - data="{$settings}" - else - data="{$settings,$mappings}" - fi - - url=$index - echo "creating index $index" - if [ -z "$3" ] ; then - http_put_request "$url" "$data" - else - file_append "$url" "$data" - fi - - #Create alias - url="$index/_alias/$alias" - echo "creating alias $alias for $index" - if [ -z "$3" ] ; then - http_put_request "$url" - else - file_append "$url" "{}" - fi -} - -# Wait for status -# $1 time to wait -es_wait_yellow() { - ESSTATUS="yellow" - attempt_counter=0 - max_attempts=5 - echo "Wait up to $max_attempts attempts for $DBURL availability" - until $(curl --output /dev/null --silent --head --fail $DBURL); do - if [ ${attempt_counter} -eq ${max_attempts} ];then - echo "Error: Max attempts reached." - exit 3 - fi - attempt_counter=$(($attempt_counter+1)) - printf '.' - sleep 5 - done - sleep 2 - echo "Wait up to $1 for status $ESSTATUS" - RES=$(curl GET "$DBURL/_cluster/health?wait_for_status=$ESSTATUS&timeout=$1&pretty" 2>/dev/null) - if [ "$?" = "0" ] ; then - if [[ "$RES" =~ .*status.*:.*yellow.* || "$RES" =~ .*status.*:.*green.* ]] ; then - echo "Status $ESSTATUS reached: $RES" - else - echo "Error: DB Reachable, but status $ESSTATUS not reached" - exit 2 - fi - else - echo "Error: $DBURL not reachable" - exit 2 - fi -} - -# Commands - -cmd_create() { - if [ -n "$WAITYELLOW" ] ; then - es_wait_yellow "$WAITYELLOW" - fi - for i in "${!ALIAS[@]}"; do - create_index_alias "${ALIAS[$i]}" "${MAPPING[$i]}" - done -} - -cmd_delete() { - if [ -n "$WAITYELLOW" ] ; then - es_wait_yellow "$WAITYELLOW" - fi - for i in "${!ALIAS[@]}"; do - delete_index_alias "${ALIAS[$i]}" - done - for i in "${!ALIAS[@]}"; do - delete_index_alias "${ALIAS[$i]}" - done -} -cmd_purge() { -# http_get_request '_cat/aliases' -# body=$(echo $response | sed -E 's/HTTPSTATUS\:[0-9]{3}$//') -# echo "$response" | awk '/^([^ ]*)[ ]*([^ ]*).*$/{ print $2"/_alias/"$1 }' -# http_get_request '_cat/indices' -# echo "indices" -# echo "$response" -# echo "$response" | awk '/^[^ ]*[ ]*[^ ]*[ ]*([^ ]*).*$/{ print $3 }' - echo "not yet implemented" -} -cmd_initfile() { - echo "Create script initfile: $INITFILENAME" - if [ -f "$INITFILENAME" ] ; then - rm $INITFILENAME - else - mkdir -p $(dirname $INITFILENAME ) - fi - for i in "${!ALIAS[@]}"; do - create_index_alias "${ALIAS[$i]}" "${MAPPING[$i]}" file - done -} - -# Prepare database startup -cmd_startup() { - ESWAIT=30s - echo "Startup ElasticSearch DBURL=$DBURL CMD=$STARTUP_CMD CLUSTER=$CLUSTER_ENABLED INDEX=$NODE_INDEX" - if $CLUSTER_ENABLED ; then - if [ "$NODE_INDEX" = "0" ] ; then - echo "Cluster node 0 detected .. create" - es_wait_yellow $ESWAIT - cmd_create - else - echo "Cluster node > 0 detected .. do nothing" - fi - else - echo "No cluster" - es_wait_yellow $ESWAIT - cmd_create - fi -} - -# Parse arguments -parse_args() { - while [[ $# -gt 0 ]] - do - par=($(echo $1 | tr '=' '\n')) - echo "" - if [ ${#par[@]} == "2" ] ; then - # Equal sign found - key=${par[0]} - value=${par[1]} - else - # No equal sign - key="$1" - value="$2" - fi - shift - #Further shift if parameter is used - case $key in - -db|--dburl|--database) - DBURL="$value" - shift - ;; - -r|--replicas) - REPLICAS="$value" - shift - ;; - -s|--shards) - SHARDS="$value" - shift - ;; - -p|--prefix) - PREFIX="$value" - shift - ;; - -f|--file) - INITFILENAME="$value" - shift - ;; - -x|--verbose) - VERBOSE="${value:-0}" - shift - ;; - -v|--version) - VERSION="${value:--v1}" - shift - ;; - -vx|--versionx) - VERSION="" - ;; - -w|--wait) - WAITYELLOW="${value:-30s}" - shift - ;; - --cmd) - STARTUP_CMD="$value" - shift - ;; - --odlcluster) - CLUSTER_ENABLED="$value" - shift - ;; - --index) - NODE_INDEX="$value" - shift - ;; - *) - ;; - esac; - done -} - -# ----------------------------------------- -# Main starts here - -TASK=$1 -shift -parse_args "$@" - -set_definition - - -echo "------------------------------" -echo "Elasticsearch for SDN-R helper" -echo "------------------------------" -echo "Uses database container $SDNRNAME" -echo "Database url $DBURL" -echo " shards=$SHARDS replicas=$REPLICAS prefix=$PREFIX verbose=$VERBOSE version='$VERSION'" - - -case "$TASK" in - "create") - getsdnrurl - if [ -z "$DBURL" ] ; then - echo "Error: unable to detect database url." - exit 1 - fi - cmd_create - ;; - "delete") - getsdnrurl - if [ -z "$DBURL" ] ; then - echo "Error: unable to detect database url." - exit 1 - fi - cmd_delete - ;; - "purge") - getsdnrurl - if [ -z "$DBURL" ] ; then - echo "Error: unable to detect database url." - exit 1 - fi - cmd_purge - ;; - "initfile") - cmd_initfile - ;; - "startup") - cmd_startup - ;; - *) - echo "usage:" - echo " es-init.sh COMMAND [OPTIONS]" - echo " Commands:" - echo " create create SDN-R used indices and aliases" - echo " delete delete SDN-R used indices and aliases" - echo " initfile Create initfile for java unit tests" - echo " purge Clear complete database (indices and aliases)" - echo " startup Initial database write if node number 01" - echo " Options:" - echo -e " -db\--database DATABASEURL" - echo -e " -r\--replicas REPLICAS" - echo -e " -s\--shards SHARDS" - echo -e " -p\--prefix DATABASE-PREFIX" - echo -e " -f\--file init filename" - echo -e " -x\--verbose Verbose level less 0 .. 2 full" - echo -e " -v\--version Version prefix" - echo -e " -vx\--versionx Version prefix empty" - echo -e " -i\--ignore Ignore error responses" - echo -e " --odlcluster true/false if odl configured as cluster" - echo -e " --index Cluster node 0.." - echo -e " --cmd startup sub command" - echo " examples:" - echo " single node db:" - echo " es-init.sh create -db http://sdnrdb:9200 -r 0" - ;; -esac 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 fcd62ff79..ad9661f66 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 @@ -30,6 +30,8 @@ interface="org.opendaylight.mdsal.binding.api.RpcProviderService" odl:type="default"/> +<!-- <reference id="bundleService" interface="org.apache.karaf.bundle.core.BundleService" odl:type="default"/> --> + <bean id="readyServlet" class="org.onap.ccsdk.features.sdnr.wt.dataprovider.http.ReadyHttpServlet"> </bean> @@ -41,7 +43,8 @@ </service> <bean id="aboutServlet" - class="org.onap.ccsdk.features.sdnr.wt.dataprovider.http.AboutHttpServlet"> + class="org.onap.ccsdk.features.sdnr.wt.dataprovider.http.about.AboutHttpServlet"> +<!-- <property name="bundleService" ref="bundleService"/> --> </bean> <service interface="javax.servlet.http.HttpServlet" ref="aboutServlet"> @@ -58,17 +61,26 @@ <entry key="alias" value="/ms"/> </service-properties> </service> + <bean id="treeServlet" + class="org.onap.ccsdk.features.sdnr.wt.dataprovider.http.DataTreeHttpServlet"> + </bean> + <service interface="javax.servlet.http.HttpServlet" ref="treeServlet"> + <service-properties> + <entry key="alias" value="/tree"/> + </service-properties> + </service> <bean id="provider" class="org.onap.ccsdk.features.sdnr.wt.dataprovider.impl.DataProviderImpl" init-method="init" destroy-method="close"> <property name="rpcProviderService" ref="rpcProviderService"/> <property name="aboutServlet" ref="aboutServlet"/> + <property name="treeServlet" ref="treeServlet"/> <property name="mediatorServerServlet" ref="msServlet"/> </bean> <bean id="yangServlet" - class="org.onap.ccsdk.features.sdnr.wt.dataprovider.http.YangSchemaHttpServlet"> + class="org.onap.ccsdk.features.sdnr.wt.dataprovider.http.yangschema.YangSchemaHttpServlet"> </bean> <service interface="javax.servlet.http.HttpServlet" ref="yangServlet"> diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestAbout.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestAbout.java index f147e8724..5d9011ab0 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestAbout.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestAbout.java @@ -25,7 +25,6 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.AboutHttpServlet; - import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestCRUDforDatabase.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestCRUDforDatabase.java index 5cf2f0644..a22f3033d 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestCRUDforDatabase.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestCRUDforDatabase.java @@ -41,6 +41,7 @@ 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.BaseRequest; import org.onap.ccsdk.features.sdnr.wt.dataprovider.data.ElasticSearchDataProvider; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.test.util.HostInfoForTest; import org.onap.ccsdk.features.sdnr.wt.dataprovider.yangtools.YangToolsMapper; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.CreateMaintenanceInput; @@ -123,12 +124,11 @@ public class TestCRUDforDatabase { private static ElasticSearchDataProvider dbProvider; private static HtDatabaseClient dbRawProvider; - public static HostInfo[] hosts = new HostInfo[] {new HostInfo("localhost", Integer - .valueOf(System.getProperty("databaseport") != null ? System.getProperty("databaseport") : "49200"))}; @BeforeClass public static void init() throws Exception { + HostInfo[] hosts = HostInfoForTest.get(); dbProvider = new ElasticSearchDataProvider(hosts); dbProvider.waitForYellowDatabaseStatus(30, TimeUnit.SECONDS); dbRawProvider = HtDatabaseClient.getClient(hosts); @@ -337,7 +337,6 @@ public class TestCRUDforDatabase { // ==UPDATE============================ System.out.println("Trying to update..."); - final String name2 = "sim88"; final String url2 = "10.5.10.2"; final long port2 = 5960; diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestConfig.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestConfig.java index 1275b0372..9a96986c0 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestConfig.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestConfig.java @@ -22,13 +22,15 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.test; import static org.junit.Assert.assertEquals; + import java.io.File; -import java.lang.reflect.Field; -import java.util.Map; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.onap.ccsdk.features.sdnr.wt.common.configuration.ConfigurationFileRepresentation; +import org.onap.ccsdk.features.sdnr.wt.common.configuration.subtypes.Section; +import org.onap.ccsdk.features.sdnr.wt.common.configuration.subtypes.Section.EnvGetter; import org.onap.ccsdk.features.sdnr.wt.dataprovider.impl.EsConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,7 +40,8 @@ public class TestConfig { private static final Logger LOG = LoggerFactory.getLogger(TestConfig.class); private static final String TESTFILENAME = "testconfig.properties"; - private static final String HOSTNAME = "localhost"; + private static String ENVSDNRDBURL = "SDNRDBURL"; + private static String SDNRDBURL = "http://sdnrdb:9200"; @After @Before @@ -52,35 +55,16 @@ public class TestConfig { @Test public void test() { - int databasePort = setSDNRDBURLEnv(); - + EnvGetter env = Section.getEnvGetter(); + Section.setEnvGetter((envname) -> { + return envname.equals(ENVSDNRDBURL) ? SDNRDBURL : env.getenv(envname); + }); ConfigurationFileRepresentation configuration = new ConfigurationFileRepresentation(TESTFILENAME); EsConfig esConfig = new EsConfig(configuration); LOG.info("Defaultconfiguration: {}", esConfig.toString()); assertEquals("http", esConfig.getHosts()[0].protocol.getValue()); - assertEquals(databasePort, esConfig.getHosts()[0].port); - assertEquals(HOSTNAME, esConfig.getHosts()[0].hostname); - - } - - public static int setSDNRDBURLEnv() { - int databasePort = Integer - .valueOf(System.getProperty("databaseport") != null ? System.getProperty("databaseport") : "49200"); - System.out.println("DB Port: " + databasePort); - setEnv("SDNRDBURL", "http://"+HOSTNAME+":"+databasePort); - return databasePort; - } + assertEquals(9200, esConfig.getHosts()[0].port); + assertEquals("sdnrdb", esConfig.getHosts()[0].hostname); - public static void setEnv(String key, String value) { - try { - Map<String, String> env = System.getenv(); - Class<?> cl = env.getClass(); - Field field = cl.getDeclaredField("m"); - field.setAccessible(true); - Map<String, String> writableEnv = (Map<String, String>) field.get(env); - writableEnv.put(key, value); - } catch (Exception e) { - throw new IllegalStateException("Failed to set environment variable", e); - } } } diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestEventService.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestEventService.java index 6d54016cd..9c95a7d98 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestEventService.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestEventService.java @@ -34,11 +34,13 @@ import org.junit.Test; import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; import org.onap.ccsdk.features.sdnr.wt.common.database.SearchHit; import org.onap.ccsdk.features.sdnr.wt.common.database.SearchResult; +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.dataprovider.data.ElasticSearchDataProvider; import org.onap.ccsdk.features.sdnr.wt.dataprovider.data.HtDatabaseEventsService; import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.test.util.HostInfoForTest; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.ConnectionLogStatus; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.ConnectionlogBuilder; @@ -78,9 +80,10 @@ public class TestEventService { @BeforeClass public static void init() throws Exception { - dbProvider = new ElasticSearchDataProvider(TestCRUDforDatabase.hosts); + HostInfo[] hosts = HostInfoForTest.get(); + dbProvider = new ElasticSearchDataProvider(hosts); dbProvider.waitForYellowDatabaseStatus(30, TimeUnit.SECONDS); - dbRawProvider = HtDatabaseClient.getClient(TestCRUDforDatabase.hosts); + dbRawProvider = HtDatabaseClient.getClient(hosts); try { service = new HtDatabaseEventsService(dbRawProvider, dbProvider); diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestFilterConversion.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestFilterConversion.java index 52ca2999d..5c2a66e75 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestFilterConversion.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestFilterConversion.java @@ -24,54 +24,89 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.test; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.util.Arrays; import java.util.List; import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.stubbing.Answer; import org.onap.ccsdk.features.sdnr.wt.common.database.queries.QueryBuilder; +import org.onap.ccsdk.features.sdnr.wt.common.database.requests.SearchRequest; import org.onap.ccsdk.features.sdnr.wt.dataprovider.data.QueryByFilter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.EntityInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.SortOrder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Filter; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.FilterBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Sortorder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.SortorderBuilder; -public class TestFilterConversion { +public class TestFilterConversion extends Mockito { private static final String PROPERTY = "node-id"; private static final String PROPERTY2 = "_id"; private static final String PROPERTY3 = "timestamp"; @Test - public void testQuestionMark() { + public void testQuestionMark1() { + EntityInput input = mock(EntityInput.class); List<Filter> filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY).setFiltervalue("si?ba").build()); - QueryBuilder query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + + QueryBuilder query = new QueryByFilter(input).getQueryBuilderByFilter(); System.out.println(query.toJSON()); + assertTrue(query.toJSON().contains("{1,1}")); - assertNotNull(QueryByFilter.getFilter(filters, PROPERTY)); - assertNull(QueryByFilter.getFilter(filters, PROPERTY2)); - filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY).setFiltervalue("si?ba").build(), + assertNotNull(new QueryByFilter(input).getQueryBuilderByFilter(PROPERTY)); + + } + + @Test + public void testQuestionMarkExcpetion() { + EntityInput input = mock(EntityInput.class); + List<Filter> filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY).setFiltervalue("si?ba").build()); + when(input.getFilter()).thenReturn(filters); + try { + new QueryByFilter(input).getSearchRequestByFilter("test1", "test2", "test3", "test4"); + fail(); + } catch (IllegalArgumentException e) { // fails if type not correct + + } + + } + + @Test + public void testQuestionMark2() { + EntityInput input = mock(EntityInput.class); + List<Filter> filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY).setFiltervalue("si?ba").build(), new FilterBuilder().setProperty(PROPERTY2).setFiltervalue("abc").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + QueryBuilder query = new QueryByFilter(input).getQueryBuilderByFilter(); System.out.println(query.toJSON()); - assertNotNull(QueryByFilter.getFilter(filters, PROPERTY2)); - filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY).setFiltervalue("si?ba").build(), + assertNotNull(new QueryByFilter(input).getQueryBuilderByFilter(PROPERTY2)); + } + + @Test + public void testQuestionMark3() { + EntityInput input = mock(EntityInput.class); + List<Filter> filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY).setFiltervalue("si?ba").build(), new FilterBuilder().setProperty(PROPERTY3).setFiltervalue("<2019-06-13T15:00:12.0Z").build()); - query = QueryByFilter.fromFilter(filters); List<Sortorder> sortorder = Arrays.asList(new SortorderBuilder().setProperty(PROPERTY).setSortorder(SortOrder.Ascending).build()); - QueryByFilter.setSortOrder(query, sortorder); - assertNotNull(QueryByFilter.getSortOrder(sortorder, PROPERTY)); + when(input.getFilter()).thenReturn(filters); + when(input.getSortorder()).thenReturn(sortorder); + + assertNotNull(new QueryByFilter(input).getQueryBuilderByFilter(PROPERTY)); } @Test public void testSortorder() { - String f = - "{\"input\":{\"filter\":[],\"sortorder\":[{\"property\":\"source-type\",\"sortorder\":\"ascending\"}],\"pagination\":{\"size\":10,\"page\":1}}}"; - - QueryBuilder query = QueryByFilter.setSortOrder(QueryByFilter.fromFilter(null), Arrays - .asList(new SortorderBuilder().setProperty("source-type").setSortorder(SortOrder.Ascending).build())); + EntityInput input = mock(EntityInput.class); + List<Sortorder> sortorder = Arrays + .asList(new SortorderBuilder().setProperty("source-type").setSortorder(SortOrder.Ascending).build()); + when(input.getSortorder()).thenReturn(sortorder); + QueryBuilder query = new QueryByFilter(input).getQueryBuilderByFilter(); System.out.println(query.toJSON()); } } diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestImplementation.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestImplementation.java index cc880d1ad..2aedabee4 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestImplementation.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestImplementation.java @@ -26,46 +26,53 @@ import static org.junit.Assert.fail; import java.util.Set; import org.junit.Test; +import org.onap.ccsdk.features.sdnr.wt.common.configuration.subtypes.Section; +import org.onap.ccsdk.features.sdnr.wt.common.configuration.subtypes.Section.EnvGetter; import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.AboutHttpServlet; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.DataTreeHttpServlet; import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.MsServlet; import org.onap.ccsdk.features.sdnr.wt.dataprovider.impl.DataProviderImpl; import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.StatusChangedHandler.StatusKey; import org.opendaylight.mdsal.binding.api.RpcProviderService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.DataProviderService; import org.opendaylight.yangtools.concepts.ObjectRegistration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcService; -import net.bytebuddy.implementation.bytecode.StackSize; - /** * @author Michael Dürre * */ public class TestImplementation { + static String XY = "http://localhost:" + + (System.getProperty("databaseport") != null ? System.getProperty("databaseport") : "49200"); + @Test public void test() { - TestConfig.setSDNRDBURLEnv(); + //TestConfig.setSDNRDBURLEnv("http://localhost:"+(System.getProperty("databaseport") != null ? System.getProperty("databaseport") : "49200")); + EnvGetter env = Section.getEnvGetter(); + Section.setEnvGetter((xy) -> { + System.out.println("Search " + xy); + return xy.equals("SDNRDBURL") ? XY : env.getenv(xy); + }); DataProviderImpl impl = new DataProviderImpl(); impl.setRpcProviderService(new RpcProviderService() { @Override public <S extends RpcService, T extends S> ObjectRegistration<T> registerRpcImplementation(Class<S> type, T implementation, Set<InstanceIdentifier<?>> paths) { - // TODO Auto-generated method stub return null; } @Override public <S extends RpcService, T extends S> ObjectRegistration<T> registerRpcImplementation(Class<S> type, T implementation) { - // TODO Auto-generated method stub return null; } }); impl.setMediatorServerServlet(new MsServlet()); impl.setAboutServlet(new AboutHttpServlet()); + impl.setTreeServlet(new DataTreeHttpServlet()); try { impl.init(); } catch (Exception e) { diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestMaintenanceServiceData.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestMaintenanceServiceData.java index 5839738e6..897fcc8d0 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestMaintenanceServiceData.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestMaintenanceServiceData.java @@ -30,10 +30,12 @@ import java.util.concurrent.TimeUnit; 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.dataprovider.data.ElasticSearchDataProvider; import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.HtDatabaseMaintenance; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.test.util.HostInfoForTest; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.Entity; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.MaintenanceBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.MaintenanceEntity; @@ -53,9 +55,10 @@ public class TestMaintenanceServiceData { @BeforeClass public static void init() throws Exception { - dbProvider = new ElasticSearchDataProvider(TestCRUDforDatabase.hosts); + HostInfo[] hosts = HostInfoForTest.get(); + dbProvider = new ElasticSearchDataProvider(hosts); dbProvider.waitForYellowDatabaseStatus(30, TimeUnit.SECONDS); - dbRawProvider = HtDatabaseClient.getClient(TestCRUDforDatabase.hosts); + dbRawProvider = HtDatabaseClient.getClient(hosts); service = dbProvider.getHtDatabaseMaintenance(); } diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestMediatorServerService.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestMediatorServerService.java index 83f8de89e..7afc5214c 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestMediatorServerService.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestMediatorServerService.java @@ -29,20 +29,20 @@ import java.util.concurrent.TimeUnit; 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.dataprovider.data.ElasticSearchDataProvider; import org.onap.ccsdk.features.sdnr.wt.dataprovider.data.MediatorServerDataProvider; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.test.util.HostInfoForTest; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.CreateMediatorServerInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.CreateMediatorServerOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.Entity; /** * @author Michael Dürre - * */ public class TestMediatorServerService { - private static final String SERVERID = null; private static ElasticSearchDataProvider dbProvider; private static HtDatabaseClient dbRawProvider; private static MediatorServerDataProvider service = null; @@ -50,13 +50,11 @@ public class TestMediatorServerService { @BeforeClass public static void init() throws Exception { - - dbProvider = new ElasticSearchDataProvider(TestCRUDforDatabase.hosts); + HostInfo[] hosts = HostInfoForTest.get(); + dbProvider = new ElasticSearchDataProvider(hosts); dbProvider.waitForYellowDatabaseStatus(30, TimeUnit.SECONDS); - dbRawProvider = HtDatabaseClient.getClient(TestCRUDforDatabase.hosts); - service = new MediatorServerDataProvider(TestCRUDforDatabase.hosts); - - + dbRawProvider = HtDatabaseClient.getClient(hosts); + service = new MediatorServerDataProvider(hosts); } @Test diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestNuMappings.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestNuMappings.java index f9c8812a8..bcd2ea75d 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestNuMappings.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestNuMappings.java @@ -21,9 +21,7 @@ */ package org.onap.ccsdk.features.sdnr.wt.dataprovider.test; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; +import static org.junit.Assert.assertTrue; import java.io.IOException; import org.junit.Test; import org.onap.ccsdk.features.sdnr.wt.dataprovider.yangtools.YangToolsMapper; @@ -34,28 +32,20 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.pro public class TestNuMappings { @Test - public void test33() { + public void testMapObjectToJson() throws IOException { + YangToolsMapper mapper = new YangToolsMapper(); + Faultcurrent c = new FaultcurrentBuilder().setSeverity(SeverityType.Critical).build(); + String json = mapper.writeValueAsString(c); + assertTrue("Critical expected", json.contains(SeverityType.Critical.getName())); + } + + @Test + public void testMapJsonToObject() throws IOException { YangToolsMapper mapper = new YangToolsMapper(); - try { - System.out.println(mapper.writeValueAsString(c) + "<=>" + SeverityType.Critical.getName()); - } catch (JsonProcessingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - try { - Faultcurrent f = mapper.readValue("{\"severity\":\"Critical\"}", Faultcurrent.class); - System.out.println(f); - System.out.println(mapper.writeValueAsString(f)); - } catch (JsonParseException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (JsonMappingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + + Faultcurrent f = mapper.readValue("{\"severity\":\"Critical\"}", Faultcurrent.class); + assertTrue("Critical expected", f.getSeverity().equals(SeverityType.Critical)); } + } diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestTimestampFilter.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestTimestampFilter.java index 39377d730..e757e24d3 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestTimestampFilter.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestTimestampFilter.java @@ -30,134 +30,165 @@ import java.util.List; import org.json.JSONObject; import org.junit.Test; +import org.mockito.Mockito; import org.onap.ccsdk.features.sdnr.wt.common.database.queries.QueryBuilder; import org.onap.ccsdk.features.sdnr.wt.dataprovider.data.QueryByFilter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.EntityInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Filter; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.FilterBuilder; -public class TestTimestampFilter { +public class TestTimestampFilter extends Mockito { @Test public void testTimestampRange() { final String PROPERTY_TIMESTAMP = "timestamp"; List<Filter> filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2017*").build()); - QueryBuilder query = QueryByFilter.fromFilter(filters); + EntityInput input = mock(EntityInput.class); + when(input.getFilter()).thenReturn(filters); + QueryBuilder query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2017-01-01T00:00:00.0Z", "2018-01-01T00:00:00.0Z"); filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2000-01-01T00:00:00.0Z", "3000-01-01T00:00:00.0Z"); filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("20*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2000-01-01T00:00:00.0Z", "2100-01-01T00:00:00.0Z"); filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("205*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-01-01T00:00:00.0Z", "2060-01-01T00:00:00.0Z"); filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-01-01T00:00:00.0Z", "2051-01-01T00:00:00.0Z"); filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-01-01T00:00:00.0Z", "2051-01-01T00:00:00.0Z"); filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-1*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-01T00:00:00.0Z", "2051-01-01T00:00:00.0Z"); filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-01T00:00:00.0Z", "2050-11-01T00:00:00.0Z"); filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-01T00:00:00.0Z", "2050-11-01T00:00:00.0Z"); filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-0*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-01T00:00:00.0Z", "2050-10-10T00:00:00.0Z"); filters = Arrays .asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-02*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-02T00:00:00.0Z", "2050-10-03T00:00:00.0Z"); filters = Arrays .asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-14*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-14T00:00:00.0Z", "2050-10-15T00:00:00.0Z"); filters = Arrays .asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-14T*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-14T00:00:00.0Z", "2050-10-15T00:00:00.0Z"); filters = Arrays .asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-14T1*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-14T10:00:00.0Z", "2050-10-14T20:00:00.0Z"); filters = Arrays .asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-14T12*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-14T12:00:00.0Z", "2050-10-14T13:00:00.0Z"); filters = Arrays .asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-14T12:*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-14T12:00:00.0Z", "2050-10-14T13:00:00.0Z"); filters = Arrays .asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-14T12:4*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-14T12:40:00.0Z", "2050-10-14T12:50:00.0Z"); filters = Arrays.asList( new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-14T12:42*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-14T12:42:00.0Z", "2050-10-14T12:43:00.0Z"); filters = Arrays.asList( new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-14T12:42:*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-14T12:42:00.0Z", "2050-10-14T12:43:00.0Z"); filters = Arrays.asList( new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-14T12:42:5*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-14T12:42:50.0Z", "2050-10-14T12:43:00.0Z"); filters = Arrays.asList( new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2050-10-14T12:42:56*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2050-10-14T12:42:56.0Z", "2050-10-14T12:42:57.0Z"); } @Test public void testExtra() { final String PROPERTY_TIMESTAMP = "end"; - List<Filter> filters = null; - QueryBuilder query = null; + EntityInput input = mock(EntityInput.class); + List<Filter> filters; + filters = Arrays .asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2020-02-19T*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + QueryBuilder query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2020-02-19T00:00:00.0Z", "2020-02-20T00:00:00.0Z"); + filters = Arrays .asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2020-02-19*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2020-02-19T00:00:00.0Z", "2020-02-20T00:00:00.0Z"); + filters = Arrays.asList(new FilterBuilder().setProperty(PROPERTY_TIMESTAMP).setFiltervalue("2020*").build()); - query = QueryByFilter.fromFilter(filters); + when(input.getFilter()).thenReturn(filters); + query = new QueryByFilter(input).getQueryBuilderByFilter(); assertRange(query.getInner(), PROPERTY_TIMESTAMP, "2020-01-01T00:00:00.0Z", "2021-01-01T00:00:00.0Z"); } + private void assertRange(JSONObject rangeQuery, String property, String lower, String upper) { System.out.println("==test for " + rangeQuery.toString()); assertTrue(rangeQuery.has("range")); 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 new file mode 100644 index 000000000..f2a7ff951 --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestTree.java @@ -0,0 +1,81 @@ +/* + * ============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.test; + +import java.io.IOException; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +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.dataprovider.data.ElasticSearchDataProvider; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.DataTreeHttpServlet; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.DataTreeHttpServlet.EntityWithTree; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.DataTreeHttpServlet.FilterMode; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.DataTreeObject; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.impl.DataTreeProviderImpl; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.test.util.HostInfoForTest; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.Entity; + +/** + * @author Michael Dürre + * + */ +public class TestTree { + + private static ElasticSearchDataProvider dbProvider; + private static HtDatabaseClient dbRawProvider; + + @BeforeClass + public static void init() throws Exception { + HostInfo[] hosts = HostInfoForTest.get(); + dbProvider = new ElasticSearchDataProvider(hosts); + dbProvider.waitForYellowDatabaseStatus(30, TimeUnit.SECONDS); + dbRawProvider = HtDatabaseClient.getClient(hosts); + } + + @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); + + tree = provider.readInventoryTree(Arrays.asList("sim1"), "CARD", FilterMode.Lazy); + System.out.println(tree.toJSON()); + + } + + @Test + public void testUriConversion() { + EntityWithTree e = DataTreeHttpServlet.getEntity("/tree/read-inventoryequipment-tree/sim1/sim1%2FODU"); + System.out.println(e); + e = DataTreeHttpServlet.getEntity("/tree/read-inventoryequipment-tree/"); + System.out.println(e); + } +} diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestYangGenSalMapping.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestYangGenSalMapping.java index 585f7dee2..4221891b3 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestYangGenSalMapping.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestYangGenSalMapping.java @@ -25,19 +25,19 @@ import java.io.IOException; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.json.JSONObject; import org.junit.Test; -import org.onap.ccsdk.features.sdnr.wt.common.database.DatabaseClient; import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; import org.onap.ccsdk.features.sdnr.wt.common.database.SearchResult; import org.onap.ccsdk.features.sdnr.wt.common.database.config.HostInfo; -import org.onap.ccsdk.features.sdnr.wt.common.database.config.HostInfo.Protocol; 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.dataprovider.database.EsDataObjectReaderWriter; +import org.onap.ccsdk.features.sdnr.wt.common.database.requests.CreateIndexRequest; +import org.onap.ccsdk.features.sdnr.wt.common.database.requests.DeleteIndexRequest; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.database.EsDataObjectReaderWriter2; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.test.util.HostInfoForTest; import org.onap.ccsdk.features.sdnr.wt.dataprovider.yangtools.YangToolsMapper; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime; @@ -58,22 +58,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.pro import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.pmdata15m.entity.PerformanceDataBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.Data; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.DataBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataContainer; -import org.opendaylight.yangtools.yang.binding.DataObject; public class TestYangGenSalMapping { // Create mapper for serialization and deserialization YangToolsMapper mapper = new YangToolsMapper(); - private static HostInfo[] getHostinfo() { - int databasePort = Integer - .valueOf(System.getProperty("databaseport") != null ? System.getProperty("databaseport") : "49200"); - System.out.println("DB Port: " + databasePort); - return new HostInfo[] {new HostInfo("localhost", databasePort, Protocol.HTTP)}; - } - @Test public void test1() throws IOException { @@ -86,9 +76,10 @@ public class TestYangGenSalMapping { loginPasswordBuilder.setPassword("myTestPassword"); netconfNodeBuilder.setCredentials(loginPasswordBuilder.build()); - OdlHelloMessageCapabilitiesBuilder odlHelloMessageCapabilitiesBuilder = new OdlHelloMessageCapabilitiesBuilder(); + OdlHelloMessageCapabilitiesBuilder odlHelloMessageCapabilitiesBuilder = + new OdlHelloMessageCapabilitiesBuilder(); List<Uri> uriList = new ArrayList<>(); - uriList.add( new Uri("test.uri") ); + uriList.add(new Uri("test.uri")); odlHelloMessageCapabilitiesBuilder.setCapability(uriList); netconfNodeBuilder.setOdlHelloMessageCapabilities(odlHelloMessageCapabilitiesBuilder.build()); @@ -104,50 +95,39 @@ public class TestYangGenSalMapping { NetconfNode generatedNode = mapper.readValue(res.getBytes(), NetconfNode.class); out(generatedNode.toString()); // Print it with specified indentation // Compare result - out("Equal? "+netconfNode.equals(generatedNode)); - } - - static class TestDataObjectBuilder implements Builder<TestDataObject> { - @Override - public @NonNull TestDataObject build() throws IllegalArgumentException { - return new TestDataObject(); - } - } - - static class TestDataObject implements DataObject { - String test; - - @Override - public Class<? extends DataContainer> getImplementedInterface() { - return null; - } + //TODO - Guilin + //out("Equal? "+netconfNode.equals(generatedNode)); } @Test - public void test2() throws Exception { + public void test2() throws Exception { - int databasePort = Integer.valueOf(System.getProperty("databaseport")!=null?System.getProperty("databaseport"):"49200"); - System.out.println("DB Port: "+databasePort); - - HostInfo[] HOSTINFOS = new HostInfo[] { new HostInfo("localhost", databasePort ,Protocol.HTTP)}; - DatabaseClient db = HtDatabaseClient.getClient(HOSTINFOS); - - EsDataObjectReaderWriter<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.Data> dataRW = - new EsDataObjectReaderWriter<>(db, "inventorytest", org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.Data.class); + final String idx = "inventorytest"; + HostInfo[] hostInfo = HostInfoForTest.get(); + HtDatabaseClient db = HtDatabaseClient.getClient(hostInfo); + EsDataObjectReaderWriter2<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.Data> dataRW = + new EsDataObjectReaderWriter2<>(db, Entity.Inventoryequipment, + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.Data.class); + if (!db.isExistsIndex(idx)) { + db.createIndex(new CreateIndexRequest(idx)); + } org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.Data d1; d1 = getInventoryDataBuilder("MyDescription", 23L).build(); - String id = dataRW.write(d1,null); + String id = dataRW.write(d1, null); org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.Data d2; d2 = dataRW.read(id); out(d2.toString()); + if (db.isExistsIndex(idx)) { + db.deleteIndex(new DeleteIndexRequest(idx)); + } } @Test - public void test3() throws IOException { + public void test3() throws IOException { PerformanceDataBuilder performanceBuilder = new PerformanceDataBuilder(); performanceBuilder.setEs(99); @@ -168,88 +148,125 @@ public class TestYangGenSalMapping { @Test public void test4() throws IOException { - - String jsonString = "{\n" + "\"node-name\": \"Sim2230\",\n" + "\"uuid-interface\": \"LP-MWPS-TTP-RADIO\",\n" - + "\"layer-protocol-name\": \"MWPS\",\n" + "\"radio-signal-id\": \"Test8\",\n" - + "\"time-stamp\": \"2017-03-01T09:15:00.0Z\",\n" + "\"granularity-period\": \"Period15Min\",\n" - + "\"scanner-id\": \"PM_RADIO_15M_4\",\n" + "\"performance-data\": {\n" + "\"unavailability\": 0,\n" - + "\"tx-level-max\": 3,\n" + "\"tx-level-avg\": 3,\n" + "\"rx-level-min\": -44,\n" - + "\"rx-level-max\": -45,\n" + "\"rx-level-avg\": -44,\n" + "\"time2-states\": 0,\n" - + "\"time4-states-s\": 0,\n" + "\"time4-states\": 0,\n" + "\"time8-states\": -1,\n" - + "\"time16-states-s\": -1,\n" + "\"time16-states\": 0,\n" + "\"time32-states\": -1,\n" - + "\"time64-states\": 900,\n" + "\"time128-states\": -1,\n" + "\"time256-states\": -1,\n" - + "\"time512-states\": -1,\n" + "\"time512-states-l\": -1,\n" + "\"time1024-states\": -1,\n" - + "\"time1024-states-l\": -1,\n" + "\"time8192-states-l\": -1,\n" + "\"time8192-states\": -1,\n" - + "\"time2048-states\": -1,\n" + "\"snir-min\": -99,\n" + "\"snir-max\": -99,\n" - + "\"snir-avg\": -99,\n" + "\"xpd-min\": -99,\n" + "\"xpd-max\": -99,\n" + "\"xpd-avg\": -99,\n" - + "\"rf-temp-min\": -99,\n" + "\"rf-temp-max\": -99,\n" + "\"rf-temp-avg\": -99,\n" - + "\"defect-blocks-sum\": -1,\n" + "\"time-period\": 900,\n" + "\"cses\": 0,\n" - + "\"time4096-states-l\": -1,\n" + "\"tx-level-min\": 3,\n" + "\"es\": 0,\n" - + "\"time2048-states-l\": -1,\n" + "\"time4096-states\": -1,\n" + "\"ses\": 0\n" + "},\n" - + "\"suspect-interval-flag\": false\n" + "}\n" + "}"; + // @formatter:off + String jsonString = "{\n" + + "\"node-name\": \"Sim2230\",\n" + + "\"uuid-interface\": \"LP-MWPS-TTP-RADIO\",\n" + + "\"layer-protocol-name\": \"MWPS\",\n" + + "\"radio-signal-id\": \"Test8\",\n" + + "\"time-stamp\": \"2017-03-01T09:15:00.0Z\",\n" + + "\"granularity-period\": \"Period15Min\",\n" + + "\"scanner-id\": \"PM_RADIO_15M_4\",\n" + + "\"performance-data\": {\n" + + "\"unavailability\": 0,\n" + + "\"tx-level-max\": 3,\n" + + "\"tx-level-avg\": 3,\n" + + "\"rx-level-min\": -44,\n" + + "\"rx-level-max\": -45,\n" + + "\"rx-level-avg\": -44,\n" + + "\"time2-states\": 0,\n" + + "\"time4-states-s\": 0,\n" + + "\"time4-states\": 0,\n" + + "\"time8-states\": -1,\n" + + "\"time16-states-s\": -1,\n" + + "\"time16-states\": 0,\n" + + "\"time32-states\": -1,\n" + + "\"time64-states\": 900,\n" + + "\"time128-states\": -1,\n" + + "\"time256-states\": -1,\n" + + "\"time512-states\": -1,\n" + + "\"time512-states-l\": -1,\n" + + "\"time1024-states\": -1,\n" + + "\"time1024-states-l\": -1,\n" + + "\"time8192-states-l\": -1,\n" + + "\"time8192-states\": -1,\n" + + "\"time2048-states\": -1,\n" + + "\"snir-min\": -99,\n" + + "\"snir-max\": -99,\n" + + "\"snir-avg\": -99,\n" + + "\"xpd-min\": -99,\n" + + "\"xpd-max\": -99,\n" + + "\"xpd-avg\": -99,\n" + + "\"rf-temp-min\": -99,\n" + + "\"rf-temp-max\": -99,\n" + + "\"rf-temp-avg\": -99,\n" + + "\"defect-blocks-sum\": -1,\n" + + "\"time-period\": 900,\n" + + "\"cses\": 0,\n" + + "\"time4096-states-l\": -1,\n" + + "\"tx-level-min\": 3,\n" + + "\"es\": 0,\n" + + "\"time2048-states-l\": -1,\n" + + "\"time4096-states\": -1,\n" + + "\"ses\": 0\n" + + "},\n" + + "\"suspect-interval-flag\": false\n" + + "}\n" + + "}"; + // @formatter:on // Map to JSON String to Object Data generatedNode = mapper.readValue(jsonString.getBytes(), Data.class); out(generatedNode.toString()); // Print it with specified indentation - } @Test public void test5() throws IOException { - String jsonString = "{\n" + - " \"time-stamp\": \"2017-03-01T06:45:00.0Z\",\n" + - " \"node-name\": \"Sim2230\",\n" + - " \"uuid-interface\": \"LP-MWPS-TTP-RADIO\",\n" + - " \"scanner-id\": \"PM_RADIO_15M_14\",\n" + - " \"layer-protocol-name\": \"MWPS\",\n" + - " \"granularity-period\": \"Period15Min\",\n" + - " \"radio-signal-id\": \"Test8\",\n" + - " \"suspect-interval-flag\": false,\n" + - " \"performance-data\": {\n" + - " \"time4096-states-l\": -1,\n" + - " \"time16-states-s\": -1,\n" + - " \"tx-level-max\": 3,\n" + - " \"snir-max\": -99,\n" + - " \"time16-states\": 0,\n" + - " \"time64-states\": 900,\n" + - " \"unavailability\": 0,\n" + - " \"time8192-states-l\": -1,\n" + - " \"time512-states\": -1,\n" + - " \"xpd-min\": -99,\n" + - " \"xpd-avg\": -99,\n" + - " \"tx-level-avg\": 3,\n" + - " \"tx-level-min\": 3,\n" + - " \"rf-temp-min\": -99,\n" + - " \"rf-temp-avg\": -99,\n" + - " \"snir-avg\": -99,\n" + - " \"snir-min\": -99,\n" + - " \"time-period\": 900,\n" + - " \"time2-states\": 0,\n" + - " \"time4-states\": 0,\n" + - " \"time8-states\": -1,\n" + - " \"ses\": 0,\n" + - " \"time2048-states-l\": -1,\n" + - " \"time2048-states\": -1,\n" + - " \"xpd-max\": -99,\n" + - " \"rf-temp-max\": -99,\n" + - " \"time8192-states\": -1,\n" + - " \"time128-states\": -1,\n" + - " \"time256-states\": -1,\n" + - " \"rx-level-min\": -44,\n" + - " \"rx-level-avg\": -44,\n" + - " \"time1024-states-l\": -1,\n" + - " \"es\": 0,\n" + - " \"cses\": 0,\n" + - " \"time4-states-s\": 0,\n" + - " \"time1024-states\": -1,\n" + - " \"time512-states-l\": -1,\n" + - " \"time4096-states\": -1,\n" + - " \"rx-level-max\": -45,\n" + - " \"defect-blocks-sum\": -1,\n" + - " \"time32-states\": -1\n" + - " }\n" + - "}"; - + // @formatter:off + String jsonString = "{\n" + + " \"time-stamp\": \"2017-03-01T06:45:00.0Z\",\n" + + " \"node-name\": \"Sim2230\",\n" + + " \"uuid-interface\": \"LP-MWPS-TTP-RADIO\",\n" + + " \"scanner-id\": \"PM_RADIO_15M_14\",\n" + + " \"layer-protocol-name\": \"MWPS\",\n" + + " \"granularity-period\": \"Period15Min\",\n" + + " \"radio-signal-id\": \"Test8\",\n" + + " \"suspect-interval-flag\": false,\n" + + " \"performance-data\": {\n" + + " \"time4096-states-l\": -1,\n" + + " \"time16-states-s\": -1,\n" + + " \"tx-level-max\": 3,\n" + + " \"snir-max\": -99,\n" + + " \"time16-states\": 0,\n" + + " \"time64-states\": 900,\n" + + " \"unavailability\": 0,\n" + + " \"time8192-states-l\": -1,\n" + + " \"time512-states\": -1,\n" + + " \"xpd-min\": -99,\n" + + " \"xpd-avg\": -99,\n" + + " \"tx-level-avg\": 3,\n" + + " \"tx-level-min\": 3,\n" + + " \"rf-temp-min\": -99,\n" + + " \"rf-temp-avg\": -99,\n" + + " \"snir-avg\": -99,\n" + + " \"snir-min\": -99,\n" + + " \"time-period\": 900,\n" + + " \"time2-states\": 0,\n" + + " \"time4-states\": 0,\n" + + " \"time8-states\": -1,\n" + + " \"ses\": 0,\n" + + " \"time2048-states-l\": -1,\n" + + " \"time2048-states\": -1,\n" + + " \"xpd-max\": -99,\n" + + " \"rf-temp-max\": -99,\n" + + " \"time8192-states\": -1,\n" + + " \"time128-states\": -1,\n" + + " \"time256-states\": -1,\n" + + " \"rx-level-min\": -44,\n" + + " \"rx-level-avg\": -44,\n" + + " \"time1024-states-l\": -1,\n" + + " \"es\": 0,\n" + + " \"cses\": 0,\n" + + " \"time4-states-s\": 0,\n" + + " \"time1024-states\": -1,\n" + + " \"time512-states-l\": -1,\n" + + " \"time4096-states\": -1,\n" + + " \"rx-level-max\": -45,\n" + + " \"defect-blocks-sum\": -1,\n" + + " \"time32-states\": -1\n" + + " }\n" + + "}"; + // @formatter:on // Map to JSON String to Object Data generatedNode = mapper.readValue(jsonString.getBytes(), Data.class); out(generatedNode.toString()); // Print it with specified indentation @@ -260,11 +277,12 @@ public class TestYangGenSalMapping { @Test public void test6() throws Exception { out(method()); - HtDatabaseClient dbClient = HtDatabaseClient.getClient(getHostinfo()); - String PMDATA15M_TYPE = "historicalperformance15min"; + HostInfo[] hostInfo = HostInfoForTest.get(); + HtDatabaseClient dbClient = HtDatabaseClient.getClient(hostInfo); - EsDataObjectReaderWriter<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.Data> pm15mRW = - new EsDataObjectReaderWriter<>(dbClient, PMDATA15M_TYPE, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.Data.class); + EsDataObjectReaderWriter2<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.Data> pm15mRW = + new EsDataObjectReaderWriter2<>(dbClient, Entity.Historicalperformance15min, + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.Data.class); pm15mRW.setEsIdAttributeName("_nodeName"); ReadPmdata15mListInputBuilder inputBuilder = new ReadPmdata15mListInputBuilder(); @@ -283,12 +301,13 @@ public class TestYangGenSalMapping { QueryBuilder query = fromFilter(input.getFilter()).from((page - 1) * pageSize).size(pageSize); setSortOrder(query, input.getSortorder()); - SearchResult<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.Data> result=pm15mRW.doReadAll(query); + SearchResult<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.Data> result = + pm15mRW.doReadAll(query); - out("Found: "+result.getHits().size()); - int t=0; + out("Found: " + result.getHits().size()); + int t = 0; for (Data hit : result.getHits()) { - out("Hit "+t+++":"+hit); + out("Hit " + t++ + ":" + hit); } setPagination(outputBuilder, page, pageSize, result.getTotal()); outputBuilder.setData(result.getHits()); @@ -297,20 +316,21 @@ public class TestYangGenSalMapping { @Test public void test7() throws Exception { out(method()); - String ESDATATYPE_MEDIATORSERVER = Entity.MediatorServer.getName(); - HtDatabaseClient dbClient = HtDatabaseClient.getClient(getHostinfo()); - EsDataObjectReaderWriter<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.mediator.server.list.output.Data> mediatorserverRW; + HostInfo[] hostInfo = HostInfoForTest.get(); + HtDatabaseClient dbClient = HtDatabaseClient.getClient(hostInfo); - mediatorserverRW = new EsDataObjectReaderWriter<>(dbClient, ESDATATYPE_MEDIATORSERVER, + EsDataObjectReaderWriter2<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.mediator.server.list.output.Data> mediatorserverRW; + mediatorserverRW = new EsDataObjectReaderWriter2<>(dbClient, Entity.MediatorServer, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.mediator.server.list.output.Data.class) - .setWriteInterface(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.MediatorServerEntity.class) - .setEsIdAttributeName("_id"); + .setWriteInterface( + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.MediatorServerEntity.class) + .setEsIdAttributeName("_id"); CreateMediatorServerInputBuilder inputBuilder = new CreateMediatorServerInputBuilder(); inputBuilder.setName("Hans"); inputBuilder.setUrl("MyGreatUrl"); - String id = mediatorserverRW.write(inputBuilder.build(),"testid"); + String id = mediatorserverRW.write(inputBuilder.build(), "testid"); System.out.println(id); } @@ -320,15 +340,15 @@ public class TestYangGenSalMapping { out(method()); String input; input = "id-dd-dd"; - System.out.println("Map " + input + " to "+YangToolsMapper.toCamelCaseAttributeName(input)); + System.out.println("Map " + input + " to " + YangToolsMapper.toCamelCaseAttributeName(input)); input = "idDdGg"; - System.out.println("Map " + input + " to "+YangToolsMapper.toCamelCaseAttributeName(input)); + System.out.println("Map " + input + " to " + YangToolsMapper.toCamelCaseAttributeName(input)); input = "_idDdGg"; - System.out.println("Map " + input + " to "+YangToolsMapper.toCamelCaseAttributeName(input)); + System.out.println("Map " + input + " to " + YangToolsMapper.toCamelCaseAttributeName(input)); input = "--ff--gfg"; - System.out.println("Map " + input + " to "+YangToolsMapper.toCamelCaseAttributeName(input)); + System.out.println("Map " + input + " to " + YangToolsMapper.toCamelCaseAttributeName(input)); input = ""; - System.out.println("Map " + input + " to "+YangToolsMapper.toCamelCaseAttributeName(input)); + System.out.println("Map " + input + " to " + YangToolsMapper.toCamelCaseAttributeName(input)); } /* --------------------------------- @@ -339,7 +359,8 @@ public class TestYangGenSalMapping { return nameofCurrMethod; } - private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.DataBuilder getInventoryDataBuilder(String description, long treeLevel) { + private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.DataBuilder getInventoryDataBuilder( + String description, long treeLevel) { org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.DataBuilder dataBuilder = new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.inventory.list.output.DataBuilder(); dataBuilder.setDescription(description); @@ -377,10 +398,9 @@ public class TestYangGenSalMapping { if (filters == null || filters.size() == 0) { return QueryBuilders.matchAllQuery(); - } else if(filters.size()==1){ + } else if (filters.size() == 1) { return QueryBuilders.matchQuery(filters.get(0).getProperty(), filters.get(0).getFiltervalue()); - } - else { + } else { BoolQueryBuilder query = new BoolQueryBuilder(); for (Filter fi : filters) { query.must(QueryBuilders.matchQuery((prefix != null ? prefix : "") + fi.getProperty(), @@ -390,6 +410,7 @@ public class TestYangGenSalMapping { } } + private static QueryBuilder setSortOrder(QueryBuilder query, @Nullable List<Sortorder> sortorder) { return setSortOrder(query, sortorder, ""); } @@ -407,9 +428,12 @@ public class TestYangGenSalMapping { } - private static void setPagination(ReadPmdata15mListOutputBuilder outputBuilder, long page, long pageSize, long totalSize) { - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.Pagination value = new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.PaginationBuilder() - .setPage(BigInteger.valueOf(page)).setSize(pageSize).setTotal(BigInteger.valueOf(totalSize)).build(); + private static void setPagination(ReadPmdata15mListOutputBuilder outputBuilder, long page, long pageSize, + long totalSize) { + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.Pagination value = + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.read.pmdata._15m.list.output.PaginationBuilder() + .setPage(BigInteger.valueOf(page)).setSize(pageSize).setTotal(BigInteger.valueOf(totalSize)) + .build(); outputBuilder.setPagination(value); } diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestYangProvider.java b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestYangProvider.java index 19bd76cae..244d6b053 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestYangProvider.java +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestYangProvider.java @@ -48,7 +48,6 @@ import org.junit.Test; import org.onap.ccsdk.features.sdnr.wt.dataprovider.data.YangFileProvider; import org.onap.ccsdk.features.sdnr.wt.dataprovider.data.YangFilename; import org.onap.ccsdk.features.sdnr.wt.dataprovider.http.YangSchemaHttpServlet; - import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; 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 new file mode 100644 index 000000000..8ea4b13aa --- /dev/null +++ b/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/util/HostInfoForTest.java @@ -0,0 +1,53 @@ +/* + * ============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.test.util; + +import org.onap.ccsdk.features.sdnr.wt.common.database.config.HostInfo; +import org.onap.ccsdk.features.sdnr.wt.common.database.config.HostInfo.Protocol; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Using pom.xml property to setup URL to database in JUnit tests. Setup impom.xml: <br> + * <properties><databaseport>49402</databaseport> </properties> in cooperation with plugin + * <groupId>com.github.alexcojocaru</groupId> <artifactId>elasticsearch-maven-plugin</artifactId> + * In local development test environment port 49200 is used. + */ +public class HostInfoForTest { + + private static final Logger LOG = LoggerFactory.getLogger(HostInfoForTest.class); + + // static methods + public static HostInfo[] get() { + int port; + + String portAsString = System.getProperty("databaseport"); + if (portAsString == null | portAsString.isEmpty()) + port = 49200; + else + port = Integer.valueOf(portAsString); + HostInfo testHost = new HostInfo("localhost", port, Protocol.HTTP); + LOG.info("Testhost {}",testHost); + return new HostInfo[] {testHost}; + } + // end of static methods +} diff --git a/sdnr/wt/data-provider/provider/src/test/resources/simplelogger.properties b/sdnr/wt/data-provider/provider/src/test/resources/simplelogger.properties index 9943c2fc3..056e91eda 100644 --- a/sdnr/wt/data-provider/provider/src/test/resources/simplelogger.properties +++ b/sdnr/wt/data-provider/provider/src/test/resources/simplelogger.properties @@ -19,10 +19,12 @@ # # -org.slf4j.simpleLogger.defaultLogLevel=INFO +org.slf4j.simpleLogger.defaultLogLevel=DEBUG org.slf4j.simpleLogger.showDateTime=true #org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z #org.slf4j.simpleLogger.showThreadName=true org.slf4j.simpleLogger.showLogName=true org.slf4j.simpleLogger.showShortLogName=false org.slf4j.simpleLogger.org.onap.ccsdk.features.sdnr.wt.dataprovider=DEBUG +org.slf4j.simpleLogger.org.onap.ccsdk.features.sdnr.wt.common=DEBUG + diff --git a/sdnr/wt/data-provider/setup/pom.xml b/sdnr/wt/data-provider/setup/pom.xml index a43ec0c52..cf7929472 100644 --- a/sdnr/wt/data-provider/setup/pom.xml +++ b/sdnr/wt/data-provider/setup/pom.xml @@ -60,12 +60,11 @@ <dependency> <groupId>commons-cli</groupId> <artifactId>commons-cli</artifactId> - <version>1.4</version> </dependency> <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-log4j12</artifactId> - </dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>sdnr-wt-common</artifactId> @@ -77,7 +76,6 @@ <version>${project.version}</version> </dependency> </dependencies> - <build> <plugins> <plugin> @@ -89,7 +87,7 @@ <clusterName>testCluster</clusterName> <transportPort>49504</transportPort> <httpPort>${databaseport}</httpPort> - <version>6.5.0</version> + <version>7.1.1</version> </configuration> <executions> <execution> @@ -133,7 +131,7 @@ </executions> <configuration> <finalName>sdnr-dmt</finalName> - <appendAssemblyId>false</appendAssemblyId> + <appendAssemblyId>false</appendAssemblyId> <archive> <manifest> <mainClass>org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.Program</mainClass> 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 dabe0047f..100f52371 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 @@ -33,7 +33,6 @@ import java.util.List; import java.util.Set; import org.json.JSONObject; import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient; -import org.onap.ccsdk.features.sdnr.wt.common.database.Portstatus; import org.onap.ccsdk.features.sdnr.wt.common.database.SearchHit; import org.onap.ccsdk.features.sdnr.wt.common.database.SearchResult; import org.onap.ccsdk.features.sdnr.wt.common.database.config.HostInfo; @@ -55,6 +54,7 @@ import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.ComponentName; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.DataContainer; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.DataMigrationReport; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.Release; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.ReleaseGroup; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.SearchHitConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,19 +63,13 @@ public class DataMigrationProviderImpl implements DataMigrationProviderService { private static final Logger LOG = LoggerFactory.getLogger(DataMigrationProviderImpl.class); + private final HtDatabaseClient dbClient; public DataMigrationProviderImpl(HostInfo[] hosts, String username, String password, boolean trustAll, - long timeoutms) { + long timeoutms) throws Exception { - if (timeoutms > 0) { - Portstatus.waitSecondsTillAvailable(timeoutms / 1000, hosts); - } - try { - this.dbClient = HtDatabaseClient.getClient(hosts, username, password, trustAll); - } catch (Exception e) { - throw new IllegalArgumentException("Can not reach database with parameters.",e); - } + dbClient = HtDatabaseClient.getClient(hosts, username, password, trustAll, timeoutms); } @Override @@ -125,7 +119,7 @@ public class DataMigrationProviderImpl implements DataMigrationProviderService { for (SearchHit item : data) { if (!dryrun) { String id = this.dbClient.doWriteRaw(indexName, dataTypeName, item.getId(), - item.getSourceAsString()); + item.getSourceAsString(), true); if (!item.getId().equals(id)) { LOG.warn("entry for {} with original id {} was written with another id {}", component.getValue(), item.getId(), id); @@ -268,6 +262,7 @@ public class DataMigrationProviderImpl implements DataMigrationProviderService { return entries; } + @Override public boolean initDatabase(Release release, int numShards, int numReplicas, String dbPrefix, boolean forceRecreate, long timeoutms) { @@ -278,6 +273,16 @@ public class DataMigrationProviderImpl implements DataMigrationProviderService { if (dbVersion == null) { return false; } + LOG.info("detected database version {}", dbVersion); + if (release == null) { + release = ReleaseGroup.CURRENT_RELEASE.getLatestCompatibleRelease(dbVersion); + if (release == null) { + LOG.warn("unable to autodetect release for this database version for release {}", + ReleaseGroup.CURRENT_RELEASE.name()); + return false; + } + LOG.info("autodetect release {}", release); + } if (!release.isDbInRange(dbVersion)) { LOG.warn("db version {} maybe not compatible with release {}", dbVersion, release); return false; @@ -342,6 +347,20 @@ public class DataMigrationProviderImpl implements DataMigrationProviderService { if (entries == null) { return false; } + if (release == null) { + EsVersion dbVersion = this.readActualVersion(); + if (dbVersion == null) { + return false; + } + LOG.info("detected database version {}", dbVersion); + release = ReleaseGroup.CURRENT_RELEASE.getLatestCompatibleRelease(dbVersion); + if (release == null) { + LOG.warn("unable to autodetect release for this database version for release {}", + ReleaseGroup.CURRENT_RELEASE.name()); + return false; + } + LOG.info("autodetect release {}", release); + } ReleaseInformation ri = ReleaseInformation.getInstance(release); AcknowledgedResponse response; if (entries.size() <= 0) { 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 c7775a96b..4b201bccc 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 @@ -53,7 +53,9 @@ public class Program { private static final String CMD_LIST_VERSION = "list"; private static final String CMD_INITDB_DESCRIPTION = "initialize databse indices and aliases"; - private static final String CMD_CLEAR_DB_DESCRIPTION = "clear database indices and aliases"; + private static final String CMD_CLEAR_DB_DESCRIPTION = "delete database indices and aliases for current release"; + private static final String CMD_CLEAR_DB_COMPLETE_DESCRIPTION = "delete all database indices and aliases"; + private static final String CMD_CREATE_PLUGIN_INIT_FILE_DESCRIPTION = "create maven plugin file"; private static final String CMD_IMPORT_DESCRIPTION = "import data into database"; private static final String CMD_EXPORT_DESCRIPTION = "export data from database"; @@ -61,31 +63,51 @@ public class Program { private static final List<String[]> commands = Arrays.asList(new String[] {CMD_INITDB, CMD_INITDB_DESCRIPTION}, new String[] {CMD_CLEAR_DB, CMD_CLEAR_DB_DESCRIPTION}, + new String[] {CMD_CLEAR_DB_COMPLETE, CMD_CLEAR_DB_COMPLETE_DESCRIPTION}, new String[] {CMD_CREATE_PLUGIN_INIT_FILE, CMD_CREATE_PLUGIN_INIT_FILE_DESCRIPTION}, new String[] {CMD_IMPORT, CMD_IMPORT_DESCRIPTION}, new String[] {CMD_EXPORT, CMD_EXPORT_DESCRIPTION}, new String[] {CMD_LIST_VERSION, CMD_LIST_VERSION_DESCRIPTION}); private static final String APPLICATION_NAME = "SDNR DataMigrationTool"; + private static final int DEFAULT_SHARDS = 5; private static final int DEFAULT_REPLICAS = 1; + private static final int DEFAULT_DATABASEWAIT_SECONDS = 30; private static final String DEFAULT_DBURL = "http://sdnrdb:9200"; private static final String DEFAULT_DBPREFIX = ""; + private static final boolean DEFAULT_TRUSTINSECURESSL = false; + private static final String OPTION_FORCE_RECREATE_SHORT = "f"; + private static final String OPTION_FORCE_RECREATE_LONG = "force-recreate"; private static final String OPTION_SILENT_SHORT = "n"; private static final String OPTION_SILENT = "silent"; private static final String OPTION_VERSION_SHORT = "v"; + private static final String OPTION_VERSION_LONG = "version"; private static final String OPTION_SHARDS_SHORT = "s"; + private static final String OPTION_SHARDS_LONG = "shards"; private static final String OPTION_REPLICAS_SHORT = "r"; + private static final String OPTION_REPLICAS_LONG = "replicas"; private static final String OPTION_OUTPUTFILE_SHORT = "of"; + private static final String OPTION_OUTPUTFILE_LONG = "output-file"; private static final String OPTION_INPUTFILE_SHORT = "if"; + private static final String OPTION_INPUTFILE_LONG = "input-file"; private static final String OPTION_DEBUG_SHORT = "x"; + private static final String OPTION_DEBUG_LONG = "verbose"; private static final String OPTION_TRUSTINSECURESSL_SHORT = "k"; + private static final String OPTION_TRUSTINSECURESSL_LONG = "trust-insecure"; private static final String OPTION_DATABASE_SHORT = "db"; + private static final String OPTION_DATABASE_LONG = "dburl"; private static final String OPTION_COMMAND_SHORT = "c"; + private static final String OPTION_COMMAND_LONG = "cmd"; private static final String OPTION_DATABASEUSER_SHORT = "dbu"; + private static final String OPTION_DATABASEUSER_LONG = "db-username"; private static final String OPTION_DATABASEPASSWORD_SHORT = "dbp"; + private static final String OPTION_DATABASEPASSWORD_LONG = "db-password"; private static final String OPTION_DATABASEPREFIX_SHORT = "p"; + private static final String OPTION_DATABASEPREFIX_LONG = "prefix"; private static final String OPTION_DATABASEWAIT_SHORT = "w"; + private static final String OPTION_DATABASEWAIT_LONG = "wait"; private static final String OPTION_HELP_SHORT = "h"; + private static final String OPTION_HELP_LONG = "help"; // end of constants // variables @@ -111,6 +133,9 @@ public class Program { if (def instanceof Long) { return cmd.hasOption(option) ? (T) Long.valueOf(cmd.getOptionValue(option)) : def; } + if (def instanceof Release) { + return cmd.hasOption(option) ? (T) Release.getValueBySuffix(cmd.getOptionValue(option)) : def; + } if (cmd.hasOption(option) && cmd.getOptionValue(option) != null) { if (option.equals(OPTION_VERSION_SHORT)) { String v = cmd.getOptionValue(option); @@ -215,7 +240,8 @@ public class Program { if (of == null) { throw new Exception("please add the parameter output-file"); } - MavenDatabasePluginInitFile.create(Release.CURRENT_RELEASE, of); + MavenDatabasePluginInitFile + .create(getOptionOrDefault(cmd, OPTION_VERSION_SHORT, Release.CURRENT_RELEASE), of); } catch (Exception e) { return exit(e); } @@ -271,11 +297,11 @@ public class Program { String username = getOptionOrDefault(cmd, OPTION_DATABASEUSER_SHORT, null); String password = getOptionOrDefault(cmd, OPTION_DATABASEPASSWORD_SHORT, null); String filename = getOptionOrDefault(cmd, OPTION_OUTPUTFILE_SHORT, null); - boolean trustAll = getOptionOrDefault(cmd, OPTION_TRUSTINSECURESSL_SHORT, false); + boolean trustAll = getOptionOrDefault(cmd, OPTION_TRUSTINSECURESSL_SHORT, DEFAULT_TRUSTINSECURESSL); if (filename == null) { throw new Exception("please add output file parameter"); } - long timeoutms = getOptionOrDefault(cmd, OPTION_DATABASEWAIT_SHORT, 30) * 1000; + long timeoutms = getTimeoutOptionMillis(cmd); DataMigrationProviderImpl service = new DataMigrationProviderImpl(new HostInfo[] {HostInfo.parse(dbUrl)}, username, password, trustAll, timeoutms); DataMigrationReport report = service.importData(filename, false); @@ -283,6 +309,7 @@ public class Program { if (!report.completed()) { throw new Exception("db import seems to be not executed completed"); } + LOG.info("database import completed successfully"); } private static void cmd_dbexport(CommandLine cmd) throws Exception { @@ -290,11 +317,11 @@ public class Program { String username = getOptionOrDefault(cmd, OPTION_DATABASEUSER_SHORT, null); String password = getOptionOrDefault(cmd, OPTION_DATABASEPASSWORD_SHORT, null); String filename = getOptionOrDefault(cmd, OPTION_OUTPUTFILE_SHORT, null); - boolean trustAll = getOptionOrDefault(cmd, OPTION_TRUSTINSECURESSL_SHORT, false); + boolean trustAll = getOptionOrDefault(cmd, OPTION_TRUSTINSECURESSL_SHORT, DEFAULT_TRUSTINSECURESSL); if (filename == null) { throw new Exception("please add output file parameter"); } - long timeoutms = getOptionOrDefault(cmd, OPTION_DATABASEWAIT_SHORT, 30) * 1000; + long timeoutms = getTimeoutOptionMillis(cmd); DataMigrationProviderImpl service = new DataMigrationProviderImpl(new HostInfo[] {HostInfo.parse(dbUrl)}, username, password, trustAll, timeoutms); DataMigrationReport report = service.exportData(filename); @@ -302,7 +329,7 @@ public class Program { if (!report.completed()) { throw new Exception("db export seems to be not executed completed"); } - + LOG.info("database export completed successfully"); } private static int exit(Exception e) { @@ -315,85 +342,96 @@ public class Program { } private static void cmd_clear_db(CommandLine cmd) throws Exception { - Release r = getOptionOrDefault(cmd, OPTION_VERSION_SHORT, Release.CURRENT_RELEASE); + Release r = getOptionOrDefault(cmd, OPTION_VERSION_SHORT, (Release) null); String dbUrl = getOptionOrDefault(cmd, OPTION_DATABASE_SHORT, DEFAULT_DBURL); 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, false); - long timeoutms = getOptionOrDefault(cmd, OPTION_DATABASEWAIT_SHORT, 30) * 1000; + 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)) { 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, false); - long timeoutms = getOptionOrDefault(cmd, OPTION_DATABASEWAIT_SHORT, 30) * 1000; + 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)) { throw new Exception("failed to init database"); } + LOG.info("database complete clear completed successfully"); } private static void cmd_init_db(CommandLine cmd) throws Exception { - Release r = getOptionOrDefault(cmd, OPTION_VERSION_SHORT, Release.CURRENT_RELEASE); + 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); 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, false); - long timeoutms = getOptionOrDefault(cmd, OPTION_DATABASEWAIT_SHORT, 30) * 1000; + 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); boolean forceRecreate = cmd.hasOption(OPTION_FORCE_RECREATE_SHORT); if (!service.initDatabase(r, numShards, numReplicas, dbPrefix, forceRecreate, timeoutms)) { throw new Exception("failed to init database"); } + LOG.info("database init completed successfully"); } private static Options init() { Options result = new Options(); - result.addOption(createOption(OPTION_COMMAND_SHORT, "cmd", true, "command to execute", false)); - result.addOption(createOption(OPTION_DATABASE_SHORT, "dburl", true, "database url", false)); - result.addOption( - createOption(OPTION_DATABASEUSER_SHORT, "db-username", true, "database basic auth username", false)); - result.addOption(createOption(OPTION_DATABASEPASSWORD_SHORT, "db-password", true, + result.addOption(createOption(OPTION_COMMAND_SHORT, OPTION_COMMAND_LONG, true, "command to execute", false)); + result.addOption(createOption(OPTION_DATABASE_SHORT, OPTION_DATABASE_LONG, true, "database url", false)); + result.addOption(createOption(OPTION_DATABASEUSER_SHORT, OPTION_DATABASEUSER_LONG, true, + "database basic auth username", false)); + result.addOption(createOption(OPTION_DATABASEPASSWORD_SHORT, OPTION_DATABASEPASSWORD_LONG, true, "database basic auth password", false)); - result.addOption(createOption(OPTION_REPLICAS_SHORT, "replicas", true, "amount of replicas", false)); - result.addOption(createOption(OPTION_SHARDS_SHORT, "shards", true, "amount of shards", false)); - result.addOption(createOption(OPTION_DATABASEPREFIX_SHORT, "prefix", true, "prefix for db indices", false)); - result.addOption(createOption(OPTION_VERSION_SHORT, "version", true, "version", false)); - result.addOption(createOption(OPTION_DEBUG_SHORT, "verbose", false, "verbose mode", false)); - result.addOption(createOption(OPTION_TRUSTINSECURESSL_SHORT, "trust-insecure", false, + result.addOption(createOption(OPTION_REPLICAS_SHORT, OPTION_REPLICAS_LONG, true, "amount of replicas", false)); + result.addOption(createOption(OPTION_SHARDS_SHORT, OPTION_SHARDS_LONG, true, "amount of shards", false)); + result.addOption(createOption(OPTION_DATABASEPREFIX_SHORT, OPTION_DATABASEPREFIX_LONG, true, + "prefix for db indices", false)); + result.addOption(createOption(OPTION_VERSION_SHORT, OPTION_VERSION_LONG, true, "version", false)); + result.addOption(createOption(OPTION_DEBUG_SHORT, OPTION_DEBUG_LONG, false, "verbose mode", false)); + result.addOption(createOption(OPTION_TRUSTINSECURESSL_SHORT, OPTION_TRUSTINSECURESSL_LONG, false, "trust insecure ssl certs", false)); - result.addOption(createOption(OPTION_DATABASEWAIT_SHORT, "wait", true, + result.addOption(createOption(OPTION_DATABASEWAIT_SHORT, OPTION_DATABASEWAIT_LONG, true, "wait for yellow status with timeout in seconds", false)); - result.addOption( - createOption(OPTION_FORCE_RECREATE_SHORT, "force-recreate", false, "delete if sth exists", false)); + result.addOption(createOption(OPTION_FORCE_RECREATE_SHORT, OPTION_FORCE_RECREATE_LONG, false, + "delete if sth exists", false)); result.addOption(createOption(OPTION_SILENT_SHORT, OPTION_SILENT, false, "prevent console output", false)); - result.addOption(createOption(OPTION_OUTPUTFILE_SHORT, "output-file", true, "file to write into", false)); - result.addOption(createOption(OPTION_INPUTFILE_SHORT, "input-file", true, "file to read from", false)); - result.addOption(createOption(OPTION_HELP_SHORT, "help", false, "show help", false)); + result.addOption( + createOption(OPTION_OUTPUTFILE_SHORT, OPTION_OUTPUTFILE_LONG, true, "file to write into", false)); + result.addOption(createOption(OPTION_INPUTFILE_SHORT, OPTION_INPUTFILE_LONG, true, "file to read from", false)); + result.addOption(createOption(OPTION_HELP_SHORT, OPTION_HELP_LONG, false, "show help", false)); return result; } + private static long getTimeoutOptionMillis(CommandLine cmd) throws ParseException { + return getOptionOrDefault(cmd, OPTION_DATABASEWAIT_SHORT, DEFAULT_DATABASEWAIT_SECONDS) * 1000; + } + /** - * @param opt - * @param longOpt - * @param hasArg - * @param description - * @param required - * @return + * 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 + * @param description description for help output + * @param required flag if is required for program + * @return option object for argparse lib */ private static Option createOption(String opt, String longOpt, boolean hasArg, String description, boolean required) { 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 cb20025ff..d772dc296 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 @@ -33,7 +33,9 @@ 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.elalto.ElAltoReleaseInformation; 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 { @@ -138,8 +140,12 @@ public abstract class ReleaseInformation { return new ElAltoReleaseInformation(); case FRANKFURT_R1: return new FrankfurtReleaseInformation(); - case GUILIN: + case FRANKFURT_R2: + return new FrankfurtReleaseInformationR2(); + case GUILIN_R1: return new GuilinReleaseInformation(); + case GUILIN_R2: + return new GuilinReleaseInformationR2(); default: return null; } diff --git a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/DatabaseInfo.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/DatabaseInfo.java index 4c38b5032..51acd0782 100644 --- a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/DatabaseInfo.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/DatabaseInfo.java @@ -28,7 +28,7 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data; public class DatabaseInfo { public final String doctype; public final String alias; - private final String mapping; + protected final String mapping; private final String settingsFormat; private final String index; diff --git a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestDataTreeSerialization.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/DatabaseInfo7.java index 60a2c50e4..58b98c2aa 100644 --- a/sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestDataTreeSerialization.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/DatabaseInfo7.java @@ -19,15 +19,26 @@ * ============LICENSE_END========================================================= * */ -package org.onap.ccsdk.features.sdnr.wt.dataprovider.test; - -import org.onap.ccsdk.features.sdnr.wt.dataprovider.yangtools.YangToolsMapper; +package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data; /** * @author Michael Dürre * */ -public class TestDataTreeSerialization { +public class DatabaseInfo7 extends DatabaseInfo { + + public DatabaseInfo7(String alias, String doctype, String mapping) { + super(alias, alias, doctype, mapping); + } + + public DatabaseInfo7(String index, String alias, String doctype, String mapping, String settingsformat) { + super(index, alias, doctype, mapping, settingsformat); + } - //YangToolsMapper + @Override + public String getMapping(boolean useStrict) { + return this.mapping == null ? null + : String.format("{%s\"properties\":%s}", useStrict ? "\"dynamic\": false," : "\"dynamic\": true,", + this.mapping); + } } diff --git a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/MavenDatabasePluginInitFile.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/MavenDatabasePluginInitFile.java index 66a5e16d0..3f6334a1e 100644 --- a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/MavenDatabasePluginInitFile.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/MavenDatabasePluginInitFile.java @@ -50,6 +50,7 @@ public class MavenDatabasePluginInitFile { ReleaseInformation ri = ReleaseInformation.getInstance(release); Set<ComponentName> comps = ri.getComponents(); List<String> lines = new ArrayList<>(); + lines.add("PUT:_cluster/settings/:{\"persistent\":{\"action.auto_create_index\":\"true\"}}"); for (ComponentName c : comps) { lines.add(String.format("PUT:%s/:{" + settings + "," + mappings + "}", ri.getIndex(c), shards, replicas, ri.getDatabaseMapping(c))); 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 13c604716..b2442df6b 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 @@ -27,11 +27,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", "", new EsVersion(6, 4, 3), - new EsVersion(6, 8, 6)), FRANKFURT_R3("frankfurt-R3", "", new EsVersion(6, 4, 3), - new EsVersion(6, 8, 6)), + 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)), - GUILIN("guilin", "", new EsVersion(6, 4, 3), new EsVersion(6, 8, 6)); + 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; @@ -67,6 +68,9 @@ public enum Release { } public static Release getValueBySuffix(String suffix) { + if (!suffix.startsWith("-")) { + suffix = "-" + suffix; + } for (Release r : Release.values()) { if (r.dbSuffix.equals(suffix)) return r; diff --git a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataTreeObject.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/ReleaseGroup.java index 4333dccb4..c7d26dbed 100644 --- a/sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/data/DataTreeObject.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/ReleaseGroup.java @@ -19,14 +19,48 @@ * ============LICENSE_END========================================================= * */ -package org.onap.ccsdk.features.sdnr.wt.dataprovider.data; +package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; + +import org.onap.ccsdk.features.sdnr.wt.common.database.data.EsVersion; /** * @author Michael Dürre * */ -public class DataTreeObject extends HashMap<String, DataTreeChildObject> { +public enum ReleaseGroup { + + EL_ALTO(Release.EL_ALTO), FRANKFURT(Release.FRANKFURT_R1, Release.FRANKFURT_R2), GUILIN(Release.GUILIN_R1, + Release.GUILIN_R2); + + public static final ReleaseGroup CURRENT_RELEASE = FRANKFURT; + + private final List<Release> releases; + + ReleaseGroup(Release... values) { + this.releases = new ArrayList<Release>(); + if (values != null) { + for (Release r : values) { + this.releases.add(r); + } + } + } + + /** + * @param dbVersion + * @return + */ + public Release getLatestCompatibleRelease(EsVersion dbVersion) { + Release match = null; + for (Release r : this.releases) { + if (r.isDbInRange(dbVersion)) { + match = r; + } + } + return match; + } + } diff --git a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/SearchHitConverter.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/SearchHitConverter.java index a95a405d6..87c4d6434 100644 --- a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/SearchHitConverter.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/data/SearchHitConverter.java @@ -22,9 +22,7 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data; import org.onap.ccsdk.features.sdnr.wt.common.database.SearchHit; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.elalto.ElAltoReleaseInformation; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.frankfurt.FrankfurtReleaseInformation; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.guilin.GuilinReleaseInformation; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.ReleaseInformation; public interface SearchHitConverter { @@ -46,17 +44,8 @@ public interface SearchHitConverter { public static class Factory { public static SearchHitConverter getInstance(Release src, Release dst, ComponentName component) { - switch (src) { - case EL_ALTO: - return new ElAltoReleaseInformation().getConverter(dst, component); - case FRANKFURT_R1: - return new FrankfurtReleaseInformation().getConverter(dst, component); - case GUILIN: - return new GuilinReleaseInformation().getConverter(dst, component); - default: - return null; - - } + ReleaseInformation ri = ReleaseInformation.getInstance(src); + return ri != null ? ri.getConverter(dst, component) : null; } } diff --git a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/frankfurt/FrankfurtReleaseInformation.java b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/frankfurt/FrankfurtReleaseInformation.java index ad0abee89..7b8c40bca 100644 --- a/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/frankfurt/FrankfurtReleaseInformation.java +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/frankfurt/FrankfurtReleaseInformation.java @@ -86,7 +86,7 @@ public class FrankfurtReleaseInformation extends ReleaseInformation { ClusterSettingsResponse response = null; try { - response = dbClient.setupClusterSettings(new ClusterSettingsRequest(false)); + response = dbClient.setupClusterSettings(new ClusterSettingsRequest(false).maxCompilationsPerMinute(400)); } catch (IOException e) { LOG.warn("problem setting up cluster: {}", e); } 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 new file mode 100644 index 000000000..e842b5c7b --- /dev/null +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/frankfurt/FrankfurtReleaseInformationR2.java @@ -0,0 +1,102 @@ +/* + * ============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.frankfurt; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +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; +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 { + + private final Logger LOG = LoggerFactory.getLogger(FrankfurtReleaseInformationR2.class); + private final Map<Release, Map<ComponentName, SearchHitConverter>> converters = new HashMap<>(); + + public FrankfurtReleaseInformationR2() { + super(Release.FRANKFURT_R2, createDBMap()); + } + + private 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\"}}")); + map.put(ComponentName.EVENTLOG, new DatabaseInfo7("eventlog", "eventlog", + "{\"node-id\": {\"type\": \"keyword\"},\"source-type\": {\"type\": \"keyword\"},\"timestamp\": {\"type\": \"date\"},\"new-value\": {\"type\": \"keyword\"},\"attribute-name\": {\"type\": \"keyword\"},\"counter\": {\"type\": \"long\"},\"object-id\": {\"type\": \"keyword\"}}")); + map.put(ComponentName.FAULTCURRENT, new DatabaseInfo7("faultcurrent", "faultcurrent", + "{\"node-id\": {\"type\": \"keyword\"},\"severity\": {\"type\": \"keyword\"},\"timestamp\": {\"type\": \"date\"},\"problem\": {\"type\": \"keyword\"},\"counter\": {\"type\": \"long\"},\"object-id\":{\"type\": \"keyword\"}}")); + map.put(ComponentName.FAULTLOG, new DatabaseInfo7("faultlog", "faultlog", + "{\"node-id\": {\"type\": \"keyword\"},\"severity\": {\"type\": \"keyword\"},\"timestamp\": {\"type\": \"date\"},\"problem\": {\"type\": \"keyword\"},\"counter\": {\"type\": \"long\"},\"object-id\":{\"type\": \"keyword\"},\"source-type\":{\"type\": \"keyword\"}}")); + map.put(ComponentName.INVENTORY, new DatabaseInfo7("inventoryequipment", "inventoryequipment", + "{\"date\": {\"type\": \"keyword\"},\"model-identifier\": {\"type\": \"keyword\"},\"manufacturer-identifier\": {\"type\": \"keyword\"},\"type-name\": {\"type\": \"keyword\"},\"description\": {\"type\": \"keyword\"},\"uuid\": {\"type\": \"keyword\"},\"version\": {\"type\": \"keyword\"},\"parent-uuid\": {\"type\": \"keyword\"},\"contained-holder\": {\"type\": \"keyword\"},\"node-id\": {\"type\": \"keyword\"},\"tree-level\": {\"type\": \"long\"},\"part-type-id\": {\"type\": \"keyword\"},\"serial\": {\"type\": \"keyword\"}}")); + map.put(ComponentName.HISTORICAL_PERFORMANCE_15M, new DatabaseInfo7("historicalperformance15min", + "historicalperformance15min", + "{\"node-name\":{\"type\": \"keyword\"},\"timestamp\":{\"type\": \"date\"},\"suspect-interval-flag\":{\"type\":\"boolean\"},\"scanner-id\":{\"type\": \"keyword\"},\"uuid-interface\":{\"type\": \"keyword\"},\"layer-protocol-name\":{\"type\": \"keyword\"},\"granularity-period\":{\"type\": \"keyword\"},\"radio-signal-id\":{\"type\": \"keyword\"}}")); + map.put(ComponentName.HISTORICAL_PERFORMANCE_24H, new DatabaseInfo7("historicalperformance24h", + "historicalperformance24h", + "{\"node-name\":{\"type\": \"keyword\"},\"timestamp\":{\"type\": \"date\"},\"suspect-interval-flag\":{\"type\":\"boolean\"},\"scanner-id\":{\"type\": \"keyword\"},\"uuid-interface\":{\"type\": \"keyword\"},\"layer-protocol-name\":{\"type\": \"keyword\"},\"granularity-period\":{\"type\": \"keyword\"},\"radio-signal-id\":{\"type\": \"keyword\"}}")); + map.put(ComponentName.REQUIRED_NETWORKELEMENT, new DatabaseInfo7("networkelement-connection", + "networkelement-connection", + "{\"node-id\": {\"type\": \"keyword\"},\"host\": {\"type\": \"keyword\"},\"port\": {\"type\": \"long\"},\"username\": {\"type\": \"keyword\"},\"password\": {\"type\": \"keyword\"},\"core-model-capability\": {\"type\": \"keyword\"},\"device-type\": {\"type\": \"keyword\"},\"is-required\": {\"type\": \"boolean\"},\"status\": {\"type\": \"keyword\"}}")); + map.put(ComponentName.MEDIATOR_SERVER, new DatabaseInfo7("mediator-server", "mediator-server", + "{\"url\":{\"type\": \"keyword\"},\"name\":{\"type\": \"keyword\"}}")); + map.put(ComponentName.MAINTENANCE, new DatabaseInfo7("maintenancemode", "maintenancemode", + "{\"node-id\": {\"type\": \"keyword\"},\"start\": {\"type\": \"date\"},\"end\": {\"type\": \"date\"},\"description\": {\"type\": \"keyword\"},\"active\": {\"type\": \"boolean\"}},\"date_detection\":false}}")); + return map; + } + + @Override + public SearchHitConverter getConverter(Release dst, ComponentName comp) { + SearchHitConverter c = this.converters.containsKey(dst) ? this.converters.get(dst).get(comp) : null; + if (c == null) { + c = super.getConverter(dst, comp); + } + return c; + } + + @Override + protected boolean runPreInitCommands(HtDatabaseClient dbClient) { + + 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 + protected boolean runPostInitCommands(HtDatabaseClient dbClient) { + return true; + } + +} 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 a81a6f0fd..2c2ac25a9 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 @@ -22,16 +22,15 @@ package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.guilin; import java.util.HashMap; -import java.util.List; 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; -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.DatabaseInfo; public class GuilinReleaseInformation extends ReleaseInformation { @@ -40,7 +39,7 @@ public class GuilinReleaseInformation extends ReleaseInformation { * @param dbMap */ public GuilinReleaseInformation() { - super(Release.GUILIN, createDBMap()); + super(Release.GUILIN_R1, createDBMap()); } @@ -63,7 +62,7 @@ public class GuilinReleaseInformation extends ReleaseInformation { @Override public SearchHitConverter getConverter(Release dst, ComponentName comp) { - if (dst == Release.GUILIN) { + if (dst == Release.GUILIN_R1) { return new KeepDataSearchHitConverter(comp); } return null; 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 new file mode 100644 index 000000000..29c79f3da --- /dev/null +++ b/sdnr/wt/data-provider/setup/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/guilin/GuilinReleaseInformationR2.java @@ -0,0 +1,81 @@ +/* + * ============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/TestData.java b/sdnr/wt/data-provider/setup/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/TestData.java index c7864560b..ab0510c9c 100644 --- a/sdnr/wt/data-provider/setup/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/TestData.java +++ b/sdnr/wt/data-provider/setup/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/setup/TestData.java @@ -48,32 +48,79 @@ import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.Release; * */ public class TestData { - private static final JSONObject EVENTLOG_SEARCHHIT = new JSONObject("{\n" + "\"_index\": \"sdnevents_v1\",\n" - + "\"_type\": \"eventlog\",\n" + "\"_id\": \"AXB7cJHlZ_FApnwi29xq\",\n" + "\"_version\": 1,\n" - + "\"_score\": 1,\n" + "\"_source\": {\n" + "\"event\": {\n" - + "\"nodeName\": \"SDN-Controller-465e2ae306ca\",\n" + "\"counter\": \"1\",\n" - + "\"timeStamp\": \"2020-02-25T08:22:19.8Z\",\n" + "\"objectId\": \"sim2230\",\n" - + "\"attributeName\": \"ConnectionStatus\",\n" + "\"newValue\": \"connecting\",\n" - + "\"type\": \"AttributeValueChangedNotificationXml\"\n" + "}\n" + "}\n" + "}"); - private static final JSONObject EVENTLOG_SEARCHHIT2 = new JSONObject("{\n" + "\"_index\": \"sdnevents_v1\",\n" - + "\"_type\": \"eventlog\",\n" + "\"_id\": \"AXB7cJHlZ_FApnwi29xq\",\n" + "\"_version\": 1,\n" - + "\"_score\": 1,\n" + "\"_source\": {\n" + "\"event\": {\n" - + "\"nodeName\": \"SDN-Controller-465e2ae306ca\",\n" + "\"counter\": \"3\",\n" - + "\"timeStamp\": \"2020-02-22T08:22:19.8Z\",\n" + "\"objectId\": \"sim2230\",\n" - + "\"attributeName\": \"ConnectionStatus\",\n" + "\"newValue\": \"connected\",\n" - + "\"type\": \"AttributeValueChangedNotificationXml\"\n" + "}\n" + "}\n" + "}"); - private static final String CONFIG_CONTENT = "[dcae]\n" + "dcaeUserCredentials=admin:admin\n" + "dcaeUrl=off\n" - + "dcaeHeartbeatPeriodSeconds=120\n" + "dcaeTestCollector=no\n" + "\n" + "[es]\n" - + "esCluster=sendateodl5\n" + "#time limit to keep increasing data in database [in seconds]\n" - + "#60*60*24*30 (30days)\n" + "esArchiveLimit=2592000\n" + "#folder where removed data will be stored\n" - + "esArchiveFolder=./backup\n" + "#interval to archive database [in seconds]\n" + "#60*60*24 (1day)\n" - + "esArchiveInterval=86400\n" + "\n" + "[aai]\n" + "#keep comment\n" - + "aaiHeaders=[\"X-TransactionId: 9999\"]\n" + "aaiUrl=http://localhost:81\n" - + "aaiUserCredentials=AAI:AAI\n" + "aaiDeleteOnMountpointRemove=false\n" + "aaiTrustAllCerts=false\n" - + "aaiApiVersion=aai/v13\n" + "aaiPropertiesFile=aaiclient.properties\n" + "aaiApplicationId=SDNR\n" + // @formatter:off + private static final JSONObject EVENTLOG_SEARCHHIT = new JSONObject("{\n" + + "\"_index\": \"sdnevents_v1\",\n" + + "\"_type\": \"eventlog\",\n" + + "\"_id\": \"AXB7cJHlZ_FApnwi29xq\",\n" + + "\"_version\": 1,\n" + + "\"_score\": 1,\n" + + "\"_source\": {\n" + + "\"event\": {\n" + + "\"nodeName\": \"SDN-Controller-465e2ae306ca\",\n" + + "\"counter\": \"1\",\n" + + "\"timeStamp\": \"2020-02-25T08:22:19.8Z\",\n" + + "\"objectId\": \"sim2230\",\n" + + "\"attributeName\": \"ConnectionStatus\",\n" + + "\"newValue\": \"connecting\",\n" + + "\"type\": \"AttributeValueChangedNotificationXml\"\n" + + "}\n" + + "}\n" + + "}"); + private static final JSONObject EVENTLOG_SEARCHHIT2 = new JSONObject("{\n" + + "\"_index\": \"sdnevents_v1\",\n" + + "\"_type\": \"eventlog\",\n" + + "\"_id\": \"AXB7cJHlZ_FApnwi29xq\",\n" + + "\"_version\": 1,\n" + + "\"_score\": 1,\n" + + "\"_source\": {\n" + + "\"event\": {\n" + + "\"nodeName\": \"SDN-Controller-465e2ae306ca\",\n" + + "\"counter\": \"3\",\n" + + "\"timeStamp\": \"2020-02-22T08:22:19.8Z\",\n" + + "\"objectId\": \"sim2230\",\n" + + "\"attributeName\": \"ConnectionStatus\",\n" + + "\"newValue\": \"connected\",\n" + + "\"type\": \"AttributeValueChangedNotificationXml\"\n" + + "}\n" + + "}\n" + + "}"); + private static final String CONFIG_CONTENT = "[dcae]\n" + + "dcaeUserCredentials=admin:admin\n" + + "dcaeUrl=off\n" + + "dcaeHeartbeatPeriodSeconds=120\n" + + "dcaeTestCollector=no\n" + + "\n" + + "[es]\n" + + "esCluster=sendateodl5\n" + + "#time limit to keep increasing data in database [in seconds]\n" + + "#60*60*24*30 (30days)\n" + + "esArchiveLimit=2592000\n" + + "#folder where removed data will be stored\n" + + "esArchiveFolder=./backup\n" + + "#interval to archive database [in seconds]\n" + + "#60*60*24 (1day)\n" + + "esArchiveInterval=86400\n" + + "\n" + + "[aai]\n" + + "#keep comment\n" + + "aaiHeaders=[\"X-TransactionId: 9999\"]\n" + + "aaiUrl=http://localhost:81\n" + + "aaiUserCredentials=AAI:AAI\n" + + "aaiDeleteOnMountpointRemove=false\n" + + "aaiTrustAllCerts=false\n" + + "aaiApiVersion=aai/v13\n" + + "aaiPropertiesFile=aaiclient.properties\n" + + "aaiApplicationId=SDNR\n" + "aaiPcks12ClientCertFile=/opt/logs/externals/data/stores/keystore.client.p12\n" - + "aaiPcks12ClientCertPassphrase=adminadmin\n" + "aaiClientConnectionTimeout=30000\n" + "\n" + "[pm]\n" - + "pmCluster=sendateodl5\n" + "pmEnabled=true\n" + ""; + + "aaiPcks12ClientCertPassphrase=adminadmin\n" + + "aaiClientConnectionTimeout=30000\n" + + "\n" + + "[pm]\n" + + "pmCluster=sendateodl5\n" + + "pmEnabled=true\n" + + ""; + // @formatter:on @Test public void testComponentData() { 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 02877f0c8..32438410f 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 @@ -27,7 +27,6 @@ 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.DataMigrationProviderImpl; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.DataMigrationReport; import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.Release; @@ -42,16 +41,20 @@ public class TestMigrationProvider { .valueOf(System.getProperty("databaseport") != null ? System.getProperty("databaseport") : "49200"))}; @Test - public void testCreateImport() { + public void testCreateImport() throws Exception { DataMigrationProviderImpl provider = new DataMigrationProviderImpl(hosts, null, null, true, 5000); try { + + //create el alto db infrastructure - provider.initDatabase(Release.FRANKFURT_R1, 5, 1, "", true, 10000); + if (!provider.initDatabase(null, 5, 1, "", true, 10000)) { + fail("unable to init database"); + } //import data into database - DataMigrationReport report = provider.importData(FRANKFURT_BACKUP_FILE, false, Release.FRANKFURT_R1); + DataMigrationReport report = provider.importData(FRANKFURT_BACKUP_FILE, false, Release.FRANKFURT_R2); assertTrue(report.completed()); - assertEquals(Release.FRANKFURT_R1, provider.autoDetectRelease()); + assertEquals(Release.FRANKFURT_R2, provider.autoDetectRelease()); } catch (Exception e) { fail(e.getMessage()); } diff --git a/sdnr/wt/data-provider/setup/tmp.log b/sdnr/wt/data-provider/setup/tmp.log deleted file mode 100644 index d2c5a8726..000000000 --- a/sdnr/wt/data-provider/setup/tmp.log +++ /dev/null @@ -1 +0,0 @@ -{"configs":{},"components":{},"release":"frankfurt-R1","created":"2020-02-25T05:29:35.3Z"} diff --git a/sdnr/wt/odlux/apps/apiDemo/package.json b/sdnr/wt/odlux/apps/apiDemo/package.json index 44dae6854..8118f92c4 100644 --- a/sdnr/wt/odlux/apps/apiDemo/package.json +++ b/sdnr/wt/odlux/apps/apiDemo/package.json @@ -24,8 +24,8 @@ "@odlux/framework": "*" }, "peerDependencies": { - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@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", diff --git a/sdnr/wt/odlux/apps/configurationApp/package.json b/sdnr/wt/odlux/apps/configurationApp/package.json index b18d1ce10..7b9dce688 100644 --- a/sdnr/wt/odlux/apps/configurationApp/package.json +++ b/sdnr/wt/odlux/apps/configurationApp/package.json @@ -24,8 +24,8 @@ "@odlux/framework": "*" }, "peerDependencies": { - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@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", diff --git a/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts b/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts index 45cdfe64d..dbe95e0d1 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts @@ -2,12 +2,14 @@ import { Action } from '../../../../framework/src/flux/action'; import { Dispatch } from '../../../../framework/src/flux/store'; import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore"; import { PushAction, ReplaceAction } from "../../../../framework/src/actions/navigationActions"; +import { AddErrorInfoAction } from "../../../../framework/src/actions/errorActions"; +import { DisplayModeType, DisplaySpecification } from '../handlers/viewDescriptionHandler'; import { restService } from "../services/restServices"; import { YangParser } from "../yang/yangParser"; import { Module } from "../models/yang"; -import { ViewSpecification, ViewElement, isViewElementReference, isViewElementList, isViewElementObjectOrList } from "../models/uiModels"; -import { AddErrorInfoAction } from "../../../../framework/src/actions/errorActions"; +import { ViewSpecification, ViewElement, isViewElementReference, isViewElementList, isViewElementObjectOrList, isViewElementRpc, isViewElementChoise, ViewElementChoiseCase } from "../models/uiModels"; +import { element } from 'prop-types'; export class EnableValueSelector extends Action { constructor(public listSpecification: ViewSpecification, public listData: any[], public keyProperty: string, public onValueSelected : (value: any) => void ) { @@ -34,7 +36,13 @@ export class UpdateDeviceDescription extends Action { } export class UpdatViewDescription extends Action { - constructor(public vPath: string, public view: ViewSpecification, public viewData: any, public displayAsList: boolean = false, public key?: string ) { + constructor (public vPath: string, public viewData: any, public displaySpecification: DisplaySpecification = { displayMode: DisplayModeType.doNotDisplay } ) { + super(); + } +} + +export class UpdatOutputData extends Action { + constructor (public outputData: any) { super(); } } @@ -159,7 +167,7 @@ const getReferencedDataList = async (refPath: string, dataPath: string, modules: return null; } -const resolveViewDescription = (defaultNS: string | null, vPath: string, view: ViewSpecification, viewData: any, displayAsList: boolean = false, key?: string): UpdatViewDescription =>{ +const resolveViewDescription = (defaultNS: string | null, vPath: string, view: ViewSpecification): ViewSpecification =>{ // check if-feature | when | and resolve all references. view = { ...view }; @@ -173,28 +181,72 @@ const resolveViewDescription = (defaultNS: string | null, vPath: string, view: V } return acc; }, {}); - return new UpdatViewDescription(vPath, view, viewData, displayAsList, key); + return view; } +const flatenViewElements = (defaultNS: string | null, parentPath: string, elements: { [name: string]: ViewElement }, views: ViewSpecification[], currentPath: string ): { [name: string]: ViewElement } => { + if (!elements) return {}; + return Object.keys(elements).reduce<{ [name: string]: ViewElement }>((acc, cur) => { + const elm = elements[cur]; + + // remove the detault namespace, and only the default namespace, sine it seems that this is also not in the restconf response + const elmKey = defaultNS && elm.id.replace(new RegExp(`^${defaultNS}:`, "i"), "") || elm.id; + const key = parentPath ? `${parentPath}.${elmKey}` : elmKey; + + if (isViewElementRpc(elm)) { + console.warn(`Flaten of RFC not supported ! [${currentPath}][${elm.label}]`); + return acc; + } else if (isViewElementObjectOrList(elm)) { + const view = views[+elm.viewId]; + const inner = view && flatenViewElements(defaultNS, key, view.elements, views, `${currentPath}/${view.name}`); + inner && Object.keys(inner).forEach(k => (acc[k] = inner[k])); + } else if (isViewElementChoise(elm)) { + acc[key] = { + ...elm, + id: key, + cases: Object.keys(elm.cases).reduce<{ [name: string]: ViewElementChoiseCase }>((accCases, curCases) => { + const caseElement = elm.cases[curCases]; + accCases[curCases] = { + ...caseElement, + // Hint: do not use key it contains elmKey, which shell be omitted for cases. + elements: flatenViewElements(defaultNS, /*key*/ parentPath, caseElement.elements, views, `${currentPath}/${elm.label}`) + }; + return accCases; + }, {}), + }; + } else { + acc[key] = { + ...elm, + id: key, + }; + } + return acc; + }, {}); +}; + export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => { const pathParts = splitVPath(vPath, /(?:([^\/\["]+)(?:\[([^\]]*)\])?)/g); // 1 = property / 2 = optional key const { configuration: { deviceDescription: { nodeId, modules, views } }, framework: { navigationState } } = getState(); let dataPath = `/restconf/config/network-topology:network-topology/topology/topology-netconf/node/${nodeId}/yang-ext:mount`; + + let inputViewSpecification: ViewSpecification | undefined = undefined; + let outputViewSpecification: ViewSpecification | undefined = undefined; + let viewSpecification: ViewSpecification = views[0]; let viewElement: ViewElement; let dataMember: string; let extractList: boolean = false; - let currentNS : string | null = null; - let defaultNS : string | null = null; + let currentNS: string | null = null; + let defaultNS: string | null = null; dispatch(new SetCollectingSelectionData(true)); try { for (let ind = 0; ind < pathParts.length; ++ind) { const [property, key] = pathParts[ind]; const namespaceInd = property && property.indexOf(":") || -1; - const namespace : string | null = namespaceInd > -1 ? (currentNS = property.slice(0, namespaceInd)) : currentNS; + const namespace: string | null = namespaceInd > -1 ? (currentNS = property.slice(0, namespaceInd)) : currentNS; if (ind === 0) { defaultNS = namespace }; @@ -206,6 +258,7 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: dispatch(new SetCollectingSelectionData(false)); throw new Error("No key for list [" + property + "]"); } else if (vPath.endsWith("[]") && pathParts.length - 1 === ind) { + // empty key is used for new element if (viewElement && "viewId" in viewElement) viewSpecification = views[+viewElement.viewId]; const data = Object.keys(viewSpecification.elements).reduce<{ [name: string]: any }>((acc, cur) => { @@ -215,7 +268,16 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: } return acc; }, {}); - return dispatch(resolveViewDescription(defaultNS, vPath, viewSpecification, data, false, isViewElementList(viewElement!) && viewElement.key || undefined)); + + // create display specification + const ds: DisplaySpecification = { + displayMode: DisplayModeType.displayAsObject, + viewSpecification: resolveViewDescription(defaultNS, vPath, viewSpecification), + keyProperty: isViewElementList(viewElement!) && viewElement.key || undefined + }; + + // update display specification + return dispatch(new UpdatViewDescription(vPath, data, ds)); } if (viewElement && isViewElementList(viewElement) && viewSpecification.parentView === "0") { // check if there is a reference as key @@ -247,11 +309,27 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: extractList = false; } - if (viewElement && "viewId" in viewElement) viewSpecification = views[+viewElement.viewId]; + if (viewElement && "viewId" in viewElement) { + viewSpecification = views[+viewElement.viewId]; + } else if (viewElement.uiType === "rpc") { + viewSpecification = views[+(viewElement.inputViewId || 0)]; + + // create new instance & flaten + inputViewSpecification = viewElement.inputViewId != null && { + ...views[+(viewElement.inputViewId || 0)], + elements: flatenViewElements(defaultNS, "", views[+(viewElement.inputViewId || 0)].elements, views, viewElement.label), + } || undefined; + outputViewSpecification = viewElement.outputViewId != null && { + ...views[+(viewElement.outputViewId || 0)], + elements: flatenViewElements(defaultNS, "", views[+(viewElement.outputViewId || 0)].elements, views, viewElement.label), + } || undefined; + + } } let data: any = {}; - if (viewSpecification && viewSpecification.id !== "0") { + // do not get any data from netconf if there is no view specified || this is the root element [0] || this is an rpc + if (viewSpecification && !(viewSpecification.id === "0" || viewElement!.uiType === "rpc")) { const restResult = (await restService.getConfigData(dataPath)); if (!restResult.data) { // special case: if this is a list without any response @@ -259,7 +337,15 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: if (!isViewElementList(viewElement!)) { throw new Error(`vPath: [${vPath}]. ViewElement has no key.`); } - return dispatch(resolveViewDescription(defaultNS, vPath, viewSpecification, [], extractList, viewElement.key)); + // create display specification + const ds: DisplaySpecification = { + displayMode: extractList ? DisplayModeType.displayAsList : DisplayModeType.displayAsObject, + viewSpecification: resolveViewDescription(defaultNS, vPath, viewSpecification), + keyProperty: viewElement.key + }; + + // update display specification + return dispatch(new UpdatViewDescription(vPath, [], ds)); } throw new Error(`Did not get response from Server. Status: [${restResult.status}]`); } else if (restResult.status < 200 || restResult.status > 299) { @@ -278,9 +364,33 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: data = extractList ? data[viewElement!.label] || [] // if the list is empty, it does not exist : data; + + } else if (viewElement! && viewElement!.uiType === "rpc") { + // set data to defaults + data = {}; + inputViewSpecification && Object.keys(inputViewSpecification.elements).forEach(key => { + const elm = inputViewSpecification && inputViewSpecification.elements[key]; + if (elm && elm.default != undefined) { + data[elm.id] = elm.default; + } + }); } - return dispatch(resolveViewDescription(defaultNS, vPath, viewSpecification, data, extractList, isViewElementList(viewElement!) && viewElement.key || undefined)); + // create display specification + const ds: DisplaySpecification = viewElement! && viewElement!.uiType === "rpc" + ? { + displayMode: DisplayModeType.displayAsRPC, + inputViewSpecification: inputViewSpecification && resolveViewDescription(defaultNS, vPath, inputViewSpecification), + outputViewSpecification: outputViewSpecification && resolveViewDescription(defaultNS, vPath, outputViewSpecification), + } + : { + displayMode: extractList ? DisplayModeType.displayAsList : DisplayModeType.displayAsObject, + viewSpecification: resolveViewDescription(defaultNS, vPath, viewSpecification), + keyProperty: isViewElementList(viewElement!) && viewElement.key || undefined, + }; + + // update display specification + return dispatch(new UpdatViewDescription(vPath, data, ds)); // https://beta.just-run.it/#/configuration/Sim12600/core-model:network-element/ltp[LTP-MWPS-TTP-01] // https://beta.just-run.it/#/configuration/Sim12600/core-model:network-element/ltp[LTP-MWPS-TTP-01]/lp } catch (error) { @@ -290,7 +400,7 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: } finally { return; } -} +}; export const updateDataActionAsyncCreator = (vPath: string, data: any) => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => { const pathParts = splitVPath(vPath, /(?:([^\/\["]+)(?:\[([^\]]*)\])?)/g); // 1 = property / 2 = optional key @@ -313,7 +423,7 @@ export const updateDataActionAsyncCreator = (vPath: string, data: any) => async const namespace: string | null = namespaceInd > -1 ? (currentNS = property.slice(0, namespaceInd)) : currentNS; if (ind === 0) { defaultNS = namespace }; - viewElement = viewSpecification.elements[property]; + viewElement = viewSpecification.elements[property] || viewSpecification.elements[`${namespace}:${property}`]; if (!viewElement) throw Error("Property [" + property + "] does not exist."); if (isViewElementList(viewElement) && !key) { @@ -330,7 +440,7 @@ export const updateDataActionAsyncCreator = (vPath: string, data: any) => async isNew = key; if (!key) { dispatch(new SetCollectingSelectionData(false)); - throw new Error("No value for key [" + viewElement.key +"] in list [" + property + "]"); + throw new Error("No value for key [" + viewElement.key + "] in list [" + property + "]"); } } } @@ -363,14 +473,183 @@ export const updateDataActionAsyncCreator = (vPath: string, data: any) => async } } - return isNew - ? dispatch(new ReplaceAction(`/configuration/${nodeId}/${vPath.replace(/\[\]$/i,`[${isNew}]`)}`)) // navigate to new element - : dispatch(resolveViewDescription(defaultNS, vPath, viewSpecification, data, embedList, isViewElementList(viewElement!) && viewElement.key || undefined)); + if (isNew) { + return dispatch(new ReplaceAction(`/configuration/${nodeId}/${vPath.replace(/\[\]$/i, `[${isNew}]`)}`)) // navigate to new element + } + + // create display specification + const ds: DisplaySpecification = { + displayMode: embedList ? DisplayModeType.displayAsList : DisplayModeType.displayAsObject, + viewSpecification: resolveViewDescription(defaultNS, vPath, viewSpecification), + keyProperty: isViewElementList(viewElement!) && viewElement.key || undefined, + }; + + // update display specification + return dispatch(new UpdatViewDescription(vPath, data, ds)); } catch (error) { history.back(); dispatch(new AddErrorInfoAction({ title: "Problem", message: error.message || `Could not change ${dataPath}` })); - dispatch(new SetCollectingSelectionData(false)); + } finally { + dispatch(new SetCollectingSelectionData(false)); return; } -}
\ No newline at end of file +}; + +export const removeElementActionAsyncCreator = (vPath: string) => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => { + const pathParts = splitVPath(vPath, /(?:([^\/\["]+)(?:\[([^\]]*)\])?)/g); // 1 = property / 2 = optional key + const { configuration: { deviceDescription: { nodeId, views } } } = getState(); + let dataPath = `/restconf/config/network-topology:network-topology/topology/topology-netconf/node/${nodeId}/yang-ext:mount`; + let viewSpecification: ViewSpecification = views[0]; + let viewElement: ViewElement; + + let currentNS: string | null = null; + let defaultNS: string | null = null; + + dispatch(new SetCollectingSelectionData(true)); + try { + for (let ind = 0; ind < pathParts.length; ++ind) { + let [property, key] = pathParts[ind]; + const namespaceInd = property && property.indexOf(":") || -1; + const namespace: string | null = namespaceInd > -1 ? (currentNS = property.slice(0, namespaceInd)) : currentNS; + + if (ind === 0) { defaultNS = namespace }; + viewElement = viewSpecification.elements[property] || viewSpecification.elements[`${namespace}:${property}`]; + if (!viewElement) throw Error("Property [" + property + "] does not exist."); + + if (isViewElementList(viewElement) && !key) { + if (viewElement && viewElement.isList && viewSpecification.parentView === "0") { + throw new Error("Found a list at root level of a module w/o a refenrece key."); + } + if (pathParts.length - 1 > ind) { + dispatch(new SetCollectingSelectionData(false)); + throw new Error("No key for list [" + property + "]"); + } else if (vPath.endsWith("[]") && pathParts.length - 1 === ind) { + // remove the whole table + } + } + + dataPath += `/${property}${key ? `/${key.replace(/\//ig, "%2F")}` : ""}`; + + if (viewElement && "viewId" in viewElement) { + viewSpecification = views[+viewElement.viewId]; + } else if (viewElement.uiType === "rpc") { + viewSpecification = views[+(viewElement.inputViewId || 0)]; + } + } + + const updateResult = await restService.removeConfigElement(dataPath); + if (updateResult.status < 200 || updateResult.status > 299) { + const message = updateResult.data && updateResult.data.errors && updateResult.data.errors.error && updateResult.data.errors.error[0] && updateResult.data.errors.error[0]["error-message"] || ""; + throw new Error(`Server Error. Status: [${updateResult.status}]\n${message || updateResult.message || ''}`); + } + } catch (error) { + dispatch(new AddErrorInfoAction({ title: "Problem", message: error.message || `Could not remove ${dataPath}` })); + } finally { + dispatch(new SetCollectingSelectionData(false)); + } + + +}; + +export const executeRpcActionAsyncCreator = (vPath: string, data: any) => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => { + const pathParts = splitVPath(vPath, /(?:([^\/\["]+)(?:\[([^\]]*)\])?)/g); // 1 = property / 2 = optional key + const { configuration: { deviceDescription: { nodeId, views }, viewDescription: oldViewDescription } } = getState(); + let dataPath = `/restconf/operations/network-topology:network-topology/topology/topology-netconf/node/${nodeId}/yang-ext:mount`; + let viewSpecification: ViewSpecification = views[0]; + let viewElement: ViewElement; + let dataMember: string; + let embedList: boolean = false; + let isNew: string | false = false; + + let currentNS: string | null = null; + let defaultNS: string | null = null; + + dispatch(new SetCollectingSelectionData(true)); + try { + for (let ind = 0; ind < pathParts.length; ++ind) { + let [property, key] = pathParts[ind]; + const namespaceInd = property && property.indexOf(":") || -1; + const namespace: string | null = namespaceInd > -1 ? (currentNS = property.slice(0, namespaceInd)) : currentNS; + + if (ind === 0) { defaultNS = namespace }; + viewElement = viewSpecification.elements[property] || viewSpecification.elements[`${namespace}:${property}`]; + if (!viewElement) throw Error("Property [" + property + "] does not exist."); + + if (isViewElementList(viewElement) && !key) { + embedList = true; + // if (viewElement && viewElement.isList && viewSpecification.parentView === "0") { + // throw new Error("Found a list at root level of a module w/o a refenrece key."); + // } + // if (pathParts.length - 1 > ind) { + // dispatch(new SetCollectingSelectionData(false)); + // throw new Error("No key for list [" + property + "]"); + // } else if (vPath.endsWith("[]") && pathParts.length - 1 === ind) { + // // handle new element + // key = viewElement.key && String(data[viewElement.key]) || ""; + // isNew = key; + // if (!key) { + // dispatch(new SetCollectingSelectionData(false)); + // throw new Error("No value for key [" + viewElement.key + "] in list [" + property + "]"); + // } + // } + } + + dataPath += `/${property}${key ? `/${key.replace(/\//ig, "%2F")}` : ""}`; + dataMember = viewElement.label; + embedList = false; + + if (viewElement && "viewId" in viewElement) { + viewSpecification = views[+viewElement.viewId]; + } else if (viewElement.uiType === "rpc") { + viewSpecification = views[+(viewElement.inputViewId || 0)]; + } + } + + // re-inflate formerly flatten rpc data + data = data && Object.keys(data).reduce < { [name: string ]: any }>((acc, cur) => { + const pathParts = cur.split("."); + let pos = 0; + const updatePath = (obj: any, key: string) => { + obj[key] = (pos >= pathParts.length) + ? data[cur] + : updatePath(obj[key] || {}, pathParts[pos++]); + return obj; + } + updatePath(acc, pathParts[pos++]); + return acc; + }, {}) || null; + + // embed the list -> key: list + data = embedList + ? { [viewElement!.label]: data } + : data; + + // embed the first element list[key] + data = isNew + ? [data] + : data; + + // do not post root member (0) + if ((viewSpecification && viewSpecification.id !== "0") || (dataMember! && !data)) { + const updateResult = await restService.executeRpc(dataPath, { [`${defaultNS}:input`]: data || {} }); + if (updateResult.status < 200 || updateResult.status > 299) { + const message = updateResult.data && updateResult.data.errors && updateResult.data.errors.error && updateResult.data.errors.error[0] && updateResult.data.errors.error[0]["error-message"] || ""; + throw new Error(`Server Error. Status: [${updateResult.status}]\n${message || updateResult.message || ''}`); + } + const viewData = { ...oldViewDescription.viewData, output: updateResult.data || null}; + dispatch(new UpdatOutputData(viewData)); + } else { + throw new Error(`There is NO RPC specified.`); + } + + + // // update display specification + // return + } catch (error) { + dispatch(new AddErrorInfoAction({ title: "Problem", message: error.message || `Could not change ${dataPath}` })); + + } finally { + dispatch(new SetCollectingSelectionData(false)); + } +}; diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementSelection.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementSelection.tsx index d46076338..8b0b890d0 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementSelection.tsx +++ b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementSelection.tsx @@ -39,6 +39,7 @@ export const UiElementSelection = (props: selectionProps) => { ? (<FormControl style={{ width: 485, marginLeft: 20, marginRight: 20 }}> <InputLabel htmlFor={`select-${element.id}`} >{element.label}</InputLabel> <Select + title={(element.options.find(o => o.key === value.toString().toLowerCase()) || { description: undefined }).description} required={!!element.mandatory} error={!!error} onChange={(e) => { props.onChange(e.target.value as string) }} @@ -50,7 +51,9 @@ export const UiElementSelection = (props: selectionProps) => { id: `select-${element.id}`, }} > - {element.options.map(option => (<MenuItem key={option.key} title={option.description} value={option.key}>{option.key}</MenuItem>))} + {element.options.map(option => ( + <MenuItem key={option.key} title={option.description} value={option.key}>{option.key}</MenuItem> + ))} </Select> <FormHelperText>{error}</FormHelperText> </FormControl>) diff --git a/sdnr/wt/odlux/apps/configurationApp/src/handlers/valueSelectorHandler.ts b/sdnr/wt/odlux/apps/configurationApp/src/handlers/valueSelectorHandler.ts index 9af640f16..5b2d55ee2 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/handlers/valueSelectorHandler.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/handlers/valueSelectorHandler.ts @@ -18,7 +18,7 @@ import { IActionHandler } from "../../../../framework/src/flux/action"; import { ViewSpecification } from "../models/uiModels"; -import { EnableValueSelector, SetSelectedValue, UpdateDeviceDescription, SetCollectingSelectionData, UpdatViewDescription } from "../actions/deviceActions"; +import { EnableValueSelector, SetSelectedValue, UpdateDeviceDescription, SetCollectingSelectionData, UpdatViewDescription, UpdatOutputData } from "../actions/deviceActions"; export interface IValueSelectorState { collectingData: boolean; @@ -62,7 +62,7 @@ export const valueSelectorHandler: IActionHandler<IValueSelectorState> = (state onValueSelected: nc, listData: [], }; - } else if (action instanceof UpdateDeviceDescription || action instanceof UpdatViewDescription) { + } else if (action instanceof UpdateDeviceDescription || action instanceof UpdatViewDescription || action instanceof UpdatOutputData) { state = { ...state, collectingData: false, diff --git a/sdnr/wt/odlux/apps/configurationApp/src/handlers/viewDescriptionHandler.ts b/sdnr/wt/odlux/apps/configurationApp/src/handlers/viewDescriptionHandler.ts index c1b3350b2..69710b9e9 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/handlers/viewDescriptionHandler.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/handlers/viewDescriptionHandler.ts @@ -18,31 +18,42 @@ import { IActionHandler } from "../../../../framework/src/flux/action"; -import { UpdatViewDescription } from "../actions/deviceActions"; +import { UpdatViewDescription, UpdatOutputData } from "../actions/deviceActions"; import { ViewSpecification } from "../models/uiModels"; +export enum DisplayModeType { + doNotDisplay = 0, + displayAsObject = 1, + displayAsList = 2, + displayAsRPC = 3 +}; + +export type DisplaySpecification = { + displayMode: DisplayModeType.doNotDisplay; +} | { + displayMode: DisplayModeType.displayAsObject | DisplayModeType.displayAsList ; + viewSpecification: ViewSpecification; + keyProperty: string | undefined; +} | { + displayMode: DisplayModeType.displayAsRPC; + inputViewSpecification?: ViewSpecification; + outputViewSpecification?: ViewSpecification; +} + export interface IViewDescriptionState { vPath: string | null; - keyProperty: string | undefined; - displayAsList: boolean; - viewSpecification: ViewSpecification; - viewData: any + displaySpecification: DisplaySpecification; + viewData: any, + outputData?: any, } const viewDescriptionStateInit: IViewDescriptionState = { vPath: null, - keyProperty: undefined, - displayAsList: false, - viewSpecification: { - id: "empty", - canEdit: false, - parentView: "", - name: "emplty", - language: "en-US", - title: "empty", - elements: {} + displaySpecification: { + displayMode: DisplayModeType.doNotDisplay, }, - viewData: null + viewData: null, + outputData: undefined, }; export const viewDescriptionHandler: IActionHandler<IViewDescriptionState> = (state = viewDescriptionStateInit, action) => { @@ -50,11 +61,15 @@ export const viewDescriptionHandler: IActionHandler<IViewDescriptionState> = (st state = { ...state, vPath: action.vPath, - keyProperty: action.key, - displayAsList: action.displayAsList, - viewSpecification: action.view, viewData: action.viewData, - } + outputData: undefined, + displaySpecification: action.displaySpecification, + }; + } else if (action instanceof UpdatOutputData) { + state = { + ...state, + outputData: action.outputData, + }; } return state; }; diff --git a/sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts b/sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts index 7b41c3845..f0391eebf 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts @@ -109,12 +109,28 @@ export type ViewElementUnion = ViewElementBase & { "elements": ViewElement[]; } +export type ViewElementChoiseCase = { id: string, label: string, description?: string, elements: { [name: string]: ViewElement } }; + export type ViewElementChoise = ViewElementBase & { "uiType": "choise"; - "cases": { [name: string]: { id: string, label: string, description?: string, elements: { [name: string]: ViewElement } } }; + "cases": { + [name: string]: ViewElementChoiseCase; + } +} + +// https://tools.ietf.org/html/rfc7950#section-7.14.1 +export type ViewElementRpc = ViewElementBase & { + "uiType": "rpc"; + "inputViewId"?: string; + "outputViewId"?: string; +} + +export type ViewElementEmpty = ViewElementBase & { + "uiType": "empty"; } export type ViewElement = + | ViewElementEmpty | ViewElementBits | ViewElementBinary | ViewElementString @@ -125,7 +141,8 @@ export type ViewElement = | ViewElementSelection | ViewElementReference | ViewElementUnion - | ViewElementChoise; + | ViewElementChoise + | ViewElementRpc; export const isViewElementString = (viewElement: ViewElement): viewElement is ViewElementString => { return viewElement && viewElement.uiType === "string"; @@ -167,16 +184,25 @@ export const isViewElementChoise = (viewElement: ViewElement): viewElement is Vi return viewElement && viewElement.uiType === "choise"; } +export const isViewElementRpc = (viewElement: ViewElement): viewElement is ViewElementRpc => { + return viewElement && viewElement.uiType === "rpc"; +} + +export const isViewElementEmpty = (viewElement: ViewElement): viewElement is ViewElementRpc => { + return viewElement && viewElement.uiType === "empty"; +} + +export const ResolveFunction = Symbol("IsResolved"); export type ViewSpecification = { "id": string; - "name": string; + "name"?: string; "title"?: string; "parentView"?: string; "language": string; "ifFeature"?: string; "when"?: string; - "uses"?: string[]; + "uses"?: (string[]) & { [ResolveFunction]?: () => void }; "elements": { [name: string]: ViewElement }; readonly "canEdit": boolean; } diff --git a/sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts b/sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts index 0d28e6653..b260f1ffb 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts @@ -57,6 +57,18 @@ class RestService { public setConfigData(path: string, data: any) { return requestRestExt<{ [key: string]: any }>(path, { method: "PUT", body: JSON.stringify(data) }); } + + public executeRpc(path: string, data: any) { + return requestRestExt<{ [key: string]: any }>(path, { method: "POST", body: JSON.stringify(data) }); + } + + /** Removes the element by restconf path. + * @param path The restconf path to identify the note to update. + * @returns The restconf result. + */ + public removeConfigElement(path: string) { + return requestRestExt<{ [key: string]: any }>(path, { method: "DELETE" }); + } } export const restService = new RestService(); diff --git a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx index 06de39b9d..385f3b52f 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx +++ b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx @@ -25,9 +25,11 @@ import connect, { IDispatcher, Connect } from "../../../../framework/src/flux/co import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore"; import MaterialTable, { ColumnModel, ColumnType, MaterialTableCtorType } from "../../../../framework/src/components/material-table"; import { Loader } from "../../../../framework/src/components/material-ui/loader"; +import { renderObject } from '../../../../framework/src/components/objectDump'; -import { SetSelectedValue, splitVPath, updateDataActionAsyncCreator, updateViewActionAsyncCreator } from "../actions/deviceActions"; -import { ViewSpecification, isViewElementString, isViewElementNumber, isViewElementBoolean, isViewElementObjectOrList, isViewElementSelection, isViewElementChoise, ViewElement, ViewElementChoise, isViewElementUnion } from "../models/uiModels"; +import { DisplayModeType } from '../handlers/viewDescriptionHandler'; +import { SetSelectedValue, splitVPath, updateDataActionAsyncCreator, updateViewActionAsyncCreator, removeElementActionAsyncCreator, executeRpcActionAsyncCreator } from "../actions/deviceActions"; +import { ViewSpecification, isViewElementString, isViewElementNumber, isViewElementBoolean, isViewElementObjectOrList, isViewElementSelection, isViewElementChoise, ViewElement, ViewElementChoise, isViewElementUnion, isViewElementRpc, ViewElementRpc, isViewElementEmpty } from "../models/uiModels"; import Fab from '@material-ui/core/Fab'; import AddIcon from '@material-ui/icons/Add'; @@ -36,17 +38,14 @@ import RemoveIcon from '@material-ui/icons/RemoveCircleOutline'; import SaveIcon from '@material-ui/icons/Save'; import EditIcon from '@material-ui/icons/Edit'; import Tooltip from "@material-ui/core/Tooltip"; -import TextField from "@material-ui/core/TextField"; import FormControl from "@material-ui/core/FormControl"; import IconButton from "@material-ui/core/IconButton"; -import InputAdornment from "@material-ui/core/InputAdornment"; import InputLabel from "@material-ui/core/InputLabel"; import Select from "@material-ui/core/Select"; import MenuItem from "@material-ui/core/MenuItem"; import Breadcrumbs from "@material-ui/core/Breadcrumbs"; import Link from "@material-ui/core/Link"; -import FormHelperText from '@material-ui/core/FormHelperText'; import { UIElementReference } from '../components/uiElementReference'; import { UiElementNumber } from '../components/uiElementNumber'; @@ -54,6 +53,7 @@ import { UiElementString } from '../components/uiElementString'; import { UiElementBoolean } from '../components/uiElementBoolean'; import { UiElementSelection } from '../components/uiElementSelection'; import { UIElementUnion } from '../components/uiElementUnion'; +import { Button } from '@material-ui/core'; const styles = (theme: Theme) => createStyles({ header: { @@ -110,6 +110,9 @@ const styles = (theme: Theme) => createStyles({ }, }, }, + uiView: { + overflowY: "auto", + }, section: { padding: "15px", borderBottom: `2px solid ${theme.palette.divider}`, @@ -130,15 +133,16 @@ const mapProps = (state: IApplicationStoreState) => ({ vPath: state.configuration.viewDescription.vPath, nodeId: state.configuration.deviceDescription.nodeId, viewData: state.configuration.viewDescription.viewData, - viewSpecification: state.configuration.viewDescription.viewSpecification, - displayAsList: state.configuration.viewDescription.displayAsList, - keyProperty: state.configuration.viewDescription.keyProperty, + outputData: state.configuration.viewDescription.outputData, + displaySpecification: state.configuration.viewDescription.displaySpecification, }); const mapDispatch = (dispatcher: IDispatcher) => ({ onValueSelected: (value: any) => dispatcher.dispatch(new SetSelectedValue(value)), onUpdateData: (vPath: string, data: any) => dispatcher.dispatch(updateDataActionAsyncCreator(vPath, data)), reloadView: (vPath: string) => dispatcher.dispatch(updateViewActionAsyncCreator(vPath)), + removeElement: (vPath: string) => dispatcher.dispatch(removeElementActionAsyncCreator(vPath)), + executeRpc: (vPath: string, data: any) => dispatcher.dispatch(executeRpcActionAsyncCreator(vPath, data)), }); const SelectElementTable = MaterialTable as MaterialTableCtorType<{ [key: string]: any }>; @@ -171,49 +175,59 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp } } + private static getChoisesFromElements = (elements: { [name: string]: ViewElement }, viewData: any) => { + return Object.keys(elements).reduce((acc, cur) => { + const elm = elements[cur]; + if (isViewElementChoise(elm)) { + const caseKeys = Object.keys(elm.cases); + + // find the right case for this choise, use the first one with data, at least use index 0 + const selectedCase = caseKeys.find(key => { + const caseElm = elm.cases[key]; + return Object.keys(caseElm.elements).some(caseElmKey => { + const caseElmElm = caseElm.elements[caseElmKey]; + return viewData[caseElmElm.label] !== undefined || viewData[caseElmElm.id] != undefined; + }); + }) || caseKeys[0]; + + // extract all data of the active case + const caseElements = elm.cases[selectedCase].elements; + const data = Object.keys(caseElements).reduce((dataAcc, dataCur) => { + const dataElm = caseElements[dataCur]; + if (isViewElementEmpty(dataElm)) { + dataAcc[dataElm.label] = null; + } else if (viewData[dataElm.label] !== undefined) { + dataAcc[dataElm.label] = viewData[dataElm.label]; + } else if (viewData[dataElm.id] !== undefined) { + dataAcc[dataElm.id] = viewData[dataElm.id]; + } + return dataAcc; + }, {} as { [name: string]: any }); + + acc[elm.id] = { + selectedCase, + data, + }; + } + return acc; + }, {} as { [path: string]: { selectedCase: string, data: { [property: string]: any } } }) || {} + } + static getDerivedStateFromProps(nextProps: ConfigurationApplicationComponentProps, prevState: ConfigurationApplicationComponentState & { [OldProps]: ConfigurationApplicationComponentProps }) { if (!prevState || !prevState[OldProps] || (prevState[OldProps].viewData !== nextProps.viewData)) { - const isNew: boolean = nextProps.vPath ?.endsWith("[]") || false; + const isNew: boolean = nextProps.vPath?.endsWith("[]") || false; const state = { ...prevState, isNew: isNew, editMode: isNew, viewData: nextProps.viewData || null, [OldProps]: nextProps, - choises: nextProps.viewSpecification && Object.keys(nextProps.viewSpecification.elements).reduce((acc, cur) => { - const elm = nextProps.viewSpecification.elements[cur]; - if (isViewElementChoise(elm)) { - const caseKeys = Object.keys(elm.cases); - - // find the right case for this choise, use the first one with data, at least use index 0 - const selectedCase = caseKeys.find(key => { - const caseElm = elm.cases[key]; - return Object.keys(caseElm.elements).some(caseElmKey => { - const caseElmElm = caseElm.elements[caseElmKey]; - return nextProps.viewData[caseElmElm.label] != null || nextProps.viewData[caseElmElm.id] != null; - }); - }) || caseKeys[0]; - - // extract all data of the active case - const caseElements = elm.cases[selectedCase].elements; - const data = Object.keys(caseElements).reduce((dataAcc, dataCur) => { - const dataElm = caseElements[dataCur]; - if (nextProps.viewData[dataElm.label] !== undefined) { - dataAcc[dataElm.label] = nextProps.viewData[dataElm.label]; - } else if (nextProps.viewData[dataElm.id] !== undefined) { - dataAcc[dataElm.id] = nextProps.viewData[dataElm.id]; - } - return dataAcc; - }, {} as { [name: string]: any }); - - acc[elm.id] = { - selectedCase, - data, - }; - } - return acc; - }, {} as { [path: string]: { selectedCase: string, data: { [property: string]: any } } }) || {} + choises: nextProps.displaySpecification.displayMode === DisplayModeType.doNotDisplay + ? null + : nextProps.displaySpecification.displayMode === DisplayModeType.displayAsRPC + ? nextProps.displaySpecification.inputViewSpecification && ConfigurationApplicationComponent.getChoisesFromElements(nextProps.displaySpecification.inputViewSpecification.elements, nextProps.viewData) || [] + : ConfigurationApplicationComponent.getChoisesFromElements(nextProps.displaySpecification.viewSpecification.elements, nextProps.viewData) } return state; } @@ -233,10 +247,46 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp }); } + private collectData = (elements: { [name: string]: ViewElement }) => { + // ensure only active choises will be contained + const viewData : { [key: string]: any }= { ...this.state.viewData }; + const choiseKeys = Object.keys(elements).filter(elmKey => isViewElementChoise(elements[elmKey])); + const elementsToRemove = choiseKeys.reduce((acc, curChoiceKey) => { + const currentChoice = elements[curChoiceKey] as ViewElementChoise; + const selectedCase = this.state.choises[curChoiceKey].selectedCase; + Object.keys(currentChoice.cases).forEach(caseKey => { + const caseElements = currentChoice.cases[caseKey].elements; + if (caseKey === selectedCase) { + Object.keys(caseElements).forEach(caseElementKey => { + const elm = caseElements[caseElementKey]; + if (isViewElementEmpty(elm)) { + // insert null for all empty elements + viewData[elm.id] = null; + } + }); + return; + }; + Object.keys(caseElements).forEach(caseElementKey => { + acc.push(caseElements[caseElementKey]); + }); + }); + return acc; + }, [] as ViewElement[]); + + return viewData && Object.keys(viewData).reduce((acc, cur) => { + if (!elementsToRemove.some(elm => elm.label === cur || elm.id === cur)) { + acc[cur] = viewData[cur]; + } + return acc; + }, {} as { [key: string]: any }); + } + private renderUIElement = (uiElement: ViewElement, viewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) => { const isKey = (uiElement.label === keyProperty); const canEdit = editMode && (isNew || (uiElement.config && !isKey)); - if (isViewElementSelection(uiElement)) { + if (isViewElementEmpty(uiElement)) { + return null; + } else if (isViewElementSelection(uiElement)) { return <UiElementSelection key={uiElement.id} @@ -283,8 +333,7 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp readOnly={!canEdit} disabled={editMode && !canEdit} onChange={(e) => { this.changeValueFor(uiElement.id, e) }} /> - } - else { + } else { if (process.env.NODE_ENV !== "production") { console.error(`Unknown element type - ${(uiElement as any).uiType} in ${(uiElement as any).id}.`) } @@ -391,16 +440,18 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp acc.references.push(elm); } else if (isViewElementChoise(elm)) { acc.choises.push(elm); + } else if (isViewElementRpc(elm)) { + acc.rpcs.push(elm); } else { acc.elements.push(elm); } return acc; - }, { elements: [] as ViewElement[], references: [] as ViewElement[], choises: [] as ViewElementChoise[] }); + }, { elements: [] as ViewElement[], references: [] as ViewElement[], choises: [] as ViewElementChoise[], rpcs: [] as ViewElementRpc[] }); sections.elements = sections.elements.sort(orderFunc); return ( - <> + <div className={classes.uiView}> <div className={classes.section} /> {sections.elements.length > 0 ? ( @@ -425,7 +476,16 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp </div> ) : null } - </> + {sections.rpcs.length > 0 + ? ( + <div className={classes.section}> + {sections.rpcs.map(element => ( + <UIElementReference key={element.id} element={element} disabled={editMode} onOpenReference={(elm) => { this.navigate(`/${elm.id}`) }} /> + ))} + </div> + ) : null + } + </div> ); }; @@ -442,7 +502,7 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp } }; - const { classes } = this.props; + const { classes, removeElement } = this.props; return ( <SelectElementTable stickyHeader idProperty={listKeyProperty} rows={listData} customActionButtons={[addNewElementAction]} columns={ @@ -457,11 +517,13 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp } return acc; }, []).concat([{ - property: "Actions", disableFilter: true, disableSorting: true, type: ColumnType.custom, customControl: (row => { + property: "Actions", disableFilter: true, disableSorting: true, type: ColumnType.custom, customControl: ( ({ rowData })=> { return ( <Tooltip title={"Remove"} > - <IconButton className={classes.button} onClick={event => { - + <IconButton className={classes.button} onClick={(e) => { + e.stopPropagation(); + e.preventDefault(); + removeElement(`${this.props.vPath}[${rowData[listKeyProperty]}]`) }} > <RemoveIcon /> </IconButton> @@ -476,10 +538,73 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp ); } + private renderUIViewRPC(inputViewSpecification: ViewSpecification | undefined, inputViewData: { [key: string]: any }, outputViewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) { + const { classes } = this.props; + + const orderFunc = (vsA: ViewElement, vsB: ViewElement) => { + if (keyProperty) { + // if (vsA.label === vsB.label) return 0; + if (vsA.label === keyProperty) return -1; + if (vsB.label === keyProperty) return +1; + } + + // if (vsA.uiType === vsB.uiType) return 0; + // if (vsA.uiType !== "object" && vsB.uiType !== "object") return 0; + // if (vsA.uiType === "object") return +1; + return -1; + }; + + const sections = inputViewSpecification && Object.keys(inputViewSpecification.elements).reduce((acc, cur) => { + const elm = inputViewSpecification.elements[cur]; + if (isViewElementObjectOrList(elm)) { + console.error("Object should not appear in RPC view !"); + } else if (isViewElementChoise(elm)) { + acc.choises.push(elm); + } else if (isViewElementRpc(elm)) { + console.error("RPC should not appear in RPC view !"); + } else { + acc.elements.push(elm); + } + return acc; + }, { elements: [] as ViewElement[], references: [] as ViewElement[], choises: [] as ViewElementChoise[], rpcs: [] as ViewElementRpc[] }) + || { elements: [] as ViewElement[], references: [] as ViewElement[], choises: [] as ViewElementChoise[], rpcs: [] as ViewElementRpc[] }; + + sections.elements = sections.elements.sort(orderFunc); + + return ( + <> + <div className={classes.section} /> + {sections.elements.length > 0 + ? ( + <div className={classes.section}> + {sections.elements.map(element => this.renderUIElement(element, inputViewData, keyProperty, editMode, isNew))} + </div> + ) : null + } + {sections.choises.length > 0 + ? ( + <div className={classes.section}> + {sections.choises.map(element => this.renderUIChoise(element, inputViewData, keyProperty, editMode, isNew))} + </div> + ) : null + } + <Button onClick={() => { + const resultingViewData = inputViewSpecification && this.collectData(inputViewSpecification.elements); + this.props.executeRpc(this.props.vPath!, resultingViewData); + }} >Exec</Button> + {outputViewData !== undefined + ? ( + renderObject(outputViewData) ) + : null + } + </> + ); + }; + private renderBreadCrumps() { const { editMode } = this.state; - const { viewSpecification, displayAsList } = this.props; - const { vPath, match: { url, path }, nodeId } = this.props; + const { displaySpecification } = this.props; + const { vPath, nodeId } = this.props; const pathParts = splitVPath(vPath!, /(?:([^\/\["]+)(?:\[([^\]]*)\])?)/g); // 1 = property / 2 = optional key let lastPath = `/configuration`; let basePath = `/configuration/${nodeId}`; @@ -527,33 +652,11 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp }} ><ArrowBack /></Fab> ) || null} { /* do not show edit if this is a list or it can't be edited */ - !displayAsList && viewSpecification.canEdit && (<div> + displaySpecification.displayMode === DisplayModeType.displayAsObject && displaySpecification.viewSpecification.canEdit && (<div> <Fab color="secondary" aria-label="edit" className={this.props.classes.fab} onClick={() => { if (this.state.editMode) { - // ensure only active choises will be contained - const choiseKeys = Object.keys(viewSpecification.elements).filter(elmKey => isViewElementChoise(viewSpecification.elements[elmKey])); - const elementsToRemove = choiseKeys.reduce((acc, cur) => { - const choise = viewSpecification.elements[cur] as ViewElementChoise; - const selectedCase = this.state.choises[cur].selectedCase; - Object.keys(choise.cases).forEach(caseKey => { - if (caseKey === selectedCase) return; - const caseElements = choise.cases[caseKey].elements; - Object.keys(caseElements).forEach(caseElementKey => { - acc.push(caseElements[caseElementKey]); - }); - }); - return acc; - }, [] as ViewElement[]); - - const viewData = this.state.viewData; - const resultingViewData = viewData && Object.keys(viewData).reduce((acc, cur) => { - if (!elementsToRemove.some(elm => elm.label === cur || elm.id === cur)) { - acc[cur] = viewData[cur]; - } - return acc; - }, {} as { [key: string]: any }); - + const resultingViewData = this.collectData(displaySpecification.viewSpecification.elements); this.props.onUpdateData(this.props.vPath!, resultingViewData); } this.setState({ editMode: !editMode }); @@ -595,15 +698,19 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp } private renderValueEditor() { - const { keyProperty, displayAsList, viewSpecification } = this.props; + const { displaySpecification: ds, outputData } = this.props; const { viewData, editMode, isNew } = this.state; return ( <div className={this.props.classes.container}> {this.renderBreadCrumps()} - {displayAsList && viewData instanceof Array - ? this.renderUIViewList(viewSpecification, keyProperty!, viewData) - : this.renderUIView(viewSpecification, viewData!, keyProperty, editMode, isNew) + {ds.displayMode === DisplayModeType.doNotDisplay + ? null + : ds.displayMode === DisplayModeType.displayAsList && viewData instanceof Array + ? this.renderUIViewList(ds.viewSpecification, ds.keyProperty!, viewData) + : ds.displayMode === DisplayModeType.displayAsRPC + ? this.renderUIViewRPC(ds.inputViewSpecification, viewData!, outputData, undefined, true, false) + : this.renderUIView(ds.viewSpecification, viewData!, ds.keyProperty, editMode, isNew) } </div > ); diff --git a/sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts b/sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts index 27859f7b6..b1c1e7430 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts @@ -15,10 +15,12 @@ * the License. * ============LICENSE_END========================================================================== */ - - import { Token, Statement, Module, Identity } from "../models/yang"; -import { ViewSpecification, ViewElement, isViewElementObjectOrList, ViewElementBase, isViewElementReference, ViewElementChoise, ViewElementBinary, ViewElementString, isViewElementString, isViewElementNumber, ViewElementNumber, Expression, YangRange, ViewElementUnion } from "../models/uiModels"; +import { + ViewSpecification, ViewElement, isViewElementObjectOrList, ViewElementBase, + isViewElementReference, ViewElementChoise, ViewElementBinary, ViewElementString, isViewElementString, + isViewElementNumber, ViewElementNumber, Expression, YangRange, ViewElementUnion, ViewElementRpc, isViewElementRpc, ResolveFunction +} from "../models/uiModels"; import { yangService } from "../services/yangService"; export const splitVPath = (vPath: string, vPathParser: RegExp): RegExpMatchArray[] => { @@ -263,7 +265,8 @@ class YangLexer { } export class YangParser { - private _groupingsToResolve: (() => void)[] = []; + private _groupingsToResolve: ViewSpecification[] = []; + private _identityToResolve: (() => void)[] = []; private _unionsToResolve: (() => void)[] = []; private _modulesToResolve: (() => void)[] = []; @@ -410,11 +413,13 @@ export class YangParser { this._modulesToResolve.push(() => { Object.keys(module.elements).forEach(key => { const viewElement = module.elements[key]; - if (!isViewElementObjectOrList(viewElement)) { - throw new Error(`Module: [${module}]. Only List or Object allowed on root level.`); + if (!(isViewElementObjectOrList(viewElement) || isViewElementRpc(viewElement))) { + console.error(new Error(`Module: [${module}]. Only Object, List or RPC are allowed on root level.`)); + } + if (isViewElementObjectOrList(viewElement)) { + const viewIdIndex = Number(viewElement.viewId); + module.views[key] = this._views[viewIdIndex]; } - const viewIdIndex = Number(viewElement.viewId); - module.views[key] = this._views[viewIdIndex]; this._views[0].elements[key] = module.elements[key]; }); }); @@ -431,8 +436,8 @@ export class YangParser { }); // process all groupings - this._groupingsToResolve.forEach(cb => { - try { cb(); } catch (error) { + this._groupingsToResolve.filter(vs => vs.uses && vs.uses[ResolveFunction]).forEach(vs => { + try { vs.uses![ResolveFunction]!(); } catch (error) { console.warn(`Error resolving: [${error.message}]`); } }); @@ -470,7 +475,6 @@ export class YangParser { return result; } - const baseIdentites: Identity[] = []; Object.keys(this.modules).forEach(modKey => { const module = this.modules[modKey]; @@ -478,7 +482,7 @@ export class YangParser { const identity = module.identities[idKey]; if (identity.base != null) { const base = this.resolveIdentity(identity.base, module); - base.children ?.push(identity); + base.children?.push(identity); } else { baseIdentites.push(identity); } @@ -765,20 +769,60 @@ export class YangParser { }, [])); } - const rpcs = this.extractNodes(statement, "rpc"); - if (rpcs && rpcs.length > 0) { - // todo: - } + const rpcStms = this.extractNodes(statement, "rpc"); + if (rpcStms && rpcStms.length > 0) { + elements.push(...rpcStms.reduce<ViewElementRpc[]>((accRpc, curRpc) => { + if (!curRpc.arg) { + throw new Error(`Module: [${context.name}]${currentPath}. Found rpc without name.`); + } + + const description = this.extractValue(curRpc, "description") || undefined; + const configValue = this.extractValue(curRpc, "config"); + const config = configValue == null ? true : configValue.toLocaleLowerCase() !== "false"; + + let inputViewId: string | undefined = undefined; + let outputViewId: string | undefined = undefined; + + const input = this.extractNodes(curRpc, "input") || undefined; + const output = this.extractNodes(curRpc, "output") || undefined; + + if (input && input.length > 0) { + const [inputView, inputSubViews] = this.extractSubViews(input[0], parentId, context, `${currentPath}/${context.name}:${curRpc.arg}`); + subViews.push(inputView, ...inputSubViews); + inputViewId = inputView.id; + } + + if (output && output.length > 0) { + const [outputView, outputSubViews] = this.extractSubViews(output[0], parentId, context, `${currentPath}/${context.name}:${curRpc.arg}`); + subViews.push(outputView, ...outputSubViews); + outputViewId = outputView.id; + } - if (!statement.arg) { - throw new Error(`Module: [${context.name}]. Found statement without name.`); + const element: ViewElementRpc = { + uiType: "rpc", + id: parentId === 0 ? `${context.name}:${curRpc.arg}` : curRpc.arg, + label: curRpc.arg, + config: config, + description: description, + inputViewId: inputViewId, + outputViewId: outputViewId, + }; + + accRpc.push(element); + + return accRpc; + }, [])); } + // if (!statement.arg) { + // throw new Error(`Module: [${context.name}]. Found statement without name.`); + // } + const viewSpec: ViewSpecification = { id: String(currentId), parentView: String(parentId), - name: statement.arg, - title: statement.arg, + name: statement.arg != null ? statement.arg : undefined, + title: statement.arg != null ? statement.arg : undefined, language: "en-us", canEdit: false, ifFeature: ifFeature, @@ -804,6 +848,8 @@ export class YangParser { if (usesRefs && usesRefs.length > 0) { viewSpec.uses = (viewSpec.uses || []); + const resolveFunctions : (()=>void)[] = []; + for (let i = 0; i < usesRefs.length; ++i) { const groupingName = usesRefs[i].arg; if (!groupingName) { @@ -812,9 +858,14 @@ export class YangParser { viewSpec.uses.push(this.resolveReferencePath(groupingName, context)); - this._groupingsToResolve.push(() => { + resolveFunctions.push(() => { const groupingViewSpec = this.resolveGrouping(groupingName, context); if (groupingViewSpec) { + + // resolve recursive + const resolveFunc = groupingViewSpec.uses && groupingViewSpec.uses[ResolveFunction]; + resolveFunc && resolveFunc(); + Object.keys(groupingViewSpec.elements).forEach(key => { const elm = groupingViewSpec.elements[key]; viewSpec.elements[key] = { @@ -826,6 +877,19 @@ export class YangParser { } }); } + + viewSpec.uses[ResolveFunction] = () => { + resolveFunctions.forEach(res => { + try { + res(); + } catch (error) { + console.error(error); + } + }); + viewSpec?.uses![ResolveFunction] = undefined; + } + + this._groupingsToResolve.push(viewSpec); } return [viewSpec, subViews]; @@ -1117,10 +1181,9 @@ export class YangParser { /* 9.11. The empty Built-In Type The empty built-in type represents a leaf that does not have any value, it conveys information by its presence or absence. */ - console.warn(`found type: empty in [${module.name}][${currentPath}][${element.label}]`); return { ...element, - uiType: "string", + uiType: "empty", }; } else if (type === "union") { // todo: ❗ handle union ⚡ diff --git a/sdnr/wt/odlux/apps/connectApp/package.json b/sdnr/wt/odlux/apps/connectApp/package.json index 774daba6b..1efd282c4 100644 --- a/sdnr/wt/odlux/apps/connectApp/package.json +++ b/sdnr/wt/odlux/apps/connectApp/package.json @@ -24,8 +24,8 @@ "@odlux/framework": "*" }, "peerDependencies": { - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@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", diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx index e3b640120..3b4cf3bb5 100644 --- a/sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx +++ b/sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx @@ -61,16 +61,19 @@ const mapDispatch = (dispatcher: IDispatcher) => ({ editNetworkElement: async (element: UpdateNetworkElement, mountElement: NetworkElementConnection) => { const values = Object.keys(element); + console.log("edit element"); + console.log(values); //make sure properties are there in case they get renamed const idProperty = propertyOf<UpdateNetworkElement>("id"); const isRequiredProperty = propertyOf<UpdateNetworkElement>("isRequired"); + if (values.length === 2 && values.includes(idProperty as string) && values.includes(isRequiredProperty as string)) { // do not mount network element, if only isRequired is changed await dispatcher.dispatch(editNetworkElementAsyncActionCreator(element)); - } else { + } else if(!(values.length===1 &&values.includes(idProperty as string))) { //do not edit or mount element, if only id was saved into object (no changes made!) await dispatcher.dispatch(editNetworkElementAsyncActionCreator(element)); await dispatcher.dispatch(mountNetworkElementAsyncActionCreator(mountElement)); } diff --git a/sdnr/wt/odlux/apps/demoApp/package.json b/sdnr/wt/odlux/apps/demoApp/package.json index b5857099b..f30a922fe 100644 --- a/sdnr/wt/odlux/apps/demoApp/package.json +++ b/sdnr/wt/odlux/apps/demoApp/package.json @@ -24,8 +24,8 @@ "@odlux/framework": "*" }, "peerDependencies": { - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@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", diff --git a/sdnr/wt/odlux/apps/eventLogApp/package.json b/sdnr/wt/odlux/apps/eventLogApp/package.json index ce8b8859d..f182374cf 100644 --- a/sdnr/wt/odlux/apps/eventLogApp/package.json +++ b/sdnr/wt/odlux/apps/eventLogApp/package.json @@ -24,8 +24,8 @@ "@odlux/framework": "*" }, "peerDependencies": { - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@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", diff --git a/sdnr/wt/odlux/apps/faultApp/package.json b/sdnr/wt/odlux/apps/faultApp/package.json index b922df351..c42d28986 100644 --- a/sdnr/wt/odlux/apps/faultApp/package.json +++ b/sdnr/wt/odlux/apps/faultApp/package.json @@ -24,8 +24,8 @@ "@odlux/framework": "*" }, "peerDependencies": { - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@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", diff --git a/sdnr/wt/odlux/apps/helpApp/package.json b/sdnr/wt/odlux/apps/helpApp/package.json index 2a331f68a..1f516cec4 100644 --- a/sdnr/wt/odlux/apps/helpApp/package.json +++ b/sdnr/wt/odlux/apps/helpApp/package.json @@ -29,8 +29,8 @@ "github-markdown-css": "2.10.0" }, "peerDependencies": { - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@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", diff --git a/sdnr/wt/odlux/apps/inventoryApp/package.json b/sdnr/wt/odlux/apps/inventoryApp/package.json index 929ca0fb4..4b1f3f9f9 100644 --- a/sdnr/wt/odlux/apps/inventoryApp/package.json +++ b/sdnr/wt/odlux/apps/inventoryApp/package.json @@ -24,8 +24,8 @@ "@odlux/framework": "*" }, "peerDependencies": { - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@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", diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/actions/inventoryTreeActions.ts b/sdnr/wt/odlux/apps/inventoryApp/src/actions/inventoryTreeActions.ts new file mode 100644 index 000000000..c09b669a1 --- /dev/null +++ b/sdnr/wt/odlux/apps/inventoryApp/src/actions/inventoryTreeActions.ts @@ -0,0 +1,104 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * 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========================================================================== + */ + +import { Action } from '../../../../framework/src/flux/action'; +import { Dispatch } from '../../../../framework/src/flux/store'; +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; + +import { InventoryType, InventoryTreeNode, TreeDemoItem } from '../models/inventory'; +import { inventoryService } from '../services/inventoryService'; +import { AddErrorInfoAction } from '../../../../framework/src/actions/errorActions'; +import { NavigateToApplication } from '../../../../framework/src/actions/navigationActions'; + +/** + * Represents the base action. + */ +export class BaseAction extends Action { } + +export class SetBusyAction extends BaseAction { + constructor(public busy: boolean = true) { + super(); + + } +} + +export class SetSearchTextAction extends BaseAction { + constructor(public searchTerm: string = "") { + super(); + + } +} + +export class UpdateInventoryTreeAction extends BaseAction { + constructor(public rootNode: InventoryTreeNode) { + super(); + + } +} + +export class UpdateSelectedNodeAction extends BaseAction { + constructor(public selectedNode?: InventoryType) { + super(); + + } +} + +export class UpdateExpandedNodesAction extends BaseAction { + constructor(public expandedNodes?: TreeDemoItem[]) { + super(); + + } +} + +export const setSearchTermAction = (searchTerm: string) => (dispatch: Dispatch, getState: () => IApplicationStoreState) =>{ + dispatch(new SetSearchTextAction(searchTerm)); +} + + +export const updateInventoryTreeAsyncAction = (mountId: string, searchTerm?: string) => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => { + dispatch(new SetBusyAction(true)); + dispatch(new SetSearchTextAction(searchTerm)); + try { + const result = await inventoryService.getInventoryTree(mountId, searchTerm); + if (!result) { + dispatch(new AddErrorInfoAction({ title: "Error", message: `Could not load inventory tree for [${mountId}]. Please check you connection to the server and try later.` })); + dispatch(new NavigateToApplication("inventory")); + } else { + dispatch(new UpdateInventoryTreeAction(result)); + } + } catch (err) { + throw new Error("Could not load inventory tree from server."); + } + finally { + dispatch(new SetBusyAction(false)); + } +}; + +export const selectInventoryNodeAsyncAction = (nodeId: string) => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => { + dispatch(new SetBusyAction(true)); + try { + const result = await inventoryService.getInventoryEntry(nodeId); + if (!result) throw new Error("Could not load inventory tree from server."); + dispatch(new UpdateSelectedNodeAction(result)); + } catch (err) { + throw new Error("Could not load inventory tree from server."); + } + finally { + dispatch(new SetBusyAction(false)); + } +}; diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/actions/panelActions.ts b/sdnr/wt/odlux/apps/inventoryApp/src/actions/panelActions.ts new file mode 100644 index 000000000..10fde8c1d --- /dev/null +++ b/sdnr/wt/odlux/apps/inventoryApp/src/actions/panelActions.ts @@ -0,0 +1,31 @@ +/** + * ============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 { PanelId } from "models/panelId"; + + +export class SetPanelAction extends Action { + constructor(public panelId: PanelId) { + super(); + } + } + +export const setPanelAction = (panelId: PanelId) => { + return new SetPanelAction(panelId); + }
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/fakeData/index.ts b/sdnr/wt/odlux/apps/inventoryApp/src/fakeData/index.ts index 692ea82c7..46827e842 100644 --- a/sdnr/wt/odlux/apps/inventoryApp/src/fakeData/index.ts +++ b/sdnr/wt/odlux/apps/inventoryApp/src/fakeData/index.ts @@ -1,3 +1,21 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * 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========================================================================== + */ + import { InventoryTreeNode, InventoryType } from "models/inventory"; import { convertPropertyNames, replaceHyphen } from "../../../../framework/src/utilities/yangHelper"; @@ -30,31 +48,31 @@ const deleay = (time: number) => () => new Promise<number>(resolve => setTimeout const getTreeElements = (searchTerm: string | null, treeLevel: number = 0, parentUUID: string | null = null): [InventoryTreeNode, boolean] => { const elements = (data.filter(e => e["tree-level"] === treeLevel && (!parentUUID || e["parent-uuid"] === parentUUID)) || []) let elementMatch = false; - const treeeNode = elements.reduce<InventoryTreeNode>((acc, cur) => { - const [children, childMatch] = getTreeElements(searchTerm, treeLevel + 1, cur["node-id"]); - const isMatch = searchTerm ? Object.keys(cur).some(k => String((cur as any)[k]).indexOf(searchTerm)) : false; + const treeNode = elements.reduce<InventoryTreeNode>((acc, cur) => { + const [children, childMatch] = getTreeElements(searchTerm, treeLevel + 1, cur["uuid"]); + const isMatch = searchTerm ? Object.keys(cur).some(k => String((cur as any)[k]).indexOf(searchTerm) > -1) : false; elementMatch = elementMatch || isMatch || childMatch; if (!searchTerm || isMatch || childMatch) { - acc[cur["node-id"]] = { - label: cur["node-id"], + acc[cur["uuid"]] = { + label: cur["uuid"], children: children, - isMatch: false, + isMatch: isMatch, }; } return acc; }, {}); - return [treeeNode, elementMatch] + return [treeNode, elementMatch] }; -export const getTree = async (searchTerm: string | null = null) : Promise<InventoryTreeNode> => { +export const getTree = async (searchTerm: string | null = null): Promise<InventoryTreeNode> => { await deleay(600); const [node] = getTreeElements(searchTerm); return node; }; -export const getElement = async (id: string ): Promise<InventoryType | undefined> => { +export const getElement = async (id: string): Promise<InventoryType | undefined> => { await deleay(600); - const res = data.find(e => e.id === id); + const res = data.find(e => e.uuid === id); return res && convertPropertyNames(res, replaceHyphen) as unknown as InventoryType; }; diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/handlers/connectedNetworkElementsHandler.ts b/sdnr/wt/odlux/apps/inventoryApp/src/handlers/connectedNetworkElementsHandler.ts new file mode 100644 index 000000000..79c12d619 --- /dev/null +++ b/sdnr/wt/odlux/apps/inventoryApp/src/handlers/connectedNetworkElementsHandler.ts @@ -0,0 +1,36 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * 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========================================================================== + */ + +import { createExternal, IExternalTableState } from '../../../../framework/src/components/material-table/utilities'; +import { createSearchDataHandler } from '../../../../framework/src/utilities/elasticSearch'; + +import { NetworkElementConnection } from '../models/networkElementConnection'; + +export interface IConnectedNetworkElementsState extends IExternalTableState<NetworkElementConnection> { } + +// create eleactic search material data fetch handler +const connectedNetworkElementsSearchHandler = createSearchDataHandler<NetworkElementConnection>('network-element-connection', { status: "Connected" }); + +export const { + actionHandler: connectedNetworkElementsActionHandler, + createActions: createConnectedNetworkElementsActions, + createProperties: createConnectedNetworkElementsProperties, + reloadAction: connectedNetworkElementsReloadAction, + + // set value action, to change a value +} = createExternal<NetworkElementConnection>(connectedNetworkElementsSearchHandler, appState => appState.inventory.connectedNetworkElements); diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/handlers/inventoryAppRootHandler.ts b/sdnr/wt/odlux/apps/inventoryApp/src/handlers/inventoryAppRootHandler.ts index 786f6d0c5..0e857ffe9 100644 --- a/sdnr/wt/odlux/apps/inventoryApp/src/handlers/inventoryAppRootHandler.ts +++ b/sdnr/wt/odlux/apps/inventoryApp/src/handlers/inventoryAppRootHandler.ts @@ -22,14 +22,23 @@ 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 { IInventoryElementsState, inventoryElementsActionHandler } from './inventoryElementsHandler'; +import { IInvenroryTree, inventoryTreeHandler } from './inventoryTreeHandler'; +import { IConnectedNetworkElementsState, connectedNetworkElementsActionHandler } from './connectedNetworkElementsHandler'; +import { PanelId } from '../models/panelId'; +import { currentOpenPanelHandler } from './panelHandler'; +import { inventoryElementsActionHandler, IInventoryElementsState } from './inventoryElementsHandler'; export interface IInventoryAppStateState { - inventoryElements: IInventoryElementsState + inventoryTree: IInvenroryTree; + connectedNetworkElements: IConnectedNetworkElementsState; // used for ne selection + currentOpenPanel: PanelId; + inventoryElements: IInventoryElementsState; } + + declare module '../../../../framework/src/store/applicationStore' { interface IApplicationStoreState { inventory: IInventoryAppStateState; @@ -37,6 +46,9 @@ declare module '../../../../framework/src/store/applicationStore' { } const actionHandlers = { + inventoryTree: inventoryTreeHandler, + connectedNetworkElements: connectedNetworkElementsActionHandler, + currentOpenPanel: currentOpenPanelHandler, inventoryElements: inventoryElementsActionHandler }; diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/handlers/inventoryElementsHandler.tsx b/sdnr/wt/odlux/apps/inventoryApp/src/handlers/inventoryElementsHandler.ts index a65319efa..a65319efa 100644 --- a/sdnr/wt/odlux/apps/inventoryApp/src/handlers/inventoryElementsHandler.tsx +++ b/sdnr/wt/odlux/apps/inventoryApp/src/handlers/inventoryElementsHandler.ts diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/handlers/inventoryTreeHandler.ts b/sdnr/wt/odlux/apps/inventoryApp/src/handlers/inventoryTreeHandler.ts new file mode 100644 index 000000000..9029a6719 --- /dev/null +++ b/sdnr/wt/odlux/apps/inventoryApp/src/handlers/inventoryTreeHandler.ts @@ -0,0 +1,68 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * 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========================================================================== + */ + +import { IActionHandler } from "../../../../framework/src/flux/action"; + +import { SetBusyAction, UpdateInventoryTreeAction, UpdateSelectedNodeAction, SetSearchTextAction, UpdateExpandedNodesAction } from "../actions/inventoryTreeActions"; +import { InventoryTreeNode, InventoryType, TreeDemoItem } from "../models/inventory"; + + +export interface IInvenroryTree { + isBusy: boolean; + rootNodes: TreeDemoItem[]; + selectedNode?: InventoryType; + expandedItems: TreeDemoItem[]; + searchTerm: string; +} + +const initialState: IInvenroryTree = { + isBusy: false, + rootNodes: [], + searchTerm: "", + selectedNode: undefined, + expandedItems: [], +} + + +const getTreeDataFromInvetoryTreeNode = (node: InventoryTreeNode): TreeDemoItem[] => Object.keys(node).reduce<TreeDemoItem[]>((acc, key) => { + const cur = node[key]; + acc.push({ + isMatch: cur.isMatch, + content: cur.label || key, + value: key, + children: cur.children && getTreeDataFromInvetoryTreeNode(cur.children), + }); + return acc; +}, []); + +export const inventoryTreeHandler: IActionHandler<IInvenroryTree> = (state = initialState, action) => { + if (action instanceof SetBusyAction) { + state = { ...state, isBusy: action.busy }; + } else if (action instanceof SetSearchTextAction) { + state = { ...state, searchTerm: action.searchTerm }; + } else if (action instanceof UpdateInventoryTreeAction) { + const rootNodes = getTreeDataFromInvetoryTreeNode(action.rootNode); + state = { ...state, rootNodes: rootNodes, expandedItems: [], selectedNode: undefined }; + } else if (action instanceof UpdateSelectedNodeAction) { + state = { ...state, selectedNode: action.selectedNode }; + } else if (action instanceof UpdateExpandedNodesAction) { + state = { ...state, expandedItems: action.expandedNodes || []} + } + + return state; +}
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/handlers/panelHandler.ts b/sdnr/wt/odlux/apps/inventoryApp/src/handlers/panelHandler.ts new file mode 100644 index 000000000..761253112 --- /dev/null +++ b/sdnr/wt/odlux/apps/inventoryApp/src/handlers/panelHandler.ts @@ -0,0 +1,11 @@ +import { PanelId } from "../models/panelId"; +import { IActionHandler } from "../../../../framework/src/flux/action"; +import { SetPanelAction } from "../actions/panelActions"; + + +export const currentOpenPanelHandler: IActionHandler<PanelId> = (state = null, action) => { + if (action instanceof SetPanelAction) { + state = action.panelId; + } + return state; + }
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/index.html b/sdnr/wt/odlux/apps/inventoryApp/src/index.html index 0cdb9e93b..75531ec1b 100644 --- a/sdnr/wt/odlux/apps/inventoryApp/src/index.html +++ b/sdnr/wt/odlux/apps/inventoryApp/src/index.html @@ -15,8 +15,9 @@ <script type="text/javascript" src="./config.js"></script> <script> // run the application - require(["app", "inventoryApp"], function (app, inventoryApp) { + require(["app", "inventoryApp", "connectApp"], function (app, inventoryApp, connectApp) { inventoryApp.register(); + connectApp.register(); app("./app.tsx").runApplication(); }); </script> diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/models/inventory.ts b/sdnr/wt/odlux/apps/inventoryApp/src/models/inventory.ts index c6b6c91cb..a6c990529 100644 --- a/sdnr/wt/odlux/apps/inventoryApp/src/models/inventory.ts +++ b/sdnr/wt/odlux/apps/inventoryApp/src/models/inventory.ts @@ -15,6 +15,9 @@ * the License. * ============LICENSE_END========================================================================== */ + +import { ExternalTreeItem } from '../../../../framework/src/components/material-ui/treeView'; + export { HitEntry, Result } from '../../../../framework/src/models'; export type InventoryType = { @@ -23,7 +26,7 @@ export type InventoryType = { nodeId: string; uuid: string; containedHolder?: (string)[] | null; - manufacturerName?: string ; + manufacturerName?: string; manufacturerIdentifier: string; serial: string; date: string; @@ -42,4 +45,6 @@ export type InventoryTreeNode = { ownSeverity?: string; childrenSeveritySummary?: string; } -}
\ No newline at end of file +} + +export type TreeDemoItem = ExternalTreeItem<string>;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/models/networkElementConnection.ts b/sdnr/wt/odlux/apps/inventoryApp/src/models/networkElementConnection.ts new file mode 100644 index 000000000..88f70181c --- /dev/null +++ b/sdnr/wt/odlux/apps/inventoryApp/src/models/networkElementConnection.ts @@ -0,0 +1,37 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * 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========================================================================== + */ + +export type NetworkElementConnection = { + id?: string; + nodeId: string; + host: string; + port: number; + username?: string; + password?: string; + isRequired?: boolean; + status?: "connected" | "mounted" | "unmounted" | "connecting" | "disconnected" | "idle"; + coreModelCapability?: string; + deviceType?: string; + nodeDetails?: { + availableCapabilities: string[]; + unavailableCapabilities: { + failureReason: string; + capability: string; + }[]; + } +} diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/models/panelId.ts b/sdnr/wt/odlux/apps/inventoryApp/src/models/panelId.ts new file mode 100644 index 000000000..b05c1db64 --- /dev/null +++ b/sdnr/wt/odlux/apps/inventoryApp/src/models/panelId.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 PanelId = null | "InventoryElementsTable" | "TreeviewTable";
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/pluginInventory.tsx b/sdnr/wt/odlux/apps/inventoryApp/src/pluginInventory.tsx index ad53285cb..665e085e6 100644 --- a/sdnr/wt/odlux/apps/inventoryApp/src/pluginInventory.tsx +++ b/sdnr/wt/odlux/apps/inventoryApp/src/pluginInventory.tsx @@ -22,43 +22,15 @@ import { withRouter, RouteComponentProps, Route, Switch, Redirect } from 'react- import { faShoppingBag } from '@fortawesome/free-solid-svg-icons'; // select app icon import applicationManager from '../../../framework/src/services/applicationManager'; -import connect, { Connect, IDispatcher } from '../../../framework/src/flux/connect'; -import { IApplicationStoreState } from "../../../framework/src/store/applicationStore"; +import { InventoryTreeView } from './views/treeview'; +import Dashboard from "./views/dashboard"; -import { Dashboard } from './views/dashboard'; import inventoryAppRootHandler from './handlers/inventoryAppRootHandler'; -import { createInventoryElementsProperties, createInventoryElementsActions, inventoryElementsReloadAction } from "./handlers/inventoryElementsHandler"; - -let currentMountId: string | undefined = undefined; - -const mapProps = (state: IApplicationStoreState) => ({ - inventoryProperties: createInventoryElementsProperties(state), -}); - -const mapDisp = (dispatcher: IDispatcher) => ({ - inventoryActions: createInventoryElementsActions(dispatcher.dispatch, true) -}); - -const InventoryApplicationRouteAdapter = connect(mapProps, mapDisp)((props: RouteComponentProps<{ mountId?: string }> & Connect<typeof mapProps, typeof mapDisp>) => { - if (currentMountId !== props.match.params.mountId) { - currentMountId = props.match.params.mountId || undefined; - window.setTimeout(() => { - if (currentMountId) { - props.inventoryActions.onFilterChanged("nodeId", currentMountId); - props.inventoryProperties.showFilter; - props.inventoryActions.onRefresh(); - } - }); - } - return ( - <Dashboard /> - ) -}); - const App = withRouter((props: RouteComponentProps) => ( <Switch> - <Route path={`${props.match.path}/:mountId?`} component={InventoryApplicationRouteAdapter} /> + <Route path={`${props.match.path}/:mountId`} component={InventoryTreeView} /> + <Route path={`${props.match.path}`} component={Dashboard} /> <Redirect to={`${props.match.path}`} /> </Switch> )); diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/services/inventoryService.ts b/sdnr/wt/odlux/apps/inventoryApp/src/services/inventoryService.ts index 252d6d425..b6025d4da 100644 --- a/sdnr/wt/odlux/apps/inventoryApp/src/services/inventoryService.ts +++ b/sdnr/wt/odlux/apps/inventoryApp/src/services/inventoryService.ts @@ -16,6 +16,7 @@ * ============LICENSE_END========================================================================== */ import { requestRest } from '../../../../framework/src/services/restService'; +import { convertPropertyNames, replaceHyphen } from '../../../../framework/src/utilities/yangHelper'; import { InventoryTreeNode, InventoryType } from '../models/inventory'; import { getTree, getElement } from '../fakeData'; @@ -24,12 +25,44 @@ import { getTree, getElement } from '../fakeData'; * Represents a web api accessor service for all maintenence entries related actions. */ class InventoryService { - public async getInventoryTree(searchTerm?: string): Promise<InventoryTreeNode> { - return await getTree(searchTerm); + public async getInventoryTree(mountId: string, searchTerm: string = ""): Promise<InventoryTreeNode | null> { + //return await getTree(searchTerm); + const path = `/tree/read-inventoryequipment-tree/${mountId}`; + const body = { + "query": searchTerm + }; + const inventoryTree = await requestRest<InventoryTreeNode>(path, { method: "POST" , body: JSON.stringify(body)}); + return inventoryTree && convertPropertyNames(inventoryTree, replaceHyphen) || null; } - public async getInventoryEntry(id: string): Promise<InventoryType| undefined> { - return await getElement(id); + public async getInventoryEntry(id: string): Promise<InventoryType | undefined> { + const path = `/restconf/operations/data-provider:read-inventory-list`; + const body = { + "input": { + "filter": [ + { property: "id", filtervalue: id }, + ], + "sortorder": [], + "pagination": { + "size": 1, + "page": 1 + } + } + }; + const inventoryTreeElement = await requestRest<{ + output: { + "pagination": { + "size": number, + "page": number, + "total": number + }, + "data": InventoryType[] + } + }>(path, { method: "POST", body: JSON.stringify(body) }); + + return inventoryTreeElement && inventoryTreeElement.output && inventoryTreeElement.output.pagination && inventoryTreeElement.output.pagination.total >= 1 && + inventoryTreeElement.output.data && convertPropertyNames(inventoryTreeElement.output.data[0], replaceHyphen) || undefined; + // return await getElement(id); } } diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/views/dashboard.tsx b/sdnr/wt/odlux/apps/inventoryApp/src/views/dashboard.tsx index b63f628a3..14792df5b 100644 --- a/sdnr/wt/odlux/apps/inventoryApp/src/views/dashboard.tsx +++ b/sdnr/wt/odlux/apps/inventoryApp/src/views/dashboard.tsx @@ -15,88 +15,163 @@ * the License. * ============LICENSE_END========================================================================== */ -import * as React from "react"; -import { withStyles, WithStyles, createStyles, Theme } from '@material-ui/core/styles'; -import { Connect, connect, IDispatcher } from '../../../../framework/src/flux/connect'; -import { MaterialTable, MaterialTableCtorType } from '../../../../framework/src/components/material-table'; -import { TreeView, TreeItem, TreeViewCtorType } from '../../../../framework/src/components/material-ui/treeView'; +import * as React from 'react'; +import { RouteComponentProps, withRouter } from 'react-router-dom'; -import { InventoryType } from '../models/inventory'; +import connect, { IDispatcher, Connect } from "../../../../framework/src/flux/connect"; import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore"; -import { createInventoryElementsProperties, createInventoryElementsActions } from "../handlers/inventoryElementsHandler"; +import { MaterialTable, MaterialTableCtorType, ColumnType } from "../../../../framework/src/components/material-table"; +import { AppBar, Tabs, Tab, MenuItem, Typography } from "@material-ui/core"; +import { PanelId } from "../models/panelId"; +import { setPanelAction } from "../actions/panelActions"; -const styles = (theme: Theme) => createStyles({ - root: { - flex: "1 0 0%", - display: "flex", - flexDirection: "row", - }, - tree: { - flex: "1 0 0%", - minWidth: "250px", - padding: `0px ${theme.spacing(1)}px` - }, - details: { - flex: "5 0 0%", - padding: `0px ${theme.spacing(1)}px` - } -}); -const InventoryTable = MaterialTable as MaterialTableCtorType<InventoryType & {_id: string}>; +import { createConnectedNetworkElementsProperties, createConnectedNetworkElementsActions } from "../handlers/connectedNetworkElementsHandler"; + +import { NetworkElementConnection } from "../models/networkElementConnection"; + +import { InventoryType } from '../models/inventory'; + +import { createInventoryElementsProperties, createInventoryElementsActions } from "../handlers/inventoryElementsHandler"; +import { NavigateToApplication } from '../../../../framework/src/actions/navigationActions'; +import { updateInventoryTreeAsyncAction } from '../actions/inventoryTreeActions'; + +const InventoryTable = MaterialTable as MaterialTableCtorType<InventoryType & { _id: string }>; const mapProps = (state: IApplicationStoreState) => ({ + connectedNetworkElementsProperties: createConnectedNetworkElementsProperties(state), + panelId: state.inventory.currentOpenPanel, inventoryElementsProperties: createInventoryElementsProperties(state), inventoryElements: state.inventory.inventoryElements }); const mapDispatch = (dispatcher: IDispatcher) => ({ - inventoryElementsActions: createInventoryElementsActions(dispatcher.dispatch) + connectedNetworkElementsActions: createConnectedNetworkElementsActions(dispatcher.dispatch), + switchActivePanel: (panelId: PanelId) => { + dispatcher.dispatch(setPanelAction(panelId)); + }, + inventoryElementsActions: createInventoryElementsActions(dispatcher.dispatch), + navigateToApplication: (applicationName: string, path?: string) => dispatcher.dispatch(new NavigateToApplication(applicationName, path)), + updateInventoryTree: (mountId: string, seatchTerm?: string) => dispatcher.dispatch(updateInventoryTreeAsyncAction(mountId, seatchTerm)), }); -const SampleTree = TreeView as any as TreeViewCtorType<string>; +let treeViewInitialSorted = false; +let inventoryInitialSorted = false; +const ConnectedElementTable = MaterialTable as MaterialTableCtorType<NetworkElementConnection>; -type TreeDemoItem = TreeItem<string>; +type DashboardComponentProps = RouteComponentProps & Connect<typeof mapProps, typeof mapDispatch>; -const treeData: TreeDemoItem[] = [ - { - content: "Erste Ebene", children: [ - { - content: "Zweite Ebene", children: [ - { content: "Dritte Ebene" }, - ] - }, - { content: "Zweite Ebene 2" }, - ] - }, - { content: "Erste Ebene 3" }, -]; +class DashboardSelectorComponent extends React.Component<DashboardComponentProps> { + + private onHandleTabChange = (event: React.ChangeEvent<{}>, newValue: PanelId) => { + this.onTogglePanel(newValue); + } + + private onTogglePanel = (panelId: PanelId) => { + const nextActivePanel = panelId; + this.props.switchActivePanel(nextActivePanel); + + switch (nextActivePanel) { + case 'InventoryElementsTable': + + if (!inventoryInitialSorted) { + this.props.inventoryElementsActions.onHandleExplicitRequestSort("nodeId", "asc"); + inventoryInitialSorted = true; + } else { + this.props.inventoryElementsActions.onRefresh(); + + } + break; + case 'TreeviewTable': + if (!treeViewInitialSorted) { + this.props.connectedNetworkElementsActions.onHandleExplicitRequestSort("nodeId", "asc"); + treeViewInitialSorted = true; + } else { + this.props.connectedNetworkElementsActions.onRefresh(); + } + break; + case null: + // do nothing if all panels are closed + break; + default: + console.warn("Unknown nextActivePanel [" + nextActivePanel + "] in connectView"); + break; + } + + }; + + getContextMenu = (rowData: InventoryType) => { + return [ + <MenuItem aria-label={"inventory-button"} onClick={event => { this.props.updateInventoryTree(rowData.nodeId, rowData.uuid); this.props.navigateToApplication("inventory", rowData.nodeId) }}><Typography>View in Treeview</Typography></MenuItem>, + ]; + + } -class DashboardComponent extends React.Component<& WithStyles<typeof styles> & Connect<typeof mapProps, typeof mapDispatch>> { render() { - return <InventoryTable stickyHeader title="Inventory" idProperty="_id" columns={[ - { property: "nodeId", title: "Node Name" }, - { property: "manufacturerIdentifier", title: "Manufacturer" }, - { property: "parentUuid", title: "Parent" }, - { property: "uuid", title: "Name" }, - { property: "serial", title: "Serial" }, - { property: "version", title: "Version" }, - { property: "date", title: "Date" }, - { property: "description", title: "Description" }, - { property: "partTypeId", title: "Part Type Id" }, - { property: "modelIdentifier", title: "Model Identifier" }, - { property: "typeName", title: "Type" }, - { property: "treeLevel", title: "Containment Level" }, - ]} {...this.props.inventoryElementsActions} {...this.props.inventoryElementsProperties} > - </InventoryTable> + + const { panelId: activePanelId } = this.props; + return ( + <> + <AppBar position="static"> + <Tabs value={activePanelId} onChange={this.onHandleTabChange} aria-label="simple tabs example"> + <Tab label="Table View" value="InventoryElementsTable" /> + <Tab label="Tree view" value="TreeviewTable" /> + </Tabs> + </AppBar> + + { + + activePanelId === "InventoryElementsTable" && + + <InventoryTable stickyHeader title="Inventory" idProperty="_id" columns={[ + { property: "nodeId", title: "Node Name" }, + { property: "manufacturerIdentifier", title: "Manufacturer" }, + { property: "parentUuid", title: "Parent" }, + { property: "uuid", title: "Name" }, + { property: "serial", title: "Serial" }, + { property: "version", title: "Version" }, + { property: "date", title: "Date" }, + { property: "description", title: "Description" }, + { property: "partTypeId", title: "Part Type Id" }, + { property: "modelIdentifier", title: "Model Identifier" }, + { property: "typeName", title: "Type" }, + { property: "treeLevel", title: "Containment Level" }, + ]} {...this.props.inventoryElementsActions} {...this.props.inventoryElementsProperties} + createContextMenu={rowData => { + + return this.getContextMenu(rowData); + }} > + </InventoryTable> + + } + { + activePanelId === "TreeviewTable" && + + <ConnectedElementTable stickyHeader onHandleClick={(e, row) => { this.props.history.push(`${this.props.match.path}/${row.nodeId}`) }} columns={[ + { property: "nodeId", title: "Name", type: ColumnType.text }, + { property: "isRequired", title: "Required ?", type: ColumnType.boolean }, + { property: "host", title: "Host", type: ColumnType.text }, + { property: "port", title: "Port", type: ColumnType.numeric }, + { property: "coreModelCapability", title: "Core Model", type: ColumnType.text }, + { property: "deviceType", title: "Type", type: ColumnType.text }, + ]} idProperty="id" {...this.props.connectedNetworkElementsActions} {...this.props.connectedNetworkElementsProperties} asynchronus > + </ConnectedElementTable> + } + </> + ); } componentDidMount() { - this.props.inventoryElementsActions.onToggleFilter(); - this.props.inventoryElementsActions.onHandleRequestSort("node-id"); + + if (this.props.panelId === null) { //set default tab if none is set + this.onTogglePanel("InventoryElementsTable"); + } + } } -export const Dashboard = connect(mapProps, mapDispatch)(withStyles(styles)(DashboardComponent)); -export default Dashboard;
\ No newline at end of file +export const Dashboard = withRouter(connect(mapProps, mapDispatch)(DashboardSelectorComponent)); +export default Dashboard; + diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/views/treeview.tsx b/sdnr/wt/odlux/apps/inventoryApp/src/views/treeview.tsx new file mode 100644 index 000000000..5f2c61080 --- /dev/null +++ b/sdnr/wt/odlux/apps/inventoryApp/src/views/treeview.tsx @@ -0,0 +1,132 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * 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========================================================================== + */ +import * as React from "react"; +import { withStyles, WithStyles, createStyles, Theme } from '@material-ui/core/styles'; + +import { renderObject } from '../../../../framework/src/components/objectDump'; +import { Connect, connect, IDispatcher } from '../../../../framework/src/flux/connect'; +import { TreeView, TreeViewCtorType, SearchMode } from '../../../../framework/src/components/material-ui/treeView'; + +import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore"; + +import { updateInventoryTreeAsyncAction, selectInventoryNodeAsyncAction, UpdateSelectedNodeAction, UpdateExpandedNodesAction, setSearchTermAction} from "../actions/inventoryTreeActions"; +import { TreeDemoItem } from "../models/inventory"; + +import { RouteComponentProps } from "react-router-dom"; + +const styles = (theme: Theme) => createStyles({ + root: { + flex: "1 0 0%", + display: "flex", + flexDirection: "row", + }, + tree: { + flex: "1 0 0%", + minWidth: "250px", + padding: `0px ${theme.spacing(1)}px` + }, + details: { + flex: "5 0 0%", + padding: `0px ${theme.spacing(1)}px` + } +}); + +const mapProps = (state: IApplicationStoreState) => ({ + isBusy: state.inventory.inventoryTree.isBusy, + rootNodes: state.inventory.inventoryTree.rootNodes, + searchTerm: state.inventory.inventoryTree.searchTerm, + selectedNode: state.inventory.inventoryTree.selectedNode, + expendedItems: state.inventory.inventoryTree.expandedItems, +}); + +const mapDispatch = (dispatcher: IDispatcher) => ({ + updateExpendedNodes: (expendedNodes: TreeDemoItem[]) => dispatcher.dispatch(new UpdateExpandedNodesAction(expendedNodes)), + updateInventoryTree: (mountId: string, seatchTerm?: string) => dispatcher.dispatch(updateInventoryTreeAsyncAction(mountId, seatchTerm)), + selectTreeNode: (nodeId?: string) => nodeId ? dispatcher.dispatch(selectInventoryNodeAsyncAction(nodeId)) : dispatcher.dispatch(new UpdateSelectedNodeAction(undefined)), + setSearchTerm: (searchTerm: string) => dispatcher.dispatch(setSearchTermAction(searchTerm)), +}); + +const propsChache = Symbol("PropsCache"); +const InventoryTree = TreeView as any as TreeViewCtorType<string>; + + + +type TreeviewComponentProps = RouteComponentProps<{ mountId: string}> & WithStyles<typeof styles> & Connect<typeof mapProps, typeof mapDispatch> + +type TreeviewComponentState = { + [propsChache]: { + rootNodes?: TreeDemoItem[]; + }; + rootNodes: TreeDemoItem[]; +} + + +class DashboardComponent extends React.Component<TreeviewComponentProps, TreeviewComponentState> { + + constructor (props: TreeviewComponentProps) { + super(props); + + this.state = { + [propsChache]: {}, + rootNodes: [], + }; + } + + static getDerivedStateFromProps(props: TreeviewComponentProps, state: TreeviewComponentState) { + if (state[propsChache].rootNodes != props.rootNodes) { + state = { ...state, rootNodes: props.rootNodes} + } + return state; + } + + render() { + const { classes, updateInventoryTree, updateExpendedNodes, expendedItems, selectedNode, selectTreeNode, searchTerm, match: { params: { mountId }} } = this.props; + return ( + <div className={classes.root}> + <InventoryTree className={classes.tree} items={this.state.rootNodes} enableSearchBar initialSearchTerm={searchTerm} searchMode={SearchMode.OnEnter} searchTerm={searchTerm} + onSearch={(searchTerm) => updateInventoryTree(mountId, searchTerm)} expandedItems={expendedItems} onFolderClick={(item) => { + const indexOfItemToToggle = expendedItems.indexOf(item); + if (indexOfItemToToggle === -1) { + updateExpendedNodes([...expendedItems, item]); + } else { + updateExpendedNodes([ + ...expendedItems.slice(0, indexOfItemToToggle), + ...expendedItems.slice(indexOfItemToToggle + 1), + ]); + } + }} + onItemClick={(elm) => selectTreeNode(elm.value)} /> + <div className={classes.details}>{ + selectedNode && renderObject(selectedNode) || null + }</div> + </div> + ); + } + + componentDidMount() { + const { updateInventoryTree, searchTerm, match: { params: { mountId } }} = this.props; + updateInventoryTree(mountId, searchTerm); + } + + componentWillUnmount(){ + this.props.setSearchTerm(""); + } +} + +export const InventoryTreeView = connect(mapProps, mapDispatch)(withStyles(styles)(DashboardComponent)); +export default InventoryTreeView;
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/inventoryApp/webpack.config.js b/sdnr/wt/odlux/apps/inventoryApp/webpack.config.js index 889bb4d8e..d81797c1e 100644 --- a/sdnr/wt/odlux/apps/inventoryApp/webpack.config.js +++ b/sdnr/wt/odlux/apps/inventoryApp/webpack.config.js @@ -146,6 +146,10 @@ module.exports = (env) => { target: "http://localhost:48181", secure: false }, + "/tree/": { + target: "http://localhost:48181", + secure: false + }, "/websocket": { target: "http://localhost:48181", ws: true, diff --git a/sdnr/wt/odlux/apps/maintenanceApp/package.json b/sdnr/wt/odlux/apps/maintenanceApp/package.json index edd582744..faaef753c 100644 --- a/sdnr/wt/odlux/apps/maintenanceApp/package.json +++ b/sdnr/wt/odlux/apps/maintenanceApp/package.json @@ -25,8 +25,8 @@ "@odlux/connect-app": "*" }, "peerDependencies": { - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@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", diff --git a/sdnr/wt/odlux/apps/mediatorApp/package.json b/sdnr/wt/odlux/apps/mediatorApp/package.json index cfd4bd9e9..1f1b7d578 100644 --- a/sdnr/wt/odlux/apps/mediatorApp/package.json +++ b/sdnr/wt/odlux/apps/mediatorApp/package.json @@ -25,8 +25,8 @@ }, "peerDependencies": { "@fortawesome/free-solid-svg-icons": "5.6.3", - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@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", diff --git a/sdnr/wt/odlux/apps/minimumApp/package.json b/sdnr/wt/odlux/apps/minimumApp/package.json index 5a8352e4b..d2b836979 100644 --- a/sdnr/wt/odlux/apps/minimumApp/package.json +++ b/sdnr/wt/odlux/apps/minimumApp/package.json @@ -24,8 +24,8 @@ "@odlux/framework": "*" }, "peerDependencies": { - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@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", diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/package.json b/sdnr/wt/odlux/apps/performanceHistoryApp/package.json index e1ca8013b..1a6415fbc 100644 --- a/sdnr/wt/odlux/apps/performanceHistoryApp/package.json +++ b/sdnr/wt/odlux/apps/performanceHistoryApp/package.json @@ -27,8 +27,8 @@ "chart.js": "2.8.0" }, "peerDependencies": { - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@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", diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/toggleContainer.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/toggleContainer.tsx index 6014b22e4..88dc9fd11 100644 --- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/toggleContainer.tsx +++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/toggleContainer.tsx @@ -59,6 +59,9 @@ const ToggleContainer: React.FunctionComponent<toggleProps> = (props) => { const children = React.Children.toArray(props.children); + //hide filter if visible + table + //put current name into state, let container handle stuff itelf, register for togglestate, get right via set name + return ( <> <div className={classes.toggleButtonContainer} > diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/webpack.config.js b/sdnr/wt/odlux/apps/performanceHistoryApp/webpack.config.js index bbbc3e43e..6579db3ec 100644 --- a/sdnr/wt/odlux/apps/performanceHistoryApp/webpack.config.js +++ b/sdnr/wt/odlux/apps/performanceHistoryApp/webpack.config.js @@ -126,15 +126,15 @@ module.exports = (env) => { }, proxy: { "/oauth2/": { - target: "http://localhost:48181", + target: "http://10.20.6.29:28181", secure: false }, "/restconf": { - target: "http://localhost:48181", + target: "http://10.20.6.29:28181", secure: false }, "/database": { - target: "http://localhost:48181", + target: "http://10.20.6.29:28181", secure: false } } diff --git a/sdnr/wt/odlux/core/features/pom.xml b/sdnr/wt/odlux/core/features/pom.xml index d63f8d892..2aa72b769 100644 --- a/sdnr/wt/odlux/core/features/pom.xml +++ b/sdnr/wt/odlux/core/features/pom.xml @@ -46,17 +46,6 @@ </license> </licenses> - <dependencyManagement> - <dependencies> - <dependency> - <groupId>org.opendaylight.controller</groupId> - <artifactId>mdsal-artifacts</artifactId> - <version>${odl.controller.mdsal.version}</version> - <type>pom</type> - <scope>import</scope> - </dependency> - </dependencies> - </dependencyManagement> <dependencies> <dependency> diff --git a/sdnr/wt/odlux/core/model/src/main/java/com/opensymphony/xwork2/util/ClassLoaderUtil.java b/sdnr/wt/odlux/core/model/src/main/java/com/opensymphony/xwork2/util/ClassLoaderUtil.java index 133b08494..636c9db29 100644 --- a/sdnr/wt/odlux/core/model/src/main/java/com/opensymphony/xwork2/util/ClassLoaderUtil.java +++ b/sdnr/wt/odlux/core/model/src/main/java/com/opensymphony/xwork2/util/ClassLoaderUtil.java @@ -22,11 +22,11 @@ import java.util.*; /** - * This class is extremely useful for loading resources and classes in a fault tolerant manner - * that works across different applications servers. + * This class is extremely useful for loading resources and classes in a fault tolerant manner that works across + * different applications servers. * - * It has come out of many months of frustrating use of multiple application servers at Atlassian, - * please don't change things unless you're sure they're not going to break in one server or another! + * It has come out of many months of frustrating use of multiple application servers at Atlassian, please don't change + * things unless you're sure they're not going to break in one server or another! * * It was brought in from oscore trunk revision 147. * @@ -37,58 +37,59 @@ public class ClassLoaderUtil { //~ Methods //////////////////////////////////////////////////////////////// /** - * Load all resources with a given name, potentially aggregating all results - * from the searched classloaders. If no results are found, the resource name - * is prepended by '/' and tried again. + * Load all resources with a given name, potentially aggregating all results from the searched classloaders. If no + * results are found, the resource name is prepended by '/' and tried again. * * This method will try to load the resources using the following methods (in order): * <ul> - * <li>From Thread.currentThread().getContextClassLoader() - * <li>From ClassLoaderUtil.class.getClassLoader() - * <li>callingClass.getClassLoader() + * <li>From Thread.currentThread().getContextClassLoader() + * <li>From ClassLoaderUtil.class.getClassLoader() + * <li>callingClass.getClassLoader() * </ul> * * @param resourceName The name of the resources to load * @param callingClass The Class object of the calling object */ - public static Iterator<URL> getResources(String resourceName, Class<?> callingClass, boolean aggregate) throws IOException { + public static Iterator<URL> getResources(String resourceName, Class<?> callingClass, boolean aggregate) + throws IOException { - AggregateIterator<URL> iterator = new AggregateIterator<>(); + AggregateIterator<URL> iterator = new AggregateIterator<>(); - iterator.addEnumeration(Thread.currentThread().getContextClassLoader().getResources(resourceName)); + iterator.addEnumeration(Thread.currentThread().getContextClassLoader().getResources(resourceName)); - if (!iterator.hasNext() || aggregate) { - iterator.addEnumeration(ClassLoaderUtil.class.getClassLoader().getResources(resourceName)); - } + if (!iterator.hasNext() || aggregate) { + iterator.addEnumeration(ClassLoaderUtil.class.getClassLoader().getResources(resourceName)); + } - if (!iterator.hasNext() || aggregate) { - ClassLoader cl = callingClass.getClassLoader(); + if (!iterator.hasNext() || aggregate) { + ClassLoader cl = callingClass.getClassLoader(); - if (cl != null) { - iterator.addEnumeration(cl.getResources(resourceName)); - } - } + if (cl != null) { + iterator.addEnumeration(cl.getResources(resourceName)); + } + } - if (!iterator.hasNext() && resourceName != null && (resourceName.length() == 0 || resourceName.charAt(0) != '/')) { - return getResources('/' + resourceName, callingClass, aggregate); - } + if (!iterator.hasNext() && resourceName != null + && (resourceName.length() == 0 || resourceName.charAt(0) != '/')) { + return getResources('/' + resourceName, callingClass, aggregate); + } - return iterator; - } + return iterator; + } /** - * Load a given resource. - * - * This method will try to load the resource using the following methods (in order): - * <ul> - * <li>From Thread.currentThread().getContextClassLoader() - * <li>From ClassLoaderUtil.class.getClassLoader() - * <li>callingClass.getClassLoader() - * </ul> - * - * @param resourceName The name IllegalStateException("Unable to call ")of the resource to load - * @param callingClass The Class object of the calling object - */ + * Load a given resource. + * + * This method will try to load the resource using the following methods (in order): + * <ul> + * <li>From Thread.currentThread().getContextClassLoader() + * <li>From ClassLoaderUtil.class.getClassLoader() + * <li>callingClass.getClassLoader() + * </ul> + * + * @param resourceName The name IllegalStateException("Unable to call ")of the resource to load + * @param callingClass The Class object of the calling object + */ public static URL getResource(String resourceName, Class<?> callingClass) { URL url = Thread.currentThread().getContextClassLoader().getResource(resourceName); @@ -112,13 +113,13 @@ public class ClassLoaderUtil { } /** - * This is a convenience method to load a resource as a stream. - * - * The algorithm used to find the resource is given in getResource() - * - * @param resourceName The name of the resource to load - * @param callingClass The Class object of the calling object - */ + * This is a convenience method to load a resource as a stream. + * + * The algorithm used to find the resource is given in getResource() + * + * @param resourceName The name of the resource to load + * @param callingClass The Class object of the calling object + */ public static InputStream getResourceAsStream(String resourceName, Class<?> callingClass) { URL url = getResource(resourceName, callingClass); @@ -130,20 +131,20 @@ public class ClassLoaderUtil { } /** - * Load a class with a given name. - * - * It will try to load the class in the following order: - * <ul> - * <li>From Thread.currentThread().getContextClassLoader() - * <li>Using the basic Class.forName() - * <li>From ClassLoaderUtil.class.getClassLoader() - * <li>From the callingClass.getClassLoader() - * </ul> - * - * @param className The name of the class to load - * @param callingClass The Class object of the calling object - * @throws ClassNotFoundException If the class cannot be found anywhere. - */ + * Load a class with a given name. + * + * It will try to load the class in the following order: + * <ul> + * <li>From Thread.currentThread().getContextClassLoader() + * <li>Using the basic Class.forName() + * <li>From ClassLoaderUtil.class.getClassLoader() + * <li>From the callingClass.getClassLoader() + * </ul> + * + * @param className The name of the class to load + * @param callingClass The Class object of the calling object + * @throws ClassNotFoundException If the class cannot be found anywhere. + */ public static Class<?> loadClass(String className, Class<?> callingClass) throws ClassNotFoundException { try { return Thread.currentThread().getContextClassLoader().loadClass(className); @@ -161,8 +162,8 @@ public class ClassLoaderUtil { } /** - * Aggregates Enumeration instances into one iterator and filters out duplicates. Always keeps one - * ahead of the enumerator to protect against returning duplicates. + * Aggregates Enumeration instances into one iterator and filters out duplicates. Always keeps one ahead of the + * enumerator to protect against returning duplicates. */ static class AggregateIterator<E> implements Iterator<E> { diff --git a/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/ClassLoaderUtilExt.java b/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/ClassLoaderUtilExt.java index f6d0b55bf..a4a0e76c3 100644 --- a/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/ClassLoaderUtilExt.java +++ b/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/ClassLoaderUtilExt.java @@ -37,7 +37,7 @@ public class ClassLoaderUtilExt { try { urls = getResources(resourceName, callingClass, true); } catch (IOException e) { - LOG.debug("No resource {}",resourceName); + LOG.debug("No resource {}", resourceName); } if (urls != null) { while (urls.hasNext()) { @@ -50,11 +50,9 @@ public class ClassLoaderUtilExt { if (url == null) { LOG.debug("res currently not found. try to find with bundle"); Bundle b = FrameworkUtil.getBundle(callingClass); - if(b!=null) - { + if (b != null) { url = b.getEntry(resourceName); - } - else { + } else { ClassLoader loader = Thread.currentThread().getContextClassLoader(); url = loader.getResource(resourceName); } diff --git a/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/OdluxBundle.java b/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/OdluxBundle.java index e1e300a0d..ab69d63c8 100644 --- a/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/OdluxBundle.java +++ b/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/OdluxBundle.java @@ -25,8 +25,8 @@ import java.io.InputStreamReader; import java.net.URL; /** - * At startup of each karaf bundle, each UI module creates an instance of this class via blueprint. - * Initialize method gets called at loading of bundle. + * At startup of each karaf bundle, each UI module creates an instance of this class via blueprint. Initialize method + * gets called at loading of bundle. */ public class OdluxBundle { @@ -103,12 +103,12 @@ public class OdluxBundle { public String getResourceFileContent(String filename) { return this.loadFileContent(this.getResource(filename)); } - + protected URL getResource(String filename) { return ClassLoaderUtilExt.getResource(filename, this.getClass()); } - protected String loadFileContent(final URL url ) { + protected String loadFileContent(final URL url) { if (url == null) return null; LOG.debug("try to load res " + url.toString()); @@ -124,15 +124,14 @@ public class OdluxBundle { } catch (IOException e) { LOG.warn("could not load resfile " + url.toString() + ": " + e.getMessage()); return null; - } - finally { - if(in!=null) { - try { - in.close(); - } catch (IOException e) { - - } - } + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + + } + } } return sb.toString(); diff --git a/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/OdluxBundleLoader.java b/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/OdluxBundleLoader.java index 455c83296..870011e85 100644 --- a/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/OdluxBundleLoader.java +++ b/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/OdluxBundleLoader.java @@ -25,6 +25,6 @@ public interface OdluxBundleLoader { public int getNumberOfBundles(); - public String getResourceContent(String fn, OdluxBundleResourceAccess indexBundle); + public String getResourceContent(String fn, OdluxBundleResourceAccess indexBundle); } diff --git a/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/OdluxBundleResourceAccess.java b/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/OdluxBundleResourceAccess.java index f9a842556..1abed468b 100644 --- a/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/OdluxBundleResourceAccess.java +++ b/sdnr/wt/odlux/core/model/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/model/bundles/OdluxBundleResourceAccess.java @@ -22,7 +22,9 @@ import java.util.List; public interface OdluxBundleResourceAccess { boolean hasResource(String fn); + String getResourceFileContent(String fn, List<String> bundleNames); + String getBundleName(); } diff --git a/sdnr/wt/odlux/core/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/IndexOdluxBundle.java b/sdnr/wt/odlux/core/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/IndexOdluxBundle.java index 75497e08c..1ea27d71f 100644 --- a/sdnr/wt/odlux/core/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/IndexOdluxBundle.java +++ b/sdnr/wt/odlux/core/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/IndexOdluxBundle.java @@ -46,15 +46,15 @@ public class IndexOdluxBundle extends OdluxBundle implements OdluxBundleResource super(null, BUNDLENAME_APP); } + @Override - protected String loadFileContent(URL url) - { + protected String loadFileContent(URL url) { return loadFileContent(url, OdluxBundleLoaderImpl.getInstance().getLoadedBundles(this.getBundleName())); } @Override public String getResourceFileContent(String fn, List<String> bundleNames) { - return loadFileContent(this.getResource(fn),bundleNames); + return loadFileContent(this.getResource(fn), bundleNames); } private static String loadFileContent(URL url, List<String> bundlesNamesList) { @@ -64,7 +64,7 @@ public class IndexOdluxBundle extends OdluxBundle implements OdluxBundleResource LOG.debug("try to load res " + url.toString()); StringBuilder sb = new StringBuilder(); Matcher matcher; - BufferedReader in=null; + BufferedReader in = null; try { in = new BufferedReader(new InputStreamReader(url.openStream())); @@ -73,8 +73,8 @@ public class IndexOdluxBundle extends OdluxBundle implements OdluxBundleResource if (url.getFile().endsWith("index.html")) { matcher = patternRequire.matcher(inputLine); if (matcher.find()) { - inputLine = inputLine.substring(0, matcher.start(1)) + "\"" + String.join("\",\"", bundlesNamesList) - + "\"" + inputLine.substring(matcher.end(1)); + inputLine = inputLine.substring(0, matcher.start(1)) + "\"" + + String.join("\",\"", bundlesNamesList) + "\"" + inputLine.substring(matcher.end(1)); } matcher = patternFunction.matcher(inputLine); if (matcher.find()) { @@ -89,26 +89,25 @@ public class IndexOdluxBundle extends OdluxBundle implements OdluxBundleResource hlp += bundle + ".register();" + LR; } } - inputLine = inputLine.substring(0, matcher.start(1)) + hlp - + inputLine.substring(matcher.start(1)); + inputLine = + inputLine.substring(0, matcher.start(1)) + hlp + inputLine.substring(matcher.start(1)); } } sb.append(inputLine + LR); } - + } catch (IOException e) { LOG.warn("could not load resfile {} : {}", url, e.getMessage()); return null; - } - finally { - try { - if (in != null) { - in.close(); - } - } catch (IOException e) { + } finally { + try { + if (in != null) { + in.close(); + } + } catch (IOException e) { - } - } + } + } return sb.toString(); } diff --git a/sdnr/wt/odlux/core/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/IndexServlet.java b/sdnr/wt/odlux/core/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/IndexServlet.java index db709b17d..a7cc2ac82 100644 --- a/sdnr/wt/odlux/core/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/IndexServlet.java +++ b/sdnr/wt/odlux/core/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/IndexServlet.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; import java.nio.file.Files; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -32,40 +31,40 @@ import org.slf4j.LoggerFactory; public class IndexServlet extends HttpServlet { - private static final long serialVersionUID = 3039669437157215355L; - private static Logger LOG = LoggerFactory.getLogger(IndexServlet.class); + private static final long serialVersionUID = 3039669437157215355L; + private static Logger LOG = LoggerFactory.getLogger(IndexServlet.class); - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - if (req.getRequestURI() != null && req.getRequestURI().contains("favicon.ico")) { - this.sendFile(resp, "etc/favicon.ico","image/x-icon"); - } else { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + if (req.getRequestURI() != null && req.getRequestURI().contains("favicon.ico")) { + this.sendFile(resp, "etc/favicon.ico", "image/x-icon"); + } else { - LOG.debug("redirect to odlux/index.html"); - resp.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); - resp.setHeader("Location", "odlux/index.html"); - } - } + LOG.debug("redirect to odlux/index.html"); + resp.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); + resp.setHeader("Location", "odlux/index.html"); + } + } - private void sendFile(HttpServletResponse response, String filename, String mimeType) { - File f = new File(filename); - if (f.exists()) { - try { - byte[] bytes = Files.readAllBytes(f.toPath()); - response.setContentType(mimeType); - response.setContentLength(bytes.length); - response.setStatus(HttpURLConnection.HTTP_OK); - OutputStream os = response.getOutputStream(); - os.write(bytes); - os.flush(); - os.close(); - } catch (IOException e) { - LOG.debug("problem sending {}: {}", filename, e); - } - } else { - LOG.debug("file not found: {}",filename); - response.setStatus(HttpURLConnection.HTTP_NOT_FOUND); - } - } + private void sendFile(HttpServletResponse response, String filename, String mimeType) { + File f = new File(filename); + if (f.exists()) { + try { + byte[] bytes = Files.readAllBytes(f.toPath()); + response.setContentType(mimeType); + response.setContentLength(bytes.length); + response.setStatus(HttpURLConnection.HTTP_OK); + OutputStream os = response.getOutputStream(); + os.write(bytes); + os.flush(); + os.close(); + } catch (IOException e) { + LOG.debug("problem sending {}: {}", filename, e); + } + } else { + LOG.debug("file not found: {}", filename); + response.setStatus(HttpURLConnection.HTTP_NOT_FOUND); + } + } } diff --git a/sdnr/wt/odlux/core/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/ResFilesServlet.java b/sdnr/wt/odlux/core/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/ResFilesServlet.java index 321924e52..b480d89eb 100644 --- a/sdnr/wt/odlux/core/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/ResFilesServlet.java +++ b/sdnr/wt/odlux/core/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/ResFilesServlet.java @@ -20,12 +20,10 @@ package org.onap.ccsdk.features.sdnr.wt.odlux; import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - import org.onap.ccsdk.features.sdnr.wt.odlux.model.bundles.OdluxBundleLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,34 +44,35 @@ public class ResFilesServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - final String fn = req.getRequestURI(); + final String fn = req.getRequestURI(); LOG.debug("Get request with for URI: {}", fn); OdluxBundleLoader odluxBundleLoader = OdluxBundleLoaderImpl.getInstance(); - if (odluxBundleLoader != null) { - String fileContent = odluxBundleLoader.getResourceContent(fn, indexBundle); - if (fileContent != null) { - //Store header info - String mimeType = getMimeType(fn); - byte[] byteContent = fileContent.getBytes(java.nio.charset.StandardCharsets.UTF_8); - int length = byteContent.length; + if (odluxBundleLoader != null) { + String fileContent = odluxBundleLoader.getResourceContent(fn, indexBundle); + if (fileContent != null) { + //Store header info + String mimeType = getMimeType(fn); + byte[] byteContent = fileContent.getBytes(java.nio.charset.StandardCharsets.UTF_8); + int length = byteContent.length; - LOG.debug("Found file in resources. Name {} mimetype {} length {} and write to output stream", fn, mimeType, length); - resp.setContentType(mimeType); - resp.setContentLength(length); - resp.setStatus(HttpURLConnection.HTTP_OK); - OutputStream os = resp.getOutputStream(); - os.write(byteContent); - os.flush(); - os.close(); - } else { - LOG.debug("File {} not found in res.", fn); - resp.setStatus(HttpURLConnection.HTTP_NOT_FOUND); - } - } else { - LOG.debug("BundleLoaderInstance to found.", fn); - resp.setStatus(HttpURLConnection.HTTP_NOT_FOUND); - } + LOG.debug("Found file in resources. Name {} mimetype {} length {} and write to output stream", fn, + mimeType, length); + resp.setContentType(mimeType); + resp.setContentLength(length); + resp.setStatus(HttpURLConnection.HTTP_OK); + OutputStream os = resp.getOutputStream(); + os.write(byteContent); + os.flush(); + os.close(); + } else { + LOG.debug("File {} not found in res.", fn); + resp.setStatus(HttpURLConnection.HTTP_NOT_FOUND); + } + } else { + LOG.debug("BundleLoaderInstance to found.", fn); + resp.setStatus(HttpURLConnection.HTTP_NOT_FOUND); + } } public String loadFileContent(String filename) { @@ -82,7 +81,7 @@ public class ResFilesServlet extends HttpServlet { //Provide own function that can be overloaded for test public String getMimeType(String fileName) { - return getServletContext().getMimeType(fileName); + return getServletContext().getMimeType(fileName); } } diff --git a/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestBundleLoaderImpl.java b/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestBundleLoaderImpl.java index c973d530b..3d817a2d2 100644 --- a/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestBundleLoaderImpl.java +++ b/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestBundleLoaderImpl.java @@ -20,7 +20,6 @@ package org.onap.ccsdk.features.sdnr.odlux.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.model.bundles.OdluxBundle; @@ -45,10 +44,10 @@ public class TestBundleLoaderImpl { bundle2.initialize(); assertNotNull(bundle1.getResourceFileContent("index.html")); assertNotNull(bundle2.getResourceFileContent("index2.html")); - assertEquals(loaded+2, loader.getNumberOfBundles()); + assertEquals(loaded + 2, loader.getNumberOfBundles()); loader.addBundle(bundle1); loader.addBundle(bundle2); - assertEquals(loaded+2, loader.getNumberOfBundles()); + assertEquals(loaded + 2, loader.getNumberOfBundles()); loader.removeBundle(bundle1); loader.removeBundle(bundle2); assertEquals(loaded, loader.getNumberOfBundles()); @@ -56,10 +55,10 @@ public class TestBundleLoaderImpl { assertTrue(bundle1.hasResource("index.html")); assertTrue(bundle2.hasResource("index2.html")); assertNotNull(bundle1.getLoader()); - assertEquals(0,bundle1.getIndex()); + assertEquals(0, bundle1.getIndex()); bundle1.clean(); bundle2.clean(); - assertEquals(loaded,loader.getNumberOfBundles()); + assertEquals(loaded, loader.getNumberOfBundles()); } diff --git a/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestLoadResources.java b/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestLoadResources.java index d9cd920de..bef3dba28 100644 --- a/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestLoadResources.java +++ b/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestLoadResources.java @@ -16,11 +16,10 @@ * ============LICENSE_END========================================================================== */ package org.onap.ccsdk.features.sdnr.odlux.test; -import static org.junit.Assert.*; +import static org.junit.Assert.*; import java.util.regex.Matcher; import java.util.regex.Pattern; - import org.junit.Test; import org.onap.ccsdk.features.sdnr.wt.odlux.ResFilesServlet; @@ -29,15 +28,16 @@ public class TestLoadResources { @Test public void test() { ResFilesServlet servlet = new ResFilesServlet(); - String indexhtml=null; - indexhtml=servlet.loadFileContent("odlux/index.html"); + String indexhtml = null; + indexhtml = servlet.loadFileContent("odlux/index.html"); assertNotNull(indexhtml); final String regex = "require\\(\\[.*\"run\".*\\]"; - final Pattern pattern = Pattern.compile(regex,Pattern.MULTILINE); + final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE); System.out.println(indexhtml); final Matcher matcher = pattern.matcher(indexhtml); - assertTrue("Can not find patter '"+regex+"'",matcher.find()); + assertTrue("Can not find patter '" + regex + "'", matcher.find()); } + @Test public void test2() { diff --git a/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestRedirect.java b/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestRedirect.java index bbf542441..68bcae547 100644 --- a/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestRedirect.java +++ b/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestRedirect.java @@ -18,40 +18,36 @@ package org.onap.ccsdk.features.sdnr.odlux.test; import static org.junit.Assert.*; - +import static org.mockito.Mockito.*; import org.junit.Test; import org.onap.ccsdk.features.sdnr.wt.odlux.IndexServlet; - -import static org.mockito.Mockito.*; - import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestRedirect { - private static final int RESPONSECODE_REDIRECT = 301; - - @Test - public void test() { - PublicIndexServlet servlet =new PublicIndexServlet(); - HttpServletRequest req = mock(HttpServletRequest.class); - HttpServletResponse resp = mock(HttpServletResponse.class); - try { - servlet.doGet(req,resp); - } catch (Exception e) { - fail(e.getMessage()); - } - verify(resp).setStatus(RESPONSECODE_REDIRECT); - } - - private static class PublicIndexServlet extends IndexServlet{ - @Override - public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - super.doGet(req, resp); - } - } + private static final int RESPONSECODE_REDIRECT = 301; + + @Test + public void test() { + PublicIndexServlet servlet = new PublicIndexServlet(); + HttpServletRequest req = mock(HttpServletRequest.class); + HttpServletResponse resp = mock(HttpServletResponse.class); + try { + servlet.doGet(req, resp); + } catch (Exception e) { + fail(e.getMessage()); + } + verify(resp).setStatus(RESPONSECODE_REDIRECT); + } + + private static class PublicIndexServlet extends IndexServlet { + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + super.doGet(req, resp); + } + } } diff --git a/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestResFileServlet.java b/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestResFileServlet.java index 0490c80d5..6d537e38b 100644 --- a/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestResFileServlet.java +++ b/sdnr/wt/odlux/core/provider/src/test/java/org/onap/ccsdk/features/sdnr/odlux/test/TestResFileServlet.java @@ -18,18 +18,16 @@ package org.onap.ccsdk.features.sdnr.odlux.test; import static org.junit.Assert.*; - +import static org.mockito.Mockito.*; import java.io.IOException; import java.io.StringWriter; import java.net.HttpURLConnection; - import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.WriteListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import static org.mockito.Mockito.*; import org.junit.Test; import org.onap.ccsdk.features.sdnr.wt.odlux.OdluxBundleLoaderImpl; import org.onap.ccsdk.features.sdnr.wt.odlux.ResFilesServlet; @@ -43,7 +41,7 @@ public class TestResFileServlet { @Test public void test() throws ServletException { servlet = new PublicResFilesServlet(); - servlet.init(); + servlet.init(); OdluxBundleLoader loader = OdluxBundleLoaderImpl.getInstance(); OdluxBundle b = new OdluxBundle(); @@ -96,9 +94,10 @@ public class TestResFileServlet { public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doGet(req, resp); } + @Override public String getMimeType(String fileName) { - return "mimetype"; + return "mimetype"; } } } diff --git a/sdnr/wt/odlux/framework/package.json b/sdnr/wt/odlux/framework/package.json index c94568857..511b97778 100644 --- a/sdnr/wt/odlux/framework/package.json +++ b/sdnr/wt/odlux/framework/package.json @@ -24,7 +24,7 @@ "author": "Matthias Fischer",
"license": "Apache-2.0",
"peerDependencies": {
- "@types/node": "11.9.5",
+ "@types/node": "11.11.6",
"@types/react": "16.9.19",
"@types/react-dom": "16.9.5",
"@types/react-router-dom": "4.3.1",
@@ -44,6 +44,8 @@ "@types/jsonwebtoken": "7.2.8"
},
"dependencies": {
+ "@babel/polyfill": "^7.0.0",
+ "@types/x2js": "^3.1.0",
"http-server": "^0.11.1"
}
-}
\ No newline at end of file +}
diff --git a/sdnr/wt/odlux/framework/pom.xml b/sdnr/wt/odlux/framework/pom.xml index b125a4537..5bb7d6f6a 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>52.3b24c2d(20/04/08)</buildno> + <buildno>56.139cd6d(20/07/08)</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/components/material-ui/treeView.tsx b/sdnr/wt/odlux/framework/src/components/material-ui/treeView.tsx index 1bb49367c..adf0b8e5a 100644 --- a/sdnr/wt/odlux/framework/src/components/material-ui/treeView.tsx +++ b/sdnr/wt/odlux/framework/src/components/material-ui/treeView.tsx @@ -77,15 +77,18 @@ type TreeViewComponentBaseProps<TData = {}> = WithTheme & WithStyles<typeof styl itemHeight?: number; depthOffset?: number; searchMode?: SearchMode; + } type TreeViewComponentWithInternalStateProps<TData = { }> = TreeViewComponentBaseProps<TData> & { + initialSearchTerm? : string; onItemClick?: (item: TreeItem<TData>) => void; onFolderClick?: (item: TreeItem<TData>) => void; } type TreeViewComponentWithExternalSearchProps<TData = {}> = TreeViewComponentBaseProps<TData> & { items: ExternalTreeItem<TData>[]; + initialSearchTerm? : string; searchTerm: string; onSearch: (searchTerm: string) => void; onItemClick?: (item: TreeItem<TData>) => void; @@ -94,6 +97,7 @@ type TreeViewComponentWithExternalSearchProps<TData = {}> = TreeViewComponentBas type TreeViewComponentWithExternalStateProps<TData = {}> = TreeViewComponentBaseProps<TData> & TreeViewComponentState<TData> & { items: ExternalTreeItem<TData>[]; + initialSearchTerm? : string; searchTerm: string; onSearch: (searchTerm: string) => void; onItemClick: (item: TreeItem<TData>) => void; @@ -137,7 +141,7 @@ class TreeViewComponent<TData = { }> extends React.Component<TreeViewComponentPr expandedItems: [], activeItem: undefined, searchTerm: undefined, - searchTermValue: undefined + searchTermValue: props.initialSearchTerm }; } diff --git a/sdnr/wt/odlux/framework/src/components/objectDump/index.tsx b/sdnr/wt/odlux/framework/src/components/objectDump/index.tsx new file mode 100644 index 000000000..d449f5cd3 --- /dev/null +++ b/sdnr/wt/odlux/framework/src/components/objectDump/index.tsx @@ -0,0 +1,173 @@ +/** + * ============LICENSE_START======================================================================== + * ONAP : ccsdk feature sdnr wt odlux + * ================================================================================================= + * 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========================================================================== + */ + +import * as React from "react"; +import { makeStyles } from '@material-ui/core/styles'; + +export const getTypeName = (obj: any): string => { + if (obj == null) { + return obj === undefined ? "Undefined" : "Null"; + } + return Object.prototype.toString.call(obj).slice(8, -1); +}; + +const isObjectLike = (obj: any) => { + return typeof obj === "object" && obj !== null; +}; + +const isBoolean = (obj: any) => { + return obj === true || obj === false || + (isObjectLike(obj) && getTypeName(obj) === "Boolean"); +}; + +const isNumber = (obj: any) => { + return typeof obj === "number" || + (isObjectLike(obj) && getTypeName(obj) === "Number"); +}; + +const isString = (obj: any) => { + return typeof obj === "string" || + (isObjectLike(obj) && getTypeName(obj) === "String"); +}; + +const isNull = (obj: any) => { + return obj === null; +}; + +const isDate = (obj: any): boolean => { + return isObjectLike(obj) && (obj instanceof Date); +}; + +const useSimpleTableStyles = makeStyles({ + root: { + }, + table: { + fontFamily: "verdana, arial, helvetica, sans-serif", + borderSpacing: "3px", + borderCollapse: "separate", + marginLeft: "30px" + }, + label: { + cursor: "pointer", + }, + th: { + textAlign: "left", + color: "white", + padding: "5px", + backgroundColor: "#cccccc", + }, + td: { + verticalAlign: "top", + padding: "0.5rem 1rem", + borderBottom: "2px solid #DDD" + }, + object: { + }, + objectTh: { + backgroundColor: "#4444cc", + }, + objectTd: { + padding: "0.5rem 1rem", + borderBottom: "2px solid #DDD" + }, +}); + + +type SimpleTableProps = { + classNameTh?: string; + label?: JSX.Element | string | null; + cols?: number; + expand?: boolean; +} + +const SimpleTable: React.FC<SimpleTableProps> = (props) => { + const { label = '', cols = 2, expand = true, classNameTh, children } = props; + const [isExpanded, setIsExpanded] = React.useState(expand); + + const classes = useSimpleTableStyles(); + + React.useEffect(() => { + setIsExpanded(expand); + }, [expand]); + + const handleClick = () => { + setIsExpanded(!isExpanded); + }; + + return ( + <table className={`${classes.root} ${classes.table}`}> + {label && (<thead> + <tr> + <th className={`${classes.th} ${classes.label} ${classNameTh ? classNameTh : ''}`} colSpan={cols} onClick={handleClick}> + {label} + </th> + </tr> + </thead>) || null + } + {isExpanded && <tbody >{children}</tbody> || null} + </table> + ); +}; + + +type ObjectRendererProps = { + className?: string; + label?: JSX.Element | string | null; + expand?: boolean; + object: { [key: string]: any }; +}; + +const ObjectRenderer: React.FC<ObjectRendererProps> = (props) => { + const { object, className, label = 'Object', expand = true } = props; + const classes = useSimpleTableStyles(); + + return ( + <SimpleTable classNameTh={classes.objectTh} label={getTypeName(object) || label} expand={expand}> + { + Object.keys(object).map(key => { + return ( + <tr key={String(key)}> + <td className={`${classes.td} ${classes.objectTd}`}>{String(key)} </td> + <td className={`${classes.td}`}>{renderObject(object[key])}</td> + </tr> + ); + }) + } + </SimpleTable> + ); +}; + + +type ArrayRendererProps = { + label?: JSX.Element | string | null; + extraRenderer?: { [label: string]: React.ComponentType<{ label?: JSX.Element | string | null; object: any; }> }; + description?: string; + object: any; +}; + +const ArrayRenderer: React.FC<ArrayRendererProps> = (props) => { + + return null; +}; + +export const renderObject = (object: any): JSX.Element | string => { + if (isString(object) || isNumber(object) || isBoolean(object)) { + return String(object); + } + return <ObjectRenderer object={object} />; +}; diff --git a/sdnr/wt/odlux/framework/src/index.html b/sdnr/wt/odlux/framework/src/index.html index 1a373392d..d51c448a9 100644 --- a/sdnr/wt/odlux/framework/src/index.html +++ b/sdnr/wt/odlux/framework/src/index.html @@ -13,11 +13,13 @@ <div id="app"></div> <script type="text/javascript" src="./require.js"></script> <script type="text/javascript" src="./config.js"></script> - <script> +<script> // run the application require(["run"], function (run) { run.runApplication(); }); + + // don't change anything in here!! </script> </body> diff --git a/sdnr/wt/odlux/framework/src/services/authenticationService.ts b/sdnr/wt/odlux/framework/src/services/authenticationService.ts index d3d62c566..cd8a93a53 100644 --- a/sdnr/wt/odlux/framework/src/services/authenticationService.ts +++ b/sdnr/wt/odlux/framework/src/services/authenticationService.ts @@ -26,7 +26,7 @@ type AuthTokenResponse = { class AuthenticationService { - public async authenticateUser(email: string, password: string, scope: string): Promise<AuthToken | null> { + public async authenticateUserOAuth(email: string, password: string, scope: string): Promise<AuthToken | null> { const result = await requestRest<string>(`oauth2/token`, { method: "POST", headers: { @@ -47,6 +47,24 @@ class AuthenticationService { expires: (new Date().valueOf()) + (resultObj.expires_in * 1000) } || null; } + + public async authenticateUserBasicAuth(email: string, password: string, scope: string): Promise<AuthToken | null> { + const result = await requestRest<string>(`restconf/modules`, { + method: "GET", + headers: { + 'Authorization': "Basic " + btoa(email + ":" + password) + }, + }, false); + if (result) { + return { + username: email, + access_token: btoa(email + ":" + password), + token_type: "Basic", + expires: (new Date()).valueOf() + 2678400000 // 31 days + } + } + return null; + } } export const authenticationService = new AuthenticationService(); diff --git a/sdnr/wt/odlux/framework/src/views/about.tsx b/sdnr/wt/odlux/framework/src/views/about.tsx index db0411793..ca3953af1 100644 --- a/sdnr/wt/odlux/framework/src/views/about.tsx +++ b/sdnr/wt/odlux/framework/src/views/about.tsx @@ -19,29 +19,51 @@ import * as React from 'react'; import * as marked from 'marked'; import * as hljs from 'highlight.js'; import { requestRestExt } from '../services/restService'; +import { Button, Typography } from '@material-ui/core'; const defaultRenderer = new marked.Renderer(); defaultRenderer.link = (href, title, text) => ( `<a target="_blank" rel="noopener noreferrer" href="${href}" title="${title}">${text}</a>` ); interface AboutState { content: string | null; + isCopiedSuccessfully: boolean; + isContentLoadedSucessfully: boolean; } class AboutComponent extends React.Component<any, AboutState> { + textarea: React.RefObject<HTMLTextAreaElement>; constructor(props: any) { super(props); - this.state = { content: null } + this.state = { content: null, isCopiedSuccessfully:false, isContentLoadedSucessfully: false } + this.textarea = React.createRef(); this.loadAboutContent(); } private loadAboutContent(): void { requestRestExt<string>('/about').then((response) => { - this.setState({ content: response.status == 200 ? response.data : `${response.status} ${response.message}` || "Server error" }) + const content = response.status == 200 ? response.data : `${response.status} ${response.message}` || "Server error"; + const loadedSucessfully = response.status == 200 ? true : false; + this.setState({ content: content, isContentLoadedSucessfully: loadedSucessfully }); }).catch((error) => { this.setState({ content: error }) }) } + + copyToClipboard = (e: React.MouseEvent<HTMLButtonElement>) =>{ + e.preventDefault(); + + if(this.textarea.current!==null){ + this.textarea.current.select(); + document.execCommand('copy'); + if(e.currentTarget != null){ // refocus on button, otherwhise the textarea would be focused + e.currentTarget.focus(); + } + this.setState({isCopiedSuccessfully: true}); + window.setTimeout(()=>{this.setState({isCopiedSuccessfully: false});},2000); + } + } + render() { const markedOptions: marked.MarkedOptions = { @@ -70,14 +92,33 @@ class AboutComponent extends React.Component<any, AboutState> { return ( <div style={containerStyle}> + { this.state.isContentLoadedSucessfully && + <div style={{float: "right", marginRight: "10px"}}> + <Button variant="contained" onClick={e => this.copyToClipboard(e)}> + Copy to clipboard + </Button> + { + this.state.isCopiedSuccessfully && + <Typography variant="body1" style={{color: "green"}} align="center"> + copied successfully + </Typography> + } + </div> + } + <div dangerouslySetInnerHTML={{ __html: html }} className={className} style={style} /> + <form> + <textarea + style={{opacity: ".01"}} + ref={this.textarea} + value={this.state.content || ''} + /> + </form> </div> - - ); } }; diff --git a/sdnr/wt/odlux/framework/src/views/login.tsx b/sdnr/wt/odlux/framework/src/views/login.tsx index fa01568ea..30b9c85a2 100644 --- a/sdnr/wt/odlux/framework/src/views/login.tsx +++ b/sdnr/wt/odlux/framework/src/views/login.tsx @@ -164,7 +164,8 @@ class LoginComponent extends React.Component<LoginProps, ILoginState> { event.preventDefault(); this.setState({ busy: true }); - const token = await authenticationService.authenticateUser(this.state.username, this.state.password, this.state.scope); + // const token = await authenticationService.authenticateUserOAuth(this.state.username, this.state.password, this.state.scope); + const token = await authenticationService.authenticateUserBasicAuth(this.state.username, this.state.password, this.state.scope); this.props.dispatch(new UpdateAuthentication(token)); this.setState({ busy: false }); diff --git a/sdnr/wt/odlux/framework/webpack.config.js b/sdnr/wt/odlux/framework/webpack.config.js index e43539dc7..4887a757e 100644 --- a/sdnr/wt/odlux/framework/webpack.config.js +++ b/sdnr/wt/odlux/framework/webpack.config.js @@ -45,6 +45,7 @@ module.exports = (env) => { app: [
"./app.tsx",
"./services",
+ "./components/objectDump",
"./components/material-table",
"./components/material-ui",
"./utilities/elasticSearch",
@@ -127,7 +128,10 @@ module.exports = (env) => { baseUrl: '',
pathUrl: '',
processOutput: function (assets) {
- return 'require.config(' + JSON.stringify(assets, null, 2) + ')';
+ let mainConfig = JSON.stringify(assets, null, 2);
+ mainConfig = mainConfig.slice(0,-1); // remove closing bracket from string
+ const entireConfig = mainConfig.concat(", waitSeconds: 30}"); // add waitSeconds to config
+ return 'require.config(' + entireConfig + ')';
}
}),
// new HtmlWebpackPlugin({
diff --git a/sdnr/wt/odlux/package.json b/sdnr/wt/odlux/package.json index 12d18c14d..9053e0886 100644 --- a/sdnr/wt/odlux/package.json +++ b/sdnr/wt/odlux/package.json @@ -22,11 +22,10 @@ "@types/jquery": "3.3.10", "@types/jsonwebtoken": "7.2.8", "@types/node": "11.11.6", - "@types/react": "16.9.11", - "@types/react-dom": "16.9.4", + "@types/react": "16.9.19", + "@types/react-dom": "16.9.5", "@types/react-router-dom": "4.3.1", "@types/react-transition-group": "2.0.15", - "@types/x2js": "3.1.0", "classnames": "2.2.6", "csstype": "2.6.8", "jquery": "3.3.1", diff --git a/sdnr/wt/odlux/yarn.lock b/sdnr/wt/odlux/yarn.lock index 448d781a9..71488be68 100644 --- a/sdnr/wt/odlux/yarn.lock +++ b/sdnr/wt/odlux/yarn.lock @@ -565,6 +565,14 @@ core-js "^2.5.7" regenerator-runtime "^0.11.1" +"@babel/polyfill@^7.0.0": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.8.7.tgz#151ec24c7135481336168c3bd8b8bf0cf91c032f" + integrity sha512-LeSfP9bNZH2UOZgcGcZ0PIHUt1ZuHub1L3CVmEyqLxCeDLm4C5Gi8jRH8ZX2PNpDhQCo0z6y/+DIs2JlliXW8w== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.4" + "@babel/preset-env@7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.1.0.tgz#e67ea5b0441cfeab1d6f41e9b5c79798800e8d11" @@ -1431,20 +1439,20 @@ integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== "@octokit/auth-token@^2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.0.tgz#b64178975218b99e4dfe948253f0673cbbb59d9f" - integrity sha512-eoOVMjILna7FVQf96iWc3+ZtE/ZT6y8ob8ZzcqKY1ibSQCnu4O/B7pJvzMx5cyZ/RjAff6DAdEb0O0Cjcxidkg== + version "2.4.2" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.2.tgz#10d0ae979b100fa6b72fa0e8e63e27e6d0dbff8a" + integrity sha512-jE/lE/IKIz2v1+/P0u4fJqv0kYwXOTujKemJMFr6FeopsxlIK3+wKDCJGnysg81XID5TgZQbIfuJ5J0lnTiuyQ== dependencies: - "@octokit/types" "^2.0.0" + "@octokit/types" "^5.0.0" -"@octokit/endpoint@^5.5.0": - version "5.5.2" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-5.5.2.tgz#ed19d01fe85ac58bc2b774661658f9e5429b8164" - integrity sha512-ICDcRA0C2vtTZZGud1nXRrBLXZqFayodXAKZfo3dkdcLNqcHsgaz3YSTupbURusYeucSVRjjG+RTcQhx6HPPcg== +"@octokit/endpoint@^6.0.1": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.3.tgz#dd09b599662d7e1b66374a177ab620d8cdf73487" + integrity sha512-Y900+r0gIz+cWp6ytnkibbD95ucEzDSKzlEnaWS52hbCDNcCJYO5mRmWW7HRAnDc7am+N/5Lnd8MppSaTYx1Yg== dependencies: - "@octokit/types" "^2.0.0" + "@octokit/types" "^5.0.0" is-plain-object "^3.0.0" - universal-user-agent "^4.0.0" + universal-user-agent "^5.0.0" "@octokit/plugin-enterprise-rest@^2.1.1": version "2.2.2" @@ -1471,7 +1479,7 @@ "@octokit/types" "^2.0.1" deprecation "^2.3.1" -"@octokit/request-error@^1.0.1", "@octokit/request-error@^1.0.2": +"@octokit/request-error@^1.0.2": version "1.2.1" resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.2.1.tgz#ede0714c773f32347576c25649dc013ae6b31801" integrity sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA== @@ -1480,19 +1488,28 @@ deprecation "^2.0.0" once "^1.4.0" +"@octokit/request-error@^2.0.0": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.2.tgz#0e76b83f5d8fdda1db99027ea5f617c2e6ba9ed0" + integrity sha512-2BrmnvVSV1MXQvEkrb9zwzP0wXFNbPJij922kYBTLIlIafukrGOb+ABBT2+c6wZiuyWDH1K1zmjGQ0toN/wMWw== + dependencies: + "@octokit/types" "^5.0.1" + deprecation "^2.0.0" + once "^1.4.0" + "@octokit/request@^5.2.0": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.3.1.tgz#3a1ace45e6f88b1be4749c5da963b3a3b4a2f120" - integrity sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg== + version "5.4.5" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.5.tgz#8df65bd812047521f7e9db6ff118c06ba84ac10b" + integrity sha512-atAs5GAGbZedvJXXdjtKljin+e2SltEs48B3naJjqWupYl2IUBbB/CJisyjbNHcKpHzb3E+OYEZ46G8eakXgQg== dependencies: - "@octokit/endpoint" "^5.5.0" - "@octokit/request-error" "^1.0.1" - "@octokit/types" "^2.0.0" + "@octokit/endpoint" "^6.0.1" + "@octokit/request-error" "^2.0.0" + "@octokit/types" "^5.0.0" deprecation "^2.0.0" is-plain-object "^3.0.0" node-fetch "^2.3.0" once "^1.4.0" - universal-user-agent "^4.0.0" + universal-user-agent "^5.0.0" "@octokit/rest@^16.16.0": version "16.43.1" @@ -1517,9 +1534,16 @@ universal-user-agent "^4.0.0" "@octokit/types@^2.0.0", "@octokit/types@^2.0.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.1.1.tgz#77e80d1b663c5f1f829e5377b728fa3c4fe5a97d" - integrity sha512-89LOYH+d/vsbDX785NOfLxTW88GjNd0lWRz1DVPVsZgg9Yett5O+3MOvwo7iHgvUwbFz0mf/yPIjBkUbs4kxoQ== + version "2.16.2" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.16.2.tgz#4c5f8da3c6fecf3da1811aef678fda03edac35d2" + integrity sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q== + dependencies: + "@types/node" ">= 8" + +"@octokit/types@^5.0.0", "@octokit/types@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-5.0.1.tgz#5459e9a5e9df8565dcc62c17a34491904d71971e" + integrity sha512-GorvORVwp244fGKEt3cgt/P+M0MGy4xEDbckw+K5ojEezxyMDgCaYPKVct+/eWQfZXOT7uq0xRpmrl/+hliabA== dependencies: "@types/node" ">= 8" @@ -1573,6 +1597,11 @@ resolved "https://registry.yarnpkg.com/@types/marked/-/marked-0.6.0.tgz#e4ac316144a84afda5c2474488d7b9fef3ab9995" integrity sha512-TxwhgR9VsIfRDJ3WwFokG8Xu+ea0nYGDRHdI783WJ983uffatz0ytIeUEIBOwPvRy241KRSNVyywQltuTqDh0w== +"@types/minimist@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" + integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= + "@types/node@*": version "12.12.7" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.7.tgz#01e4ea724d9e3bd50d90c11fd5980ba317d8fa11" @@ -1584,19 +1613,24 @@ integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== "@types/node@>= 8": - version "13.7.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.0.tgz#b417deda18cf8400f278733499ad5547ed1abec4" - integrity sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ== + version "14.0.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.13.tgz#ee1128e881b874c371374c1f72201893616417c9" + integrity sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA== + +"@types/normalize-package-data@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" + integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== "@types/prop-types@*": version "15.7.3" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== -"@types/react-dom@16.9.4": - version "16.9.4" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.4.tgz#0b58df09a60961dcb77f62d4f1832427513420df" - integrity sha512-fya9xteU/n90tda0s+FtN5Ym4tbgxpq/hb/Af24dvs6uYnYn+fspaxw5USlw0R8apDNwxsqumdRoCoKitckQqw== +"@types/react-dom@16.9.5": + version "16.9.5" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.5.tgz#5de610b04a35d07ffd8f44edad93a71032d9aaa7" + integrity sha512-BX6RQ8s9D+2/gDhxrj8OW+YD4R+8hj7FEM/OJHGNR0KipE1h1mSsf39YeyC81qafkq+N3rU3h3RFbLSwE5VqUg== dependencies: "@types/react" "*" @@ -1631,7 +1665,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@16.9.11": +"@types/react@*": version "16.9.11" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.11.tgz#70e0b7ad79058a7842f25ccf2999807076ada120" integrity sha512-UBT4GZ3PokTXSWmdgC/GeCGEJXE5ofWyibCcecRLUVN2ZBpXQGVgQGtG2foS7CrTKFKlQVVswLvf7Js6XA/CVQ== @@ -1639,7 +1673,15 @@ "@types/prop-types" "*" csstype "^2.2.0" -"@types/x2js@3.1.0": +"@types/react@16.9.19": + version "16.9.19" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.19.tgz#c842aa83ea490007d29938146ff2e4d9e4360c40" + integrity sha512-LJV97//H+zqKWMms0kvxaKYJDG05U2TtQB3chRLF8MPNs+MQh/H1aGlyDUxjaHvu08EAGerdX2z4LTBc7ns77A== + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + +"@types/x2js@^3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@types/x2js/-/x2js-3.1.0.tgz#d809ef1ace1a8b55b3e8cb6a1a0b282af66475be" integrity sha1-2AnvGs4ai1Wz6MtqGgsoKvZkdb4= @@ -2072,6 +2114,11 @@ arrify@^1.0.0, arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= +arrify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + asap@^2.0.0, asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -2703,7 +2750,28 @@ cacache@^11.0.2, cacache@^11.3.3: unique-filename "^1.1.1" y18n "^4.0.0" -cacache@^12.0.0, cacache@^12.0.2: +cacache@^12.0.0: + version "12.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" + integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + infer-owner "^1.0.3" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cacache@^12.0.2: version "12.0.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== @@ -2788,6 +2856,15 @@ camelcase-keys@^4.0.0: map-obj "^2.0.0" quick-lru "^1.0.0" +camelcase-keys@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" + integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== + dependencies: + camelcase "^5.3.1" + map-obj "^4.0.0" + quick-lru "^4.0.1" + camelcase@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" @@ -2803,11 +2880,16 @@ camelcase@^4.1.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= -camelcase@^5.0.0: +camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +camelcase@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e" + integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w== + caniuse-lite@^1.0.30000884, caniuse-lite@^1.0.30001004: version "1.0.30001010" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001010.tgz#397a14034d384260453cc81994f494626d34b938" @@ -2892,11 +2974,16 @@ chokidar@^2.0.0, chokidar@^2.0.2: optionalDependencies: fsevents "^1.2.7" -chownr@^1.0.1, chownr@^1.1.1, chownr@^1.1.2: +chownr@^1.0.1, chownr@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== +chownr@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + chrome-trace-event@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" @@ -2947,9 +3034,9 @@ cli-cursor@^2.1.0: restore-cursor "^2.0.0" cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" + integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== cliui@^3.2.0: version "3.2.0" @@ -3088,9 +3175,9 @@ commondir@^1.0.1: integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= compare-func@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-1.3.2.tgz#99dd0ba457e1f9bc722b12c08ec33eeab31fa648" - integrity sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg= + version "1.3.4" + resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-1.3.4.tgz#6b07c4c5e8341119baf44578085bda0f4a823516" + integrity sha512-sq2sWtrqKPkEXAC8tEJA1+BqAH9GbFkGBtUOqrUX57VSfwp8xyktctk+uLoRy5eccTdxzDcVIztlYDpKs3Jv1Q== dependencies: array-ify "^1.0.0" dot-prop "^3.0.0" @@ -3186,9 +3273,9 @@ content-type@~1.0.4: integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== conventional-changelog-angular@^5.0.3: - version "5.0.6" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz#269540c624553aded809c29a3508fdc2b544c059" - integrity sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA== + version "5.0.10" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.10.tgz#5cf7b00dd315b6a6a558223c80d5ef24ddb34205" + integrity sha512-k7RPPRs0vp8+BtPsM9uDxRl6KcgqtCJmzRD1wRtgqmhQ96g8ifBGo9O/TZBG23jqlXS/rg8BKRDELxfnQQGiaA== dependencies: compare-func "^1.3.1" q "^1.5.1" @@ -3213,43 +3300,43 @@ conventional-changelog-core@^3.1.6: through2 "^3.0.0" conventional-changelog-preset-loader@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.0.tgz#580fa8ab02cef22c24294d25e52d7ccd247a9a6a" - integrity sha512-/rHb32J2EJnEXeK4NpDgMaAVTFZS3o1ExmjKMtYVgIC4MQn0vkNSbYpdGRotkfGGRWiqk3Ri3FBkiZGbAfIfOQ== + version "2.3.4" + resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c" + integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g== conventional-changelog-writer@^4.0.6: - version "4.0.11" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.0.11.tgz#9f56d2122d20c96eb48baae0bf1deffaed1edba4" - integrity sha512-g81GQOR392I+57Cw3IyP1f+f42ME6aEkbR+L7v1FBBWolB0xkjKTeCWVguzRrp6UiT1O6gBpJbEy2eq7AnV1rw== + version "4.0.16" + resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.0.16.tgz#ca10f2691a8ea6d3c2eb74bd35bcf40aa052dda5" + integrity sha512-jmU1sDJDZpm/dkuFxBeRXvyNcJQeKhGtVcFFkwTphUAzyYWcwz2j36Wcv+Mv2hU3tpvLMkysOPXJTLO55AUrYQ== dependencies: compare-func "^1.3.1" - conventional-commits-filter "^2.0.2" + conventional-commits-filter "^2.0.6" dateformat "^3.0.0" - handlebars "^4.4.0" + handlebars "^4.7.6" json-stringify-safe "^5.0.1" lodash "^4.17.15" - meow "^5.0.0" + meow "^7.0.0" semver "^6.0.0" split "^1.0.0" through2 "^3.0.0" -conventional-commits-filter@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz#f122f89fbcd5bb81e2af2fcac0254d062d1039c1" - integrity sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ== +conventional-commits-filter@^2.0.2, conventional-commits-filter@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.6.tgz#0935e1240c5ca7698329affee1b6a46d33324c4c" + integrity sha512-4g+sw8+KA50/Qwzfr0hL5k5NWxqtrOVw4DDk3/h6L85a9Gz0/Eqp3oP+CWCNfesBvZZZEFHF7OTEbRe+yYSyKw== dependencies: lodash.ismatch "^4.4.0" modify-values "^1.0.0" conventional-commits-parser@^3.0.2, conventional-commits-parser@^3.0.3: - version "3.0.8" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.0.8.tgz#23310a9bda6c93c874224375e72b09fb275fe710" - integrity sha512-YcBSGkZbYp7d+Cr3NWUeXbPDFUN6g3SaSIzOybi8bjHL5IJ5225OSCxJJ4LgziyEJ7AaJtE9L2/EU6H7Nt/DDQ== + version "3.1.0" + resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.1.0.tgz#10140673d5e7ef5572633791456c5d03b69e8be4" + integrity sha512-RSo5S0WIwXZiRxUGTPuYFbqvrR4vpJ1BDdTlthFgvHt5kEdnd1+pdvwWphWn57/oIl4V72NMmOocFqqJ8mFFhA== dependencies: JSONStream "^1.0.4" is-text-path "^1.0.1" lodash "^4.17.15" - meow "^5.0.0" + meow "^7.0.0" split2 "^2.0.0" through2 "^3.0.0" trim-off-newlines "^1.0.0" @@ -3326,6 +3413,11 @@ core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.10.tgz#8a5b8391f8cc7013da703411ce5b585706300d7f" integrity sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA== +core-js@^2.6.5: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -3563,7 +3655,7 @@ debuglog@^1.0.1: resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= -decamelize-keys@^1.0.0: +decamelize-keys@^1.0.0, decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= @@ -4392,7 +4484,12 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" -figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: +figgy-pudding@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" + integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== + +figgy-pudding@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== @@ -4499,6 +4596,14 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + findup-sync@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" @@ -4901,11 +5006,16 @@ graceful-fs@4.1.4: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.4.tgz#ef089d2880f033b011823ce5c8fae798da775dbd" integrity sha1-7widKIDwM7ARgjzlyPrnmNp3Xb0= -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2: version "4.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== +graceful-fs@^4.1.6: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -4927,14 +5037,15 @@ handlebars@^4.0.3: optionalDependencies: uglify-js "^3.1.4" -handlebars@^4.4.0: - version "4.7.3" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.3.tgz#8ece2797826886cf8082d1726ff21d2a022550ee" - integrity sha512-SRGwSYuNfx8DwHD/6InAPzD6RgeruWLT+B8e8a7gGs8FWgHzlExpTFMEq2IA6QpAfOClpKHy6+8IqTjeBCu6Kg== +handlebars@^4.7.6: + version "4.7.6" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e" + integrity sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA== dependencies: + minimist "^1.2.5" neo-async "^2.6.0" - optimist "^0.6.1" source-map "^0.6.1" + wordwrap "^1.0.0" optionalDependencies: uglify-js "^3.1.4" @@ -4959,6 +5070,11 @@ har-validator@~5.1.0: ajv "^6.5.5" har-schema "^2.0.0" +hard-rejection@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" + integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -5098,11 +5214,16 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4, hosted-git-info@^2.7.1: +hosted-git-info@^2.1.4: version "2.8.5" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c" integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg== +hosted-git-info@^2.7.1: + version "2.8.8" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" @@ -5405,6 +5526,11 @@ indent-string@^3.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + infer-owner@^1.0.3, infer-owner@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" @@ -5772,11 +5898,6 @@ is-primitive@^2.0.0: resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= -is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= - is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" @@ -6540,6 +6661,11 @@ kind-of@^6.0.0, kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== +kind-of@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + kleur@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/kleur/-/kleur-2.0.2.tgz#b704f4944d95e255d038f0cb05fb8a602c55a300" @@ -6655,6 +6781,11 @@ lightercollective@^0.1.0: resolved "https://registry.yarnpkg.com/lightercollective/-/lightercollective-0.1.0.tgz#70df102c530dcb8d0ccabfe6175a8d00d5f61300" integrity sha512-J9tg5uraYoQKaWbmrzDDexbG6hHnMcWS1qLYgJSWE+mpA3U5OCSeMUhb+K55otgZJ34oFdR0ECvdIb3xuO5JOQ== +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -6726,6 +6857,13 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -6964,6 +7102,11 @@ map-obj@^2.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= +map-obj@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.1.0.tgz#b91221b542734b9f14256c0132c897c5d7256fd5" + integrity sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g== + map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -7051,20 +7194,24 @@ meow@^4.0.0: redent "^2.0.0" trim-newlines "^2.0.0" -meow@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" - integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig== - dependencies: - camelcase-keys "^4.0.0" - decamelize-keys "^1.0.0" - loud-rejection "^1.0.0" - minimist-options "^3.0.1" - normalize-package-data "^2.3.4" - read-pkg-up "^3.0.0" - redent "^2.0.0" - trim-newlines "^2.0.0" - yargs-parser "^10.0.0" +meow@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/meow/-/meow-7.0.1.tgz#1ed4a0a50b3844b451369c48362eb0515f04c1dc" + integrity sha512-tBKIQqVrAHqwit0vfuFPY3LlzJYkEOFyKa3bPgxzNl6q/RtN8KQ+ALYEASYuFayzSAsjlhXj/JZ10rH85Q6TUw== + dependencies: + "@types/minimist" "^1.2.0" + arrify "^2.0.1" + camelcase "^6.0.0" + camelcase-keys "^6.2.2" + decamelize-keys "^1.1.0" + hard-rejection "^2.1.0" + minimist-options "^4.0.2" + normalize-package-data "^2.5.0" + read-pkg-up "^7.0.1" + redent "^3.0.0" + trim-newlines "^3.0.0" + type-fest "^0.13.1" + yargs-parser "^18.1.3" merge-descriptors@1.0.1: version "1.0.1" @@ -7079,9 +7226,9 @@ merge-stream@^1.0.1: readable-stream "^2.0.1" merge2@^1.2.3: - version "1.3.0" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" - integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== merge@^1.2.0: version "1.2.1" @@ -7171,6 +7318,11 @@ mimic-fn@^2.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -7196,6 +7348,15 @@ minimist-options@^3.0.1: arrify "^1.0.1" is-plain-obj "^1.1.0" +minimist-options@^4.0.2: + version "4.1.0" + resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" + integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== + dependencies: + arrify "^1.0.1" + is-plain-obj "^1.1.0" + kind-of "^6.0.3" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -7206,6 +7367,11 @@ minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" @@ -7410,9 +7576,9 @@ no-case@^2.2.0: lower-case "^1.1.1" node-fetch-npm@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7" - integrity sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw== + version "2.0.4" + resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz#6507d0e17a9ec0be3bec516958a497cec54bf5a4" + integrity sha512-iOuIQDWDyjhv9qSDrj9aq/klt6F9z1p2otB3AV7v3zBDcL/x+OfGsvGQZZCcMZbUf4Ujw1xGNQkjvGnVT22cKg== dependencies: encoding "^0.1.11" json-parse-better-errors "^1.0.0" @@ -7571,7 +7737,7 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.3.5, normalize-package-data@^2.4.0: +normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.3.5, normalize-package-data@^2.4.0, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -7691,9 +7857,9 @@ npm-registry-fetch@^3.9.0: npm-package-arg "^6.1.0" npm-registry-fetch@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz#2b1434f93ccbe6b6385f8e45f45db93e16921d7a" - integrity sha512-Z0IFtPEozNdeZRPh3aHHxdG+ZRpzcbQaJLthsm3VhNf6DScicTFRHZzK82u8RsJUsUHkX+QH/zcB/5pmd20H4A== + version "4.0.4" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-4.0.4.tgz#2da1ecf3f43d419d96abf313664291a4623d3ea5" + integrity sha512-6jb34hX/iYNQebqWUHtU8YF6Cjb1H6ouTFPClYsyiW6lpFkljTpdeftm53rRojtja1rKAvKNIIiTS5Sjpw4wsA== dependencies: JSONStream "^1.3.4" bluebird "^3.5.1" @@ -7972,6 +8138,13 @@ p-limit@^2.0.0: dependencies: p-try "^2.0.0" +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -7986,6 +8159,13 @@ p-locate@^3.0.0: dependencies: p-limit "^2.0.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-map-series@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-1.0.0.tgz#bf98fe575705658a9e1351befb85ae4c1f07bdca" @@ -8124,6 +8304,16 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" +parse-json@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" + integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + lines-and-columns "^1.1.6" + parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" @@ -8184,6 +8374,11 @@ path-exists@^3.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -8602,6 +8797,11 @@ quick-lru@^1.0.0: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= +quick-lru@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" + integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== + randomatic@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" @@ -8767,6 +8967,15 @@ read-pkg-up@^3.0.0: find-up "^2.0.0" read-pkg "^3.0.0" +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" @@ -8785,6 +8994,16 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + read@1, read@~1.0.1: version "1.0.7" resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" @@ -8806,9 +9025,9 @@ read@1, read@~1.0.1: util-deprecate "~1.0.1" "readable-stream@2 || 3", readable-stream@^3.0.2: - version "3.5.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.5.0.tgz#465d70e6d1087f6162d079cd0b5db7fbebfd1606" - integrity sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA== + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" @@ -8865,6 +9084,14 @@ redent@^2.0.0: indent-string "^3.0.0" strip-indent "^2.0.0" +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + reflect-metadata@^0.1.12: version "0.1.13" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" @@ -8892,6 +9119,11 @@ regenerator-runtime@^0.13.2: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== +regenerator-runtime@^0.13.4: + version "0.13.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== + regenerator-transform@^0.14.0: version "0.14.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" @@ -9192,11 +9424,9 @@ rsvp@^3.3.3: integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= - dependencies: - is-promise "^2.1.0" + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" @@ -9206,9 +9436,9 @@ run-queue@^1.0.0, run-queue@^1.0.3: aproba "^1.1.1" rxjs@^6.4.0: - version "6.5.4" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" - integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== + version "6.5.5" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec" + integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ== dependencies: tslib "^1.9.0" @@ -9217,11 +9447,16 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== +safe-buffer@^5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" @@ -9875,6 +10110,13 @@ strip-indent@^2.0.0: resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -10184,6 +10426,11 @@ trim-newlines@^2.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA= +trim-newlines@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.0.tgz#79726304a6a898aa8373427298d54c2ee8b1cb30" + integrity sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA== + trim-off-newlines@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" @@ -10373,6 +10620,21 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type-fest@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" + integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -10481,9 +10743,16 @@ unique-slug@^2.0.0: imurmurhash "^0.1.4" universal-user-agent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.0.tgz#27da2ec87e32769619f68a14996465ea1cb9df16" - integrity sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA== + version "4.0.1" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.1.tgz#fd8d6cb773a679a709e967ef8288a31fcc03e557" + integrity sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg== + dependencies: + os-name "^3.1.0" + +universal-user-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-5.0.0.tgz#a3182aa758069bf0e79952570ca757de3579c1d9" + integrity sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q== dependencies: os-name "^3.1.0" @@ -10892,9 +11161,9 @@ wide-align@^1.1.0: string-width "^1.0.2 || 2" windows-release@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.2.0.tgz#8122dad5afc303d833422380680a79cdfa91785f" - integrity sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA== + version "3.3.1" + resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.1.tgz#cb4e80385f8550f709727287bf71035e209c4ace" + integrity sha512-Pngk/RDCaI/DkuHPlGTdIkDiTAnAkyMjoQMZqRsxydNl1qGXNIoZrB7RK8g53F2tEgQBMqQJHQdYZuQEEAu54A== dependencies: execa "^1.0.0" @@ -10903,6 +11172,11 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" @@ -11018,7 +11292,7 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yargs-parser@10.x, yargs-parser@^10.0.0, yargs-parser@^10.1.0: +yargs-parser@10.x, yargs-parser@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== @@ -11033,6 +11307,14 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^18.1.3: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" |