@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License .
* /
package org.thingsboard.server.service.entitiy.entityV iew ;
package org.thingsboard.server.service.entitiy.entityv iew ;
import com.google.common.util.concurrent.FutureCallback ;
import com.google.common.util.concurrent.Futures ;
@ -28,9 +28,9 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.DataConstants ;
import org.thingsboard.server.common.data.EntityType ;
import org.thingsboard.server.common.data.EntityView ;
import org.thingsboard.server.common.data.User ;
import org.thingsboard.server.common.data.audit.ActionType ;
import org.thingsboard.server.common.data.edge.Edge ;
import org.thingsboard.server.common.data.edge.EdgeEventActionType ;
import org.thingsboard.server.common.data.exception.ThingsboardException ;
import org.thingsboard.server.common.data.id.CustomerId ;
import org.thingsboard.server.common.data.id.EdgeId ;
@ -43,9 +43,11 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
import org.thingsboard.server.common.data.kv.TsKvEntry ;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent ;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg ;
import org.thingsboard.server.dao.attributes.AttributesService ;
import org.thingsboard.server.dao.entityview.EntityViewService ;
import org.thingsboard.server.dao.timeseries.TimeseriesService ;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService ;
import org.thingsboard.server.service.security.model.SecurityUser ;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService ;
import javax.annotation.Nullable ;
import java.util.ArrayList ;
@ -64,16 +66,20 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
@Slf4j
public class DefaultTbEntityViewService extends AbstractTbEntityService implements TbEntityViewService {
private final EntityViewService entityViewService ;
private final AttributesService attributesService ;
private final TelemetrySubscriptionService tsSubService ;
private final TimeseriesService tsService ;
final Map < TenantId , Map < EntityId , List < EntityView > > > localCache = new ConcurrentHashMap < > ( ) ;
@Override
public EntityView save ( EntityView entityView , EntityView existingEntityView , Security User user ) throws ThingsboardException {
public EntityView save ( EntityView entityView , EntityView existingEntityView , User user ) throws ThingsboardException {
ActionType actionType = entityView . getId ( ) = = null ? ActionType . ADDED : ActionType . UPDATED ;
TenantId tenantId = entityView . getTenantId ( ) ;
try {
EntityView savedEntityView = checkNotNull ( entityViewService . saveEntityView ( entityView ) ) ;
this . updateEntityViewAttributes ( user , savedEntityView , existingEntityView ) ;
this . updateEntityViewAttributes ( tenantId , savedEntityView , existingEntityView , user ) ;
notificationEntityService . notifyCreateOrUpdateEntity ( savedEntityView . getTenantId ( ) , savedEntityView . getId ( ) , savedEntityView ,
null , actionType , user ) ;
localCache . computeIfAbsent ( savedEntityView . getTenantId ( ) , ( k ) - > new ConcurrentReferenceHashMap < > ( ) ) . clear ( ) ;
@ -81,48 +87,44 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
entityView . getId ( ) = = null ? ComponentLifecycleEvent . CREATED : ComponentLifecycleEvent . UPDATED ) ;
return savedEntityView ;
} catch ( Exception e ) {
notificationEntityService . notifyEntity ( user . getTenantId ( ) , emptyId ( EntityType . ENTITY_VIEW ) , entityView , null , actionType , user , e ) ;
throw handl eException ( e ) ;
notificationEntityService . logEntityAction ( user . getTenantId ( ) , emptyId ( EntityType . ENTITY_VIEW ) , entityView , actionType , user , e ) ;
throw e ;
}
}
@Override
public void updateEntityViewAttributes ( SecurityUser user , EntityView savedEntityView , EntityView oldEntityView ) throws ThingsboardException {
try {
List < ListenableFuture < ? > > futures = new ArrayList < > ( ) ;
if ( oldEntityView ! = null ) {
if ( oldEntityView . getKeys ( ) ! = null & & oldEntityView . getKeys ( ) . getAttributes ( ) ! = null ) {
futures . add ( deleteAttributesFromEntityView ( oldEntityView , DataConstants . CLIENT_SCOPE , oldEntityView . getKeys ( ) . getAttributes ( ) . getCs ( ) , user ) ) ;
futures . add ( deleteAttributesFromEntityView ( oldEntityView , DataConstants . SERVER_SCOPE , oldEntityView . getKeys ( ) . getAttributes ( ) . getSs ( ) , user ) ) ;
futures . add ( deleteAttributesFromEntityView ( oldEntityView , DataConstants . SHARED_SCOPE , oldEntityView . getKeys ( ) . getAttributes ( ) . getSh ( ) , user ) ) ;
}
List < String > tsKeys = oldEntityView . getKeys ( ) ! = null & & oldEntityView . getKeys ( ) . getTimeseries ( ) ! = null ?
oldEntityView . getKeys ( ) . getTimeseries ( ) : Collections . emptyList ( ) ;
futures . add ( deleteLatestFromEntityView ( oldEntityView , tsKeys , user ) ) ;
public void updateEntityViewAttributes ( TenantId tenantId , EntityView savedEntityView , EntityView oldEntityView , User user ) throws ThingsboardException {
List < ListenableFuture < ? > > futures = new ArrayList < > ( ) ;
if ( oldEntityView ! = null ) {
if ( oldEntityView . getKeys ( ) ! = null & & oldEntityView . getKeys ( ) . getAttributes ( ) ! = null ) {
futures . add ( deleteAttributesFromEntityView ( oldEntityView , DataConstants . CLIENT_SCOPE , oldEntityView . getKeys ( ) . getAttributes ( ) . getCs ( ) , user ) ) ;
futures . add ( deleteAttributesFromEntityView ( oldEntityView , DataConstants . SERVER_SCOPE , oldEntityView . getKeys ( ) . getAttributes ( ) . getSs ( ) , user ) ) ;
futures . add ( deleteAttributesFromEntityView ( oldEntityView , DataConstants . SHARED_SCOPE , oldEntityView . getKeys ( ) . getAttributes ( ) . getSh ( ) , user ) ) ;
}
if ( savedEntityView . getKeys ( ) ! = null ) {
if ( savedEntityView . getKeys ( ) . getAttributes ( ) ! = null ) {
futures . add ( copyAttributesFromEntityToEntityView ( savedEntityView , DataConstants . CLIENT_SCOPE , savedEntityView . getKeys ( ) . getAttributes ( ) . getCs ( ) , user ) ) ;
futures . add ( copyAttributesFromEntityToEntityView ( savedEntityView , DataConstants . SERVER_SCOPE , savedEntityView . getKeys ( ) . getAttributes ( ) . getSs ( ) , user ) ) ;
futures . add ( copyAttributesFromEntityToEntityView ( savedEntityView , DataConstants . SHARED_SCOPE , savedEntityView . getKeys ( ) . getAttributes ( ) . getSh ( ) , user ) ) ;
}
futures . add ( copyLatestFromEntityToEntityView ( savedEntityView , user ) ) ;
List < String > tsKeys = oldEntityView . getKeys ( ) ! = null & & oldEntityView . getKeys ( ) . getTimeseries ( ) ! = null ?
oldEntityView . getKeys ( ) . getTimeseries ( ) : Collections . emptyList ( ) ;
futures . add ( deleteLatestFromEntityView ( oldEntityView , tsKeys , user ) ) ;
}
if ( savedEntityView . getKeys ( ) ! = null ) {
if ( savedEntityView . getKeys ( ) . getAttributes ( ) ! = null ) {
futures . add ( copyAttributesFromEntityToEntityView ( savedEntityView , DataConstants . CLIENT_SCOPE , savedEntityView . getKeys ( ) . getAttributes ( ) . getCs ( ) , user ) ) ;
futures . add ( copyAttributesFromEntityToEntityView ( savedEntityView , DataConstants . SERVER_SCOPE , savedEntityView . getKeys ( ) . getAttributes ( ) . getSs ( ) , user ) ) ;
futures . add ( copyAttributesFromEntityToEntityView ( savedEntityView , DataConstants . SHARED_SCOPE , savedEntityView . getKeys ( ) . getAttributes ( ) . getSh ( ) , user ) ) ;
}
for ( ListenableFuture < ? > future : futures ) {
try {
future . get ( ) ;
} catch ( InterruptedException | ExecutionException e ) {
throw new RuntimeException ( "Failed to copy attributes to entity view" , e ) ;
}
futures . add ( copyLatestFromEntityToEntityView ( tenantId , savedEntityView ) ) ;
}
for ( ListenableFuture < ? > future : futures ) {
try {
future . get ( ) ;
} catch ( InterruptedException | ExecutionException e ) {
throw new RuntimeException ( "Failed to copy attributes to entity view" , e ) ;
}
} catch ( Exception e ) {
throw handleException ( e ) ;
}
}
@Override
public void delete ( EntityView entityView , Security User user ) throws ThingsboardException {
public void delete ( EntityView entityView , User user ) throws ThingsboardException {
TenantId tenantId = entityView . getTenantId ( ) ;
EntityViewId entityViewId = entityView . getId ( ) ;
try {
@ -134,94 +136,89 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
localCache . computeIfAbsent ( tenantId , ( k ) - > new ConcurrentReferenceHashMap < > ( ) ) . clear ( ) ;
tbClusterService . broadcastEntityStateChangeEvent ( tenantId , entityViewId , ComponentLifecycleEvent . DELETED ) ;
} catch ( Exception e ) {
notificationEntityService . notifyEntity ( tenantId , emptyId ( EntityType . ENTITY_VIEW ) , null , null ,
notificationEntityService . logEntityAction ( tenantId , emptyId ( EntityType . ENTITY_VIEW ) ,
ActionType . DELETED , user , e , entityViewId . toString ( ) ) ;
throw handl eException ( e ) ;
throw e ;
}
}
@Override
public EntityView assignEntityViewToCustomer ( TenantId tenantId , EntityViewId entityViewId , Customer customer , SecurityUser user ) throws ThingsboardException {
ActionType actionType = ActionType . ASSIGNED_TO_CUSTOMER ;
public EntityView assignEntityViewToCustomer ( TenantId tenantId , EntityViewId entityViewId , Customer customer , User user ) throws ThingsboardException {
CustomerId customerId = customer . getId ( ) ;
try {
EntityView savedEntityView = checkNotNull ( entityViewService . assignEntityViewToCustomer ( tenantId , entityViewId , customerId ) ) ;
notificationEntityService . notifyAssignOrUnassignEntityToCustomer ( tenantId , entityViewId , customerId , savedEntityView ,
actionType , EdgeEvent ActionType. ASSIGNED_TO_CUSTOMER , user , true , customerId . toString ( ) , customer . getName ( ) ) ;
ActionType . ASSIGNED_TO_CUSTOMER , user , true , entityViewId . toString ( ) , customerId . toString ( ) , customer . getName ( ) ) ;
return savedEntityView ;
} catch ( Exception e ) {
notificationEntityService . notifyEntity ( tenantId , emptyId ( EntityType . ENTITY_VIEW ) , null , null ,
actionType , user , e , entityViewId . toString ( ) , customerId . toString ( ) ) ;
throw handl eException ( e ) ;
notificationEntityService . logEntityAction ( tenantId , emptyId ( EntityType . ENTITY_VIEW ) ,
ActionType . ASSIGNED_TO_CUSTOMER , user , e , entityViewId . toString ( ) , customerId . toString ( ) ) ;
throw e ;
}
}
@Override
public EntityView assignEntityViewToPublicCustomer ( TenantId tenantId , CustomerId customerId , Customer publicCustomer ,
EntityViewId entityViewId , SecurityUser user ) throws ThingsboardException {
ActionType actionType = ActionType . ASSIGNED_TO_CUSTOMER ;
EntityViewId entityViewId , User user ) throws ThingsboardException {
try {
EntityView savedEntityView = checkNotNull ( entityViewService . assignEntityViewToCustomer ( tenantId ,
entityViewId , publicCustomer . getId ( ) ) ) ;
notificationEntityService . notifyAssignOrUnassignEntityToCustomer ( tenantId , entityViewId , customerId , savedEntityView ,
actionType , null , user , false , savedEntityView . getEntityId ( ) . toString ( ) ,
ActionType . ASSIGNED_TO_CUSTOMER , user , false , savedEntityView . getEntityId ( ) . toString ( ) ,
publicCustomer . getId ( ) . toString ( ) , publicCustomer . getName ( ) ) ;
return savedEntityView ;
} catch ( Exception e ) {
notificationEntityService . notifyEntity ( tenantId , emptyId ( EntityType . ENTITY_VIEW ) , null , null ,
actionType , user , e , entityViewId . toString ( ) ) ;
throw handl eException ( e ) ;
notificationEntityService . logEntityAction ( tenantId , emptyId ( EntityType . ENTITY_VIEW ) ,
ActionType . ASSIGNED_TO_CUSTOMER , user , e , entityViewId . toString ( ) ) ;
throw e ;
}
}
@Override
public EntityView assignEntityViewToEdge ( TenantId tenantId , CustomerId customerId , EntityViewId entityViewId , Edge edge , SecurityUser user ) throws ThingsboardException {
ActionType actionType = ActionType . ASSIGNED_TO_EDGE ;
public EntityView assignEntityViewToEdge ( TenantId tenantId , CustomerId customerId , EntityViewId entityViewId , Edge edge , User user ) throws ThingsboardException {
EdgeId edgeId = edge . getId ( ) ;
EntityView savedEntityView = checkNotNull ( entityViewService . assignEntityViewToEdge ( tenantId , entityViewId , edgeId ) ) ;
try {
EntityView savedEntityView = checkNotNull ( entityViewService . assignEntityViewToEdge ( tenantId , entityViewId , edgeId ) ) ;
notificationEntityService . notifyAssignOrUnassignEntityToEdge ( tenantId , entityViewId , customerId ,
edgeId , savedEntityView , actionType , user , savedEntityView . getEntityId ( ) . toString ( ) ,
edgeId , savedEntityView , ActionType . ASSIGNED_TO_EDGE , user , savedEntityView . getEntityId ( ) . toString ( ) ,
edgeId . toString ( ) , edge . getName ( ) ) ;
return savedEntityView ;
} catch ( Exception e ) {
notificationEntityService . notifyEntity ( tenantId , emptyId ( EntityType . D EVIC E) , null , null ,
actionType , user , e , entityViewId . toString ( ) , edgeId . toString ( ) ) ;
throw handl eException ( e ) ;
notificationEntityService . logEntityAction ( tenantId , emptyId ( EntityType . ENTITY_ VIEW ) ,
ActionType . ASSIGNED_TO_EDGE , user , e , entityViewId . toString ( ) , edgeId . toString ( ) ) ;
throw e ;
}
}
@Override
public EntityView unassignEntityViewFromEdge ( TenantId tenantId , CustomerId customerId , EntityView entityView ,
Edge edge , SecurityUser user ) throws ThingsboardException {
ActionType actionType = ActionType . UNASSIGNED_FROM_EDGE ;
Edge edge , User user ) throws ThingsboardException {
EntityViewId entityViewId = entityView . getId ( ) ;
EdgeId edgeId = edge . getId ( ) ;
try {
EntityView savedEntityView = checkNotNull ( entityViewService . unassignEntityViewFromEdge ( tenantId , entityViewId , edgeId ) ) ;
notificationEntityService . notifyAssignOrUnassignEntityToEdge ( tenantId , entityViewId , customerId ,
edgeId , entityView , actionType , user , entityViewId . toString ( ) ,
edgeId , entityView , ActionType . UNASSIGNED_FROM_EDGE , user , entityViewId . toString ( ) ,
edgeId . toString ( ) , edge . getName ( ) ) ;
return savedEntityView ;
} catch ( Exception e ) {
notificationEntityService . notifyEntity ( tenantId , emptyId ( EntityType . ENTITY_VIEW ) , null , null ,
actionType , user , e , entityViewId . toString ( ) , edgeId . toString ( ) ) ;
throw handl eException ( e ) ;
notificationEntityService . logEntityAction ( tenantId , emptyId ( EntityType . ENTITY_VIEW ) ,
ActionType . UNASSIGNED_FROM_EDGE , user , e , entityViewId . toString ( ) , edgeId . toString ( ) ) ;
throw e ;
}
}
@Override
public EntityView unassignEntityViewFromCustomer ( TenantId tenantId , EntityViewId entityViewId , Customer customer , SecurityUser user ) throws ThingsboardException {
ActionType actionType = ActionType . UNASSIGNED_FROM_CUSTOMER ;
public EntityView unassignEntityViewFromCustomer ( TenantId tenantId , EntityViewId entityViewId , Customer customer , User user ) throws ThingsboardException {
try {
EntityView savedEntityView = checkNotNull ( entityViewService . unassignEntityViewFromCustomer ( tenantId , entityViewId ) ) ;
notificationEntityService . notifyAssignOrUnassignEntityToCustomer ( tenantId , entityViewId , customer . getId ( ) , savedEntityView ,
actionType , EdgeEvent ActionType. UNASSIGNED_FROM_CUSTOMER , user , true , customer . getId ( ) . toString ( ) , customer . getName ( ) ) ;
ActionType . UNASSIGNED_FROM_CUSTOMER , user , true , customer . getId ( ) . toString ( ) , customer . getName ( ) ) ;
return savedEntityView ;
} catch ( Exception e ) {
notificationEntityService . notifyEntity ( tenantId , emptyId ( EntityType . ENTITY_VIEW ) , null , null ,
actionType , user , e , entityViewId . toString ( ) ) ;
throw handl eException ( e ) ;
notificationEntityService . logEntityAction ( tenantId , emptyId ( EntityType . ENTITY_VIEW ) ,
ActionType . UNASSIGNED_FROM_CUSTOMER , user , e , entityViewId . toString ( ) ) ;
throw e ;
}
}
@ -270,7 +267,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
}
}
private ListenableFuture < List < Void > > copyAttributesFromEntityToEntityView ( EntityView entityView , String scope , Collection < String > keys , Security User user ) throws ThingsboardException {
private ListenableFuture < List < Void > > copyAttributesFromEntityToEntityView ( EntityView entityView , String scope , Collection < String > keys , User user ) throws ThingsboardException {
EntityViewId entityId = entityView . getId ( ) ;
if ( keys ! = null & & ! keys . isEmpty ( ) ) {
ListenableFuture < List < AttributeKvEntry > > getAttrFuture = attributesService . find ( entityView . getTenantId ( ) , entityView . getEntityId ( ) , scope , keys ) ;
@ -315,7 +312,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
}
}
private ListenableFuture < List < Void > > copyLatestFromEntityToEntityView ( EntityView entityView , SecurityUser user ) {
private ListenableFuture < List < Void > > copyLatestFromEntityToEntityView ( TenantId tenantId , EntityView entityView ) {
EntityViewId entityId = entityView . getId ( ) ;
List < String > keys = entityView . getKeys ( ) ! = null & & entityView . getKeys ( ) . getTimeseries ( ) ! = null ?
entityView . getKeys ( ) . getTimeseries ( ) : Collections . emptyList ( ) ;
@ -323,7 +320,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
long endTs = entityView . getEndTimeMs ( ) = = 0 ? Long . MAX_VALUE : entityView . getEndTimeMs ( ) ;
ListenableFuture < List < String > > keysFuture ;
if ( keys . isEmpty ( ) ) {
keysFuture = Futures . transform ( tsService . findAllLatest ( user . ge tT enantId( ) ,
keysFuture = Futures . transform ( tsService . findAllLatest ( tenantId ,
entityView . getEntityId ( ) ) , latest - > latest . stream ( ) . map ( TsKvEntry : : getKey ) . collect ( Collectors . toList ( ) ) , MoreExecutors . directExecutor ( ) ) ;
} else {
keysFuture = Futures . immediateFuture ( keys ) ;
@ -331,7 +328,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
ListenableFuture < List < TsKvEntry > > latestFuture = Futures . transformAsync ( keysFuture , fetchKeys - > {
List < ReadTsKvQuery > queries = fetchKeys . stream ( ) . filter ( key - > ! isBlank ( key ) ) . map ( key - > new BaseReadTsKvQuery ( key , startTs , endTs , 1 , "DESC" ) ) . collect ( Collectors . toList ( ) ) ;
if ( ! queries . isEmpty ( ) ) {
return tsService . findAll ( user . ge tT enantId( ) , entityView . getEntityId ( ) , queries ) ;
return tsService . findAll ( tenantId , entityView . getEntityId ( ) , queries ) ;
} else {
return Futures . immediateFuture ( null ) ;
}
@ -352,7 +349,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
} , MoreExecutors . directExecutor ( ) ) ;
}
private ListenableFuture < Void > deleteAttributesFromEntityView ( EntityView entityView , String scope , List < String > keys , Security User user ) {
private ListenableFuture < Void > deleteAttributesFromEntityView ( EntityView entityView , String scope , List < String > keys , User user ) {
EntityViewId entityId = entityView . getId ( ) ;
SettableFuture < Void > resultFuture = SettableFuture . create ( ) ;
if ( keys ! = null & & ! keys . isEmpty ( ) ) {
@ -383,7 +380,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
return resultFuture ;
}
private ListenableFuture < Void > deleteLatestFromEntityView ( EntityView entityView , List < String > keys , Security User user ) {
private ListenableFuture < Void > deleteLatestFromEntityView ( EntityView entityView , List < String > keys , User user ) {
EntityViewId entityId = entityView . getId ( ) ;
SettableFuture < Void > resultFuture = SettableFuture . create ( ) ;
if ( keys ! = null & & ! keys . isEmpty ( ) ) {
@ -434,16 +431,16 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
return resultFuture ;
}
private void logAttributesUpdated ( TenantId tenantId , Security User user , EntityId entityId , String scope , List < AttributeKvEntry > attributes , Throwable e ) throws ThingsboardException {
notificationEntityService . notifyEntity ( tenantId , entityId , null , null , ActionType . ATTRIBUTES_UPDATED , user , toException ( e ) , scope , attributes ) ;
private void logAttributesUpdated ( TenantId tenantId , User user , EntityId entityId , String scope , List < AttributeKvEntry > attributes , Throwable e ) throws ThingsboardException {
notificationEntityService . logEntityAction ( tenantId , entityId , ActionType . ATTRIBUTES_UPDATED , user , toException ( e ) , scope , attributes ) ;
}
private void logAttributesDeleted ( TenantId tenantId , Security User user , EntityId entityId , String scope , List < String > keys , Throwable e ) throws ThingsboardException {
notificationEntityService . notifyEntity ( tenantId , entityId , null , null , ActionType . ATTRIBUTES_DELETED , user , toException ( e ) , scope , keys ) ;
private void logAttributesDeleted ( TenantId tenantId , User user , EntityId entityId , String scope , List < String > keys , Throwable e ) throws ThingsboardException {
notificationEntityService . logEntityAction ( tenantId , entityId , ActionType . ATTRIBUTES_DELETED , user , toException ( e ) , scope , keys ) ;
}
private void logTimeseriesDeleted ( TenantId tenantId , Security User user , EntityId entityId , List < String > keys , Throwable e ) throws ThingsboardException {
notificationEntityService . notifyEntity ( tenantId , entityId , null , null , ActionType . TIMESERIES_DELETED , user , toException ( e ) , keys ) ;
private void logTimeseriesDeleted ( TenantId tenantId , User user , EntityId entityId , List < String > keys , Throwable e ) throws ThingsboardException {
notificationEntityService . logEntityAction ( tenantId , entityId , ActionType . TIMESERIES_DELETED , user , toException ( e ) , keys ) ;
}
public static Exception toException ( Throwable error ) {