Browse Source
# Conflicts: # application/src/main/java/org/thingsboard/server/controller/AdminController.java # application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java # application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.javapull/7297/head
1075 changed files with 36973 additions and 8393 deletions
@ -0,0 +1,234 @@ |
|||
-- |
|||
-- Copyright © 2016-2022 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. |
|||
-- |
|||
|
|||
CREATE TABLE IF NOT EXISTS rule_node_debug_event ( |
|||
id uuid NOT NULL, |
|||
tenant_id uuid NOT NULL , |
|||
ts bigint NOT NULL, |
|||
entity_id uuid NOT NULL, |
|||
service_id varchar, |
|||
e_type varchar, |
|||
e_entity_id uuid, |
|||
e_entity_type varchar, |
|||
e_msg_id uuid, |
|||
e_msg_type varchar, |
|||
e_data_type varchar, |
|||
e_relation_type varchar, |
|||
e_data varchar, |
|||
e_metadata varchar, |
|||
e_error varchar |
|||
) PARTITION BY RANGE (ts); |
|||
|
|||
CREATE TABLE IF NOT EXISTS rule_chain_debug_event ( |
|||
id uuid NOT NULL, |
|||
tenant_id uuid NOT NULL, |
|||
ts bigint NOT NULL, |
|||
entity_id uuid NOT NULL, |
|||
service_id varchar NOT NULL, |
|||
e_message varchar, |
|||
e_error varchar |
|||
) PARTITION BY RANGE (ts); |
|||
|
|||
CREATE TABLE IF NOT EXISTS stats_event ( |
|||
id uuid NOT NULL, |
|||
tenant_id uuid NOT NULL, |
|||
ts bigint NOT NULL, |
|||
entity_id uuid NOT NULL, |
|||
service_id varchar NOT NULL, |
|||
e_messages_processed bigint NOT NULL, |
|||
e_errors_occurred bigint NOT NULL |
|||
) PARTITION BY RANGE (ts); |
|||
|
|||
CREATE TABLE IF NOT EXISTS lc_event ( |
|||
id uuid NOT NULL, |
|||
tenant_id uuid NOT NULL, |
|||
ts bigint NOT NULL, |
|||
entity_id uuid NOT NULL, |
|||
service_id varchar NOT NULL, |
|||
e_type varchar NOT NULL, |
|||
e_success boolean NOT NULL, |
|||
e_error varchar |
|||
) PARTITION BY RANGE (ts); |
|||
|
|||
CREATE TABLE IF NOT EXISTS error_event ( |
|||
id uuid NOT NULL, |
|||
tenant_id uuid NOT NULL, |
|||
ts bigint NOT NULL, |
|||
entity_id uuid NOT NULL, |
|||
service_id varchar NOT NULL, |
|||
e_method varchar NOT NULL, |
|||
e_error varchar |
|||
) PARTITION BY RANGE (ts); |
|||
|
|||
CREATE INDEX IF NOT EXISTS idx_rule_node_debug_event_main |
|||
ON rule_node_debug_event (tenant_id ASC, entity_id ASC, ts DESC NULLS LAST) WITH (FILLFACTOR=95); |
|||
|
|||
CREATE INDEX IF NOT EXISTS idx_rule_chain_debug_event_main |
|||
ON rule_chain_debug_event (tenant_id ASC, entity_id ASC, ts DESC NULLS LAST) WITH (FILLFACTOR=95); |
|||
|
|||
CREATE INDEX IF NOT EXISTS idx_stats_event_main |
|||
ON stats_event (tenant_id ASC, entity_id ASC, ts DESC NULLS LAST) WITH (FILLFACTOR=95); |
|||
|
|||
CREATE INDEX IF NOT EXISTS idx_lc_event_main |
|||
ON lc_event (tenant_id ASC, entity_id ASC, ts DESC NULLS LAST) WITH (FILLFACTOR=95); |
|||
|
|||
CREATE INDEX IF NOT EXISTS idx_error_event_main |
|||
ON error_event (tenant_id ASC, entity_id ASC, ts DESC NULLS LAST) WITH (FILLFACTOR=95); |
|||
|
|||
CREATE OR REPLACE FUNCTION to_safe_json(p_json text) RETURNS json |
|||
LANGUAGE plpgsql AS |
|||
$$ |
|||
BEGIN |
|||
return REPLACE(p_json, '\u0000', '' )::json; |
|||
EXCEPTION |
|||
WHEN OTHERS THEN |
|||
return '{}'::json; |
|||
END; |
|||
$$; |
|||
|
|||
-- Useful to migrate old events to the new table structure; |
|||
CREATE OR REPLACE PROCEDURE migrate_regular_events(IN start_ts_in_ms bigint, IN end_ts_in_ms bigint, IN partition_size_in_hours int) |
|||
LANGUAGE plpgsql AS |
|||
$$ |
|||
DECLARE |
|||
partition_size_in_ms bigint; |
|||
p record; |
|||
table_name varchar; |
|||
BEGIN |
|||
partition_size_in_ms = partition_size_in_hours * 3600 * 1000; |
|||
|
|||
FOR p IN SELECT DISTINCT event_type as event_type, (created_time - created_time % partition_size_in_ms) as partition_ts FROM event e WHERE e.event_type in ('STATS', 'LC_EVENT', 'ERROR') and ts >= start_ts_in_ms and ts < end_ts_in_ms |
|||
LOOP |
|||
IF p.event_type = 'STATS' THEN |
|||
table_name := 'stats_event'; |
|||
ELSEIF p.event_type = 'LC_EVENT' THEN |
|||
table_name := 'lc_event'; |
|||
ELSEIF p.event_type = 'ERROR' THEN |
|||
table_name := 'error_event'; |
|||
END IF; |
|||
RAISE NOTICE '[%] Partition to create : [%-%]', table_name, p.partition_ts, (p.partition_ts + partition_size_in_ms); |
|||
EXECUTE format('CREATE TABLE IF NOT EXISTS %s_%s PARTITION OF %s FOR VALUES FROM ( %s ) TO ( %s )', table_name, p.partition_ts, table_name, p.partition_ts, (p.partition_ts + partition_size_in_ms)); |
|||
END LOOP; |
|||
|
|||
INSERT INTO stats_event |
|||
SELECT id, |
|||
tenant_id, |
|||
ts, |
|||
entity_id, |
|||
body ->> 'server', |
|||
(body ->> 'messagesProcessed')::bigint, |
|||
(body ->> 'errorsOccurred')::bigint |
|||
FROM |
|||
(select id, tenant_id, ts, entity_id, to_safe_json(body) as body |
|||
FROM event WHERE ts >= start_ts_in_ms and ts < end_ts_in_ms AND event_type = 'STATS' AND to_safe_json(body) ->> 'server' IS NOT NULL |
|||
) safe_event |
|||
ON CONFLICT DO NOTHING; |
|||
|
|||
INSERT INTO lc_event |
|||
SELECT id, |
|||
tenant_id, |
|||
ts, |
|||
entity_id, |
|||
body ->> 'server', |
|||
body ->> 'event', |
|||
(body ->> 'success')::boolean, |
|||
body ->> 'error' |
|||
FROM |
|||
(select id, tenant_id, ts, entity_id, to_safe_json(body) as body |
|||
FROM event WHERE ts >= start_ts_in_ms and ts < end_ts_in_ms AND event_type = 'LC_EVENT' AND to_safe_json(body) ->> 'server' IS NOT NULL |
|||
) safe_event |
|||
ON CONFLICT DO NOTHING; |
|||
|
|||
INSERT INTO error_event |
|||
SELECT id, |
|||
tenant_id, |
|||
ts, |
|||
entity_id, |
|||
body ->> 'server', |
|||
body ->> 'method', |
|||
body ->> 'error' |
|||
FROM |
|||
(select id, tenant_id, ts, entity_id, to_safe_json(body) as body |
|||
FROM event WHERE ts >= start_ts_in_ms and ts < end_ts_in_ms AND event_type = 'ERROR' AND to_safe_json(body) ->> 'server' IS NOT NULL |
|||
) safe_event |
|||
ON CONFLICT DO NOTHING; |
|||
|
|||
END |
|||
$$; |
|||
|
|||
-- Useful to migrate old debug events to the new table structure; |
|||
CREATE OR REPLACE PROCEDURE migrate_debug_events(IN start_ts_in_ms bigint, IN end_ts_in_ms bigint, IN partition_size_in_hours int) |
|||
LANGUAGE plpgsql AS |
|||
$$ |
|||
DECLARE |
|||
partition_size_in_ms bigint; |
|||
p record; |
|||
table_name varchar; |
|||
BEGIN |
|||
partition_size_in_ms = partition_size_in_hours * 3600 * 1000; |
|||
|
|||
FOR p IN SELECT DISTINCT event_type as event_type, (created_time - created_time % partition_size_in_ms) as partition_ts FROM event e WHERE e.event_type in ('DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN') and ts >= start_ts_in_ms and ts < end_ts_in_ms |
|||
LOOP |
|||
IF p.event_type = 'DEBUG_RULE_NODE' THEN |
|||
table_name := 'rule_node_debug_event'; |
|||
ELSEIF p.event_type = 'DEBUG_RULE_CHAIN' THEN |
|||
table_name := 'rule_chain_debug_event'; |
|||
END IF; |
|||
RAISE NOTICE '[%] Partition to create : [%-%]', table_name, p.partition_ts, (p.partition_ts + partition_size_in_ms); |
|||
EXECUTE format('CREATE TABLE IF NOT EXISTS %s_%s PARTITION OF %s FOR VALUES FROM ( %s ) TO ( %s )', table_name, p.partition_ts, table_name, p.partition_ts, (p.partition_ts + partition_size_in_ms)); |
|||
END LOOP; |
|||
|
|||
INSERT INTO rule_node_debug_event |
|||
SELECT id, |
|||
tenant_id, |
|||
ts, |
|||
entity_id, |
|||
body ->> 'server', |
|||
body ->> 'type', |
|||
(body ->> 'entityId')::uuid, |
|||
body ->> 'entityName', |
|||
(body ->> 'msgId')::uuid, |
|||
body ->> 'msgType', |
|||
body ->> 'dataType', |
|||
body ->> 'relationType', |
|||
body ->> 'data', |
|||
body ->> 'metadata', |
|||
body ->> 'error' |
|||
FROM |
|||
(select id, tenant_id, ts, entity_id, to_safe_json(body) as body |
|||
FROM event WHERE ts >= start_ts_in_ms and ts < end_ts_in_ms AND event_type = 'DEBUG_RULE_NODE' AND to_safe_json(body) ->> 'server' IS NOT NULL |
|||
) safe_event |
|||
ON CONFLICT DO NOTHING; |
|||
|
|||
INSERT INTO rule_chain_debug_event |
|||
SELECT id, |
|||
tenant_id, |
|||
ts, |
|||
entity_id, |
|||
body ->> 'server', |
|||
body ->> 'message', |
|||
body ->> 'error' |
|||
FROM |
|||
(select id, tenant_id, ts, entity_id, to_safe_json(body) as body |
|||
FROM event WHERE ts >= start_ts_in_ms and ts < end_ts_in_ms AND event_type = 'DEBUG_RULE_CHAIN' AND to_safe_json(body) ->> 'server' IS NOT NULL |
|||
) safe_event |
|||
ON CONFLICT DO NOTHING; |
|||
END |
|||
$$; |
|||
|
|||
UPDATE tb_user |
|||
SET additional_info = REPLACE(additional_info, '"lang":"ja_JA"', '"lang":"ja_JP"') |
|||
WHERE additional_info LIKE '%"lang":"ja_JA"%'; |
|||
@ -0,0 +1,74 @@ |
|||
-- |
|||
-- Copyright © 2016-2022 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. |
|||
-- |
|||
|
|||
DO |
|||
$$ |
|||
DECLARE table_partition RECORD; |
|||
BEGIN |
|||
-- in case of running the upgrade script a second time: |
|||
IF NOT (SELECT exists(SELECT FROM pg_tables WHERE tablename = 'old_audit_log')) THEN |
|||
ALTER TABLE audit_log RENAME TO old_audit_log; |
|||
ALTER INDEX IF EXISTS idx_audit_log_tenant_id_and_created_time RENAME TO idx_old_audit_log_tenant_id_and_created_time; |
|||
|
|||
FOR table_partition IN SELECT tablename AS name, split_part(tablename, '_', 3) AS partition_ts |
|||
FROM pg_tables WHERE tablename LIKE 'audit_log_%' |
|||
LOOP |
|||
EXECUTE format('ALTER TABLE %s RENAME TO old_audit_log_%s', table_partition.name, table_partition.partition_ts); |
|||
END LOOP; |
|||
ELSE |
|||
RAISE NOTICE 'Table old_audit_log already exists, leaving as is'; |
|||
END IF; |
|||
END; |
|||
$$; |
|||
|
|||
CREATE TABLE IF NOT EXISTS audit_log ( |
|||
id uuid NOT NULL, |
|||
created_time bigint NOT NULL, |
|||
tenant_id uuid, |
|||
customer_id uuid, |
|||
entity_id uuid, |
|||
entity_type varchar(255), |
|||
entity_name varchar(255), |
|||
user_id uuid, |
|||
user_name varchar(255), |
|||
action_type varchar(255), |
|||
action_data varchar(1000000), |
|||
action_status varchar(255), |
|||
action_failure_details varchar(1000000) |
|||
) PARTITION BY RANGE (created_time); |
|||
CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time DESC); |
|||
|
|||
CREATE OR REPLACE PROCEDURE migrate_audit_logs(IN start_time_ms BIGINT, IN end_time_ms BIGINT, IN partition_size_ms BIGINT) |
|||
LANGUAGE plpgsql AS |
|||
$$ |
|||
DECLARE |
|||
p RECORD; |
|||
partition_end_ts BIGINT; |
|||
BEGIN |
|||
FOR p IN SELECT DISTINCT (created_time - created_time % partition_size_ms) AS partition_ts FROM old_audit_log |
|||
WHERE created_time >= start_time_ms AND created_time < end_time_ms |
|||
LOOP |
|||
partition_end_ts = p.partition_ts + partition_size_ms; |
|||
RAISE NOTICE '[audit_log] Partition to create : [%-%]', p.partition_ts, partition_end_ts; |
|||
EXECUTE format('CREATE TABLE IF NOT EXISTS audit_log_%s PARTITION OF audit_log ' || |
|||
'FOR VALUES FROM ( %s ) TO ( %s )', p.partition_ts, p.partition_ts, partition_end_ts); |
|||
END LOOP; |
|||
|
|||
INSERT INTO audit_log |
|||
SELECT * FROM old_audit_log |
|||
WHERE created_time >= start_time_ms AND created_time < end_time_ms; |
|||
END; |
|||
$$; |
|||
@ -0,0 +1,21 @@ |
|||
-- |
|||
-- Copyright © 2016-2022 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. |
|||
-- |
|||
|
|||
DROP PROCEDURE IF EXISTS update_asset_profiles; |
|||
|
|||
ALTER TABLE asset ALTER COLUMN asset_profile_id SET NOT NULL; |
|||
ALTER TABLE asset DROP CONSTRAINT IF EXISTS fk_asset_profile; |
|||
ALTER TABLE asset ADD CONSTRAINT fk_asset_profile FOREIGN KEY (asset_profile_id) REFERENCES asset_profile(id); |
|||
@ -0,0 +1,45 @@ |
|||
-- |
|||
-- Copyright © 2016-2022 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. |
|||
-- |
|||
|
|||
CREATE TABLE IF NOT EXISTS asset_profile ( |
|||
id uuid NOT NULL CONSTRAINT asset_profile_pkey PRIMARY KEY, |
|||
created_time bigint NOT NULL, |
|||
name varchar(255), |
|||
image varchar(1000000), |
|||
description varchar, |
|||
search_text varchar(255), |
|||
is_default boolean, |
|||
tenant_id uuid, |
|||
default_rule_chain_id uuid, |
|||
default_dashboard_id uuid, |
|||
default_queue_name varchar(255), |
|||
external_id uuid, |
|||
CONSTRAINT asset_profile_name_unq_key UNIQUE (tenant_id, name), |
|||
CONSTRAINT asset_profile_external_id_unq_key UNIQUE (tenant_id, external_id), |
|||
CONSTRAINT fk_default_rule_chain_asset_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id), |
|||
CONSTRAINT fk_default_dashboard_asset_profile FOREIGN KEY (default_dashboard_id) REFERENCES dashboard(id) |
|||
); |
|||
|
|||
CREATE OR REPLACE PROCEDURE update_asset_profiles() |
|||
LANGUAGE plpgsql AS |
|||
$$ |
|||
BEGIN |
|||
UPDATE asset as a SET asset_profile_id = p.id |
|||
FROM |
|||
(SELECT id, tenant_id, name from asset_profile) as p |
|||
WHERE a.asset_profile_id IS NULL AND p.tenant_id = a.tenant_id AND a.type = p.name; |
|||
END; |
|||
$$; |
|||
@ -0,0 +1,227 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.controller; |
|||
|
|||
import io.swagger.annotations.ApiOperation; |
|||
import io.swagger.annotations.ApiParam; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.PathVariable; |
|||
import org.springframework.web.bind.annotation.RequestBody; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestMethod; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.ResponseBody; |
|||
import org.springframework.web.bind.annotation.ResponseStatus; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.thingsboard.server.common.data.asset.AssetProfile; |
|||
import org.thingsboard.server.common.data.asset.AssetProfileInfo; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.AssetProfileId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.dao.timeseries.TimeseriesService; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.entitiy.asset.profile.TbAssetProfileService; |
|||
import org.thingsboard.server.service.security.permission.Operation; |
|||
import org.thingsboard.server.service.security.permission.Resource; |
|||
|
|||
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_ID; |
|||
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_ID_PARAM_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_INFO_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES; |
|||
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_TEXT_SEARCH_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; |
|||
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; |
|||
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; |
|||
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; |
|||
import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; |
|||
import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; |
|||
|
|||
@RestController |
|||
@TbCoreComponent |
|||
@RequestMapping("/api") |
|||
@RequiredArgsConstructor |
|||
@Slf4j |
|||
public class AssetProfileController extends BaseController { |
|||
|
|||
private final TbAssetProfileService tbAssetProfileService; |
|||
|
|||
@ApiOperation(value = "Get Asset Profile (getAssetProfileById)", |
|||
notes = "Fetch the Asset Profile object based on the provided Asset Profile Id. " + |
|||
"The server checks that the asset profile is owned by the same tenant. " + TENANT_AUTHORITY_PARAGRAPH, |
|||
produces = "application/json") |
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/assetProfile/{assetProfileId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public AssetProfile getAssetProfileById( |
|||
@ApiParam(value = ASSET_PROFILE_ID_PARAM_DESCRIPTION) |
|||
@PathVariable(ASSET_PROFILE_ID) String strAssetProfileId) throws ThingsboardException { |
|||
checkParameter(ASSET_PROFILE_ID, strAssetProfileId); |
|||
try { |
|||
AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId)); |
|||
return checkAssetProfileId(assetProfileId, Operation.READ); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@ApiOperation(value = "Get Asset Profile Info (getAssetProfileInfoById)", |
|||
notes = "Fetch the Asset Profile Info object based on the provided Asset Profile Id. " |
|||
+ ASSET_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, |
|||
produces = "application/json") |
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/assetProfileInfo/{assetProfileId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public AssetProfileInfo getAssetProfileInfoById( |
|||
@ApiParam(value = ASSET_PROFILE_ID_PARAM_DESCRIPTION) |
|||
@PathVariable(ASSET_PROFILE_ID) String strAssetProfileId) throws ThingsboardException { |
|||
checkParameter(ASSET_PROFILE_ID, strAssetProfileId); |
|||
try { |
|||
AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId)); |
|||
return new AssetProfileInfo(checkAssetProfileId(assetProfileId, Operation.READ)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@ApiOperation(value = "Get Default Asset Profile (getDefaultAssetProfileInfo)", |
|||
notes = "Fetch the Default Asset Profile Info object. " + |
|||
ASSET_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, |
|||
produces = "application/json") |
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/assetProfileInfo/default", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public AssetProfileInfo getDefaultAssetProfileInfo() throws ThingsboardException { |
|||
try { |
|||
return checkNotNull(assetProfileService.findDefaultAssetProfileInfo(getTenantId())); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@ApiOperation(value = "Create Or Update Asset Profile (saveAssetProfile)", |
|||
notes = "Create or update the Asset Profile. When creating asset profile, platform generates asset profile id as " + UUID_WIKI_LINK + |
|||
"The newly created asset profile id will be present in the response. " + |
|||
"Specify existing asset profile id to update the asset profile. " + |
|||
"Referencing non-existing asset profile Id will cause 'Not Found' error. " + NEW_LINE + |
|||
"Asset profile name is unique in the scope of tenant. Only one 'default' asset profile may exist in scope of tenant. " + |
|||
"Remove 'id', 'tenantId' from the request body example (below) to create new Asset Profile entity. " + |
|||
TENANT_AUTHORITY_PARAGRAPH, |
|||
produces = "application/json", |
|||
consumes = "application/json") |
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/assetProfile", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public AssetProfile saveAssetProfile( |
|||
@ApiParam(value = "A JSON value representing the asset profile.") |
|||
@RequestBody AssetProfile assetProfile) throws Exception { |
|||
assetProfile.setTenantId(getTenantId()); |
|||
checkEntity(assetProfile.getId(), assetProfile, Resource.ASSET_PROFILE); |
|||
return tbAssetProfileService.save(assetProfile, getCurrentUser()); |
|||
} |
|||
|
|||
@ApiOperation(value = "Delete asset profile (deleteAssetProfile)", |
|||
notes = "Deletes the asset profile. Referencing non-existing asset profile Id will cause an error. " + |
|||
"Can't delete the asset profile if it is referenced by existing assets." + TENANT_AUTHORITY_PARAGRAPH, |
|||
produces = "application/json") |
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/assetProfile/{assetProfileId}", method = RequestMethod.DELETE) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deleteAssetProfile( |
|||
@ApiParam(value = ASSET_PROFILE_ID_PARAM_DESCRIPTION) |
|||
@PathVariable(ASSET_PROFILE_ID) String strAssetProfileId) throws ThingsboardException { |
|||
checkParameter(ASSET_PROFILE_ID, strAssetProfileId); |
|||
AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId)); |
|||
AssetProfile assetProfile = checkAssetProfileId(assetProfileId, Operation.DELETE); |
|||
tbAssetProfileService.delete(assetProfile, getCurrentUser()); |
|||
} |
|||
|
|||
@ApiOperation(value = "Make Asset Profile Default (setDefaultAssetProfile)", |
|||
notes = "Marks asset profile as default within a tenant scope." + TENANT_AUTHORITY_PARAGRAPH, |
|||
produces = "application/json") |
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/assetProfile/{assetProfileId}/default", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public AssetProfile setDefaultAssetProfile( |
|||
@ApiParam(value = ASSET_PROFILE_ID_PARAM_DESCRIPTION) |
|||
@PathVariable(ASSET_PROFILE_ID) String strAssetProfileId) throws ThingsboardException { |
|||
checkParameter(ASSET_PROFILE_ID, strAssetProfileId); |
|||
AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId)); |
|||
AssetProfile assetProfile = checkAssetProfileId(assetProfileId, Operation.WRITE); |
|||
AssetProfile previousDefaultAssetProfile = assetProfileService.findDefaultAssetProfile(getTenantId()); |
|||
return tbAssetProfileService.setDefaultAssetProfile(assetProfile, previousDefaultAssetProfile, getCurrentUser()); |
|||
} |
|||
|
|||
@ApiOperation(value = "Get Asset Profiles (getAssetProfiles)", |
|||
notes = "Returns a page of asset profile objects owned by tenant. " + |
|||
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, |
|||
produces = "application/json") |
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/assetProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public PageData<AssetProfile> getAssetProfiles( |
|||
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) |
|||
@RequestParam int pageSize, |
|||
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) |
|||
@RequestParam int page, |
|||
@ApiParam(value = ASSET_PROFILE_TEXT_SEARCH_DESCRIPTION) |
|||
@RequestParam(required = false) String textSearch, |
|||
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ASSET_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES) |
|||
@RequestParam(required = false) String sortProperty, |
|||
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) |
|||
@RequestParam(required = false) String sortOrder) throws ThingsboardException { |
|||
try { |
|||
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
|||
return checkNotNull(assetProfileService.findAssetProfiles(getTenantId(), pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@ApiOperation(value = "Get Asset Profile infos (getAssetProfileInfos)", |
|||
notes = "Returns a page of asset profile info objects owned by tenant. " + |
|||
PAGE_DATA_PARAMETERS + ASSET_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, |
|||
produces = "application/json") |
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/assetProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public PageData<AssetProfileInfo> getAssetProfileInfos( |
|||
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) |
|||
@RequestParam int pageSize, |
|||
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) |
|||
@RequestParam int page, |
|||
@ApiParam(value = ASSET_PROFILE_TEXT_SEARCH_DESCRIPTION) |
|||
@RequestParam(required = false) String textSearch, |
|||
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ASSET_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES) |
|||
@RequestParam(required = false) String sortProperty, |
|||
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) |
|||
@RequestParam(required = false) String sortOrder) throws ThingsboardException { |
|||
try { |
|||
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
|||
return checkNotNull(assetProfileService.findAssetProfileInfos(getTenantId(), pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.edge.rpc.constructor; |
|||
|
|||
import com.google.protobuf.ByteString; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.asset.AssetProfile; |
|||
import org.thingsboard.server.common.data.id.AssetProfileId; |
|||
import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg; |
|||
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@TbCoreComponent |
|||
public class AssetProfileMsgConstructor { |
|||
|
|||
public AssetProfileUpdateMsg constructAssetProfileUpdatedMsg(UpdateMsgType msgType, AssetProfile assetProfile) { |
|||
AssetProfileUpdateMsg.Builder builder = AssetProfileUpdateMsg.newBuilder() |
|||
.setMsgType(msgType) |
|||
.setIdMSB(assetProfile.getId().getId().getMostSignificantBits()) |
|||
.setIdLSB(assetProfile.getId().getId().getLeastSignificantBits()) |
|||
.setName(assetProfile.getName()) |
|||
.setDefault(assetProfile.isDefault()); |
|||
if (assetProfile.getDefaultDashboardId() != null) { |
|||
builder.setDefaultDashboardIdMSB(assetProfile.getDefaultDashboardId().getId().getMostSignificantBits()) |
|||
.setDefaultDashboardIdLSB(assetProfile.getDefaultDashboardId().getId().getLeastSignificantBits()); |
|||
} |
|||
if (assetProfile.getDefaultQueueName() != null) { |
|||
builder.setDefaultQueueName(assetProfile.getDefaultQueueName()); |
|||
} |
|||
if (assetProfile.getDescription() != null) { |
|||
builder.setDescription(assetProfile.getDescription()); |
|||
} |
|||
if (assetProfile.getImage() != null) { |
|||
builder.setImage(ByteString.copyFrom(assetProfile.getImage().getBytes(StandardCharsets.UTF_8))); |
|||
} |
|||
return builder.build(); |
|||
} |
|||
|
|||
public AssetProfileUpdateMsg constructAssetProfileDeleteMsg(AssetProfileId assetProfileId) { |
|||
return AssetProfileUpdateMsg.newBuilder() |
|||
.setMsgType(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE) |
|||
.setIdMSB(assetProfileId.getId().getMostSignificantBits()) |
|||
.setIdLSB(assetProfileId.getId().getLeastSignificantBits()).build(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.edge.rpc.constructor; |
|||
|
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.gen.edge.v1.EdgeConfiguration; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
@Component |
|||
@TbCoreComponent |
|||
public class EdgeMsgConstructor { |
|||
|
|||
public EdgeConfiguration constructEdgeConfiguration(Edge edge) { |
|||
EdgeConfiguration.Builder builder = EdgeConfiguration.newBuilder() |
|||
.setEdgeIdMSB(edge.getId().getId().getMostSignificantBits()) |
|||
.setEdgeIdLSB(edge.getId().getId().getLeastSignificantBits()) |
|||
.setTenantIdMSB(edge.getTenantId().getId().getMostSignificantBits()) |
|||
.setTenantIdLSB(edge.getTenantId().getId().getLeastSignificantBits()) |
|||
.setName(edge.getName()) |
|||
.setType(edge.getType()) |
|||
.setRoutingKey(edge.getRoutingKey()) |
|||
.setSecret(edge.getSecret()) |
|||
.setAdditionalInfo(JacksonUtil.toString(edge.getAdditionalInfo())) |
|||
.setCloudType("CE"); |
|||
if (edge.getCustomerId() != null) { |
|||
builder.setCustomerIdMSB(edge.getCustomerId().getId().getMostSignificantBits()) |
|||
.setCustomerIdLSB(edge.getCustomerId().getId().getLeastSignificantBits()); |
|||
} |
|||
return builder.build(); |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.edge.rpc.fetch; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.EdgeUtils; |
|||
import org.thingsboard.server.common.data.asset.AssetProfile; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.dao.asset.AssetProfileService; |
|||
|
|||
@AllArgsConstructor |
|||
@Slf4j |
|||
public class AssetProfilesEdgeEventFetcher extends BasePageableEdgeEventFetcher<AssetProfile> { |
|||
|
|||
private final AssetProfileService assetProfileService; |
|||
|
|||
@Override |
|||
PageData<AssetProfile> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
return assetProfileService.findAssetProfiles(tenantId, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, AssetProfile assetProfile) { |
|||
return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ASSET_PROFILE, |
|||
EdgeEventActionType.ADDED, assetProfile.getId(), null); |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.edge.rpc.fetch; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.EdgeUtils; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
|
|||
@AllArgsConstructor |
|||
@Slf4j |
|||
public class DevicesEdgeEventFetcher extends BasePageableEdgeEventFetcher<Device> { |
|||
|
|||
private final DeviceService deviceService; |
|||
|
|||
@Override |
|||
PageData<Device> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
return deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edge.getId(), pageLink); |
|||
} |
|||
|
|||
@Override |
|||
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, Device device) { |
|||
return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, |
|||
EdgeEventActionType.ADDED, device.getId(), null); |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.edge.rpc.fetch; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.EdgeUtils; |
|||
import org.thingsboard.server.common.data.EntityView; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.dao.entityview.EntityViewService; |
|||
|
|||
@AllArgsConstructor |
|||
@Slf4j |
|||
public class EntityViewsEdgeEventFetcher extends BasePageableEdgeEventFetcher<EntityView> { |
|||
|
|||
private final EntityViewService entityViewService; |
|||
|
|||
@Override |
|||
PageData<EntityView> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
return entityViewService.findEntityViewsByTenantIdAndEdgeId(tenantId, edge.getId(), pageLink); |
|||
} |
|||
|
|||
@Override |
|||
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, EntityView entityView) { |
|||
return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ENTITY_VIEW, |
|||
EdgeEventActionType.ADDED, entityView.getId(), null); |
|||
} |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.edge.rpc.processor; |
|||
|
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.EdgeUtils; |
|||
import org.thingsboard.server.common.data.asset.AssetProfile; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.id.AssetProfileId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg; |
|||
import org.thingsboard.server.gen.edge.v1.DownlinkMsg; |
|||
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
@Component |
|||
@Slf4j |
|||
@TbCoreComponent |
|||
public class AssetProfileEdgeProcessor extends BaseEdgeProcessor { |
|||
|
|||
public DownlinkMsg convertAssetProfileEventToDownlink(EdgeEvent edgeEvent) { |
|||
AssetProfileId assetProfileId = new AssetProfileId(edgeEvent.getEntityId()); |
|||
DownlinkMsg downlinkMsg = null; |
|||
switch (edgeEvent.getAction()) { |
|||
case ADDED: |
|||
case UPDATED: |
|||
AssetProfile assetProfile = assetProfileService.findAssetProfileById(edgeEvent.getTenantId(), assetProfileId); |
|||
if (assetProfile != null) { |
|||
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction()); |
|||
AssetProfileUpdateMsg assetProfileUpdateMsg = |
|||
assetProfileMsgConstructor.constructAssetProfileUpdatedMsg(msgType, assetProfile); |
|||
downlinkMsg = DownlinkMsg.newBuilder() |
|||
.setDownlinkMsgId(EdgeUtils.nextPositiveInt()) |
|||
.addAssetProfileUpdateMsg(assetProfileUpdateMsg) |
|||
.build(); |
|||
} |
|||
break; |
|||
case DELETED: |
|||
AssetProfileUpdateMsg assetProfileUpdateMsg = |
|||
assetProfileMsgConstructor.constructAssetProfileDeleteMsg(assetProfileId); |
|||
downlinkMsg = DownlinkMsg.newBuilder() |
|||
.setDownlinkMsgId(EdgeUtils.nextPositiveInt()) |
|||
.addAssetProfileUpdateMsg(assetProfileUpdateMsg) |
|||
.build(); |
|||
break; |
|||
} |
|||
return downlinkMsg; |
|||
} |
|||
|
|||
public ListenableFuture<Void> processAssetProfileNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { |
|||
return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg); |
|||
} |
|||
|
|||
} |
|||
@ -1,235 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.edge.rpc.processor; |
|||
|
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.EdgeUtils; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.EdgeId; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.EntityIdFactory; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.common.data.rule.RuleChain; |
|||
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; |
|||
import org.thingsboard.server.gen.edge.v1.DeviceCredentialsRequestMsg; |
|||
import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg; |
|||
import org.thingsboard.server.gen.edge.v1.DownlinkMsg; |
|||
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
|
|||
@Component |
|||
@Slf4j |
|||
@TbCoreComponent |
|||
public class EntityEdgeProcessor extends BaseEdgeProcessor { |
|||
|
|||
public DownlinkMsg processEntityMergeRequestMessageToEdge(Edge edge, EdgeEvent edgeEvent) { |
|||
DownlinkMsg downlinkMsg = null; |
|||
if (EdgeEventType.DEVICE.equals(edgeEvent.getType())) { |
|||
DeviceId deviceId = new DeviceId(edgeEvent.getEntityId()); |
|||
Device device = deviceService.findDeviceById(edge.getTenantId(), deviceId); |
|||
CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(device, edge); |
|||
String conflictName = null; |
|||
if(edgeEvent.getBody() != null) { |
|||
conflictName = edgeEvent.getBody().get("conflictName").asText(); |
|||
} |
|||
DeviceUpdateMsg deviceUpdateMsg = deviceMsgConstructor |
|||
.constructDeviceUpdatedMsg(UpdateMsgType.ENTITY_MERGE_RPC_MESSAGE, device, customerId, conflictName); |
|||
downlinkMsg = DownlinkMsg.newBuilder() |
|||
.setDownlinkMsgId(EdgeUtils.nextPositiveInt()) |
|||
.addDeviceUpdateMsg(deviceUpdateMsg) |
|||
.build(); |
|||
} |
|||
return downlinkMsg; |
|||
} |
|||
|
|||
public DownlinkMsg processCredentialsRequestMessageToEdge(EdgeEvent edgeEvent) { |
|||
DownlinkMsg downlinkMsg = null; |
|||
if (EdgeEventType.DEVICE.equals(edgeEvent.getType())) { |
|||
DeviceId deviceId = new DeviceId(edgeEvent.getEntityId()); |
|||
DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = DeviceCredentialsRequestMsg.newBuilder() |
|||
.setDeviceIdMSB(deviceId.getId().getMostSignificantBits()) |
|||
.setDeviceIdLSB(deviceId.getId().getLeastSignificantBits()) |
|||
.build(); |
|||
DownlinkMsg.Builder builder = DownlinkMsg.newBuilder() |
|||
.setDownlinkMsgId(EdgeUtils.nextPositiveInt()) |
|||
.addDeviceCredentialsRequestMsg(deviceCredentialsRequestMsg); |
|||
downlinkMsg = builder.build(); |
|||
} |
|||
return downlinkMsg; |
|||
} |
|||
|
|||
public ListenableFuture<Void> processEntityNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { |
|||
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); |
|||
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); |
|||
EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, |
|||
new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); |
|||
EdgeId edgeId = safeGetEdgeId(edgeNotificationMsg); |
|||
switch (actionType) { |
|||
case ADDED: // used only for USER entity
|
|||
case UPDATED: |
|||
case CREDENTIALS_UPDATED: |
|||
return pushNotificationToAllRelatedEdges(tenantId, entityId, type, actionType); |
|||
case ASSIGNED_TO_CUSTOMER: |
|||
case UNASSIGNED_FROM_CUSTOMER: |
|||
return pushNotificationToAllRelatedCustomerEdges(tenantId, edgeNotificationMsg, entityId, actionType, type); |
|||
case DELETED: |
|||
if (edgeId != null) { |
|||
return saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null); |
|||
} else { |
|||
return pushNotificationToAllRelatedEdges(tenantId, entityId, type, actionType); |
|||
} |
|||
case ASSIGNED_TO_EDGE: |
|||
case UNASSIGNED_FROM_EDGE: |
|||
ListenableFuture<Void> future = saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null); |
|||
return Futures.transformAsync(future, unused -> { |
|||
if (type.equals(EdgeEventType.RULE_CHAIN)) { |
|||
return updateDependentRuleChains(tenantId, new RuleChainId(entityId.getId()), edgeId); |
|||
} else { |
|||
return Futures.immediateFuture(null); |
|||
} |
|||
}, dbCallbackExecutorService); |
|||
default: |
|||
return Futures.immediateFuture(null); |
|||
} |
|||
} |
|||
|
|||
private ListenableFuture<Void> pushNotificationToAllRelatedCustomerEdges(TenantId tenantId, |
|||
TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, |
|||
EntityId entityId, |
|||
EdgeEventActionType actionType, |
|||
EdgeEventType type) { |
|||
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); |
|||
PageData<EdgeId> pageData; |
|||
List<ListenableFuture<Void>> futures = new ArrayList<>(); |
|||
do { |
|||
pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId, pageLink); |
|||
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { |
|||
for (EdgeId relatedEdgeId : pageData.getData()) { |
|||
try { |
|||
CustomerId customerId = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class); |
|||
ListenableFuture<Edge> future = edgeService.findEdgeByIdAsync(tenantId, relatedEdgeId); |
|||
futures.add(Futures.transformAsync(future, edge -> { |
|||
if (edge != null && edge.getCustomerId() != null && |
|||
!edge.getCustomerId().isNullUid() && edge.getCustomerId().equals(customerId)) { |
|||
return saveEdgeEvent(tenantId, relatedEdgeId, type, actionType, entityId, null); |
|||
} else { |
|||
return Futures.immediateFuture(null); |
|||
} |
|||
}, dbCallbackExecutorService)); |
|||
} catch (Exception e) { |
|||
log.error("Can't parse customer id from entity body [{}]", edgeNotificationMsg, e); |
|||
return Futures.immediateFailedFuture(e); |
|||
} |
|||
} |
|||
if (pageData.hasNext()) { |
|||
pageLink = pageLink.nextPageLink(); |
|||
} |
|||
} |
|||
} while (pageData != null && pageData.hasNext()); |
|||
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService); |
|||
} |
|||
|
|||
private EdgeId safeGetEdgeId(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { |
|||
if (edgeNotificationMsg.getEdgeIdMSB() != 0 && edgeNotificationMsg.getEdgeIdLSB() != 0) { |
|||
return new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB())); |
|||
} else { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
private ListenableFuture<Void> pushNotificationToAllRelatedEdges(TenantId tenantId, EntityId entityId, EdgeEventType type, EdgeEventActionType actionType) { |
|||
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); |
|||
PageData<EdgeId> pageData; |
|||
List<ListenableFuture<Void>> futures = new ArrayList<>(); |
|||
do { |
|||
pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId, pageLink); |
|||
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { |
|||
for (EdgeId relatedEdgeId : pageData.getData()) { |
|||
futures.add(saveEdgeEvent(tenantId, relatedEdgeId, type, actionType, entityId, null)); |
|||
} |
|||
if (pageData.hasNext()) { |
|||
pageLink = pageLink.nextPageLink(); |
|||
} |
|||
} |
|||
} while (pageData != null && pageData.hasNext()); |
|||
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService); |
|||
} |
|||
|
|||
private ListenableFuture<Void> updateDependentRuleChains(TenantId tenantId, RuleChainId processingRuleChainId, EdgeId edgeId) { |
|||
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); |
|||
PageData<RuleChain> pageData; |
|||
List<ListenableFuture<Void>> futures = new ArrayList<>(); |
|||
do { |
|||
pageData = ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, pageLink); |
|||
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { |
|||
for (RuleChain ruleChain : pageData.getData()) { |
|||
if (!ruleChain.getId().equals(processingRuleChainId)) { |
|||
List<RuleChainConnectionInfo> connectionInfos = |
|||
ruleChainService.loadRuleChainMetaData(ruleChain.getTenantId(), ruleChain.getId()).getRuleChainConnections(); |
|||
if (connectionInfos != null && !connectionInfos.isEmpty()) { |
|||
for (RuleChainConnectionInfo connectionInfo : connectionInfos) { |
|||
if (connectionInfo.getTargetRuleChainId().equals(processingRuleChainId)) { |
|||
futures.add(saveEdgeEvent(tenantId, |
|||
edgeId, |
|||
EdgeEventType.RULE_CHAIN_METADATA, |
|||
EdgeEventActionType.UPDATED, |
|||
ruleChain.getId(), |
|||
null)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
if (pageData.hasNext()) { |
|||
pageLink = pageLink.nextPageLink(); |
|||
} |
|||
} |
|||
} while (pageData != null && pageData.hasNext()); |
|||
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService); |
|||
} |
|||
|
|||
public ListenableFuture<Void> processEntityNotificationForAllEdges(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { |
|||
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); |
|||
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); |
|||
EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); |
|||
switch (actionType) { |
|||
case ADDED: |
|||
case UPDATED: |
|||
case DELETED: |
|||
return processActionForAllEdges(tenantId, type, actionType, entityId); |
|||
default: |
|||
return Futures.immediateFuture(null); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,110 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.entitiy.asset.profile; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.asset.AssetProfile; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.AssetProfileId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
|||
import org.thingsboard.server.dao.asset.AssetProfileService; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; |
|||
|
|||
import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE; |
|||
|
|||
@Service |
|||
@TbCoreComponent |
|||
@AllArgsConstructor |
|||
@Slf4j |
|||
public class DefaultTbAssetProfileService extends AbstractTbEntityService implements TbAssetProfileService { |
|||
|
|||
private final AssetProfileService assetProfileService; |
|||
|
|||
@Override |
|||
public AssetProfile save(AssetProfile assetProfile, User user) throws Exception { |
|||
ActionType actionType = assetProfile.getId() == null ? ActionType.ADDED : ActionType.UPDATED; |
|||
TenantId tenantId = assetProfile.getTenantId(); |
|||
try { |
|||
if (TB_SERVICE_QUEUE.equals(assetProfile.getName())) { |
|||
throw new ThingsboardException("Unable to save asset profile with name " + TB_SERVICE_QUEUE, ThingsboardErrorCode.BAD_REQUEST_PARAMS); |
|||
} else if (assetProfile.getId() != null) { |
|||
AssetProfile foundAssetProfile = assetProfileService.findAssetProfileById(tenantId, assetProfile.getId()); |
|||
if (foundAssetProfile != null && TB_SERVICE_QUEUE.equals(foundAssetProfile.getName())) { |
|||
throw new ThingsboardException("Updating asset profile with name " + TB_SERVICE_QUEUE + " is prohibited!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); |
|||
} |
|||
} |
|||
AssetProfile savedAssetProfile = checkNotNull(assetProfileService.saveAssetProfile(assetProfile)); |
|||
autoCommit(user, savedAssetProfile.getId()); |
|||
tbClusterService.broadcastEntityStateChangeEvent(tenantId, savedAssetProfile.getId(), |
|||
actionType.equals(ActionType.ADDED) ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); |
|||
|
|||
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedAssetProfile.getId(), |
|||
savedAssetProfile, user, actionType, true, null); |
|||
return savedAssetProfile; |
|||
} catch (Exception e) { |
|||
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET_PROFILE), assetProfile, actionType, user, e); |
|||
throw e; |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void delete(AssetProfile assetProfile, User user) { |
|||
AssetProfileId assetProfileId = assetProfile.getId(); |
|||
TenantId tenantId = assetProfile.getTenantId(); |
|||
try { |
|||
assetProfileService.deleteAssetProfile(tenantId, assetProfileId); |
|||
|
|||
tbClusterService.broadcastEntityStateChangeEvent(tenantId, assetProfileId, ComponentLifecycleEvent.DELETED); |
|||
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, assetProfileId, assetProfile, |
|||
user, ActionType.DELETED, true, null, assetProfileId.toString()); |
|||
} catch (Exception e) { |
|||
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET_PROFILE), ActionType.DELETED, |
|||
user, e, assetProfileId.toString()); |
|||
throw e; |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public AssetProfile setDefaultAssetProfile(AssetProfile assetProfile, AssetProfile previousDefaultAssetProfile, User user) throws ThingsboardException { |
|||
TenantId tenantId = assetProfile.getTenantId(); |
|||
AssetProfileId assetProfileId = assetProfile.getId(); |
|||
try { |
|||
if (assetProfileService.setDefaultAssetProfile(tenantId, assetProfileId)) { |
|||
if (previousDefaultAssetProfile != null) { |
|||
previousDefaultAssetProfile = assetProfileService.findAssetProfileById(tenantId, previousDefaultAssetProfile.getId()); |
|||
notificationEntityService.logEntityAction(tenantId, previousDefaultAssetProfile.getId(), previousDefaultAssetProfile, |
|||
ActionType.UPDATED, user); |
|||
} |
|||
assetProfile = assetProfileService.findAssetProfileById(tenantId, assetProfileId); |
|||
|
|||
notificationEntityService.logEntityAction(tenantId, assetProfileId, assetProfile, ActionType.UPDATED, user); |
|||
} |
|||
return assetProfile; |
|||
} catch (Exception e) { |
|||
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET_PROFILE), ActionType.UPDATED, |
|||
user, e, assetProfileId.toString()); |
|||
throw e; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.entitiy.asset.profile; |
|||
|
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.asset.AssetProfile; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.service.entitiy.SimpleTbEntityService; |
|||
|
|||
public interface TbAssetProfileService extends SimpleTbEntityService<AssetProfile> { |
|||
|
|||
AssetProfile setDefaultAssetProfile(AssetProfile assetProfile, AssetProfile previousDefaultAssetProfile, User user) throws ThingsboardException; |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue