Commit 7e8837603016db5c3ab79bd0408f6b7df14710db

Authored by YevhenBondarenko
1 parent 9ec4b776

created alias ApiUsageState

... ... @@ -62,7 +62,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
62 62 @Value("${usage.stats.report.enabled:true}")
63 63 private boolean enabled;
64 64
65   - @Value("${usage.stats.check.cycle:60000}")
  65 + @Value("${usage.stats.check.cycle:6000}")
66 66 private long nextCycleCheckInterval;
67 67
68 68 private final Lock updateLock = new ReentrantLock();
... ... @@ -107,7 +107,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
107 107 } finally {
108 108 updateLock.unlock();
109 109 }
110   - tsService.save(tenantId, tenantState.getEntityId(), updatedEntries, 0L);
  110 + tsService.save(tenantId, tenantState.getId(), updatedEntries, 0L);
111 111 }
112 112
113 113 @Override
... ... @@ -150,7 +150,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
150 150 dbStateEntity = apiUsageStateService.findTenantApiUsageState(tenantId);
151 151 }
152 152 }
153   - tenantState = new TenantApiUsageState(dbStateEntity.getEntityId());
  153 + tenantState = new TenantApiUsageState(dbStateEntity.getId());
154 154 try {
155 155 List<TsKvEntry> dbValues = tsService.findAllLatest(tenantId, dbStateEntity.getEntityId()).get();
156 156 for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {
... ...
... ... @@ -17,6 +17,7 @@ package org.thingsboard.server.service.apiusage;
17 17
18 18 import lombok.Getter;
19 19 import org.thingsboard.server.common.data.ApiUsageRecordKey;
  20 +import org.thingsboard.server.common.data.id.ApiUsageStateId;
20 21 import org.thingsboard.server.common.data.id.EntityId;
21 22 import org.thingsboard.server.common.msg.tools.SchedulerUtils;
22 23
... ... @@ -29,7 +30,7 @@ public class TenantApiUsageState {
29 30 private final Map<ApiUsageRecordKey, Long> currentHourValues = new ConcurrentHashMap<>();
30 31
31 32 @Getter
32   - private final EntityId entityId;
  33 + private final ApiUsageStateId id;
33 34 @Getter
34 35 private volatile long currentCycleTs;
35 36 @Getter
... ... @@ -37,8 +38,8 @@ public class TenantApiUsageState {
37 38 @Getter
38 39 private volatile long currentHourTs;
39 40
40   - public TenantApiUsageState(EntityId entityId) {
41   - this.entityId = entityId;
  41 + public TenantApiUsageState(ApiUsageStateId id) {
  42 + this.id = id;
42 43 this.currentCycleTs = SchedulerUtils.getStartOfCurrentMonth();
43 44 this.nextCycleTs = SchedulerUtils.getStartOfNextMonth();
44 45 this.currentHourTs = SchedulerUtils.getStartOfCurrentHour();
... ...
... ... @@ -396,6 +396,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
396 396 if (mainConsumer != null) {
397 397 mainConsumer.unsubscribe();
398 398 }
  399 + if (usageStatsConsumer != null) {
  400 + usageStatsConsumer.unsubscribe();
  401 + }
399 402 }
400 403
401 404 }
... ...
... ... @@ -25,6 +25,7 @@ import org.springframework.http.ResponseEntity;
25 25 import org.springframework.stereotype.Component;
26 26 import org.springframework.web.context.request.async.DeferredResult;
27 27 import org.thingsboard.common.util.ThingsBoardThreadFactory;
  28 +import org.thingsboard.server.common.data.ApiUsageState;
28 29 import org.thingsboard.server.common.data.Customer;
29 30 import org.thingsboard.server.common.data.Device;
30 31 import org.thingsboard.server.common.data.DeviceProfile;
... ... @@ -33,6 +34,7 @@ import org.thingsboard.server.common.data.Tenant;
33 34 import org.thingsboard.server.common.data.User;
34 35 import org.thingsboard.server.common.data.asset.Asset;
35 36 import org.thingsboard.server.common.data.exception.ThingsboardException;
  37 +import org.thingsboard.server.common.data.id.ApiUsageStateId;
36 38 import org.thingsboard.server.common.data.id.AssetId;
37 39 import org.thingsboard.server.common.data.id.CustomerId;
38 40 import org.thingsboard.server.common.data.id.DeviceId;
... ... @@ -55,6 +57,7 @@ import org.thingsboard.server.dao.device.DeviceService;
55 57 import org.thingsboard.server.dao.entityview.EntityViewService;
56 58 import org.thingsboard.server.dao.rule.RuleChainService;
57 59 import org.thingsboard.server.dao.tenant.TenantService;
  60 +import org.thingsboard.server.dao.usagerecord.ApiUsageStateService;
58 61 import org.thingsboard.server.dao.user.UserService;
59 62 import org.thingsboard.server.service.security.model.SecurityUser;
60 63 import org.thingsboard.server.service.security.permission.AccessControlService;
... ... @@ -111,6 +114,9 @@ public class AccessValidator {
111 114 @Autowired
112 115 protected AccessControlService accessControlService;
113 116
  117 + @Autowired
  118 + protected ApiUsageStateService apiUsageStateService;
  119 +
114 120 private ExecutorService executor;
115 121
116 122 @PostConstruct
... ... @@ -193,6 +199,9 @@ public class AccessValidator {
193 199 case ENTITY_VIEW:
194 200 validateEntityView(currentUser, operation, entityId, callback);
195 201 return;
  202 + case API_USAGE_STATE:
  203 + validateApiUsageState(currentUser, operation, entityId, callback);
  204 + return;
196 205 default:
197 206 //TODO: add support of other entities
198 207 throw new IllegalStateException("Not Implemented!");
... ... @@ -237,6 +246,24 @@ public class AccessValidator {
237 246 }
238 247 }
239 248
  249 + private void validateApiUsageState(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) {
  250 + if (currentUser.isSystemAdmin()) {
  251 + callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
  252 + } else {
  253 + ApiUsageState apiUsageState = apiUsageStateService.findApiUsageStateById(currentUser.getTenantId(), new ApiUsageStateId(entityId.getId()));
  254 + if (apiUsageState == null) {
  255 + callback.onSuccess(ValidationResult.entityNotFound("Api Usage State with requested id wasn't found!"));
  256 + } else {
  257 + try {
  258 + accessControlService.checkPermission(currentUser, Resource.API_USAGE_STATE, operation, entityId, apiUsageState);
  259 + } catch (ThingsboardException e) {
  260 + callback.onSuccess(ValidationResult.accessDenied(e.getMessage()));
  261 + }
  262 + callback.onSuccess(ValidationResult.ok(apiUsageState));
  263 + }
  264 + }
  265 + }
  266 +
240 267 private void validateAsset(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) {
241 268 if (currentUser.isSystemAdmin()) {
242 269 callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
... ...
... ... @@ -35,7 +35,8 @@ public enum Resource {
35 35 OAUTH2_CONFIGURATION_INFO(),
36 36 OAUTH2_CONFIGURATION_TEMPLATE(),
37 37 TENANT_PROFILE(EntityType.TENANT_PROFILE),
38   - DEVICE_PROFILE(EntityType.DEVICE_PROFILE);
  38 + DEVICE_PROFILE(EntityType.DEVICE_PROFILE),
  39 + API_USAGE_STATE(EntityType.API_USAGE_STATE);
39 40
40 41 private final EntityType entityType;
41 42
... ...
... ... @@ -40,6 +40,7 @@ public class TenantAdminPermissions extends AbstractPermissions {
40 40 put(Resource.WIDGETS_BUNDLE, widgetsPermissionChecker);
41 41 put(Resource.WIDGET_TYPE, widgetsPermissionChecker);
42 42 put(Resource.DEVICE_PROFILE, tenantEntityPermissionChecker);
  43 + put(Resource.API_USAGE_STATE, tenantEntityPermissionChecker);
43 44 }
44 45
45 46 public static final PermissionChecker tenantEntityPermissionChecker = new PermissionChecker() {
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.dao.usagerecord;
17 17
18 18 import org.thingsboard.server.common.data.ApiUsageState;
  19 +import org.thingsboard.server.common.data.id.ApiUsageStateId;
19 20 import org.thingsboard.server.common.data.id.TenantId;
20 21
21 22 public interface ApiUsageStateService {
... ... @@ -25,4 +26,6 @@ public interface ApiUsageStateService {
25 26 void deleteApiUsageStateByTenantId(TenantId tenantId);
26 27
27 28 ApiUsageState createDefaultApiUsageState(TenantId id);
  29 +
  30 + ApiUsageState findApiUsageStateById(TenantId tenantId, ApiUsageStateId id);
28 31 }
... ...
... ... @@ -66,6 +66,8 @@ public class EntityIdFactory {
66 66 return new DeviceProfileId(uuid);
67 67 case TENANT_PROFILE:
68 68 return new TenantProfileId(uuid);
  69 + case API_USAGE_STATE:
  70 + return new ApiUsageStateId(uuid);
69 71 }
70 72 throw new IllegalArgumentException("EntityType " + type + " is not supported!");
71 73 }
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.id.EntityId;
  20 +
  21 +@Data
  22 +public class ApiUsageStateFilter implements EntityFilter {
  23 + @Override
  24 + public EntityFilterType getType() {
  25 + return EntityFilterType.API_USAGE_STATE;
  26 + }
  27 +
  28 +}
... ...
... ... @@ -32,6 +32,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
32 32 @JsonSubTypes.Type(value = AssetTypeFilter.class, name = "assetType"),
33 33 @JsonSubTypes.Type(value = DeviceTypeFilter.class, name = "deviceType"),
34 34 @JsonSubTypes.Type(value = EntityViewTypeFilter.class, name = "entityViewType"),
  35 + @JsonSubTypes.Type(value = ApiUsageStateFilter.class, name = "apiUsageState"),
35 36 @JsonSubTypes.Type(value = RelationsQueryFilter.class, name = "relationsQuery"),
36 37 @JsonSubTypes.Type(value = AssetSearchQueryFilter.class, name = "assetSearchQuery"),
37 38 @JsonSubTypes.Type(value = DeviceSearchQueryFilter.class, name = "deviceSearchQuery"),
... ...
... ... @@ -25,7 +25,8 @@ public enum EntityFilterType {
25 25 RELATIONS_QUERY("relationsQuery"),
26 26 ASSET_SEARCH_QUERY("assetSearchQuery"),
27 27 DEVICE_SEARCH_QUERY("deviceSearchQuery"),
28   - ENTITY_VIEW_SEARCH_QUERY("entityViewSearchQuery");
  28 + ENTITY_VIEW_SEARCH_QUERY("entityViewSearchQuery"),
  29 + API_USAGE_STATE("apiUsageState");
29 30
30 31 private final String label;
31 32
... ...
... ... @@ -210,6 +210,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
210 210 entityTableMap.put(EntityType.CUSTOMER, "customer");
211 211 entityTableMap.put(EntityType.USER, "tb_user");
212 212 entityTableMap.put(EntityType.TENANT, "tenant");
  213 + entityTableMap.put(EntityType.API_USAGE_STATE, "(select aus.id, aus.created_time, aus.tenant_id, '' as name, '' as additional_info from api_usage_state as aus)");
213 214 }
214 215
215 216 public static EntityType[] RELATION_QUERY_ENTITY_TYPES = new EntityType[]{
... ... @@ -431,6 +432,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
431 432 case DEVICE_SEARCH_QUERY:
432 433 case ASSET_SEARCH_QUERY:
433 434 case ENTITY_VIEW_SEARCH_QUERY:
  435 + case API_USAGE_STATE:
434 436 return "";
435 437 default:
436 438 throw new RuntimeException("Not implemented!");
... ... @@ -682,6 +684,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
682 684 return EntityType.ENTITY_VIEW;
683 685 case RELATIONS_QUERY:
684 686 return ((RelationsQueryFilter) entityFilter).getRootEntity().getEntityType();
  687 + case API_USAGE_STATE:
  688 + return EntityType.API_USAGE_STATE;
685 689 default:
686 690 throw new RuntimeException("Not implemented!");
687 691 }
... ...
... ... @@ -20,6 +20,7 @@ import org.springframework.stereotype.Service;
20 20 import org.thingsboard.server.common.data.EntityType;
21 21 import org.thingsboard.server.common.data.Tenant;
22 22 import org.thingsboard.server.common.data.ApiUsageState;
  23 +import org.thingsboard.server.common.data.id.ApiUsageStateId;
23 24 import org.thingsboard.server.common.data.id.TenantId;
24 25 import org.thingsboard.server.dao.entity.AbstractEntityService;
25 26 import org.thingsboard.server.dao.exception.DataValidationException;
... ... @@ -66,6 +67,13 @@ public class ApiApiUsageStateServiceImpl extends AbstractEntityService implement
66 67 return apiUsageStateDao.findTenantApiUsageState(tenantId.getId());
67 68 }
68 69
  70 + @Override
  71 + public ApiUsageState findApiUsageStateById(TenantId tenantId, ApiUsageStateId id) {
  72 + log.trace("Executing findApiUsageStateById, tenantId [{}], apiUsageStateId [{}]", tenantId, id);
  73 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  74 + validateId(id, "Incorrect apiUsageStateId " + id);
  75 + return apiUsageStateDao.findById(tenantId, id.getId()); }
  76 +
69 77 private DataValidator<ApiUsageState> apiUsageStateValidator =
70 78 new DataValidator<ApiUsageState>() {
71 79 @Override
... ...
... ... @@ -753,6 +753,9 @@ export class EntityService {
753 753 case AliasFilterType.entityViewType:
754 754 result.entityFilter = deepClone(filter);
755 755 return of(result);
  756 + case AliasFilterType.apiUsageState:
  757 + result.entityFilter = deepClone(filter);
  758 + return of(result);
756 759 case AliasFilterType.relationsQuery:
757 760 result.stateEntity = filter.rootStateEntity;
758 761 let rootEntityType;
... ...
... ... @@ -28,6 +28,7 @@ export enum AliasFilterType {
28 28 assetType = 'assetType',
29 29 deviceType = 'deviceType',
30 30 entityViewType = 'entityViewType',
  31 + apiUsageState = 'apiUsageState',
31 32 relationsQuery = 'relationsQuery',
32 33 assetSearchQuery = 'assetSearchQuery',
33 34 deviceSearchQuery = 'deviceSearchQuery',
... ... @@ -43,6 +44,7 @@ export const aliasFilterTypeTranslationMap = new Map<AliasFilterType, string>(
43 44 [ AliasFilterType.assetType, 'alias.filter-type-asset-type' ],
44 45 [ AliasFilterType.deviceType, 'alias.filter-type-device-type' ],
45 46 [ AliasFilterType.entityViewType, 'alias.filter-type-entity-view-type' ],
  47 + [ AliasFilterType.apiUsageState, 'alias.filter-type-apiUsageState' ],
46 48 [ AliasFilterType.relationsQuery, 'alias.filter-type-relations-query' ],
47 49 [ AliasFilterType.assetSearchQuery, 'alias.filter-type-asset-search-query' ],
48 50 [ AliasFilterType.deviceSearchQuery, 'alias.filter-type-device-search-query' ],
... ... @@ -106,6 +108,10 @@ export interface EntitySearchQueryFilter {
106 108 fetchLastLevelOnly?: boolean;
107 109 }
108 110
  111 +export interface ApiUsageStateFilter {
  112 +
  113 +}
  114 +
109 115 export interface AssetSearchQueryFilter extends EntitySearchQueryFilter {
110 116 assetTypes?: string[];
111 117 }
... ... @@ -129,7 +135,8 @@ export type EntityFilters =
129 135 RelationsQueryFilter &
130 136 AssetSearchQueryFilter &
131 137 DeviceSearchQueryFilter &
132   - EntityViewSearchQueryFilter;
  138 + EntityViewSearchQueryFilter &
  139 + EntitySearchQueryFilter;
133 140
134 141 export interface EntityAliasFilter extends EntityFilters {
135 142 type?: AliasFilterType;
... ...
... ... @@ -288,6 +288,7 @@
288 288 "filter-type-device-search-query-description": "Devices with types {{deviceTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}",
289 289 "filter-type-entity-view-search-query": "Entity view search query",
290 290 "filter-type-entity-view-search-query-description": "Entity views with types {{entityViewTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}",
  291 + "filter-type-apiUsageState": "Api Usage State",
291 292 "entity-filter": "Entity filter",
292 293 "resolve-multiple": "Resolve as multiple entities",
293 294 "filter-type": "Filter type",
... ...