Merge branch 'master' into fix/3969-LwM2M-resource-title-read-only

This commit is contained in:
Max Petrov 2024-07-23 11:55:59 +03:00 committed by GitHub
commit b1cc582691
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 280 additions and 136 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -18,7 +18,6 @@ package org.thingsboard.server.edge;
import com.google.protobuf.AbstractMessage; import com.google.protobuf.AbstractMessage;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;

View File

@ -59,12 +59,7 @@ public class OAuth2EdgeTest extends AbstractEdgeTest {
oAuth2Info.setEnabled(false); oAuth2Info.setEnabled(false);
oAuth2Info.setEdgeEnabled(false); oAuth2Info.setEdgeEnabled(false);
doPost("/api/oauth2/config", oAuth2Info, OAuth2Info.class); doPost("/api/oauth2/config", oAuth2Info, OAuth2Info.class);
Assert.assertTrue(edgeImitator.waitForMessages()); Assert.assertFalse(edgeImitator.waitForMessages(5));
latestMessage = edgeImitator.getLatestMessage();
Assert.assertTrue(latestMessage instanceof OAuth2UpdateMsg);
oAuth2UpdateMsg = (OAuth2UpdateMsg) latestMessage;
result = JacksonUtil.fromString(oAuth2UpdateMsg.getEntity(), OAuth2Info.class, true);
Assert.assertEquals(oAuth2Info, result);
edgeImitator.ignoreType(OAuth2UpdateMsg.class); edgeImitator.ignoreType(OAuth2UpdateMsg.class);
loginTenantAdmin(); loginTenantAdmin();

View File

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.cache; package org.thingsboard.server.cache;
import jakarta.annotation.PostConstruct;
import lombok.Data; import lombok.Data;
import lombok.Getter; import lombok.Getter;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -22,7 +23,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.thingsboard.server.common.data.CacheConstants; import org.thingsboard.server.common.data.CacheConstants;
import jakarta.annotation.PostConstruct;
import java.util.Map; import java.util.Map;
@Configuration @Configuration

View File

@ -29,7 +29,6 @@ import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.thingsboard.server.common.data.FstStatsService; import org.thingsboard.server.common.data.FstStatsService;
import redis.clients.jedis.Connection;
import redis.clients.jedis.Jedis; import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPool;
import redis.clients.jedis.util.JedisClusterCRC16; import redis.clients.jedis.util.JedisClusterCRC16;
@ -40,6 +39,8 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
@Slf4j @Slf4j
public abstract class RedisTbTransactionalCache<K extends Serializable, V extends Serializable> implements TbTransactionalCache<K, V> { public abstract class RedisTbTransactionalCache<K extends Serializable, V extends Serializable> implements TbTransactionalCache<K, V> {
@ -57,6 +58,7 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
private final TbRedisSerializer<K, V> valueSerializer; private final TbRedisSerializer<K, V> valueSerializer;
private final Expiration evictExpiration; private final Expiration evictExpiration;
private final Expiration cacheTtl; private final Expiration cacheTtl;
private final boolean cacheEnabled;
public RedisTbTransactionalCache(String cacheName, public RedisTbTransactionalCache(String cacheName,
CacheSpecsMap cacheSpecsMap, CacheSpecsMap cacheSpecsMap,
@ -73,10 +75,19 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
.map(CacheSpecs::getTimeToLiveInMinutes) .map(CacheSpecs::getTimeToLiveInMinutes)
.map(t -> Expiration.from(t, TimeUnit.MINUTES)) .map(t -> Expiration.from(t, TimeUnit.MINUTES))
.orElseGet(Expiration::persistent); .orElseGet(Expiration::persistent);
this.cacheEnabled = Optional.ofNullable(cacheSpecsMap)
.map(CacheSpecsMap::getSpecs)
.map(x -> x.get(cacheName))
.map(CacheSpecs::getMaxSize)
.map(size -> size > 0)
.orElse(false);
} }
@Override @Override
public TbCacheValueWrapper<V> get(K key) { public TbCacheValueWrapper<V> get(K key) {
if (!cacheEnabled) {
return null;
}
try (var connection = connectionFactory.getConnection()) { try (var connection = connectionFactory.getConnection()) {
byte[] rawKey = getRawKey(key); byte[] rawKey = getRawKey(key);
byte[] rawValue = connection.get(rawKey); byte[] rawValue = connection.get(rawKey);
@ -98,6 +109,9 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
@Override @Override
public void put(K key, V value) { public void put(K key, V value) {
if (!cacheEnabled) {
return;
}
try (var connection = connectionFactory.getConnection()) { try (var connection = connectionFactory.getConnection()) {
put(connection, key, value, RedisStringCommands.SetOption.UPSERT); put(connection, key, value, RedisStringCommands.SetOption.UPSERT);
} }
@ -105,6 +119,9 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
@Override @Override
public void putIfAbsent(K key, V value) { public void putIfAbsent(K key, V value) {
if (!cacheEnabled) {
return;
}
try (var connection = connectionFactory.getConnection()) { try (var connection = connectionFactory.getConnection()) {
put(connection, key, value, RedisStringCommands.SetOption.SET_IF_ABSENT); put(connection, key, value, RedisStringCommands.SetOption.SET_IF_ABSENT);
} }
@ -112,6 +129,9 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
@Override @Override
public void evict(K key) { public void evict(K key) {
if (!cacheEnabled) {
return;
}
try (var connection = connectionFactory.getConnection()) { try (var connection = connectionFactory.getConnection()) {
connection.del(getRawKey(key)); connection.del(getRawKey(key));
} }
@ -119,6 +139,9 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
@Override @Override
public void evict(Collection<K> keys) { public void evict(Collection<K> keys) {
if (!cacheEnabled) {
return;
}
//Redis expects at least 1 key to delete. Otherwise - ERR wrong number of arguments for 'del' command //Redis expects at least 1 key to delete. Otherwise - ERR wrong number of arguments for 'del' command
if (keys.isEmpty()) { if (keys.isEmpty()) {
return; return;
@ -130,6 +153,9 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
@Override @Override
public void evictOrPut(K key, V value) { public void evictOrPut(K key, V value) {
if (!cacheEnabled) {
return;
}
try (var connection = connectionFactory.getConnection()) { try (var connection = connectionFactory.getConnection()) {
var rawKey = getRawKey(key); var rawKey = getRawKey(key);
var records = connection.del(rawKey); var records = connection.del(rawKey);
@ -153,6 +179,14 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
return new RedisTbCacheTransaction<>(this, connection); return new RedisTbCacheTransaction<>(this, connection);
} }
@Override
public <R> R getAndPutInTransaction(K key, Supplier<R> dbCall, Function<V, R> cacheValueToResult, Function<R, V> dbValueToCacheValue, boolean cacheNullValue) {
if (!cacheEnabled) {
return dbCall.get();
}
return TbTransactionalCache.super.getAndPutInTransaction(key, dbCall, cacheValueToResult, dbValueToCacheValue, cacheNullValue);
}
private RedisConnection getConnection(byte[] rawKey) { private RedisConnection getConnection(byte[] rawKey) {
if (!connectionFactory.isRedisClusterAware()) { if (!connectionFactory.isRedisClusterAware()) {
return connectionFactory.getConnection(); return connectionFactory.getConnection();
@ -214,6 +248,9 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
} }
public void put(RedisConnection connection, K key, V value, RedisStringCommands.SetOption setOption) { public void put(RedisConnection connection, K key, V value, RedisStringCommands.SetOption setOption) {
if (!cacheEnabled) {
return;
}
byte[] rawKey = getRawKey(key); byte[] rawKey = getRawKey(key);
byte[] rawValue = getRawValue(value); byte[] rawValue = getRawValue(value);
connection.set(rawKey, rawValue, cacheTtl, setOption); connection.set(rawKey, rawValue, cacheTtl, setOption);

View File

@ -60,15 +60,20 @@ public interface TbTransactionalCache<K extends Serializable, V extends Serializ
} }
default V getAndPutInTransaction(K key, Supplier<V> dbCall, boolean cacheNullValue) { default V getAndPutInTransaction(K key, Supplier<V> dbCall, boolean cacheNullValue) {
return getAndPutInTransaction(key, dbCall, Function.identity(), Function.identity(), cacheNullValue);
}
default <R> R getAndPutInTransaction(K key, Supplier<R> dbCall, Function<V, R> cacheValueToResult, Function<R, V> dbValueToCacheValue, boolean cacheNullValue) {
TbCacheValueWrapper<V> cacheValueWrapper = get(key); TbCacheValueWrapper<V> cacheValueWrapper = get(key);
if (cacheValueWrapper != null) { if (cacheValueWrapper != null) {
return cacheValueWrapper.get(); V cacheValue = cacheValueWrapper.get();
return cacheValue != null ? cacheValueToResult.apply(cacheValue) : null;
} }
var cacheTransaction = newTransactionForKey(key); var cacheTransaction = newTransactionForKey(key);
try { try {
V dbValue = dbCall.get(); R dbValue = dbCall.get();
if (dbValue != null || cacheNullValue) { if (dbValue != null || cacheNullValue) {
cacheTransaction.putIfAbsent(key, dbValue); cacheTransaction.putIfAbsent(key, dbValueToCacheValue.apply(dbValue));
cacheTransaction.commit(); cacheTransaction.commit();
return dbValue; return dbValue;
} else { } else {
@ -94,27 +99,4 @@ public interface TbTransactionalCache<K extends Serializable, V extends Serializ
} }
} }
default <R> R getAndPutInTransaction(K key, Supplier<R> dbCall, Function<V, R> cacheValueToResult, Function<R, V> dbValueToCacheValue, boolean cacheNullValue) {
TbCacheValueWrapper<V> cacheValueWrapper = get(key);
if (cacheValueWrapper != null) {
var cacheValue = cacheValueWrapper.get();
return cacheValue == null ? null : cacheValueToResult.apply(cacheValue);
}
var cacheTransaction = newTransactionForKey(key);
try {
R dbValue = dbCall.get();
if (dbValue != null || cacheNullValue) {
cacheTransaction.putIfAbsent(key, dbValueToCacheValue.apply(dbValue));
cacheTransaction.commit();
return dbValue;
} else {
cacheTransaction.rollback();
return null;
}
} catch (Throwable e) {
cacheTransaction.rollback();
throw e;
}
}
} }

View File

@ -62,4 +62,5 @@ public class CacheSpecsMapTest {
public void givenCacheConfig_whenCacheManagerReady_thenVerifyNonExistedCaches() { public void givenCacheConfig_whenCacheManagerReady_thenVerifyNonExistedCaches() {
assertThat(cacheManager.getCache("rainbows_and_unicorns")).isNull(); assertThat(cacheManager.getCache("rainbows_and_unicorns")).isNull();
} }
}
}

View File

@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.ToString;
import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
@ -53,9 +54,12 @@ public class AlarmCreateOrUpdateActiveRequest implements AlarmModificationReques
private long startTs; private long startTs;
@Schema(description = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522") @Schema(description = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522")
private long endTs; private long endTs;
@ToString.Exclude
@NoXss @NoXss
@Schema(description = "JSON object with alarm details") @Schema(description = "JSON object with alarm details")
private JsonNode details; private JsonNode details;
@Valid @Valid
@Schema(description = "JSON object with propagation details") @Schema(description = "JSON object with propagation details")
private AlarmPropagationInfo propagation; private AlarmPropagationInfo propagation;

View File

@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.ToString;
import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
@ -47,9 +48,12 @@ public class AlarmUpdateRequest implements AlarmModificationRequest {
private long startTs; private long startTs;
@Schema(description = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522") @Schema(description = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522")
private long endTs; private long endTs;
@ToString.Exclude
@NoXss @NoXss
@Schema(description = "JSON object with alarm details") @Schema(description = "JSON object with alarm details")
private JsonNode details; private JsonNode details;
@Valid @Valid
@Schema(description = "JSON object with propagation details") @Schema(description = "JSON object with propagation details")
private AlarmPropagationInfo propagation; private AlarmPropagationInfo propagation;

View File

@ -342,9 +342,12 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A
@Override @Override
public AlarmApiCallResult createOrUpdateActiveAlarm(AlarmCreateOrUpdateActiveRequest request, boolean alarmCreationEnabled) { public AlarmApiCallResult createOrUpdateActiveAlarm(AlarmCreateOrUpdateActiveRequest request, boolean alarmCreationEnabled) {
UUID tenantUUID = request.getTenantId().getId();
log.debug("[{}] createOrUpdateActiveAlarm [{}] {}", tenantUUID, alarmCreationEnabled, request);
AlarmPropagationInfo ap = getSafePropagationInfo(request.getPropagation()); AlarmPropagationInfo ap = getSafePropagationInfo(request.getPropagation());
return toAlarmApiResult(alarmRepository.createOrUpdateActiveAlarm( return toAlarmApiResult(alarmRepository.createOrUpdateActiveAlarm(
request.getTenantId().getId(), tenantUUID,
request.getCustomerId() != null ? request.getCustomerId().getId() : CustomerId.NULL_UUID, request.getCustomerId() != null ? request.getCustomerId().getId() : CustomerId.NULL_UUID,
request.getEdgeAlarmId() != null ? request.getEdgeAlarmId().getId() : UUID.randomUUID(), request.getEdgeAlarmId() != null ? request.getEdgeAlarmId().getId() : UUID.randomUUID(),
System.currentTimeMillis(), System.currentTimeMillis(),
@ -364,10 +367,14 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A
@Override @Override
public AlarmApiCallResult updateAlarm(AlarmUpdateRequest request) { public AlarmApiCallResult updateAlarm(AlarmUpdateRequest request) {
UUID tenantUUID = request.getTenantId().getId();
UUID alarmUUID = request.getAlarmId().getId();
log.debug("[{}][{}] updateAlarm {}", tenantUUID, alarmUUID, request);
AlarmPropagationInfo ap = getSafePropagationInfo(request.getPropagation()); AlarmPropagationInfo ap = getSafePropagationInfo(request.getPropagation());
return toAlarmApiResult(alarmRepository.updateAlarm( return toAlarmApiResult(alarmRepository.updateAlarm(
request.getTenantId().getId(), tenantUUID,
request.getAlarmId().getId(), alarmUUID,
request.getSeverity().name(), request.getSeverity().name(),
request.getStartTs(), request.getEndTs(), request.getStartTs(), request.getEndTs(),
getDetailsAsString(request.getDetails()), getDetailsAsString(request.getDetails()),
@ -380,11 +387,13 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A
@Override @Override
public AlarmApiCallResult acknowledgeAlarm(TenantId tenantId, AlarmId id, long ackTs) { public AlarmApiCallResult acknowledgeAlarm(TenantId tenantId, AlarmId id, long ackTs) {
log.debug("[{}][{}] acknowledgeAlarm [{}]", tenantId, id, ackTs);
return toAlarmApiResult(alarmRepository.acknowledgeAlarm(tenantId.getId(), id.getId(), ackTs)); return toAlarmApiResult(alarmRepository.acknowledgeAlarm(tenantId.getId(), id.getId(), ackTs));
} }
@Override @Override
public AlarmApiCallResult clearAlarm(TenantId tenantId, AlarmId id, long clearTs, JsonNode details) { public AlarmApiCallResult clearAlarm(TenantId tenantId, AlarmId id, long clearTs, JsonNode details) {
log.debug("[{}][{}] clearAlarm [{}]", tenantId, id, clearTs);
return toAlarmApiResult(alarmRepository.clearAlarm(tenantId.getId(), id.getId(), clearTs, details != null ? getDetailsAsString(details) : null)); return toAlarmApiResult(alarmRepository.clearAlarm(tenantId.getId(), id.getId(), clearTs, details != null ? getDetailsAsString(details) : null));
} }

View File

@ -0,0 +1,82 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.cache;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.thingsboard.server.cache.CacheSpecsMap;
import org.thingsboard.server.cache.RedisSslCredentials;
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.dao.relation.RelationCacheKey;
import org.thingsboard.server.dao.relation.RelationRedisCache;
import java.util.List;
import java.util.UUID;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {RelationRedisCache.class, CacheSpecsMap.class, TBRedisCacheConfiguration.class})
@TestPropertySource(properties = {
"cache.type=redis",
"cache.specs.relations.timeToLiveInMinutes=1440",
"cache.specs.relations.maxSize=0",
})
@Slf4j
public class RedisTbTransactionalCacheTest {
@MockBean
private RelationRedisCache relationRedisCache;
@MockBean
private RedisConnectionFactory connectionFactory;
@MockBean
private RedisConnection redisConnection;
@MockBean
private RedisSslCredentials redisSslCredentials;
@Test
public void testNoOpWhenCacheDisabled() {
when(connectionFactory.getConnection()).thenReturn(redisConnection);
relationRedisCache.put(createRelationCacheKey(), null);
relationRedisCache.putIfAbsent(createRelationCacheKey(), null);
relationRedisCache.evict(createRelationCacheKey());
relationRedisCache.evict(List.of(createRelationCacheKey()));
relationRedisCache.getAndPutInTransaction(createRelationCacheKey(), null, false);
relationRedisCache.getAndPutInTransaction(createRelationCacheKey(), null, null, null, false);
relationRedisCache.getOrFetchFromDB(createRelationCacheKey(), null, false, false);
verify(connectionFactory, never()).getConnection();
verifyNoInteractions(redisConnection);
}
private RelationCacheKey createRelationCacheKey() {
return new RelationCacheKey(new DeviceId(UUID.randomUUID()), new DeviceId(UUID.randomUUID()), null, RelationTypeGroup.COMMON);
}
}

View File

@ -58,7 +58,6 @@ import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.user.UserService;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -245,8 +244,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
// Check child relation // Check child relation
PageData<AlarmInfo> alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder() PageData<AlarmInfo> alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
.affectedEntityId(childId) .affectedEntityId(childId)
.severityList(Arrays.asList(AlarmSeverity.CRITICAL)) .severityList(List.of(AlarmSeverity.CRITICAL))
.statusList(Arrays.asList(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink( .statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
new TimePageLink(1, 0, "", new TimePageLink(1, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis()) new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
).build()); ).build());
@ -257,8 +256,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
// Check parent relation // Check parent relation
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder() alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
.affectedEntityId(parentId) .affectedEntityId(parentId)
.severityList(Arrays.asList(AlarmSeverity.CRITICAL)) .severityList(List.of(AlarmSeverity.CRITICAL))
.statusList(Arrays.asList(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink( .statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
new TimePageLink(1, 0, "", new TimePageLink(1, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis()) new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
).build()); ).build());
@ -272,8 +271,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
// Check child relation // Check child relation
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder() alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
.affectedEntityId(childId) .affectedEntityId(childId)
.severityList(Arrays.asList(AlarmSeverity.CRITICAL)) .severityList(List.of(AlarmSeverity.CRITICAL))
.statusList(Arrays.asList(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink( .statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
new TimePageLink(1, 0, "", new TimePageLink(1, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis()) new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
).build()); ).build());
@ -284,8 +283,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
// Check parent relation // Check parent relation
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder() alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
.affectedEntityId(parentId) .affectedEntityId(parentId)
.severityList(Arrays.asList(AlarmSeverity.CRITICAL)) .severityList(List.of(AlarmSeverity.CRITICAL))
.statusList(Arrays.asList(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink( .statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
new TimePageLink(1, 0, "", new TimePageLink(1, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis()) new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
).build()); ).build());
@ -298,8 +297,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder() alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
.affectedEntityId(childId) .affectedEntityId(childId)
.severityList(Arrays.asList(AlarmSeverity.CRITICAL)) .severityList(List.of(AlarmSeverity.CRITICAL))
.statusList(Arrays.asList(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.ACK)).pageLink( .statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.ACK)).pageLink(
new TimePageLink(1, 0, "", new TimePageLink(1, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis()) new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
).build()); ).build());
@ -310,8 +309,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
// Check not existing relation // Check not existing relation
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder() alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
.affectedEntityId(childId) .affectedEntityId(childId)
.severityList(Arrays.asList(AlarmSeverity.CRITICAL)) .severityList(List.of(AlarmSeverity.CRITICAL))
.statusList(Arrays.asList(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink( .statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
new TimePageLink(1, 0, "", new TimePageLink(1, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis()) new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
).build()); ).build());
@ -323,8 +322,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder() alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
.affectedEntityId(childId) .affectedEntityId(childId)
.severityList(Arrays.asList(AlarmSeverity.CRITICAL)) .severityList(List.of(AlarmSeverity.CRITICAL))
.statusList(Arrays.asList(AlarmSearchStatus.CLEARED, AlarmSearchStatus.ACK)).pageLink( .statusList(List.of(AlarmSearchStatus.CLEARED, AlarmSearchStatus.ACK)).pageLink(
new TimePageLink(1, 0, "", new TimePageLink(1, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis()) new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
).build()); ).build());
@ -334,7 +333,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
} }
@Test @Test
public void testFindAssignedAlarm() throws ExecutionException, InterruptedException { public void testFindAssignedAlarm() {
AssetId parentId = new AssetId(Uuids.timeBased()); AssetId parentId = new AssetId(Uuids.timeBased());
AssetId childId = new AssetId(Uuids.timeBased()); AssetId childId = new AssetId(Uuids.timeBased());
@ -368,7 +367,6 @@ public class AlarmServiceTest extends AbstractServiceTest {
PageData<AlarmInfo> alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() PageData<AlarmInfo> alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder()
.assigneeId(tenantUser.getId()) .assigneeId(tenantUser.getId())
.fetchOriginator(true)
.pageLink(new TimePageLink(1, 0, "", .pageLink(new TimePageLink(1, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis()) new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
).build()); ).build());
@ -405,7 +403,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
} }
@Test @Test
public void testFindCustomerAlarm() throws ExecutionException, InterruptedException { public void testFindCustomerAlarm() {
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTitle("TestCustomer"); customer.setTitle("TestCustomer");
customer.setTenantId(tenantId); customer.setTenantId(tenantId);
@ -451,10 +449,10 @@ public class AlarmServiceTest extends AbstractServiceTest {
pageLink.setStartTs(0L); pageLink.setStartTs(0L);
pageLink.setEndTs(System.currentTimeMillis()); pageLink.setEndTs(System.currentTimeMillis());
pageLink.setSearchPropagatedAlarms(true); pageLink.setSearchPropagatedAlarms(true);
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
PageData<AlarmData> tenantAlarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Arrays.asList(tenantDevice.getId(), customerDevice.getId())); PageData<AlarmData> tenantAlarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), List.of(tenantDevice.getId(), customerDevice.getId()));
Assert.assertEquals(2, tenantAlarms.getData().size()); Assert.assertEquals(2, tenantAlarms.getData().size());
PageData<AlarmData> customerAlarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(customerDevice.getId())); PageData<AlarmData> customerAlarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(customerDevice.getId()));
@ -473,7 +471,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
} }
@Test @Test
public void testFindPropagatedCustomerAssetAlarm() throws ExecutionException, InterruptedException { public void testFindPropagatedCustomerAssetAlarm() {
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTitle("TestCustomer"); customer.setTitle("TestCustomer");
customer.setTenantId(tenantId); customer.setTenantId(tenantId);
@ -525,8 +523,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
pageLink.setStartTs(0L); pageLink.setStartTs(0L);
pageLink.setEndTs(System.currentTimeMillis()); pageLink.setEndTs(System.currentTimeMillis());
pageLink.setSearchPropagatedAlarms(true); pageLink.setSearchPropagatedAlarms(true);
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
//TEST that propagated alarms are visible on the asset level. //TEST that propagated alarms are visible on the asset level.
PageData<AlarmData> customerAlarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(customerAsset.getId())); PageData<AlarmData> customerAlarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(customerAsset.getId()));
@ -576,7 +574,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
pageLink.setStartTs(0L); pageLink.setStartTs(0L);
pageLink.setEndTs(System.currentTimeMillis()); pageLink.setEndTs(System.currentTimeMillis());
pageLink.setSearchPropagatedAlarms(true); pageLink.setSearchPropagatedAlarms(true);
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
pageLink.setStatusList(Collections.singletonList(AlarmSearchStatus.ACTIVE)); pageLink.setStatusList(Collections.singletonList(AlarmSearchStatus.ACTIVE));
//TEST that propagated alarms are visible on the asset level. //TEST that propagated alarms are visible on the asset level.
@ -599,7 +597,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
} }
@Test @Test
public void testFindHighestAlarmSeverity() throws ExecutionException, InterruptedException { public void testFindHighestAlarmSeverity() {
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTitle("TestCustomer"); customer.setTitle("TestCustomer");
customer.setTenantId(tenantId); customer.setTenantId(tenantId);
@ -679,8 +677,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
pageLink.setStartTs(0L); pageLink.setStartTs(0L);
pageLink.setEndTs(System.currentTimeMillis()); pageLink.setEndTs(System.currentTimeMillis());
pageLink.setSearchPropagatedAlarms(false); pageLink.setSearchPropagatedAlarms(false);
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
PageData<AlarmData> alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId)); PageData<AlarmData> alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId));
@ -695,8 +693,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
pageLink.setStartTs(0L); pageLink.setStartTs(0L);
pageLink.setEndTs(System.currentTimeMillis()); pageLink.setEndTs(System.currentTimeMillis());
pageLink.setSearchPropagatedAlarms(false); pageLink.setSearchPropagatedAlarms(false);
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId)); alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId));
Assert.assertNotNull(alarms.getData()); Assert.assertNotNull(alarms.getData());
@ -722,8 +720,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
pageLink.setStartTs(0L); pageLink.setStartTs(0L);
pageLink.setEndTs(System.currentTimeMillis()); pageLink.setEndTs(System.currentTimeMillis());
pageLink.setSearchPropagatedAlarms(true); pageLink.setSearchPropagatedAlarms(true);
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId)); alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId));
Assert.assertNotNull(alarms.getData()); Assert.assertNotNull(alarms.getData());
@ -738,8 +736,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
pageLink.setStartTs(0L); pageLink.setStartTs(0L);
pageLink.setEndTs(System.currentTimeMillis()); pageLink.setEndTs(System.currentTimeMillis());
pageLink.setSearchPropagatedAlarms(true); pageLink.setSearchPropagatedAlarms(true);
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(parentId)); alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(parentId));
Assert.assertNotNull(alarms.getData()); Assert.assertNotNull(alarms.getData());
@ -748,7 +746,6 @@ public class AlarmServiceTest extends AbstractServiceTest {
PageData<AlarmInfo> alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder() PageData<AlarmInfo> alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder()
.affectedEntityId(childId) .affectedEntityId(childId)
.fetchOriginator(true)
.status(AlarmStatus.ACTIVE_UNACK).pageLink( .status(AlarmStatus.ACTIVE_UNACK).pageLink(
new TimePageLink(10, 0, "", new TimePageLink(10, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis()) new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
@ -759,7 +756,6 @@ public class AlarmServiceTest extends AbstractServiceTest {
alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder() alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder()
.affectedEntityId(parentId) .affectedEntityId(parentId)
.fetchOriginator(true)
.status(AlarmStatus.ACTIVE_UNACK).pageLink( .status(AlarmStatus.ACTIVE_UNACK).pageLink(
new TimePageLink(10, 0, "", new TimePageLink(10, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis()) new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
@ -770,7 +766,6 @@ public class AlarmServiceTest extends AbstractServiceTest {
alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder() alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder()
.affectedEntityId(parentId2) .affectedEntityId(parentId2)
.fetchOriginator(true)
.status(AlarmStatus.ACTIVE_UNACK).pageLink( .status(AlarmStatus.ACTIVE_UNACK).pageLink(
new TimePageLink(10, 0, "", new TimePageLink(10, 0, "",
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis()) new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
@ -786,8 +781,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
pageLink.setStartTs(0L); pageLink.setStartTs(0L);
pageLink.setEndTs(System.currentTimeMillis()); pageLink.setEndTs(System.currentTimeMillis());
pageLink.setSearchPropagatedAlarms(true); pageLink.setSearchPropagatedAlarms(true);
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(parentId)); alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(parentId));
Assert.assertNotNull(alarms.getData()); Assert.assertNotNull(alarms.getData());
@ -803,8 +798,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
pageLink.setStartTs(0L); pageLink.setStartTs(0L);
pageLink.setEndTs(System.currentTimeMillis()); pageLink.setEndTs(System.currentTimeMillis());
pageLink.setSearchPropagatedAlarms(true); pageLink.setSearchPropagatedAlarms(true);
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId)); alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId));
Assert.assertNotNull(alarms.getData()); Assert.assertNotNull(alarms.getData());
@ -813,7 +808,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
} }
@Test @Test
public void testCountAlarmsUsingAlarmDataQuery() throws ExecutionException, InterruptedException { public void testCountAlarmsUsingAlarmDataQuery() {
AssetId childId = new AssetId(Uuids.timeBased()); AssetId childId = new AssetId(Uuids.timeBased());
long ts = System.currentTimeMillis(); long ts = System.currentTimeMillis();
@ -829,7 +824,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
.startTs(0L) .startTs(0L)
.endTs(System.currentTimeMillis()) .endTs(System.currentTimeMillis())
.searchPropagatedAlarms(false) .searchPropagatedAlarms(false)
.severityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)) .severityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING))
.statusList(List.of(AlarmSearchStatus.ACTIVE)) .statusList(List.of(AlarmSearchStatus.ACTIVE))
.build(); .build();
@ -841,7 +836,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
.startTs(0L) .startTs(0L)
.endTs(System.currentTimeMillis()) .endTs(System.currentTimeMillis())
.searchPropagatedAlarms(true) .searchPropagatedAlarms(true)
.severityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)) .severityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING))
.statusList(List.of(AlarmSearchStatus.ACTIVE)) .statusList(List.of(AlarmSearchStatus.ACTIVE))
.build(); .build();
@ -866,7 +861,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
.startTs(0L) .startTs(0L)
.endTs(System.currentTimeMillis()) .endTs(System.currentTimeMillis())
.searchPropagatedAlarms(true) .searchPropagatedAlarms(true)
.severityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)) .severityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING))
.statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.CLEARED)) .statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.CLEARED))
.build(); .build();
@ -939,6 +934,6 @@ public class AlarmServiceTest extends AbstractServiceTest {
).build()); ).build());
Assert.assertNotNull(alarms.getData()); Assert.assertNotNull(alarms.getData());
Assert.assertEquals(0, alarms.getData().size()); Assert.assertEquals(0, alarms.getData().size());
} }
} }

View File

@ -27,10 +27,10 @@ import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec; import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbContext;
@ -132,6 +132,7 @@ public class TbHttpClient {
this.webClient = WebClient.builder() this.webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient)) .clientConnector(new ReactorClientHttpConnector(httpClient))
.defaultHeader(HttpHeaders.CONNECTION, "close") //In previous realization this header was present! (Added for hotfix "Connection reset")
.build(); .build();
} catch (SSLException e) { } catch (SSLException e) {
throw new TbNodeException(e); throw new TbNodeException(e);
@ -170,7 +171,7 @@ public class TbHttpClient {
BiConsumer<TbMsg, Throwable> onFailure) { BiConsumer<TbMsg, Throwable> onFailure) {
try { try {
if (semaphore != null && !semaphore.tryAcquire(config.getReadTimeoutMs(), TimeUnit.MILLISECONDS)) { if (semaphore != null && !semaphore.tryAcquire(config.getReadTimeoutMs(), TimeUnit.MILLISECONDS)) {
ctx.tellFailure(msg, new RuntimeException("Timeout during waiting for reply!")); onFailure.accept(msg, new RuntimeException("Timeout during waiting for reply!"));
return; return;
} }
@ -183,10 +184,10 @@ public class TbHttpClient {
.uri(uri) .uri(uri)
.headers(headers -> prepareHeaders(headers, msg)); .headers(headers -> prepareHeaders(headers, msg));
if (HttpMethod.POST.equals(method) || HttpMethod.PUT.equals(method) || if ((HttpMethod.POST.equals(method) || HttpMethod.PUT.equals(method) ||
HttpMethod.PATCH.equals(method) || HttpMethod.DELETE.equals(method) || HttpMethod.PATCH.equals(method) || HttpMethod.DELETE.equals(method)) &&
!config.isIgnoreRequestBody()) { !config.isIgnoreRequestBody()) {
request.body(BodyInserters.fromValue(getData(msg, config.isIgnoreRequestBody(), config.isParseToPlainText()))); request.body(BodyInserters.fromValue(getData(msg, config.isParseToPlainText())));
} }
request request
@ -236,11 +237,9 @@ public class TbHttpClient {
return uri; return uri;
} }
private String getData(TbMsg tbMsg, boolean ignoreBody, boolean parseToPlainText) { private Object getData(TbMsg tbMsg, boolean parseToPlainText) {
if (!ignoreBody && parseToPlainText) { String data = tbMsg.getData();
return JacksonUtil.toPlainText(tbMsg.getData()); return parseToPlainText ? JacksonUtil.toPlainText(data) : JacksonUtil.toJsonNode(data);
}
return tbMsg.getData();
} }
private TbMsg processResponse(TbContext ctx, TbMsg origMsg, ResponseEntity<String> response) { private TbMsg processResponse(TbContext ctx, TbMsg origMsg, ResponseEntity<String> response) {
@ -283,10 +282,9 @@ public class TbHttpClient {
private TbMsg processException(TbMsg origMsg, Throwable e) { private TbMsg processException(TbMsg origMsg, Throwable e) {
TbMsgMetaData metaData = origMsg.getMetaData(); TbMsgMetaData metaData = origMsg.getMetaData();
metaData.putValue(ERROR, e.getClass() + ": " + e.getMessage()); metaData.putValue(ERROR, e.getClass() + ": " + e.getMessage());
if (e instanceof RestClientResponseException) { if (e instanceof WebClientResponseException restClientResponseException) {
RestClientResponseException restClientResponseException = (RestClientResponseException) e;
metaData.putValue(STATUS, restClientResponseException.getStatusText()); metaData.putValue(STATUS, restClientResponseException.getStatusText());
metaData.putValue(STATUS_CODE, restClientResponseException.getRawStatusCode() + ""); metaData.putValue(STATUS_CODE, restClientResponseException.getStatusCode().value() + "");
metaData.putValue(ERROR_BODY, restClientResponseException.getResponseBodyAsString()); metaData.putValue(ERROR_BODY, restClientResponseException.getResponseBodyAsString());
} }
return TbMsg.transformMsgMetadata(origMsg, metaData); return TbMsg.transformMsgMetadata(origMsg, metaData);

View File

@ -168,7 +168,7 @@ public class TbRestApiCallNodeTest extends AbstractRuleNodeUpgradeTest {
try { try {
assertEquals(path, request.getRequestLine().getUri(), "Request path matches"); assertEquals(path, request.getRequestLine().getUri(), "Request path matches");
assertTrue(request.containsHeader("Content-Type"), "Content-Type included"); assertTrue(request.containsHeader("Content-Type"), "Content-Type included");
assertEquals("text/plain;charset=UTF-8", assertEquals("application/json",
request.getFirstHeader("Content-Type").getValue(), "Content-Type value"); request.getFirstHeader("Content-Type").getValue(), "Content-Type value");
assertTrue(request.containsHeader("Content-Length"), "Content-Length included"); assertTrue(request.containsHeader("Content-Length"), "Content-Length included");
assertEquals("2", assertEquals("2",

View File

@ -456,6 +456,10 @@ export class UtilsService {
return isDefined(value); return isDefined(value);
} }
public isDefinedAndNotNull(value: any): boolean {
return isDefinedAndNotNull(value);
}
public defaultValue(value: any, defaultValue: any): any { public defaultValue(value: any, defaultValue: any): any {
if (isDefinedAndNotNull(value)) { if (isDefinedAndNotNull(value)) {
return value; return value;

View File

@ -160,7 +160,7 @@
</div> </div>
<tb-chart-fill-settings <tb-chart-fill-settings
formControlName="barBackgroundSettings" formControlName="barBackgroundSettings"
title="widgets.chart.background" titleText="widgets.chart.background"
fillNoneTitle="widgets.chart.fill-type-solid"> fillNoneTitle="widgets.chart.fill-type-solid">
</tb-chart-fill-settings> </tb-chart-fill-settings>
<tb-time-series-no-aggregation-bar-width-settings <tb-time-series-no-aggregation-bar-width-settings

View File

@ -203,23 +203,29 @@ export class UnreadNotificationWidgetComponent implements OnInit, OnDestroy {
} }
markAsRead(id: string) { markAsRead(id: string) {
const cmd = NotificationSubscriber.createMarkAsReadCommand(this.notificationWsService, [id]); if (!this.ctx.isEdit && !this.ctx.isPreview) {
cmd.subscribe(); const cmd = NotificationSubscriber.createMarkAsReadCommand(this.notificationWsService, [id]);
cmd.subscribe();
}
} }
markAsAllRead($event: Event) { markAsAllRead($event: Event) {
if ($event) { if (!this.ctx.isEdit && !this.ctx.isPreview) {
$event.stopPropagation(); if ($event) {
$event.stopPropagation();
}
const cmd = NotificationSubscriber.createMarkAllAsReadCommand(this.notificationWsService);
cmd.subscribe();
} }
const cmd = NotificationSubscriber.createMarkAllAsReadCommand(this.notificationWsService);
cmd.subscribe();
} }
viewAll($event: Event) { viewAll($event: Event) {
if ($event) { if (!this.ctx.isEdit && !this.ctx.isPreview) {
$event.stopPropagation(); if ($event) {
$event.stopPropagation();
}
this.router.navigateByUrl(this.router.parseUrl('/notification/inbox')).then(() => {});
} }
this.router.navigateByUrl(this.router.parseUrl('/notification/inbox')).then(() => {});
} }
trackById(index: number, item: NotificationRequest): string { trackById(index: number, item: NotificationRequest): string {

View File

@ -169,6 +169,6 @@ export class TimeSeriesChartWidgetComponent implements OnInit, OnDestroy, AfterV
} }
public toggleLegendKey(legendKey: LegendKey) { public toggleLegendKey(legendKey: LegendKey) {
this.timeSeriesChart.toggleKey(legendKey.dataKey); this.timeSeriesChart.toggleKey(legendKey.dataKey, legendKey.dataIndex);
} }
} }

View File

@ -56,7 +56,14 @@ import {
measureAxisNameSize measureAxisNameSize
} from '@home/components/widget/lib/chart/echarts-widget.models'; } from '@home/components/widget/lib/chart/echarts-widget.models';
import { DateFormatProcessor, ValueSourceType } from '@shared/models/widget-settings.models'; import { DateFormatProcessor, ValueSourceType } from '@shared/models/widget-settings.models';
import { formattedDataFormDatasourceData, formatValue, isDefinedAndNotNull, isEqual, mergeDeep } from '@core/utils'; import {
formattedDataFormDatasourceData,
formatValue,
isDefined,
isDefinedAndNotNull,
isEqual,
mergeDeep
} from '@core/utils';
import { DataKey, Datasource, DatasourceType, FormattedData, widgetType } from '@shared/models/widget.models'; import { DataKey, Datasource, DatasourceType, FormattedData, widgetType } from '@shared/models/widget.models';
import * as echarts from 'echarts/core'; import * as echarts from 'echarts/core';
import { CallbackDataParams, PiecewiseVisualMapOption } from 'echarts/types/dist/shared'; import { CallbackDataParams, PiecewiseVisualMapOption } from 'echarts/types/dist/shared';
@ -300,7 +307,7 @@ export class TbTimeSeriesChart {
} }
} }
public toggleKey(dataKey: DataKey): void { public toggleKey(dataKey: DataKey, dataIndex?: number): void {
const enable = dataKey.hidden; const enable = dataKey.hidden;
const dataItem = this.dataItems.find(d => d.dataKey === dataKey); const dataItem = this.dataItems.find(d => d.dataKey === dataKey);
if (dataItem) { if (dataItem) {
@ -320,6 +327,9 @@ export class TbTimeSeriesChart {
this.timeSeriesChart.setOption(this.timeSeriesChartOptions, this.stackMode ? {notMerge: true} : {replaceMerge: mergeList}); this.timeSeriesChart.setOption(this.timeSeriesChartOptions, this.stackMode ? {notMerge: true} : {replaceMerge: mergeList});
this.updateAxes(); this.updateAxes();
dataKey.hidden = !enable; dataKey.hidden = !enable;
if (isDefined(dataIndex)) {
this.ctx.defaultSubscription.updateDataVisibility(dataIndex);
}
if (enable) { if (enable) {
this.timeSeriesChart.dispatchAction({ this.timeSeriesChart.dispatchAction({
type: 'highlight', type: 'highlight',

View File

@ -79,7 +79,7 @@
</div> </div>
<tb-chart-fill-settings <tb-chart-fill-settings
formControlName="barBackgroundSettings" formControlName="barBackgroundSettings"
title="widgets.chart.background" titleText="widgets.chart.background"
fillNoneTitle="widgets.chart.fill-type-solid"> fillNoneTitle="widgets.chart.fill-type-solid">
</tb-chart-fill-settings> </tb-chart-fill-settings>
<tb-time-series-no-aggregation-bar-width-settings <tb-time-series-no-aggregation-bar-width-settings

View File

@ -77,7 +77,7 @@
</div> </div>
<tb-chart-fill-settings <tb-chart-fill-settings
formControlName="backgroundSettings" formControlName="backgroundSettings"
title="widgets.chart.background" titleText="widgets.chart.background"
fillNoneTitle="widgets.chart.fill-type-solid"> fillNoneTitle="widgets.chart.fill-type-solid">
</tb-chart-fill-settings> </tb-chart-fill-settings>
</ng-container> </ng-container>

View File

@ -18,7 +18,7 @@
<ng-container [formGroup]="fillSettingsFormGroup"> <ng-container [formGroup]="fillSettingsFormGroup">
<div class="tb-form-row column"> <div class="tb-form-row column">
<div class="tb-form-row no-border no-padding space-between"> <div class="tb-form-row no-border no-padding space-between">
<div>{{ title | translate }}</div> <div>{{ titleText | translate }}</div>
<tb-toggle-select formControlName="type"> <tb-toggle-select formControlName="type">
<tb-toggle-option *ngFor="let type of chartFillTypes" [value]="type">{{ chartFillTypeTranslationMap.get(type) | translate }}</tb-toggle-option> <tb-toggle-option *ngFor="let type of chartFillTypes" [value]="type">{{ chartFillTypeTranslationMap.get(type) | translate }}</tb-toggle-option>
</tb-toggle-select> </tb-toggle-select>

View File

@ -55,7 +55,7 @@ export class ChartFillSettingsComponent implements OnInit, ControlValueAccessor
disabled: boolean; disabled: boolean;
@Input() @Input()
title = 'widgets.chart.fill'; titleText = 'widgets.chart.fill';
@Input() @Input()
fillNoneTitle = 'widgets.chart.fill-type-none'; fillNoneTitle = 'widgets.chart.fill-type-none';

View File

@ -487,6 +487,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
} }
if (!this.widgetContext.inited && this.isReady()) { if (!this.widgetContext.inited && this.isReady()) {
this.widgetContext.inited = true; this.widgetContext.inited = true;
this.widgetContext.destroyed = false;
this.dashboardWidget.updateWidgetParams(); this.dashboardWidget.updateWidgetParams();
this.widgetContext.detectContainerChanges(); this.widgetContext.detectContainerChanges();
if (this.cafs.init) { if (this.cafs.init) {

View File

@ -449,6 +449,8 @@ export class WidgetContext {
labelPattern.destroy(); labelPattern.destroy();
} }
this.labelPatterns.clear(); this.labelPatterns.clear();
this.width = undefined;
this.height = undefined;
this.destroyed = true; this.destroyed = true;
} }

View File

@ -25,11 +25,17 @@ import {
SimpleChanges, SimpleChanges,
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import {
ControlValueAccessor,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
UntypedFormBuilder,
UntypedFormGroup,
ValidationErrors,
Validators
} from '@angular/forms';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { filter, map, mergeMap, share, tap } from 'rxjs/operators'; import { filter, map, mergeMap, share, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { EntityType } from '@shared/models/entity-type.models'; import { EntityType } from '@shared/models/entity-type.models';
import { BaseData } from '@shared/models/base-data'; import { BaseData } from '@shared/models/base-data';
@ -49,6 +55,11 @@ import { SubscriptSizing } from '@angular/material/form-field';
provide: NG_VALUE_ACCESSOR, provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => EntityListComponent), useExisting: forwardRef(() => EntityListComponent),
multi: true multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => EntityListComponent),
multi: true
} }
] ]
}) })
@ -56,7 +67,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
entityListFormGroup: UntypedFormGroup; entityListFormGroup: UntypedFormGroup;
modelValue: Array<string> | null; private modelValue: Array<string> | null;
@Input() @Input()
entityType: EntityType; entityType: EntityType;
@ -108,17 +119,16 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
private propagateChange = (v: any) => { }; private propagateChange = (v: any) => { };
constructor(private store: Store<AppState>, constructor(public translate: TranslateService,
public translate: TranslateService,
private entityService: EntityService, private entityService: EntityService,
private fb: UntypedFormBuilder) { private fb: UntypedFormBuilder) {
this.entityListFormGroup = this.fb.group({ this.entityListFormGroup = this.fb.group({
entities: [this.entities, this.required ? [Validators.required] : []], entities: [this.entities],
entity: [null] entity: [null]
}); });
} }
updateValidators() { private updateValidators() {
this.entityListFormGroup.get('entities').setValidators(this.required ? [Validators.required] : []); this.entityListFormGroup.get('entities').setValidators(this.required ? [Validators.required] : []);
this.entityListFormGroup.get('entities').updateValueAndValidity(); this.entityListFormGroup.get('entities').updateValueAndValidity();
} }
@ -189,7 +199,13 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
this.dirty = true; this.dirty = true;
} }
reset() { validate(): ValidationErrors | null {
return this.entityListFormGroup.valid ? null : {
entities: {valid: false}
};
}
private reset() {
this.entities = []; this.entities = [];
this.entityListFormGroup.get('entities').setValue(this.entities); this.entityListFormGroup.get('entities').setValue(this.entities);
this.modelValue = null; this.modelValue = null;
@ -201,7 +217,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
this.dirty = true; this.dirty = true;
} }
add(entity: BaseData<EntityId>): void { private add(entity: BaseData<EntityId>): void {
if (!this.modelValue || this.modelValue.indexOf(entity.id.id) === -1) { if (!this.modelValue || this.modelValue.indexOf(entity.id.id) === -1) {
if (!this.modelValue) { if (!this.modelValue) {
this.modelValue = []; this.modelValue = [];
@ -214,7 +230,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
this.clear(); this.clear();
} }
remove(entity: BaseData<EntityId>) { public remove(entity: BaseData<EntityId>) {
let index = this.entities.indexOf(entity); let index = this.entities.indexOf(entity);
if (index >= 0) { if (index >= 0) {
this.entities.splice(index, 1); this.entities.splice(index, 1);
@ -229,11 +245,11 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
} }
} }
displayEntityFn(entity?: BaseData<EntityId>): string | undefined { public displayEntityFn(entity?: BaseData<EntityId>): string | undefined {
return entity ? entity.name : undefined; return entity ? entity.name : undefined;
} }
fetchEntities(searchText?: string): Observable<Array<BaseData<EntityId>>> { private fetchEntities(searchText?: string): Observable<Array<BaseData<EntityId>>> {
this.searchText = searchText; this.searchText = searchText;
return this.entityService.getEntitiesByNameFilter(this.entityType, searchText, return this.entityService.getEntitiesByNameFilter(this.entityType, searchText,
@ -241,14 +257,14 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
map((data) => data ? data : [])); map((data) => data ? data : []));
} }
onFocus() { public onFocus() {
if (this.dirty) { if (this.dirty) {
this.entityListFormGroup.get('entity').updateValueAndValidity({onlySelf: true, emitEvent: true}); this.entityListFormGroup.get('entity').updateValueAndValidity({onlySelf: true, emitEvent: true});
this.dirty = false; this.dirty = false;
} }
} }
clear(value: string = '') { private clear(value: string = '') {
this.entityInput.nativeElement.value = value; this.entityInput.nativeElement.value = value;
this.entityListFormGroup.get('entity').patchValue(value, {emitEvent: true}); this.entityListFormGroup.get('entity').patchValue(value, {emitEvent: true});
setTimeout(() => { setTimeout(() => {
@ -257,8 +273,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
}, 0); }, 0);
} }
textIsNotEmpty(text: string): boolean { public textIsNotEmpty(text: string): boolean {
return (text && text.length > 0); return (text && text.length > 0);
} }
} }