Browse Source

Merge pull request #6562 from thingsboard/feature/vc-microservice

Feature/vc microservice
pull/6566/head
Andrew Shvayka 4 years ago
committed by GitHub
parent
commit
d2c918c2f9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      application/pom.xml
  2. 4
      application/src/main/java/org/thingsboard/server/controller/AssetController.java
  3. 4
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  4. 4
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  5. 16
      application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
  6. 4
      application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java
  7. 4
      application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java
  8. 4
      application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java
  9. 20
      application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java
  10. 10
      application/src/main/java/org/thingsboard/server/service/sync/ie/EntitiesExportImportService.java
  11. 2
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/DefaultExportableEntitiesService.java
  12. 6
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/EntityExportService.java
  13. 5
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/ExportableEntitiesService.java
  14. 6
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java
  15. 10
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java
  16. 4
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceExportService.java
  17. 4
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/RuleChainExportService.java
  18. 8
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/EntityImportService.java
  19. 3
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/AbstractBulkImportService.java
  20. 2
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/BulkImportColumnType.java
  21. 2
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/BulkImportRequest.java
  22. 2
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/BulkImportResult.java
  23. 2
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/ImportedEntityInfo.java
  24. 4
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetImportService.java
  25. 12
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java
  26. 4
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/CustomerImportService.java
  27. 6
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java
  28. 4
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceImportService.java
  29. 4
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java
  30. 6
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/RuleChainImportService.java
  31. 253
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java
  32. 16
      application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java
  33. 258
      application/src/main/java/org/thingsboard/server/service/sync/vc/LocalGitVersionControlService.java
  34. 5
      application/src/main/resources/thingsboard.yml
  35. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/JsonTbEntity.java
  36. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ThrowingRunnable.java
  37. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceExportData.java
  38. 4
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityExportData.java
  39. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityExportSettings.java
  40. 6
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityImportResult.java
  41. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityImportSettings.java
  42. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/RuleChainExportData.java
  43. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntitiesVersionControlSettings.java
  44. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityVersion.java
  45. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionCreationResult.java
  46. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionLoadResult.java
  47. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionedEntityInfo.java
  48. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/ComplexVersionCreateRequest.java
  49. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/EntityTypeVersionCreateConfig.java
  50. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/SingleEntityVersionCreateRequest.java
  51. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/SyncStrategy.java
  52. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/VersionCreateConfig.java
  53. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/VersionCreateRequest.java
  54. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/VersionCreateRequestType.java
  55. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/EntityTypeVersionLoadConfig.java
  56. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/EntityTypeVersionLoadRequest.java
  57. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/SingleEntityVersionLoadRequest.java
  58. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/VersionLoadConfig.java
  59. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/VersionLoadRequest.java
  60. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/VersionLoadRequestType.java
  61. 1
      common/pom.xml
  62. 115
      common/version-control/pom.xml
  63. 239
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java
  64. 2
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java
  65. 48
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepositoryService.java
  66. 60
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java
  67. 36
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/PendingCommit.java
  68. 5
      pom.xml

8
application/pom.xml

@ -69,6 +69,10 @@
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>
<artifactId>cluster-api</artifactId> <artifactId>cluster-api</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>version-control</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.thingsboard.rule-engine</groupId> <groupId>org.thingsboard.rule-engine</groupId>
<artifactId>rule-engine-components</artifactId> <artifactId>rule-engine-components</artifactId>
@ -341,10 +345,6 @@
<artifactId>Java-WebSocket</artifactId> <artifactId>Java-WebSocket</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

4
application/src/main/java/org/thingsboard/server/controller/AssetController.java

@ -51,8 +51,8 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.asset.AssetBulkImportService; import org.thingsboard.server.service.asset.AssetBulkImportService;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportRequest; import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportResult; import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.service.entitiy.asset.TbAssetService; import org.thingsboard.server.service.entitiy.asset.TbAssetService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;

4
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -66,8 +66,8 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.device.DeviceBulkImportService; import org.thingsboard.server.service.device.DeviceBulkImportService;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportRequest; import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportResult; import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.service.entitiy.device.TbDeviceService; import org.thingsboard.server.service.entitiy.device.TbDeviceService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;

4
application/src/main/java/org/thingsboard/server/controller/EdgeController.java

@ -52,8 +52,8 @@ import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.EdgeBulkImportService; import org.thingsboard.server.service.edge.EdgeBulkImportService;
import org.thingsboard.server.service.entitiy.edge.TbEdgeService; import org.thingsboard.server.service.entitiy.edge.TbEdgeService;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportRequest; import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportResult; import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.permission.Resource;

16
application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java

@ -32,13 +32,13 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import org.thingsboard.server.service.sync.vc.data.EntitiesVersionControlSettings; import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.service.sync.vc.data.EntityVersion; import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.service.sync.vc.data.VersionCreationResult; import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.service.sync.vc.data.VersionLoadResult; import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
import org.thingsboard.server.service.sync.vc.data.VersionedEntityInfo; import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateRequest; import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import org.thingsboard.server.service.sync.vc.data.request.load.VersionLoadRequest; import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadRequest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -172,7 +172,7 @@ public class EntitiesVersionControlController extends BaseController {
@PathVariable EntityType entityType, @PathVariable EntityType entityType,
@PathVariable String versionId) throws ThingsboardException { @PathVariable String versionId) throws ThingsboardException {
try { try {
return versionControlService.listEntitiesAtVersion(getTenantId(), entityType, branch, versionId); return versionControlService.listEntitiesAtVersion(getTenantId(), branch, versionId, entityType);
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }

4
application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java

@ -26,8 +26,8 @@ import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.exportimport.importing.csv.AbstractBulkImportService; import org.thingsboard.server.service.sync.ie.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportColumnType; import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.entitiy.asset.TbAssetService; import org.thingsboard.server.service.entitiy.asset.TbAssetService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;

4
application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java

@ -49,8 +49,8 @@ import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.exportimport.importing.csv.AbstractBulkImportService; import org.thingsboard.server.service.sync.ie.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportColumnType; import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.entitiy.device.TbDeviceService; import org.thingsboard.server.service.entitiy.device.TbDeviceService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;

4
application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java

@ -28,8 +28,8 @@ import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.exportimport.importing.csv.AbstractBulkImportService; import org.thingsboard.server.service.sync.ie.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportColumnType; import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.entitiy.edge.TbEdgeService; import org.thingsboard.server.service.entitiy.edge.TbEdgeService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;

20
application/src/main/java/org/thingsboard/server/service/sync/exportimport/DefaultEntitiesExportImportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport; package org.thingsboard.server.service.sync.ie;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -27,15 +27,15 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exportimport.exporting.EntityExportService; import org.thingsboard.server.service.sync.ie.exporting.EntityExportService;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings; import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.impl.BaseEntityExportService; import org.thingsboard.server.service.sync.ie.exporting.impl.BaseEntityExportService;
import org.thingsboard.server.service.sync.exportimport.exporting.impl.DefaultEntityExportService; import org.thingsboard.server.service.sync.ie.exporting.impl.DefaultEntityExportService;
import org.thingsboard.server.service.sync.exportimport.importing.EntityImportService; import org.thingsboard.server.service.sync.ie.importing.EntityImportService;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportResult; import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings; import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.utils.ThrowingRunnable; import org.thingsboard.server.common.data.sync.ThrowingRunnable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;

10
application/src/main/java/org/thingsboard/server/service/sync/exportimport/EntitiesExportImportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/EntitiesExportImportService.java

@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport; package org.thingsboard.server.service.sync.ie;
import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings; import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportResult; import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings; import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import java.util.List; import java.util.List;

2
application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/DefaultExportableEntitiesService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/DefaultExportableEntitiesService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.exporting; package org.thingsboard.server.service.sync.ie.exporting;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;

6
application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/EntityExportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/EntityExportService.java

@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.exporting; package org.thingsboard.server.service.sync.ie.exporting;
import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings; import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
public interface EntityExportService<I extends EntityId, E extends ExportableEntity<I>, D extends EntityExportData<E>> { public interface EntityExportService<I extends EntityId, E extends ExportableEntity<I>, D extends EntityExportData<E>> {

5
application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/ExportableEntitiesService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/ExportableEntitiesService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.exporting; package org.thingsboard.server.service.sync.ie.exporting;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.ExportableEntity;
@ -25,9 +25,6 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateConfig;
import java.util.List;
public interface ExportableEntitiesService { public interface ExportableEntitiesService {

6
application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/impl/BaseEntityExportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.exporting.impl; package org.thingsboard.server.service.sync.ie.exporting.impl;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.ExportableEntity;
@ -21,8 +21,8 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings; import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import java.util.Set; import java.util.Set;

10
application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/impl/DefaultEntityExportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.exporting.impl; package org.thingsboard.server.service.sync.ie.exporting.impl;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@ -28,10 +28,10 @@ import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings; import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.EntityExportService; import org.thingsboard.server.service.sync.ie.exporting.EntityExportService;
import org.thingsboard.server.service.sync.exportimport.exporting.ExportableEntitiesService; import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

4
application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/impl/DeviceExportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceExportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.exporting.impl; package org.thingsboard.server.service.sync.ie.exporting.impl;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.exportimport.exporting.data.DeviceExportData; import org.thingsboard.server.common.data.sync.ie.DeviceExportData;
import java.util.Set; import java.util.Set;

4
application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/impl/RuleChainExportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/RuleChainExportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.exporting.impl; package org.thingsboard.server.service.sync.ie.exporting.impl;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.exportimport.exporting.data.RuleChainExportData; import org.thingsboard.server.common.data.sync.ie.RuleChainExportData;
import java.util.Set; import java.util.Set;

8
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/EntityImportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/EntityImportService.java

@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing; package org.thingsboard.server.service.sync.ie.importing;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportResult; import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings; import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
public interface EntityImportService<I extends EntityId, E extends ExportableEntity<I>, D extends EntityExportData<E>> { public interface EntityImportService<I extends EntityId, E extends ExportableEntity<I>, D extends EntityExportData<E>> {

3
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/AbstractBulkImportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/AbstractBulkImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.csv; package org.thingsboard.server.service.sync.ie.importing.csv;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
@ -66,7 +66,6 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;

2
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/BulkImportColumnType.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/BulkImportColumnType.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.csv; package org.thingsboard.server.service.sync.ie.importing.csv;
import lombok.Getter; import lombok.Getter;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;

2
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/BulkImportRequest.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/BulkImportRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.csv; package org.thingsboard.server.service.sync.ie.importing.csv;
import lombok.Data; import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/BulkImportResult.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/BulkImportResult.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.csv; package org.thingsboard.server.service.sync.ie.importing.csv;
import lombok.Data; import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/ImportedEntityInfo.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/ImportedEntityInfo.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.csv; package org.thingsboard.server.service.sync.ie.importing.csv;
import lombok.Data; import lombok.Data;

4
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/AssetImportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.impl; package org.thingsboard.server.service.sync.ie.importing.impl;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
@Service @Service
@TbCoreComponent @TbCoreComponent

12
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/BaseEntityImportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.impl; package org.thingsboard.server.service.sync.ie.importing.impl;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -35,11 +35,11 @@ import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.service.action.EntityActionService; import org.thingsboard.server.service.action.EntityActionService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportResult; import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings; import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.ExportableEntitiesService; import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.importing.EntityImportService; import org.thingsboard.server.service.sync.ie.importing.EntityImportService;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

4
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/CustomerImportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/CustomerImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.impl; package org.thingsboard.server.service.sync.ie.importing.impl;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
@Service @Service
@TbCoreComponent @TbCoreComponent

6
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/DashboardImportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.impl; package org.thingsboard.server.service.sync.ie.importing.impl;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -30,8 +30,8 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings; import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.utils.RegexUtils; import org.thingsboard.server.utils.RegexUtils;
import java.util.Collections; import java.util.Collections;

4
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/DeviceImportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.impl; package org.thingsboard.server.service.sync.ie.importing.impl;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -25,7 +25,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exportimport.exporting.data.DeviceExportData; import org.thingsboard.server.common.data.sync.ie.DeviceExportData;
@Service @Service
@TbCoreComponent @TbCoreComponent

4
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/DeviceProfileImportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.impl; package org.thingsboard.server.service.sync.ie.importing.impl;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -28,7 +28,7 @@ import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.ota.OtaPackageStateService; import org.thingsboard.server.service.ota.OtaPackageStateService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import java.util.Objects; import java.util.Objects;

6
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/RuleChainImportService.java → application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/RuleChainImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.impl; package org.thingsboard.server.service.sync.ie.importing.impl;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -32,8 +32,8 @@ import org.thingsboard.server.common.data.rule.RuleChainUpdateResult;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings; import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.RuleChainExportData; import org.thingsboard.server.common.data.sync.ie.RuleChainExportData;
import org.thingsboard.server.utils.RegexUtils; import org.thingsboard.server.utils.RegexUtils;
import java.util.Collections; import java.util.Collections;

253
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java

@ -55,28 +55,27 @@ import org.thingsboard.server.queue.util.AfterStartUp;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.sync.exportimport.EntitiesExportImportService; import org.thingsboard.server.service.sync.ie.EntitiesExportImportService;
import org.thingsboard.server.service.sync.exportimport.exporting.ExportableEntitiesService; import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings; import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportResult; import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings; import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.service.sync.vc.data.EntitiesVersionControlSettings; import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.service.sync.vc.data.EntityVersion; import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.service.sync.vc.data.VersionCreationResult; import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.service.sync.vc.data.VersionLoadResult; import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
import org.thingsboard.server.service.sync.vc.data.VersionedEntityInfo; import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.service.sync.vc.data.request.create.ComplexVersionCreateRequest; import org.thingsboard.server.common.data.sync.vc.request.create.ComplexVersionCreateRequest;
import org.thingsboard.server.service.sync.vc.data.request.create.SingleEntityVersionCreateRequest; import org.thingsboard.server.common.data.sync.vc.request.create.SingleEntityVersionCreateRequest;
import org.thingsboard.server.service.sync.vc.data.request.create.SyncStrategy; import org.thingsboard.server.common.data.sync.vc.request.create.SyncStrategy;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateConfig; import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateRequest; import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import org.thingsboard.server.service.sync.vc.data.request.load.EntityTypeVersionLoadRequest; import org.thingsboard.server.common.data.sync.vc.request.load.EntityTypeVersionLoadRequest;
import org.thingsboard.server.service.sync.vc.data.request.load.SingleEntityVersionLoadRequest; import org.thingsboard.server.common.data.sync.vc.request.load.SingleEntityVersionLoadRequest;
import org.thingsboard.server.service.sync.vc.data.request.load.VersionLoadConfig; import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadConfig;
import org.thingsboard.server.service.sync.vc.data.request.load.VersionLoadRequest; import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadRequest;
import org.thingsboard.server.utils.GitRepository; import org.thingsboard.server.common.data.sync.ThrowingRunnable;
import org.thingsboard.server.utils.ThrowingRunnable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -105,85 +104,31 @@ import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.CREATED_TIME
@Slf4j @Slf4j
public class DefaultEntitiesVersionControlService implements EntitiesVersionControlService { public class DefaultEntitiesVersionControlService implements EntitiesVersionControlService {
private final GitVersionControlService gitService;
private final EntitiesExportImportService exportImportService; private final EntitiesExportImportService exportImportService;
private final ExportableEntitiesService exportableEntitiesService; private final ExportableEntitiesService exportableEntitiesService;
private final AttributesService attributesService; private final AttributesService attributesService;
private final EntityService entityService; private final EntityService entityService;
private final TenantDao tenantDao;
private final TransactionTemplate transactionTemplate; private final TransactionTemplate transactionTemplate;
// TODO [viacheslav]: concurrency public static final String SETTINGS_KEY = "vc";
private final Map<TenantId, GitRepository> repositories = new ConcurrentHashMap<>();
@Value("${java.io.tmpdir}/repositories")
private String repositoriesFolder;
private static final String SETTINGS_KEY = "vc";
private final ObjectWriter jsonWriter = new ObjectMapper().writer(SerializationFeature.INDENT_OUTPUT);
@AfterStartUp
public void init() {
DaoUtil.processInBatches(tenantDao::findTenantsIds, 100, tenantId -> {
EntitiesVersionControlSettings settings = getSettings(tenantId);
if (settings != null) {
try {
initRepository(tenantId, settings);
} catch (Exception e) {
log.warn("Failed to init repository for tenant {}", tenantId, e);
}
}
});
Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(() -> {
repositories.forEach((tenantId, repository) -> {
try {
repository.fetch();
log.info("Fetching remote repository for tenant {}", tenantId);
} catch (Exception e) {
log.warn("Failed to fetch repository for tenant {}", tenantId, e);
}
});
}, 5, 5, TimeUnit.SECONDS);
}
@Override @Override
public VersionCreationResult saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception { public VersionCreationResult saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception {
GitRepository repository = checkRepository(user.getTenantId());
var commit = gitService.prepareCommit(user.getTenantId(), request);
repository.fetch();
if (repository.listBranches().contains(request.getBranch())) {
repository.checkout("origin/" + request.getBranch(), false);
try {
repository.checkout(request.getBranch(), true);
} catch (RefAlreadyExistsException e) {
repository.checkout(request.getBranch(), false);
}
repository.merge(request.getBranch());
} else { // TODO [viacheslav]: rollback orphan branch on failure
try {
repository.createAndCheckoutOrphanBranch(request.getBranch()); // FIXME [viacheslav]: Checkout returned unexpected result NO_CHANGE for master branch
} catch (JGitInternalException e) {
if (!e.getMessage().contains("NO_CHANGE")) {
throw e;
}
}
}
switch (request.getType()) { switch (request.getType()) {
case SINGLE_ENTITY: { case SINGLE_ENTITY: {
SingleEntityVersionCreateRequest versionCreateRequest = (SingleEntityVersionCreateRequest) request; SingleEntityVersionCreateRequest versionCreateRequest = (SingleEntityVersionCreateRequest) request;
saveEntityData(user, repository, versionCreateRequest.getEntityId(), versionCreateRequest.getConfig()); saveEntityData(user, commit, versionCreateRequest.getEntityId(), versionCreateRequest.getConfig());
break; break;
} }
case COMPLEX: { case COMPLEX: {
ComplexVersionCreateRequest versionCreateRequest = (ComplexVersionCreateRequest) request; ComplexVersionCreateRequest versionCreateRequest = (ComplexVersionCreateRequest) request;
versionCreateRequest.getEntityTypes().forEach((entityType, config) -> { versionCreateRequest.getEntityTypes().forEach((entityType, config) -> {
if (ObjectUtils.defaultIfNull(config.getSyncStrategy(), versionCreateRequest.getSyncStrategy()) == SyncStrategy.OVERWRITE) { if (ObjectUtils.defaultIfNull(config.getSyncStrategy(), versionCreateRequest.getSyncStrategy()) == SyncStrategy.OVERWRITE) {
try { gitService.deleteAll(commit, entityType);
FileUtils.deleteDirectory(Path.of(repository.getDirectory(), getRelativePath(entityType, null)).toFile());
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
if (config.isAllEntities()) { if (config.isAllEntities()) {
@ -203,7 +148,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
}, 100, data -> { }, 100, data -> {
EntityId entityId = data.getEntityId(); EntityId entityId = data.getEntityId();
try { try {
saveEntityData(user, repository, entityId, config); saveEntityData(user, commit, entityId, config);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -211,7 +156,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
} else { } else {
for (UUID entityId : config.getEntityIds()) { for (UUID entityId : config.getEntityIds()) {
try { try {
saveEntityData(user, repository, EntityIdFactory.getByTypeAndUuid(entityType, entityId), config); saveEntityData(user, commit, EntityIdFactory.getByTypeAndUuid(entityType, entityId), config);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -223,90 +168,50 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
} }
} }
repository.add("."); return gitService.push(commit);
VersionCreationResult result = new VersionCreationResult();
GitRepository.Status status = repository.status();
result.setAdded(status.getAdded().size());
result.setModified(status.getModified().size());
result.setRemoved(status.getRemoved().size());
GitRepository.Commit commit = repository.commit(request.getVersionName());
repository.push();
result.setVersion(toVersion(commit));
return result;
} }
private void saveEntityData(SecurityUser user, GitRepository repository, EntityId entityId, VersionCreateConfig config) throws Exception { private void saveEntityData(SecurityUser user, PendingCommit commit, EntityId entityId, VersionCreateConfig config) throws Exception {
EntityExportData<ExportableEntity<EntityId>> entityData = exportImportService.exportEntity(user, entityId, EntityExportSettings.builder() EntityExportData<ExportableEntity<EntityId>> entityData = exportImportService.exportEntity(user, entityId, EntityExportSettings.builder()
.exportRelations(config.isSaveRelations()) .exportRelations(config.isSaveRelations())
.build()); .build());
String entityDataJson = jsonWriter.writeValueAsString(entityData); gitService.addToCommit(commit, entityData);
FileUtils.write(Path.of(repository.getDirectory(), getRelativePath(entityData.getEntityType(),
entityData.getEntity().getId().toString())).toFile(), entityDataJson, StandardCharsets.UTF_8);
} }
@Override @Override
public List<EntityVersion> listEntityVersions(TenantId tenantId, String branch, EntityId externalId) throws Exception { public List<EntityVersion> listEntityVersions(TenantId tenantId, String branch, EntityId externalId) throws Exception {
return listVersions(tenantId, branch, getRelativePath(externalId.getEntityType(), externalId.getId().toString())); return gitService.listVersions(tenantId, branch, externalId);
} }
@Override @Override
public List<EntityVersion> listEntityTypeVersions(TenantId tenantId, String branch, EntityType entityType) throws Exception { public List<EntityVersion> listEntityTypeVersions(TenantId tenantId, String branch, EntityType entityType) throws Exception {
return listVersions(tenantId, branch, getRelativePath(entityType, null)); return gitService.listVersions(tenantId, branch, entityType);
} }
@Override @Override
public List<EntityVersion> listVersions(TenantId tenantId, String branch) throws Exception { public List<EntityVersion> listVersions(TenantId tenantId, String branch) throws Exception {
return listVersions(tenantId, branch, null); return gitService.listVersions(tenantId, branch);
}
private List<EntityVersion> listVersions(TenantId tenantId, String branch, String path) throws Exception {
GitRepository repository = checkRepository(tenantId);
return repository.listCommits(branch, path, Integer.MAX_VALUE).stream()
.map(this::toVersion)
.collect(Collectors.toList());
} }
@Override @Override
public List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, EntityType entityType, String branch, String versionId) throws Exception { public List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) throws Exception {
return listEntitiesAtVersion(tenantId, branch, versionId, getRelativePath(entityType, null)); return gitService.listEntitiesAtVersion(tenantId, branch, versionId, entityType);
} }
@Override @Override
public List<VersionedEntityInfo> listAllEntitiesAtVersion(TenantId tenantId, String branch, String versionId) throws Exception { public List<VersionedEntityInfo> listAllEntitiesAtVersion(TenantId tenantId, String branch, String versionId) throws Exception {
return listEntitiesAtVersion(tenantId, branch, versionId, null); return gitService.listEntitiesAtVersion(tenantId, branch, versionId);
} }
private List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, String path) throws Exception {
GitRepository repository = checkRepository(tenantId);
checkVersion(tenantId, branch, versionId);
return repository.listFilesAtCommit(versionId, path).stream()
.map(filePath -> {
EntityId entityId = fromRelativePath(filePath);
VersionedEntityInfo info = new VersionedEntityInfo();
info.setExternalId(entityId);
return info;
})
.collect(Collectors.toList());
}
@Override @Override
public List<VersionLoadResult> loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception { public List<VersionLoadResult> loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception {
GitRepository repository = checkRepository(user.getTenantId());
EntityVersion version = checkVersion(user.getTenantId(), request.getBranch(), request.getVersionId());
switch (request.getType()) { switch (request.getType()) {
case SINGLE_ENTITY: { case SINGLE_ENTITY: {
SingleEntityVersionLoadRequest versionLoadRequest = (SingleEntityVersionLoadRequest) request; SingleEntityVersionLoadRequest versionLoadRequest = (SingleEntityVersionLoadRequest) request;
EntityImportResult<?> importResult = transactionTemplate.execute(status -> { EntityImportResult<?> importResult = transactionTemplate.execute(status -> {
try { try {
EntityImportResult<?> result = loadEntity(user, repository, versionLoadRequest.getExternalEntityId(), version.getId(), versionLoadRequest.getConfig()); EntityImportResult<?> result = loadEntity(user, request, versionLoadRequest.getConfig(), versionLoadRequest.getExternalEntityId());
result.getSaveReferencesCallback().run(); result.getSaveReferencesCallback().run();
return result; return result;
} catch (Exception e) { } catch (Exception e) {
@ -340,11 +245,11 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
Set<EntityId> remoteEntities; Set<EntityId> remoteEntities;
try { try {
remoteEntities = listEntitiesAtVersion(user.getTenantId(), request.getBranch(), request.getVersionId(), getRelativePath(entityType, null)).stream() remoteEntities = listEntitiesAtVersion(user.getTenantId(), request.getBranch(), request.getVersionId(), entityType).stream()
.map(VersionedEntityInfo::getExternalId) .map(VersionedEntityInfo::getExternalId)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
for (EntityId externalEntityId : remoteEntities) { for (EntityId externalEntityId : remoteEntities) {
EntityImportResult<?> importResult = loadEntity(user, repository, externalEntityId, version.getId(), config); EntityImportResult<?> importResult = loadEntity(user, request, config, externalEntityId);
if (importResult.getOldEntity() == null) created.incrementAndGet(); if (importResult.getOldEntity() == null) created.incrementAndGet();
else updated.incrementAndGet(); else updated.incrementAndGet();
@ -402,10 +307,8 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
} }
} }
private EntityImportResult<?> loadEntity(SecurityUser user, GitRepository repository, EntityId externalId, String versionId, VersionLoadConfig config) throws Exception { private EntityImportResult<?> loadEntity(SecurityUser user, VersionLoadRequest request, VersionLoadConfig config, EntityId entityId) throws Exception {
String entityDataJson = repository.getFileContentAtCommit(getRelativePath(externalId.getEntityType(), externalId.getId().toString()), versionId); EntityExportData entityData = gitService.getEntity(user.getTenantId(), request.getVersionId(), entityId);
EntityExportData entityData = JacksonUtil.fromString(entityDataJson, EntityExportData.class);
return exportImportService.importEntity(user, entityData, EntityImportSettings.builder() return exportImportService.importEntity(user, entityData, EntityImportSettings.builder()
.updateRelations(config.isLoadRelations()) .updateRelations(config.isLoadRelations())
.findExistingByName(config.isFindExistingEntityByName()) .findExistingByName(config.isFindExistingEntityByName())
@ -415,43 +318,9 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
@Override @Override
public List<String> listBranches(TenantId tenantId) throws Exception { public List<String> listBranches(TenantId tenantId) throws Exception {
GitRepository repository = checkRepository(tenantId); return gitService.listBranches(tenantId);
return repository.listBranches();
}
private EntityVersion checkVersion(TenantId tenantId, String branch, String versionId) throws Exception {
return listVersions(tenantId, branch, null).stream()
.filter(version -> version.getId().equals(versionId))
.findFirst().orElseThrow(() -> new IllegalArgumentException("Version not found"));
}
private GitRepository checkRepository(TenantId tenantId) {
return Optional.ofNullable(repositories.get(tenantId))
.orElseThrow(() -> new IllegalStateException("Repository is not initialized"));
}
private void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings) throws Exception {
Path repositoryDirectory = Path.of(repositoriesFolder, tenantId.getId().toString());
GitRepository repository;
if (Files.exists(repositoryDirectory)) {
FileUtils.forceDelete(repositoryDirectory.toFile());
}
Files.createDirectories(repositoryDirectory);
repository = GitRepository.clone(settings.getRepositoryUri(), settings.getUsername(), settings.getPassword(), repositoryDirectory.toFile());
repositories.put(tenantId, repository);
}
private void clearRepository(TenantId tenantId) throws IOException {
GitRepository repository = repositories.get(tenantId);
if (repository != null) {
FileUtils.deleteDirectory(new File(repository.getDirectory()));
repositories.remove(tenantId);
}
} }
@SneakyThrows @SneakyThrows
@Override @Override
public void saveSettings(TenantId tenantId, EntitiesVersionControlSettings settings) { public void saveSettings(TenantId tenantId, EntitiesVersionControlSettings settings) {
@ -459,41 +328,11 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
new BaseAttributeKvEntry(System.currentTimeMillis(), new JsonDataEntry(SETTINGS_KEY, JacksonUtil.toString(settings))) new BaseAttributeKvEntry(System.currentTimeMillis(), new JsonDataEntry(SETTINGS_KEY, JacksonUtil.toString(settings)))
)).get(); )).get();
initRepository(tenantId, settings); gitService.initRepository(tenantId, settings);
} }
@SneakyThrows
@Override @Override
public EntitiesVersionControlSettings getSettings(TenantId tenantId) { public EntitiesVersionControlSettings getSettings(TenantId tenantId) {
return attributesService.find(tenantId, tenantId, DataConstants.SERVER_SCOPE, SETTINGS_KEY).get() return gitService.getSettings(tenantId);
.flatMap(KvEntry::getJsonValue)
.map(json -> {
try {
return JacksonUtil.fromString(json, EntitiesVersionControlSettings.class);
} catch (IllegalArgumentException e) {
return null;
}
})
.orElse(null);
}
private EntityVersion toVersion(GitRepository.Commit commit) {
return new EntityVersion(commit.getId(), commit.getMessage());
}
private String getRelativePath(EntityType entityType, String entityId) {
String path = entityType.name().toLowerCase();
if (entityId != null) {
path += "/" + entityId + ".json";
}
return path;
} }
private EntityId fromRelativePath(String path) {
EntityType entityType = EntityType.valueOf(StringUtils.substringBefore(path, "/").toUpperCase());
String entityId = StringUtils.substringBetween(path, "/", ".json");
return EntityIdFactory.getByTypeAndUuid(entityType, entityId);
}
} }

16
application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java

@ -19,13 +19,13 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.vc.data.EntitiesVersionControlSettings; import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.service.sync.vc.data.EntityVersion; import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.service.sync.vc.data.VersionCreationResult; import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.service.sync.vc.data.VersionLoadResult; import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
import org.thingsboard.server.service.sync.vc.data.VersionedEntityInfo; import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.service.sync.vc.data.request.load.VersionLoadRequest; import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadRequest;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateRequest; import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import java.util.List; import java.util.List;
@ -41,7 +41,7 @@ public interface EntitiesVersionControlService {
List<EntityVersion> listVersions(TenantId tenantId, String branch) throws Exception; List<EntityVersion> listVersions(TenantId tenantId, String branch) throws Exception;
List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, EntityType entityType, String branch, String versionId) throws Exception; List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) throws Exception;
List<VersionedEntityInfo> listAllEntitiesAtVersion(TenantId tenantId, String branch, String versionId) throws Exception; List<VersionedEntityInfo> listAllEntitiesAtVersion(TenantId tenantId, String branch, String versionId) throws Exception;

258
application/src/main/java/org/thingsboard/server/service/sync/vc/LocalGitVersionControlService.java

@ -0,0 +1,258 @@
/**
* 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.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
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.VersionedEntityInfo;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.tenant.TenantDao;
import org.thingsboard.server.queue.util.AfterStartUp;
import java.io.IOException;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Function;
@Slf4j
@RequiredArgsConstructor
@Service
@ConditionalOnProperty(prefix = "vc", value = "git.service", havingValue = "local", matchIfMissing = true)
public class LocalGitVersionControlService implements GitVersionControlService {
private final ObjectWriter jsonWriter = new ObjectMapper().writer(SerializationFeature.INDENT_OUTPUT);
private final GitRepositoryService gitRepositoryService;
private final TenantDao tenantDao;
private final AttributesService attributesService;
private final ConcurrentMap<TenantId, Lock> tenantRepoLocks = new ConcurrentHashMap<>();
private final Map<TenantId, PendingCommit> pendingCommitMap = new HashMap<>();
@AfterStartUp
public void init() {
DaoUtil.processInBatches(tenantDao::findTenantsIds, 100, tenantId -> {
EntitiesVersionControlSettings settings = getSettings(tenantId);
if (settings != null) {
try {
gitRepositoryService.initRepository(tenantId, settings);
} catch (Exception e) {
log.warn("Failed to init repository for tenant {}", tenantId, e);
}
}
});
}
@Override
@SneakyThrows
public EntitiesVersionControlSettings getSettings(TenantId tenantId) {
return attributesService.find(tenantId, tenantId, DataConstants.SERVER_SCOPE, DefaultEntitiesVersionControlService.SETTINGS_KEY).get()
.flatMap(KvEntry::getJsonValue)
.map(json -> {
try {
return JacksonUtil.fromString(json, EntitiesVersionControlSettings.class);
} catch (IllegalArgumentException e) {
return null;
}
})
.orElse(null);
}
@Override
public void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings) {
var lock = getRepoLock(tenantId);
lock.lock();
try {
gitRepositoryService.initRepository(tenantId, settings);
} catch (Exception e) {
//TODO: analyze and return meaningful exceptions that we can show to the client;
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
@Override
public PendingCommit prepareCommit(TenantId tenantId, VersionCreateRequest request) {
var lock = getRepoLock(tenantId);
lock.lock();
try {
var pendingCommit = new PendingCommit(tenantId, request);
PendingCommit old = pendingCommitMap.put(tenantId, pendingCommit);
if (old != null) {
gitRepositoryService.abort(old);
}
gitRepositoryService.prepareCommit(pendingCommit);
return pendingCommit;
} finally {
lock.unlock();
}
}
@Override
public void deleteAll(PendingCommit commit, EntityType entityType) {
doInsideLock(commit, c -> {
try {
gitRepositoryService.deleteFolderContent(commit, getRelativePath(entityType, null));
} catch (IOException e) {
//TODO: analyze and return meaningful exceptions that we can show to the client;
throw new RuntimeException(e);
}
});
}
@Override
public void addToCommit(PendingCommit commit, EntityExportData<ExportableEntity<EntityId>> entityData) {
doInsideLock(commit, c -> {
String entityDataJson;
try {
entityDataJson = jsonWriter.writeValueAsString(entityData);
gitRepositoryService.add(c, getRelativePath(entityData.getEntityType(),
entityData.getEntity().getId().toString()), entityDataJson);
} catch (IOException e) {
//TODO: analyze and return meaningful exceptions that we can show to the client;
throw new RuntimeException(e);
}
});
}
@Override
public VersionCreationResult push(PendingCommit commit) {
return executeInsideLock(commit, gitRepositoryService::push);
}
@Override
public List<EntityVersion> listVersions(TenantId tenantId, String branch) {
return listVersions(tenantId, branch, (String) null);
}
@Override
public List<EntityVersion> listVersions(TenantId tenantId, String branch, EntityType entityType) {
return listVersions(tenantId, branch, getRelativePath(entityType, null));
}
@Override
public List<EntityVersion> listVersions(TenantId tenantId, String branch, EntityId entityId) {
return listVersions(tenantId, branch, getRelativePath(entityId.getEntityType(), entityId.getId().toString()));
}
@Override
public List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) {
try {
return gitRepositoryService.listEntitiesAtVersion(tenantId, branch, versionId, entityType != null ? getRelativePath(entityType, null) : null);
} catch (Exception e) {
//TODO: analyze and return meaningful exceptions that we can show to the client;
throw new RuntimeException(e);
}
}
@Override
public List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId) {
return listEntitiesAtVersion(tenantId, branch, versionId, null);
}
@Override
public List<String> listBranches(TenantId tenantId) {
return gitRepositoryService.listBranches(tenantId);
}
@Override
public EntityExportData<?> getEntity(TenantId tenantId, String versionId, EntityId entityId) {
try {
String entityDataJson = gitRepositoryService.getFileContentAtCommit(tenantId,
getRelativePath(entityId.getEntityType(), entityId.getId().toString()), versionId);
return JacksonUtil.fromString(entityDataJson, EntityExportData.class);
} catch (Exception e) {
//TODO: analyze and return meaningful exceptions that we can show to the client;
throw new RuntimeException(e);
}
}
private List<EntityVersion> listVersions(TenantId tenantId, String branch, String path) {
try {
return gitRepositoryService.listVersions(tenantId, branch, path);
} catch (Exception e) {
//TODO: analyze and return meaningful exceptions that we can show to the client;
throw new RuntimeException(e);
}
}
private void doInsideLock(PendingCommit commit, Consumer<PendingCommit> r) {
var lock = getRepoLock(commit.getTenantId());
lock.lock();
try {
checkCommit(commit);
r.accept(commit);
} finally {
lock.unlock();
}
}
private <T> T executeInsideLock(PendingCommit commit, Function<PendingCommit, T> c) {
var lock = getRepoLock(commit.getTenantId());
lock.lock();
try {
checkCommit(commit);
return c.apply(commit);
} finally {
lock.unlock();
}
}
private void checkCommit(PendingCommit commit) {
PendingCommit existing = pendingCommitMap.get(commit.getTenantId());
if (existing == null || !existing.getTxId().equals(commit.getTxId())) {
throw new ConcurrentModificationException();
}
}
private String getRelativePath(EntityType entityType, String entityId) {
String path = entityType.name().toLowerCase();
if (entityId != null) {
path += "/" + entityId + ".json";
}
return path;
}
private Lock getRepoLock(TenantId tenantId) {
return tenantRepoLocks.computeIfAbsent(tenantId, t -> new ReentrantLock());
}
}

5
application/src/main/resources/thingsboard.yml

@ -1115,6 +1115,11 @@ metrics:
# Metrics percentiles returned by actuator for timer metrics. List of double values (divided by ,). # Metrics percentiles returned by actuator for timer metrics. List of double values (divided by ,).
percentiles: "${METRICS_TIMER_PERCENTILES:0.5}" percentiles: "${METRICS_TIMER_PERCENTILES:0.5}"
vc:
git:
service: "${JS_VC_GIT_SERVICE:local}" # local/remote
repos-poll-interval: "${TB_VC_GIT_REPOS_POLL_INTERVAL_SEC:60}"
management: management:
endpoints: endpoints:
web: web:

2
application/src/main/java/org/thingsboard/server/utils/JsonTbEntity.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/JsonTbEntity.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.utils; package org.thingsboard.server.common.data.sync;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes;

2
application/src/main/java/org/thingsboard/server/utils/ThrowingRunnable.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/ThrowingRunnable.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.utils; package org.thingsboard.server.common.data.sync;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;

2
application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/data/DeviceExportData.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceExportData.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.exporting.data; package org.thingsboard.server.common.data.sync.ie;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;

4
application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/data/EntityExportData.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityExportData.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.exporting.data; package org.thingsboard.server.common.data.sync.ie;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
@ -25,7 +25,7 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.utils.JsonTbEntity; import org.thingsboard.server.common.data.sync.JsonTbEntity;
import java.util.List; import java.util.List;

2
application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/data/EntityExportSettings.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityExportSettings.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.exporting.data; package org.thingsboard.server.common.data.sync.ie;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;

6
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/data/EntityImportResult.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityImportResult.java

@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.data; package org.thingsboard.server.common.data.sync.ie;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.utils.JsonTbEntity; import org.thingsboard.server.common.data.sync.JsonTbEntity;
import org.thingsboard.server.utils.ThrowingRunnable; import org.thingsboard.server.common.data.sync.ThrowingRunnable;
@Data @Data
public class EntityImportResult<E extends ExportableEntity<? extends EntityId>> { public class EntityImportResult<E extends ExportableEntity<? extends EntityId>> {

2
application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/data/EntityImportSettings.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityImportSettings.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.importing.data; package org.thingsboard.server.common.data.sync.ie;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;

2
application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/data/RuleChainExportData.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/RuleChainExportData.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.exportimport.exporting.data; package org.thingsboard.server.common.data.sync.ie;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesVersionControlSettings.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntitiesVersionControlSettings.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data; package org.thingsboard.server.common.data.sync.vc;
import lombok.Data; import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntityVersion.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityVersion.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data; package org.thingsboard.server.common.data.sync.vc;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/VersionCreationResult.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionCreationResult.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data; package org.thingsboard.server.common.data.sync.vc;
import lombok.Data; import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/VersionLoadResult.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionLoadResult.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data; package org.thingsboard.server.common.data.sync.vc;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/VersionedEntityInfo.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionedEntityInfo.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data; package org.thingsboard.server.common.data.sync.vc;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/ComplexVersionCreateRequest.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/ComplexVersionCreateRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.create; package org.thingsboard.server.common.data.sync.vc.request.create;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/EntityTypeVersionCreateConfig.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/EntityTypeVersionCreateConfig.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.create; package org.thingsboard.server.common.data.sync.vc.request.create;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/SingleEntityVersionCreateRequest.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/SingleEntityVersionCreateRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.create; package org.thingsboard.server.common.data.sync.vc.request.create;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/SyncStrategy.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/SyncStrategy.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.create; package org.thingsboard.server.common.data.sync.vc.request.create;
public enum SyncStrategy { public enum SyncStrategy {
MERGE, MERGE,

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/VersionCreateConfig.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/VersionCreateConfig.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.create; package org.thingsboard.server.common.data.sync.vc.request.create;
import lombok.Data; import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/VersionCreateRequest.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/VersionCreateRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.create; package org.thingsboard.server.common.data.sync.vc.request.create;
import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type; import com.fasterxml.jackson.annotation.JsonSubTypes.Type;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/VersionCreateRequestType.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/create/VersionCreateRequestType.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.create; package org.thingsboard.server.common.data.sync.vc.request.create;
public enum VersionCreateRequestType { public enum VersionCreateRequestType {
SINGLE_ENTITY, SINGLE_ENTITY,

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/EntityTypeVersionLoadConfig.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/EntityTypeVersionLoadConfig.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.load; package org.thingsboard.server.common.data.sync.vc.request.load;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/EntityTypeVersionLoadRequest.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/EntityTypeVersionLoadRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.load; package org.thingsboard.server.common.data.sync.vc.request.load;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/SingleEntityVersionLoadRequest.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/SingleEntityVersionLoadRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.load; package org.thingsboard.server.common.data.sync.vc.request.load;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/VersionLoadConfig.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/VersionLoadConfig.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.load; package org.thingsboard.server.common.data.sync.vc.request.load;
import lombok.Data; import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/VersionLoadRequest.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/VersionLoadRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.load; package org.thingsboard.server.common.data.sync.vc.request.load;
import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/VersionLoadRequestType.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/VersionLoadRequestType.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.vc.data.request.load; package org.thingsboard.server.common.data.sync.vc.request.load;
public enum VersionLoadRequestType { public enum VersionLoadRequestType {
SINGLE_ENTITY, SINGLE_ENTITY,

1
common/pom.xml

@ -46,6 +46,7 @@
<module>cache</module> <module>cache</module>
<module>coap-server</module> <module>coap-server</module>
<module>edge-api</module> <module>edge-api</module>
<module>version-control</module>
</modules> </modules>
</project> </project>

115
common/version-control/pom.xml

@ -0,0 +1,115 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.thingsboard</groupId>
<version>3.4.0-SNAPSHOT</version>
<artifactId>common</artifactId>
</parent>
<groupId>org.thingsboard.common</groupId>
<artifactId>version-control</artifactId>
<packaging>jar</packaging>
<name>Thingsboard Server Version Control API</name>
<url>https://thingsboard.io</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<main.dir>${basedir}/../..</main.dir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>data</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
</plugins>
</build>
</project>

239
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java

@ -0,0 +1,239 @@
/**
* 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.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
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.VersionedEntityInfo;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@ConditionalOnProperty(prefix = "vc", value = "git.service", havingValue = "local", matchIfMissing = true)
@Service
public class DefaultGitRepositoryService implements GitRepositoryService {
@Value("${vc.git.repos-poll-interval:${java.io.tmpdir}/repositories}")
private String repositoriesFolder;
@Value("${vc.git.repos-poll-interval:60}")
private long reposPollInterval;
private ScheduledExecutorService scheduler;
private final Map<TenantId, GitRepository> repositories = new ConcurrentHashMap<>();
@PostConstruct
public void init() {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleWithFixedDelay(() -> {
repositories.forEach((tenantId, repository) -> {
try {
repository.fetch();
log.info("Fetching remote repository for tenant {}", tenantId);
} catch (Exception e) {
log.warn("Failed to fetch repository for tenant {}", tenantId, e);
}
});
}, reposPollInterval, reposPollInterval, TimeUnit.SECONDS);
}
@PreDestroy
public void stop() {
if (scheduler != null) {
scheduler.shutdownNow();
}
}
@Override
public void prepareCommit(PendingCommit commit) {
GitRepository repository = checkRepository(commit.getTenantId());
String branch = commit.getRequest().getBranch();
try {
repository.fetch();
if (repository.listBranches().contains(branch)) {
repository.checkout("origin/" + branch, false);
try {
repository.checkout(branch, true);
} catch (RefAlreadyExistsException e) {
repository.checkout(branch, false);
}
repository.merge(branch);
} else { // TODO [viacheslav]: rollback orphan branch on failure
try {
repository.createAndCheckoutOrphanBranch(branch); // FIXME [viacheslav]: Checkout returned unexpected result NO_CHANGE for master branch
} catch (JGitInternalException e) {
if (!e.getMessage().contains("NO_CHANGE")) {
throw e;
}
}
}
} catch (IOException | GitAPIException gitAPIException) {
//TODO: analyze and return meaningful exceptions that we can show to the client;
throw new RuntimeException(gitAPIException);
}
}
@Override
public void deleteFolderContent(PendingCommit commit, String relativePath) throws IOException {
GitRepository repository = checkRepository(commit.getTenantId());
FileUtils.deleteDirectory(Path.of(repository.getDirectory(), relativePath).toFile());
}
@Override
public void add(PendingCommit commit, String relativePath, String entityDataJson) throws IOException {
GitRepository repository = checkRepository(commit.getTenantId());
FileUtils.write(Path.of(repository.getDirectory(), relativePath).toFile(), entityDataJson, StandardCharsets.UTF_8);
}
@Override
public VersionCreationResult push(PendingCommit commit) {
GitRepository repository = checkRepository(commit.getTenantId());
try {
repository.add(".");
VersionCreationResult result = new VersionCreationResult();
GitRepository.Status status = repository.status();
result.setAdded(status.getAdded().size());
result.setModified(status.getModified().size());
result.setRemoved(status.getRemoved().size());
GitRepository.Commit gitCommit = repository.commit(commit.getRequest().getVersionName());
repository.push();
result.setVersion(toVersion(gitCommit));
return result;
} catch (GitAPIException gitAPIException) {
//TODO: analyze and return meaningful exceptions that we can show to the client;
throw new RuntimeException(gitAPIException);
}
}
@Override
public void abort(PendingCommit commit) {
//TODO: implement;
}
@Override
public String getFileContentAtCommit(TenantId tenantId, String relativePath, String versionId) throws IOException {
GitRepository repository = checkRepository(tenantId);
return repository.getFileContentAtCommit(relativePath, versionId);
}
@Override
public List<String> listBranches(TenantId tenantId) {
GitRepository repository = checkRepository(tenantId);
try {
return repository.listBranches();
} catch (GitAPIException gitAPIException) {
//TODO: analyze and return meaningful exceptions that we can show to the client;
throw new RuntimeException(gitAPIException);
}
}
private EntityVersion checkVersion(TenantId tenantId, String branch, String versionId) throws Exception {
return listVersions(tenantId, branch, null).stream()
.filter(version -> version.getId().equals(versionId))
.findFirst().orElseThrow(() -> new IllegalArgumentException("Version not found"));
}
private GitRepository checkRepository(TenantId tenantId) {
return Optional.ofNullable(repositories.get(tenantId))
.orElseThrow(() -> new IllegalStateException("Repository is not initialized"));
}
@Override
public List<EntityVersion> listVersions(TenantId tenantId, String branch, String path) throws Exception {
GitRepository repository = checkRepository(tenantId);
return repository.listCommits(branch, path, Integer.MAX_VALUE).stream()
.map(this::toVersion)
.collect(Collectors.toList());
}
@Override
public List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, String path) throws Exception {
GitRepository repository = checkRepository(tenantId);
checkVersion(tenantId, branch, versionId);
return repository.listFilesAtCommit(versionId, path).stream()
.map(filePath -> {
EntityId entityId = fromRelativePath(filePath);
VersionedEntityInfo info = new VersionedEntityInfo();
info.setExternalId(entityId);
return info;
})
.collect(Collectors.toList());
}
@Override
public void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings) throws Exception {
Path repositoryDirectory = Path.of(repositoriesFolder, tenantId.getId().toString());
GitRepository repository;
if (Files.exists(repositoryDirectory)) {
FileUtils.forceDelete(repositoryDirectory.toFile());
}
Files.createDirectories(repositoryDirectory);
repository = GitRepository.clone(settings.getRepositoryUri(), settings.getUsername(), settings.getPassword(), repositoryDirectory.toFile());
repositories.put(tenantId, repository);
}
private void clearRepository(TenantId tenantId) throws IOException {
GitRepository repository = repositories.get(tenantId);
if (repository != null) {
FileUtils.deleteDirectory(new File(repository.getDirectory()));
repositories.remove(tenantId);
}
}
private EntityVersion toVersion(GitRepository.Commit commit) {
return new EntityVersion(commit.getId(), commit.getMessage());
}
private EntityId fromRelativePath(String path) {
EntityType entityType = EntityType.valueOf(StringUtils.substringBefore(path, "/").toUpperCase());
String entityId = StringUtils.substringBetween(path, "/", ".json");
return EntityIdFactory.getByTypeAndUuid(entityType, entityId);
}
}

2
application/src/main/java/org/thingsboard/server/utils/GitRepository.java → common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.utils; package org.thingsboard.server.service.sync.vc;
import com.google.common.collect.Streams; import com.google.common.collect.Streams;
import lombok.Data; import lombok.Data;

48
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepositoryService.java

@ -0,0 +1,48 @@
/**
* 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.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
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.VersionedEntityInfo;
import java.io.IOException;
import java.util.List;
public interface GitRepositoryService {
void prepareCommit(PendingCommit pendingCommit);
List<EntityVersion> listVersions(TenantId tenantId, String branch, String path) throws Exception;
List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, String path) throws Exception;
void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings) throws Exception;
void add(PendingCommit commit, String relativePath, String entityDataJson) throws IOException;
void deleteFolderContent(PendingCommit commit, String relativePath) throws IOException;
VersionCreationResult push(PendingCommit commit);
void abort(PendingCommit commit);
List<String> listBranches(TenantId tenantId);
String getFileContentAtCommit(TenantId tenantId, String relativePath, String versionId) throws IOException;
}

60
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java

@ -0,0 +1,60 @@
/**
* 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.SneakyThrows;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
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.VersionedEntityInfo;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import java.util.List;
public interface GitVersionControlService {
@SneakyThrows
EntitiesVersionControlSettings getSettings(TenantId tenantId);
void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings);
PendingCommit prepareCommit(TenantId tenantId, VersionCreateRequest request);
void addToCommit(PendingCommit commit, EntityExportData<ExportableEntity<EntityId>> entityData);
void deleteAll(PendingCommit pendingCommit, EntityType entityType);
VersionCreationResult push(PendingCommit commit);
List<EntityVersion> listVersions(TenantId tenantId, String branch);
List<EntityVersion> listVersions(TenantId tenantId, String branch, EntityType entityType);
List<EntityVersion> listVersions(TenantId tenantId, String branch, EntityId entityId);
List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType);
List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId);
List<String> listBranches(TenantId tenantId);
EntityExportData<?> getEntity(TenantId tenantId, String versionId, EntityId entityId);
}

36
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/PendingCommit.java

@ -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 lombok.Data;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import java.util.UUID;
@Data
public class PendingCommit {
private final UUID txId;
private final TenantId tenantId;
private final VersionCreateRequest request;
public PendingCommit(TenantId tenantId, VersionCreateRequest request) {
this.txId = UUID.randomUUID();
this.tenantId = tenantId;
this.request = request;
}
}

5
pom.xml

@ -866,6 +866,11 @@
<artifactId>util</artifactId> <artifactId>util</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>version-control</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>
<artifactId>cache</artifactId> <artifactId>cache</artifactId>

Loading…
Cancel
Save