Version Control Progress implementation
This commit is contained in:
		
							parent
							
								
									bdd8432049
								
							
						
					
					
						commit
						b08b39fb08
					
				@ -49,6 +49,7 @@ public class ControllerConstants {
 | 
			
		||||
    protected static final String RULE_NODE_ID_PARAM_DESCRIPTION = "A string value representing the rule node id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
 | 
			
		||||
    protected static final String WIDGET_BUNDLE_ID_PARAM_DESCRIPTION = "A string value representing the widget bundle id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
 | 
			
		||||
    protected static final String WIDGET_TYPE_ID_PARAM_DESCRIPTION = "A string value representing the widget type id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
 | 
			
		||||
    protected static final String VC_REQUEST_ID_PARAM_DESCRIPTION = "A string value representing the version control request id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
 | 
			
		||||
    protected static final String RESOURCE_ID_PARAM_DESCRIPTION = "A string value representing the resource id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
 | 
			
		||||
    protected static final String SYSTEM_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' authority.";
 | 
			
		||||
    protected static final String SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' or 'TENANT_ADMIN' authority.";
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,6 @@ import org.thingsboard.server.common.data.sync.vc.EntityDataDiff;
 | 
			
		||||
import org.thingsboard.server.common.data.sync.vc.EntityDataInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
 | 
			
		||||
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
 | 
			
		||||
import org.thingsboard.server.common.data.sync.vc.EntityTypeLoadResult;
 | 
			
		||||
import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
 | 
			
		||||
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
 | 
			
		||||
@ -65,6 +64,7 @@ import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VERSI
 | 
			
		||||
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
 | 
			
		||||
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
 | 
			
		||||
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
 | 
			
		||||
import static org.thingsboard.server.controller.ControllerConstants.VC_REQUEST_ID_PARAM_DESCRIPTION;
 | 
			
		||||
 | 
			
		||||
@RestController
 | 
			
		||||
@TbCoreComponent
 | 
			
		||||
@ -117,14 +117,19 @@ public class EntitiesVersionControlController extends BaseController {
 | 
			
		||||
            "  }\n" +
 | 
			
		||||
            "}\n```")
 | 
			
		||||
    @PostMapping("/version")
 | 
			
		||||
    public DeferredResult<VersionCreationResult> saveEntitiesVersion(@RequestBody VersionCreateRequest request) throws ThingsboardException {
 | 
			
		||||
    public DeferredResult<UUID> saveEntitiesVersion(@RequestBody VersionCreateRequest request) throws Exception {
 | 
			
		||||
        SecurityUser user = getCurrentUser();
 | 
			
		||||
        try {
 | 
			
		||||
            accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
 | 
			
		||||
            return wrapFuture(versionControlService.saveEntitiesVersion(user, request));
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw handleException(e);
 | 
			
		||||
        }
 | 
			
		||||
        accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
 | 
			
		||||
        return wrapFuture(versionControlService.saveEntitiesVersion(user, request));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation(value = "", notes = "")
 | 
			
		||||
    @GetMapping(value = "/version/{requestId}/status")
 | 
			
		||||
    public VersionCreationResult getVersionCreateRequestStatus(@ApiParam(value = VC_REQUEST_ID_PARAM_DESCRIPTION, required = true)
 | 
			
		||||
                                                               @PathVariable UUID requestId
 | 
			
		||||
    ) throws Exception {
 | 
			
		||||
        accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
        return versionControlService.getVersionCreateStatus(getCurrentUser(), requestId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation(value = "", notes = "" +
 | 
			
		||||
@ -147,15 +152,11 @@ public class EntitiesVersionControlController extends BaseController {
 | 
			
		||||
                                                                      @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "timestamp")
 | 
			
		||||
                                                                      @RequestParam(required = false) String sortProperty,
 | 
			
		||||
                                                                      @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
 | 
			
		||||
                                                                      @RequestParam(required = false) String sortOrder) throws ThingsboardException {
 | 
			
		||||
        try {
 | 
			
		||||
            accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
            EntityId externalEntityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid);
 | 
			
		||||
            PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
 | 
			
		||||
            return wrapFuture(versionControlService.listEntityVersions(getTenantId(), branch, externalEntityId, pageLink));
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw handleException(e);
 | 
			
		||||
        }
 | 
			
		||||
                                                                      @RequestParam(required = false) String sortOrder) throws Exception {
 | 
			
		||||
        accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
        EntityId externalEntityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid);
 | 
			
		||||
        PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
 | 
			
		||||
        return wrapFuture(versionControlService.listEntityVersions(getTenantId(), branch, externalEntityId, pageLink));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation(value = "", notes = "" +
 | 
			
		||||
@ -177,14 +178,10 @@ public class EntitiesVersionControlController extends BaseController {
 | 
			
		||||
                                                                          @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "timestamp")
 | 
			
		||||
                                                                          @RequestParam(required = false) String sortProperty,
 | 
			
		||||
                                                                          @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
 | 
			
		||||
                                                                          @RequestParam(required = false) String sortOrder) throws ThingsboardException {
 | 
			
		||||
        try {
 | 
			
		||||
            accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
            PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
 | 
			
		||||
            return wrapFuture(versionControlService.listEntityTypeVersions(getTenantId(), branch, entityType, pageLink));
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw handleException(e);
 | 
			
		||||
        }
 | 
			
		||||
                                                                          @RequestParam(required = false) String sortOrder) throws Exception {
 | 
			
		||||
        accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
        PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
 | 
			
		||||
        return wrapFuture(versionControlService.listEntityTypeVersions(getTenantId(), branch, entityType, pageLink));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation(value = "", notes = "" +
 | 
			
		||||
@ -213,65 +210,45 @@ public class EntitiesVersionControlController extends BaseController {
 | 
			
		||||
                                                                @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "timestamp")
 | 
			
		||||
                                                                @RequestParam(required = false) String sortProperty,
 | 
			
		||||
                                                                @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
 | 
			
		||||
                                                                @RequestParam(required = false) String sortOrder) throws ThingsboardException {
 | 
			
		||||
        try {
 | 
			
		||||
            accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
            PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
 | 
			
		||||
            return wrapFuture(versionControlService.listVersions(getTenantId(), branch, pageLink));
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw handleException(e);
 | 
			
		||||
        }
 | 
			
		||||
                                                                @RequestParam(required = false) String sortOrder) throws Exception {
 | 
			
		||||
        accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
        PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
 | 
			
		||||
        return wrapFuture(versionControlService.listVersions(getTenantId(), branch, pageLink));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/entity/{branch}/{entityType}/{versionId}")
 | 
			
		||||
    public DeferredResult<List<VersionedEntityInfo>> listEntitiesAtVersion(@PathVariable String branch,
 | 
			
		||||
                                                                           @PathVariable EntityType entityType,
 | 
			
		||||
                                                                           @PathVariable String versionId) throws ThingsboardException {
 | 
			
		||||
        try {
 | 
			
		||||
            accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
            return wrapFuture(versionControlService.listEntitiesAtVersion(getTenantId(), branch, versionId, entityType));
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw handleException(e);
 | 
			
		||||
        }
 | 
			
		||||
                                                                           @PathVariable String versionId) throws Exception {
 | 
			
		||||
        accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
        return wrapFuture(versionControlService.listEntitiesAtVersion(getTenantId(), branch, versionId, entityType));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/entity/{branch}/{versionId}")
 | 
			
		||||
    public DeferredResult<List<VersionedEntityInfo>> listAllEntitiesAtVersion(@PathVariable String branch,
 | 
			
		||||
                                                                              @PathVariable String versionId) throws ThingsboardException {
 | 
			
		||||
        try {
 | 
			
		||||
            accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
            return wrapFuture(versionControlService.listAllEntitiesAtVersion(getTenantId(), branch, versionId));
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw handleException(e);
 | 
			
		||||
        }
 | 
			
		||||
                                                                              @PathVariable String versionId) throws Exception {
 | 
			
		||||
        accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
        return wrapFuture(versionControlService.listAllEntitiesAtVersion(getTenantId(), branch, versionId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/info/{versionId}/{entityType}/{externalEntityUuid}")
 | 
			
		||||
    public DeferredResult<EntityDataInfo> getEntityDataInfo(@PathVariable String versionId,
 | 
			
		||||
                                                            @PathVariable EntityType entityType,
 | 
			
		||||
                                                            @PathVariable UUID externalEntityUuid) throws ThingsboardException {
 | 
			
		||||
        try {
 | 
			
		||||
            accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
            EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid);
 | 
			
		||||
            return wrapFuture(versionControlService.getEntityDataInfo(getCurrentUser(), entityId, versionId));
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw handleException(e);
 | 
			
		||||
        }
 | 
			
		||||
                                                            @PathVariable UUID externalEntityUuid) throws Exception {
 | 
			
		||||
        accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
        EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid);
 | 
			
		||||
        return wrapFuture(versionControlService.getEntityDataInfo(getCurrentUser(), entityId, versionId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/diff/{branch}/{entityType}/{internalEntityUuid}")
 | 
			
		||||
    public DeferredResult<EntityDataDiff> compareEntityDataToVersion(@PathVariable String branch,
 | 
			
		||||
                                                                     @PathVariable EntityType entityType,
 | 
			
		||||
                                                                     @PathVariable UUID internalEntityUuid,
 | 
			
		||||
                                                                     @RequestParam String versionId) throws ThingsboardException {
 | 
			
		||||
        try {
 | 
			
		||||
            accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
            EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, internalEntityUuid);
 | 
			
		||||
            return wrapFuture(versionControlService.compareEntityDataToVersion(getCurrentUser(), branch, entityId, versionId));
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw handleException(e);
 | 
			
		||||
        }
 | 
			
		||||
                                                                     @RequestParam String versionId) throws Exception {
 | 
			
		||||
        accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
        EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, internalEntityUuid);
 | 
			
		||||
        return wrapFuture(versionControlService.compareEntityDataToVersion(getCurrentUser(), branch, entityId, versionId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation(value = "", notes = "" +
 | 
			
		||||
@ -307,14 +284,10 @@ public class EntitiesVersionControlController extends BaseController {
 | 
			
		||||
            "  }\n" +
 | 
			
		||||
            "}\n```")
 | 
			
		||||
    @PostMapping("/entity")
 | 
			
		||||
    public DeferredResult<VersionLoadResult> loadEntitiesVersion(@RequestBody VersionLoadRequest request) throws ThingsboardException {
 | 
			
		||||
    public UUID loadEntitiesVersion(@RequestBody VersionLoadRequest request) throws Exception {
 | 
			
		||||
        SecurityUser user = getCurrentUser();
 | 
			
		||||
        try {
 | 
			
		||||
            accessControlService.checkPermission(user, Resource.VERSION_CONTROL, Operation.READ);
 | 
			
		||||
            return wrapFuture(versionControlService.loadEntitiesVersion(user, request));
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw handleException(e);
 | 
			
		||||
        }
 | 
			
		||||
        accessControlService.checkPermission(user, Resource.VERSION_CONTROL, Operation.WRITE);
 | 
			
		||||
        return versionControlService.loadEntitiesVersion(user, request);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -25,9 +25,13 @@ import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.transaction.support.TransactionTemplate;
 | 
			
		||||
import org.springframework.web.context.request.async.DeferredResult;
 | 
			
		||||
import org.thingsboard.common.util.DonAsynchron;
 | 
			
		||||
import org.thingsboard.common.util.JacksonUtil;
 | 
			
		||||
import org.thingsboard.common.util.TbStopWatch;
 | 
			
		||||
import org.thingsboard.common.util.ThingsBoardExecutors;
 | 
			
		||||
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
 | 
			
		||||
import org.thingsboard.server.cache.TbTransactionalCache;
 | 
			
		||||
import org.thingsboard.server.common.data.EntityType;
 | 
			
		||||
import org.thingsboard.server.common.data.ExportableEntity;
 | 
			
		||||
import org.thingsboard.server.common.data.StringUtils;
 | 
			
		||||
@ -73,6 +77,7 @@ import org.thingsboard.server.service.sync.ie.EntitiesExportImportService;
 | 
			
		||||
import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService;
 | 
			
		||||
import org.thingsboard.server.service.sync.ie.importing.impl.MissingEntityException;
 | 
			
		||||
import org.thingsboard.server.service.sync.vc.autocommit.TbAutoCommitSettingsService;
 | 
			
		||||
import org.thingsboard.server.service.sync.vc.data.CommitGitRequest;
 | 
			
		||||
import org.thingsboard.server.service.sync.vc.data.ComplexEntitiesExportCtx;
 | 
			
		||||
import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx;
 | 
			
		||||
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
 | 
			
		||||
@ -110,6 +115,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
 | 
			
		||||
    private final ExportableEntitiesService exportableEntitiesService;
 | 
			
		||||
    private final TbNotificationEntityService entityNotificationService;
 | 
			
		||||
    private final TransactionTemplate transactionTemplate;
 | 
			
		||||
    private final TbTransactionalCache<UUID, VersionControlTaskCacheEntry> taskCache;
 | 
			
		||||
 | 
			
		||||
    private ListeningExecutorService executor;
 | 
			
		||||
 | 
			
		||||
@ -130,23 +136,55 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("UnstableApiUsage")
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<VersionCreationResult> saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception {
 | 
			
		||||
    public ListenableFuture<UUID> saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception {
 | 
			
		||||
        var pendingCommit = gitServiceQueue.prepareCommit(user, request);
 | 
			
		||||
 | 
			
		||||
        return transformAsync(pendingCommit, commit -> {
 | 
			
		||||
            List<ListenableFuture<Void>> gitFutures = new ArrayList<>();
 | 
			
		||||
            switch (request.getType()) {
 | 
			
		||||
                case SINGLE_ENTITY: {
 | 
			
		||||
                    handleSingleEntityRequest(new SimpleEntitiesExportCtx(user, commit, (SingleEntityVersionCreateRequest) request));
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case COMPLEX: {
 | 
			
		||||
                    handleComplexRequest(new ComplexEntitiesExportCtx(user, commit, (ComplexVersionCreateRequest) request));
 | 
			
		||||
                    break;
 | 
			
		||||
        DonAsynchron.withCallback(pendingCommit, commit -> {
 | 
			
		||||
            cachePut(commit.getTxId(), new VersionCreationResult());
 | 
			
		||||
            try {
 | 
			
		||||
                List<ListenableFuture<Void>> gitFutures = new ArrayList<>();
 | 
			
		||||
                switch (request.getType()) {
 | 
			
		||||
                    case SINGLE_ENTITY: {
 | 
			
		||||
                        handleSingleEntityRequest(new SimpleEntitiesExportCtx(user, commit, (SingleEntityVersionCreateRequest) request));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    case COMPLEX: {
 | 
			
		||||
                        handleComplexRequest(new ComplexEntitiesExportCtx(user, commit, (ComplexVersionCreateRequest) request));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                var resultFuture = Futures.transformAsync(Futures.allAsList(gitFutures), f -> gitServiceQueue.push(commit), executor);
 | 
			
		||||
                DonAsynchron.withCallback(resultFuture, result -> cachePut(commit.getTxId(), result), e -> processCommitError(user, request, commit, e), executor);
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                processCommitError(user, request, commit, e);
 | 
			
		||||
            }
 | 
			
		||||
            return transformAsync(Futures.allAsList(gitFutures), success -> gitServiceQueue.push(commit), executor);
 | 
			
		||||
        }, executor);
 | 
			
		||||
        }, t -> log.debug("[{}] Failed to prepare the commit: {}", user.getId(), request, t));
 | 
			
		||||
 | 
			
		||||
        return transform(pendingCommit, CommitGitRequest::getTxId, MoreExecutors.directExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public VersionCreationResult getVersionCreateStatus(SecurityUser user, UUID requestId) throws ThingsboardException {
 | 
			
		||||
        return getStatus(user, requestId, VersionControlTaskCacheEntry::getExportResult);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public VersionLoadResult getVersionLoadStatus(SecurityUser user, UUID requestId) throws ThingsboardException {
 | 
			
		||||
        return getStatus(user, requestId, VersionControlTaskCacheEntry::getImportResult);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private <T> T getStatus(SecurityUser user, UUID requestId, Function<VersionControlTaskCacheEntry, T> getter) throws ThingsboardException {
 | 
			
		||||
        var cacheEntry = taskCache.get(requestId);
 | 
			
		||||
        if (cacheEntry == null || cacheEntry.get() == null) {
 | 
			
		||||
            throw new ThingsboardException(ThingsboardErrorCode.ITEM_NOT_FOUND);
 | 
			
		||||
        } else {
 | 
			
		||||
            var entry = cacheEntry.get();
 | 
			
		||||
            var result = getter.apply(entry);
 | 
			
		||||
            if (result == null) {
 | 
			
		||||
                throw new ThingsboardException(ThingsboardErrorCode.BAD_REQUEST_PARAMS);
 | 
			
		||||
            } else {
 | 
			
		||||
                return result;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void handleSingleEntityRequest(SimpleEntitiesExportCtx ctx) throws Exception {
 | 
			
		||||
@ -214,26 +252,31 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings({"UnstableApiUsage", "rawtypes"})
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<VersionLoadResult> loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception {
 | 
			
		||||
    public UUID loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception {
 | 
			
		||||
        EntitiesImportCtx ctx = new EntitiesImportCtx(UUID.randomUUID(), user, request.getVersionId());
 | 
			
		||||
        switch (request.getType()) {
 | 
			
		||||
            case SINGLE_ENTITY: {
 | 
			
		||||
                SingleEntityVersionLoadRequest versionLoadRequest = (SingleEntityVersionLoadRequest) request;
 | 
			
		||||
                VersionLoadConfig config = versionLoadRequest.getConfig();
 | 
			
		||||
                ListenableFuture<EntityExportData> future = gitServiceQueue.getEntity(user.getTenantId(), request.getVersionId(), versionLoadRequest.getExternalEntityId());
 | 
			
		||||
                return Futures.transform(future, entityData -> doInTemplate(user, request, ctx -> loadSingleEntity(ctx, config, entityData)), executor);
 | 
			
		||||
                DonAsynchron.withCallback(future, entityData -> doInTemplate(ctx, request, c -> loadSingleEntity(c, config, entityData)),
 | 
			
		||||
                        e -> processLoadError(ctx, e), executor);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case ENTITY_TYPE: {
 | 
			
		||||
                EntityTypeVersionLoadRequest versionLoadRequest = (EntityTypeVersionLoadRequest) request;
 | 
			
		||||
                return executor.submit(() -> doInTemplate(user, request, ctx -> loadMultipleEntities(ctx, versionLoadRequest)));
 | 
			
		||||
                executor.submit(() -> doInTemplate(ctx, request, c -> loadMultipleEntities(c, versionLoadRequest)));
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            default:
 | 
			
		||||
                throw new IllegalArgumentException("Unsupported version load request");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ctx.getRequestId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private <R> VersionLoadResult doInTemplate(SecurityUser user, VersionLoadRequest request, Function<EntitiesImportCtx, VersionLoadResult> function) {
 | 
			
		||||
    private <R> VersionLoadResult doInTemplate(EntitiesImportCtx ctx, VersionLoadRequest request, Function<EntitiesImportCtx, VersionLoadResult> function) {
 | 
			
		||||
        try {
 | 
			
		||||
            EntitiesImportCtx ctx = new EntitiesImportCtx(user, request.getVersionId());
 | 
			
		||||
            VersionLoadResult result = transactionTemplate.execute(status -> function.apply(ctx));
 | 
			
		||||
            try {
 | 
			
		||||
                for (ThrowingRunnable throwingRunnable : ctx.getEventCallbacks()) {
 | 
			
		||||
@ -246,7 +289,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
 | 
			
		||||
        } catch (LoadEntityException e) {
 | 
			
		||||
            return onError(e.getData(), e.getCause());
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            log.info("[{}] Failed to process request [{}] due to: ", user.getTenantId(), request, e);
 | 
			
		||||
            log.info("[{}] Failed to process request [{}] due to: ", ctx.getTenantId(), request, e);
 | 
			
		||||
            throw e;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -477,7 +520,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<VersionCreationResult> autoCommit(SecurityUser user, EntityId entityId) throws Exception {
 | 
			
		||||
    public ListenableFuture<UUID> autoCommit(SecurityUser user, EntityId entityId) throws Exception {
 | 
			
		||||
        var repositorySettings = repositorySettingsService.get(user.getTenantId());
 | 
			
		||||
        if (repositorySettings == null) {
 | 
			
		||||
            return Futures.immediateFuture(null);
 | 
			
		||||
@ -504,7 +547,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<VersionCreationResult> autoCommit(SecurityUser user, EntityType entityType, List<UUID> entityIds) throws Exception {
 | 
			
		||||
    public ListenableFuture<UUID> autoCommit(SecurityUser user, EntityType entityType, List<UUID> entityIds) throws Exception {
 | 
			
		||||
        var repositorySettings = repositorySettingsService.get(user.getTenantId());
 | 
			
		||||
        if (repositorySettings == null) {
 | 
			
		||||
            return Futures.immediateFuture(null);
 | 
			
		||||
@ -550,5 +593,21 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void processCommitError(SecurityUser user, VersionCreateRequest request, CommitGitRequest commit, Throwable e) {
 | 
			
		||||
        log.debug("[{}] Failed to prepare the commit: {}", user.getId(), request, e);
 | 
			
		||||
        cachePut(commit.getTxId(), new VersionCreationResult(e.getMessage()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void processLoadError(EntitiesImportCtx ctx, Throwable e) {
 | 
			
		||||
        log.debug("[{}] Failed to load the commit: {}", ctx.getRequestId(), ctx.getVersionId(), e);
 | 
			
		||||
        cachePut(ctx.getRequestId(), VersionLoadResult.error(EntityLoadError.runtimeError(e.getMessage())));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void cachePut(UUID requestId, VersionCreationResult result) {
 | 
			
		||||
        taskCache.put(requestId, VersionControlTaskCacheEntry.newForExport(result));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void cachePut(UUID requestId, VersionLoadResult result) {
 | 
			
		||||
        taskCache.put(requestId, VersionControlTaskCacheEntry.newForImport(result));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,9 @@
 | 
			
		||||
package org.thingsboard.server.service.sync.vc;
 | 
			
		||||
 | 
			
		||||
import com.google.common.util.concurrent.ListenableFuture;
 | 
			
		||||
import org.springframework.web.context.request.async.DeferredResult;
 | 
			
		||||
import org.thingsboard.server.common.data.EntityType;
 | 
			
		||||
import org.thingsboard.server.common.data.exception.ThingsboardException;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.page.PageData;
 | 
			
		||||
@ -38,7 +40,9 @@ import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
public interface EntitiesVersionControlService {
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<VersionCreationResult> saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception;
 | 
			
		||||
    ListenableFuture<UUID> saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception;
 | 
			
		||||
 | 
			
		||||
    VersionCreationResult getVersionCreateStatus(SecurityUser user, UUID requestId) throws ThingsboardException;
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<PageData<EntityVersion>> listEntityVersions(TenantId tenantId, String branch, EntityId externalId, PageLink pageLink) throws Exception;
 | 
			
		||||
 | 
			
		||||
@ -50,7 +54,9 @@ public interface EntitiesVersionControlService {
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<List<VersionedEntityInfo>> listAllEntitiesAtVersion(TenantId tenantId, String branch, String versionId) throws Exception;
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<VersionLoadResult> loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception;
 | 
			
		||||
    UUID loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception;
 | 
			
		||||
 | 
			
		||||
    VersionLoadResult getVersionLoadStatus(SecurityUser user, UUID requestId) throws ThingsboardException;
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<EntityDataDiff> compareEntityDataToVersion(SecurityUser user, String branch, EntityId entityId, String versionId) throws Exception;
 | 
			
		||||
 | 
			
		||||
@ -64,9 +70,10 @@ public interface EntitiesVersionControlService {
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<Void> checkVersionControlAccess(TenantId tenantId, RepositorySettings settings) throws Exception;
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<VersionCreationResult> autoCommit(SecurityUser user, EntityId entityId) throws Exception;
 | 
			
		||||
    ListenableFuture<UUID> autoCommit(SecurityUser user, EntityId entityId) throws Exception;
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<VersionCreationResult> autoCommit(SecurityUser user, EntityType entityType, List<UUID> entityIds) throws Exception;
 | 
			
		||||
    ListenableFuture<UUID> autoCommit(SecurityUser user, EntityType entityType, List<UUID> entityIds) throws Exception;
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<EntityDataInfo> getEntityDataInfo(SecurityUser user, EntityId entityId, String versionId);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,43 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.sync.vc;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
 | 
			
		||||
import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class VersionControlTaskCacheEntry implements Serializable {
 | 
			
		||||
 | 
			
		||||
    private static final long serialVersionUID = -7875992200801588119L;
 | 
			
		||||
 | 
			
		||||
    private VersionCreationResult exportResult;
 | 
			
		||||
    private VersionLoadResult importResult;
 | 
			
		||||
 | 
			
		||||
    public static VersionControlTaskCacheEntry newForExport(VersionCreationResult result) {
 | 
			
		||||
        return new VersionControlTaskCacheEntry(result, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static VersionControlTaskCacheEntry newForImport(VersionLoadResult result) {
 | 
			
		||||
        return new VersionControlTaskCacheEntry(null, result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,36 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.sync.vc;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 | 
			
		||||
import org.springframework.cache.CacheManager;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
 | 
			
		||||
import org.thingsboard.server.common.data.CacheConstants;
 | 
			
		||||
import org.thingsboard.server.common.data.id.DeviceId;
 | 
			
		||||
import org.thingsboard.server.gen.transport.TransportProtos;
 | 
			
		||||
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
 | 
			
		||||
@Service("VersionControlTaskCache")
 | 
			
		||||
public class VersionControlTaskCaffeineCache extends CaffeineTbTransactionalCache<UUID, VersionControlTaskCacheEntry> {
 | 
			
		||||
 | 
			
		||||
    public VersionControlTaskCaffeineCache(CacheManager cacheManager) {
 | 
			
		||||
        super(cacheManager, CacheConstants.VERSION_CONTROL_TASK_CACHE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,41 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.sync.vc;
 | 
			
		||||
 | 
			
		||||
import com.google.protobuf.InvalidProtocolBufferException;
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 | 
			
		||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
 | 
			
		||||
import org.springframework.data.redis.serializer.RedisSerializer;
 | 
			
		||||
import org.springframework.data.redis.serializer.SerializationException;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.thingsboard.server.cache.CacheSpecsMap;
 | 
			
		||||
import org.thingsboard.server.cache.RedisTbTransactionalCache;
 | 
			
		||||
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
 | 
			
		||||
import org.thingsboard.server.cache.TbRedisSerializer;
 | 
			
		||||
import org.thingsboard.server.common.data.CacheConstants;
 | 
			
		||||
import org.thingsboard.server.common.data.id.DeviceId;
 | 
			
		||||
import org.thingsboard.server.gen.transport.TransportProtos;
 | 
			
		||||
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
 | 
			
		||||
@Service("VersionControlTaskCache")
 | 
			
		||||
public class VersionControlTaskRedisCache extends RedisTbTransactionalCache<UUID, VersionControlTaskCacheEntry> {
 | 
			
		||||
 | 
			
		||||
    public VersionControlTaskRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
 | 
			
		||||
        super(CacheConstants.VERSION_CONTROL_TASK_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbRedisSerializer<>());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -35,11 +35,13 @@ import java.util.LinkedHashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
@Data
 | 
			
		||||
public class EntitiesImportCtx {
 | 
			
		||||
 | 
			
		||||
    private final UUID requestId;
 | 
			
		||||
    private final SecurityUser user;
 | 
			
		||||
    private final String versionId;
 | 
			
		||||
 | 
			
		||||
@ -57,11 +59,12 @@ public class EntitiesImportCtx {
 | 
			
		||||
    private EntityImportSettings settings;
 | 
			
		||||
    private EntityImportResult<?> currentImportResult;
 | 
			
		||||
 | 
			
		||||
    public EntitiesImportCtx(SecurityUser user, String versionId) {
 | 
			
		||||
        this(user, versionId, null);
 | 
			
		||||
    public EntitiesImportCtx(UUID requestId, SecurityUser user, String versionId) {
 | 
			
		||||
        this(requestId, user, versionId, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public EntitiesImportCtx(SecurityUser user, String versionId, EntityImportSettings settings) {
 | 
			
		||||
    public EntitiesImportCtx(UUID requestId, SecurityUser user, String versionId, EntityImportSettings settings) {
 | 
			
		||||
        this.requestId = requestId;
 | 
			
		||||
        this.user = user;
 | 
			
		||||
        this.versionId = versionId;
 | 
			
		||||
        this.settings = settings;
 | 
			
		||||
 | 
			
		||||
@ -421,6 +421,9 @@ cache:
 | 
			
		||||
    twoFaVerificationCodes:
 | 
			
		||||
      timeToLiveInMinutes: "${CACHE_SPECS_TWO_FA_VERIFICATION_CODES_TTL:60}"
 | 
			
		||||
      maxSize: "${CACHE_SPECS_TWO_FA_VERIFICATION_CODES_MAX_SIZE:100000}"
 | 
			
		||||
    versionControlTask:
 | 
			
		||||
      timeToLiveInMinutes: "${CACHE_SPECS_VERSION_CONTROL_TASK_TTL:60}"
 | 
			
		||||
      maxSize: "${CACHE_SPECS_VERSION_CONTROL_TASK_MAX_SIZE:100000}"
 | 
			
		||||
 | 
			
		||||
redis:
 | 
			
		||||
  # standalone or cluster
 | 
			
		||||
 | 
			
		||||
@ -34,4 +34,5 @@ public class CacheConstants {
 | 
			
		||||
    public static final String REPOSITORY_SETTINGS_CACHE = "repositorySettings";
 | 
			
		||||
    public static final String AUTO_COMMIT_SETTINGS_CACHE = "autoCommitSettings";
 | 
			
		||||
    public static final String TWO_FA_VERIFICATION_CODES_CACHE = "twoFaVerificationCodes";
 | 
			
		||||
    public static final String VERSION_CONTROL_TASK_CACHE = "versionControlTask";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,7 @@ public class EntityLoadError {
 | 
			
		||||
    private String type;
 | 
			
		||||
    private EntityId source;
 | 
			
		||||
    private EntityId target;
 | 
			
		||||
    private String message;
 | 
			
		||||
 | 
			
		||||
    public static EntityLoadError credentialsError(EntityId sourceId) {
 | 
			
		||||
        return EntityLoadError.builder().type("DEVICE_CREDENTIALS_CONFLICT").source(sourceId).build();
 | 
			
		||||
@ -39,4 +40,8 @@ public class EntityLoadError {
 | 
			
		||||
        return EntityLoadError.builder().type("MISSING_REFERENCED_ENTITY").source(sourceId).target(targetId).build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static EntityLoadError runtimeError(String msg) {
 | 
			
		||||
        return EntityLoadError.builder().type("RUNTIME").message(msg).build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,10 +19,15 @@ import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
public class EntityVersion {
 | 
			
		||||
public class EntityVersion implements Serializable {
 | 
			
		||||
 | 
			
		||||
    private static final long serialVersionUID = -3705022663019175258L;
 | 
			
		||||
    
 | 
			
		||||
    private long timestamp;
 | 
			
		||||
    private String id;
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
@ -16,11 +16,34 @@
 | 
			
		||||
package org.thingsboard.server.common.data.sync.vc;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class VersionCreationResult {
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
public class VersionCreationResult implements Serializable {
 | 
			
		||||
    private static final long serialVersionUID = 8032189124530267838L;
 | 
			
		||||
 | 
			
		||||
    private EntityVersion version;
 | 
			
		||||
    private int added;
 | 
			
		||||
    private int modified;
 | 
			
		||||
    private int removed;
 | 
			
		||||
 | 
			
		||||
    private String error;
 | 
			
		||||
    private boolean done;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public VersionCreationResult(EntityVersion version, int added, int modified, int removed) {
 | 
			
		||||
        this.version = version;
 | 
			
		||||
        this.added = added;
 | 
			
		||||
        this.modified = modified;
 | 
			
		||||
        this.removed = removed;
 | 
			
		||||
        this.done = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public VersionCreationResult(String error) {
 | 
			
		||||
        this.error = error;
 | 
			
		||||
        this.done = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,26 +19,30 @@ import com.fasterxml.jackson.annotation.JsonInclude;
 | 
			
		||||
import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@Builder
 | 
			
		||||
@JsonInclude(JsonInclude.Include.NON_NULL)
 | 
			
		||||
public class VersionLoadResult {
 | 
			
		||||
public class VersionLoadResult implements Serializable {
 | 
			
		||||
 | 
			
		||||
    private static final long serialVersionUID = -1386093599856747449L;
 | 
			
		||||
 | 
			
		||||
    private List<EntityTypeLoadResult> result;
 | 
			
		||||
    private EntityLoadError error;
 | 
			
		||||
    private boolean done;
 | 
			
		||||
 | 
			
		||||
    public static VersionLoadResult success(List<EntityTypeLoadResult> result) {
 | 
			
		||||
        return VersionLoadResult.builder().result(result).build();
 | 
			
		||||
        return VersionLoadResult.builder().result(result).done(true).build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static VersionLoadResult success(EntityTypeLoadResult result) {
 | 
			
		||||
        return VersionLoadResult.builder().result(List.of(result)).build();
 | 
			
		||||
        return VersionLoadResult.builder().result(List.of(result)).done(true).build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static VersionLoadResult error(EntityLoadError error) {
 | 
			
		||||
        return VersionLoadResult.builder().error(error).build();
 | 
			
		||||
        return VersionLoadResult.builder().error(error).done(true).build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user