From 5860a0651b3974be3ce010795d0ff87238a2eb63 Mon Sep 17 00:00:00 2001 From: mp-loki Date: Sun, 30 Apr 2017 20:33:43 -0400 Subject: [PATCH] JPA WidgetType, WidgetsBundle, Tenant DAO --- .../server/dao/model/sql/TenantEntity.java | 139 ++++-------------- .../server/dao/model/sql/UserEntity.java | 8 +- .../dao/model/sql/WidgetTypeEntity.java | 30 +++- .../server/dao/sql/JpaAbstractDao.java | 23 +-- .../server/dao/sql/tenant/JpaTenantDao.java | 57 +++++++ .../dao/sql/tenant/TenantRepository.java | 28 ++++ .../server/dao/sql/user/JpaUserDao.java | 23 ++- .../server/dao/sql/user/UserRepository.java | 34 ++++- .../dao/sql/widget/JpaWidgetTypeDao.java | 52 +++++++ .../dao/sql/widget/JpaWidgetsBundleDao.java | 10 +- .../dao/sql/widget/WidgetTypeRepository.java | 20 +++ .../sql/widget/WidgetsBundleRepository.java | 12 +- .../dao/sql/tenant/JpaTenantDaoTest.java | 55 +++++++ .../server/dao/sql/user/JpaUserDaoTest.java | 64 +++++++- .../dao/sql/widget/JpaWidgetTypeDaoTest.java | 40 +++++ dao/src/test/resources/dbunit/users.xml | 2 - dao/src/test/resources/dbunit/widget_type.xml | 31 ++++ 17 files changed, 471 insertions(+), 157 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java create mode 100644 dao/src/test/resources/dbunit/widget_type.xml diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantEntity.java index 8987425f00..6c54fd01c7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantEntity.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2017 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 - * + *

+ * 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. @@ -16,20 +16,28 @@ package org.thingsboard.server.dao.model.sql; import com.datastax.driver.core.utils.UUIDs; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Transient; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; import com.fasterxml.jackson.databind.JsonNode; +import java.io.IOException; import java.util.UUID; -//@Entity +@Slf4j +@Data +@Entity @Table(name = ModelConstants.TENANT_COLUMN_FAMILY_NAME) public final class TenantEntity implements SearchTextEntity { @@ -37,21 +45,21 @@ public final class TenantEntity implements SearchTextEntity { private static final long serialVersionUID = -4330655990232136337L; @Id - @Column(name = ModelConstants.ID_PROPERTY) + @Column(name = ModelConstants.ID_PROPERTY, columnDefinition = "BINARY(16)") private UUID id; @Column(name = ModelConstants.TENANT_TITLE_PROPERTY) private String title; - + @Column(name = ModelConstants.SEARCH_TEXT_PROPERTY) private String searchText; @Column(name = ModelConstants.TENANT_REGION_PROPERTY) private String region; - + @Column(name = ModelConstants.COUNTRY_PROPERTY) private String country; - + @Column(name = ModelConstants.STATE_PROPERTY) private String state; @@ -74,7 +82,7 @@ public final class TenantEntity implements SearchTextEntity { private String email; @Column(name = ModelConstants.TENANT_ADDITIONAL_INFO_PROPERTY) - private JsonNode additionalInfo; + private String additionalInfo; public TenantEntity() { super(); @@ -94,104 +102,11 @@ public final class TenantEntity implements SearchTextEntity { this.zip = tenant.getZip(); this.phone = tenant.getPhone(); this.email = tenant.getEmail(); - this.additionalInfo = tenant.getAdditionalInfo(); - } - - public UUID getId() { - return id; + if (tenant.getAdditionalInfo() != null) { + this.additionalInfo = tenant.getAdditionalInfo().toString(); + } } - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getRegion() { - return region; - } - - public void setRegion(String region) { - this.region = region; - } - - public String getCountry() { - return country; - } - - public void setCountry(String country) { - this.country = country; - } - - public String getState() { - return state; - } - - public void setState(String state) { - this.state = state; - } - - public String getCity() { - return city; - } - - public void setCity(String city) { - this.city = city; - } - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - public String getAddress2() { - return address2; - } - - public void setAddress2(String address2) { - this.address2 = address2; - } - - public String getZip() { - return zip; - } - - public void setZip(String zip) { - this.zip = zip; - } - - public String getPhone() { - return phone; - } - - public void setPhone(String phone) { - this.phone = phone; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public JsonNode getAdditionalInfo() { - return additionalInfo; - } - - public void setAdditionalInfo(JsonNode additionalInfo) { - this.additionalInfo = additionalInfo; - } @Override public String getSearchTextSource() { @@ -202,7 +117,7 @@ public final class TenantEntity implements SearchTextEntity { public void setSearchText(String searchText) { this.searchText = searchText; } - + public String getSearchText() { return searchText; } @@ -343,7 +258,15 @@ public final class TenantEntity implements SearchTextEntity { tenant.setZip(zip); tenant.setPhone(phone); tenant.setEmail(email); - tenant.setAdditionalInfo(additionalInfo); + ObjectMapper mapper = new ObjectMapper(); + if (additionalInfo != null) { + try { + JsonNode jsonNode = mapper.readTree(additionalInfo); + tenant.setAdditionalInfo(jsonNode); + } catch (IOException e) { + log.warn(String.format("Error parsing JsonNode: %s. Reason: %s ", additionalInfo, e.getMessage()), e); + } + } return tenant; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserEntity.java index bf006bb22d..9df32e3eda 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserEntity.java @@ -19,6 +19,7 @@ import com.datastax.driver.core.utils.UUIDs; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; +import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; @@ -34,6 +35,7 @@ import java.util.UUID; /** * Created by Valerii Sosliuk on 4/21/2017. */ +@Slf4j @Data @Entity @Table(name = ModelConstants.USER_COLUMN_FAMILY_NAME) @@ -86,7 +88,9 @@ public class UserEntity implements SearchTextEntity { this.email = user.getEmail(); this.firstName = user.getFirstName(); this.lastName = user.getLastName(); - this.additionalInfo = user.getAdditionalInfo().toString(); + if (user.getAdditionalInfo() != null) { + this.additionalInfo = user.getAdditionalInfo().toString(); + } } @Override @@ -152,7 +156,7 @@ public class UserEntity implements SearchTextEntity { JsonNode jsonNode = mapper.readTree(additionalInfo); user.setAdditionalInfo(jsonNode); } catch (IOException e) { - e.printStackTrace(); + log.warn(String.format("Error parsing JsonNode: %s. Reason: %s ", additionalInfo, e.getMessage()), e); } } return user; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeEntity.java index 2c84f72d9e..790089182f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeEntity.java @@ -24,15 +24,19 @@ import javax.persistence.Transient; import com.datastax.driver.mapping.annotations.PartitionKey; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.dao.model.BaseEntity; import org.thingsboard.server.dao.model.ModelConstants; +import java.io.IOException; import java.util.UUID; -//@Entity +@Slf4j +@Entity @Table(name = ModelConstants.WIDGET_TYPE_COLUMN_FAMILY_NAME) public final class WidgetTypeEntity implements BaseEntity { @@ -40,11 +44,11 @@ public final class WidgetTypeEntity implements BaseEntity { private static final long serialVersionUID = -5436279069884988630L; @Id - @Column(name = ModelConstants.ID_PROPERTY) + @Column(name = ModelConstants.ID_PROPERTY, columnDefinition = "BINARY(16)") private UUID id; @PartitionKey(value = 1) - @Column(name = ModelConstants.WIDGET_TYPE_TENANT_ID_PROPERTY) + @Column(name = ModelConstants.WIDGET_TYPE_TENANT_ID_PROPERTY, columnDefinition = "BINARY(16)") private UUID tenantId; @PartitionKey(value = 2) @@ -58,7 +62,7 @@ public final class WidgetTypeEntity implements BaseEntity { private String name; @Column(name = ModelConstants.WIDGET_TYPE_DESCRIPTOR_PROPERTY) - private JsonNode descriptor; + private String descriptor; public WidgetTypeEntity() { super(); @@ -74,7 +78,9 @@ public final class WidgetTypeEntity implements BaseEntity { this.bundleAlias = widgetType.getBundleAlias(); this.alias = widgetType.getAlias(); this.name = widgetType.getName(); - this.descriptor = widgetType.getDescriptor(); + if (widgetType.getDescriptor() != null) { + this.descriptor = widgetType.getDescriptor().toString(); + } } @Override @@ -119,11 +125,11 @@ public final class WidgetTypeEntity implements BaseEntity { this.name = name; } - public JsonNode getDescriptor() { + public String getDescriptor() { return descriptor; } - public void setDescriptor(JsonNode descriptor) { + public void setDescriptor(String descriptor) { this.descriptor = descriptor; } @@ -176,7 +182,15 @@ public final class WidgetTypeEntity implements BaseEntity { widgetType.setBundleAlias(bundleAlias); widgetType.setAlias(alias); widgetType.setName(name); - widgetType.setDescriptor(descriptor); + ObjectMapper mapper = new ObjectMapper(); + if (descriptor != null) { + try { + JsonNode jsonNode = mapper.readTree(descriptor); + widgetType.setDescriptor(jsonNode); + } catch (IOException e) { + log.warn(String.format("Error parsing JsonNode: %s. Reason: %s ", descriptor, e.getMessage()), e); + } + } return widgetType; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java index f38f49e25f..414c213240 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2017 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 - * + *

+ * 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. @@ -17,6 +17,8 @@ package org.thingsboard.server.dao.sql; import com.google.common.collect.Lists; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; import org.springframework.data.repository.CrudRepository; import org.thingsboard.server.dao.Dao; @@ -26,6 +28,7 @@ import org.thingsboard.server.dao.model.SearchTextEntity; import java.util.List; import java.util.UUID; +import java.util.concurrent.Executors; /** * @author Valerii Sosliuk @@ -51,7 +54,8 @@ public abstract class JpaAbstractDao, D> implements Dao< } catch (Exception e) { log.error("Can't create entity for domain object {}", domain, e); throw new IllegalArgumentException("Can't create entity for domain object {" + domain + "}", e); - } if (isSearchTextDao()) { + } + if (isSearchTextDao()) { ((SearchTextEntity) entity).setSearchText(((SearchTextEntity) entity).getSearchTextSource().toLowerCase()); } log.debug("Saving entity {}", entity); @@ -68,10 +72,11 @@ public abstract class JpaAbstractDao, D> implements Dao< @Override public ListenableFuture findByIdAsync(UUID key) { - log.debug("Get entity by key {}", key); - // org.springframework.util.concurrent.ListenableFuture entityFuture = getCrudRepository().findByIdAsync(key); - // TODO: vsosliuk implement - return null; + log.debug("Get entity by key async {}", key); + // Should it be a field? + ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)); + ListenableFuture listenableFuture = service.submit(() -> DaoUtil.getData(getCrudRepository().findOne(key))); + return listenableFuture; } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java new file mode 100644 index 0000000000..7cdb72796b --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java @@ -0,0 +1,57 @@ +package org.thingsboard.server.dao.sql.tenant; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.dao.DaoUtil; +import org.thingsboard.server.dao.model.sql.TenantEntity; +import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.tenant.TenantDao; + +import java.util.List; +import java.util.UUID; + +import static org.thingsboard.server.dao.model.ModelConstants.TENANT_COLUMN_FAMILY_NAME; + +/** + * Created by Valerii Sosliuk on 4/30/2017. + */ +@Component +@ConditionalOnProperty(prefix = "sql", value = "enabled", havingValue = "true", matchIfMissing = false) +public class JpaTenantDao extends JpaAbstractDao implements TenantDao { + + @Autowired + private TenantRepository tenantRepository; + + @Override + protected Class getEntityClass() { + return TenantEntity.class; + } + + @Override + protected String getColumnFamilyName() { + return TENANT_COLUMN_FAMILY_NAME; + } + + @Override + protected CrudRepository getCrudRepository() { + return tenantRepository; + } + + @Override + protected boolean isSearchTextDao() { + return true; + } + + @Override + public List findTenantsByRegion(String region, TextPageLink pageLink) { + if (pageLink.getIdOffset() == null) { + return DaoUtil.convertDataList(tenantRepository.findByRegionFirstPage(pageLink.getLimit(), region, pageLink.getTextSearch())); + } else { + return DaoUtil.convertDataList(tenantRepository.findByRegionNextPage(pageLink.getLimit(), region, pageLink.getTextSearch(), pageLink.getIdOffset())); + } + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java new file mode 100644 index 0000000000..ec533f47a0 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java @@ -0,0 +1,28 @@ +package org.thingsboard.server.dao.sql.tenant; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.thingsboard.server.dao.model.sql.TenantEntity; + +import java.util.List; +import java.util.UUID; + +/** + * Created by Valerii Sosliuk on 4/30/2017. + */ +@ConditionalOnProperty(prefix = "sql", value = "enabled", havingValue = "true", matchIfMissing = false) +public interface TenantRepository extends CrudRepository { + + + @Query(nativeQuery = true, value = "SELECT * FROM TENANT WHERE REGION = ?2 " + + "AND LOWER(SEARCH_TEXT) LIKE LOWER(CONCAT(?3, '%')) " + + "ORDER BY ID LIMIT ?1") + List findByRegionFirstPage(int limit, String region, String textSearch); + + + @Query(nativeQuery = true, value = "SELECT * FROM TENANT WHERE REGION = ?2 " + + "AND LOWER(SEARCH_TEXT) LIKE LOWER(CONCAT(?3, '%')) " + + "AND ID > ?4 ORDER BY ID LIMIT ?1") + List findByRegionNextPage(int limit, String region, String textSearch, UUID idOffset); +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java index 662dbeea06..cffccdb291 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2017 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 - * + *

+ * 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. @@ -34,7 +34,7 @@ import java.util.UUID; * @author Valerii Sosliuk */ @Component -@ConditionalOnProperty(prefix="sql", value="enabled",havingValue = "true", matchIfMissing = false) +@ConditionalOnProperty(prefix = "sql", value = "enabled", havingValue = "true", matchIfMissing = false) public class JpaUserDao extends JpaAbstractDao implements UserDao { @Autowired @@ -62,11 +62,20 @@ public class JpaUserDao extends JpaAbstractDao implements User @Override public List findTenantAdmins(UUID tenantId, TextPageLink pageLink) { - throw new RuntimeException("Not Implemented"); + if (pageLink.getIdOffset() == null) { + return DaoUtil.convertDataList(userRepository.findTenantAdminsFirstPage(pageLink.getLimit(), tenantId)); + } else { + return DaoUtil.convertDataList(userRepository.findTenantAdminsNextPage(pageLink.getLimit(), tenantId, pageLink.getIdOffset())); + } } @Override public List findCustomerUsers(UUID tenantId, UUID customerId, TextPageLink pageLink) { - throw new RuntimeException("Not Implemented"); + if (pageLink.getIdOffset() == null) { + return DaoUtil.convertDataList(userRepository.findCustomerUsersFirstPage(pageLink.getLimit(), tenantId, customerId)); + } else { + return DaoUtil.convertDataList(userRepository.findCustomerUsersNextPage(pageLink.getLimit(), tenantId, + customerId, pageLink.getIdOffset())); + } } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java index aec4137366..cc4df06b94 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2017 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 - * + *

+ * 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. @@ -16,17 +16,39 @@ package org.thingsboard.server.dao.sql.user; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.thingsboard.server.dao.model.sql.UserEntity; +import java.util.List; import java.util.UUID; /** * @author Valerii Sosliuk */ -@ConditionalOnProperty(prefix="sql", value="enabled",havingValue = "true", matchIfMissing = false) +@ConditionalOnProperty(prefix = "sql", value = "enabled", havingValue = "true", matchIfMissing = false) public interface UserRepository extends CrudRepository { UserEntity findByEmail(String email); -} + @Query(nativeQuery = true, value = "SELECT * FROM USER WHERE TENANT_ID = ?2 " + + "AND CUSTOMER_ID IS NULL AND AUTHORITY = 1 " + + "ORDER BY ID LIMIT ?1") + List findTenantAdminsFirstPage(int limit, UUID tenantId); + + @Query(nativeQuery = true, value = "SELECT * FROM USER WHERE TENANT_ID = ?2 " + + "AND CUSTOMER_ID IS NULL AND AUTHORITY = 1 " + + "AND ID > ?3 ORDER BY ID LIMIT ?1") + List findTenantAdminsNextPage(int limit, UUID tenantId, UUID idOffset); + + @Query(nativeQuery = true, value = "SELECT * FROM USER WHERE TENANT_ID = ?2 " + + "AND CUSTOMER_ID = ?3 AND AUTHORITY = 2 " + + "ORDER BY ID LIMIT ?1") + List findCustomerUsersFirstPage(int limit, UUID tenantId, UUID customerId); + + @Query(nativeQuery = true, value = "SELECT * FROM USER WHERE TENANT_ID = ?2 " + + "AND CUSTOMER_ID = ?3 AND AUTHORITY = 2 " + + "AND ID > ?4 ORDER BY ID LIMIT ?1") + List findCustomerUsersNextPage(int limit, UUID tenantId, UUID customerId, UUID idOffset); + +} \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java new file mode 100644 index 0000000000..9cc89b23f6 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java @@ -0,0 +1,52 @@ +package org.thingsboard.server.dao.sql.widget; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.widget.WidgetType; +import org.thingsboard.server.dao.DaoUtil; +import org.thingsboard.server.dao.model.sql.WidgetTypeEntity; +import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.widget.WidgetTypeDao; + +import java.util.List; +import java.util.UUID; + +import static org.thingsboard.server.dao.model.ModelConstants.WIDGET_TYPE_COLUMN_FAMILY_NAME; + +/** + * Created by Valerii Sosliuk on 4/29/2017. + */ +@Component +@ConditionalOnProperty(prefix = "sql", value = "enabled", havingValue = "true", matchIfMissing = false) +public class JpaWidgetTypeDao extends JpaAbstractDao implements WidgetTypeDao { + + @Autowired + private WidgetTypeRepository widgetTypeRepository; + + @Override + protected Class getEntityClass() { + return WidgetTypeEntity.class; + } + + @Override + protected String getColumnFamilyName() { + return WIDGET_TYPE_COLUMN_FAMILY_NAME; + } + + @Override + protected CrudRepository getCrudRepository() { + return widgetTypeRepository; + } + + @Override + public List findWidgetTypesByTenantIdAndBundleAlias(UUID tenantId, String bundleAlias) { + return DaoUtil.convertDataList(widgetTypeRepository.findByTenantIdAndBundleAlias(tenantId, bundleAlias)); + } + + @Override + public WidgetType findByTenantIdBundleAliasAndAlias(UUID tenantId, String bundleAlias, String alias) { + return DaoUtil.getData(widgetTypeRepository.findByTenantIdAndBundleAliasAndAlias(tenantId, bundleAlias, alias)); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java index 512e661d1c..ff40dd29af 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java @@ -61,6 +61,11 @@ public class JpaWidgetsBundleDao extends JpaAbstractDao findSystemWidgetsBundles(TextPageLink pageLink) { if (pageLink.getIdOffset() == null) { @@ -93,9 +98,4 @@ public class JpaWidgetsBundleDao extends JpaAbstractDao { + + List findByTenantIdAndBundleAlias(UUID tenantId, String bundleAlias); + + WidgetTypeEntity findByTenantIdAndBundleAliasAndAlias(UUID tenantId, String bundleAlias, String alias); +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java index cc47762de9..d94dd1370d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java @@ -15,25 +15,19 @@ */ package org.thingsboard.server.dao.sql.widget; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; -import org.springframework.data.repository.query.Param; -import org.thingsboard.server.common.data.page.TextPageLink; -import org.thingsboard.server.dao.model.ToData; import org.thingsboard.server.dao.model.sql.WidgetsBundleEntity; -import java.util.Collection; import java.util.List; import java.util.UUID; /** * Created by Valerii Sosliuk on 4/23/2017. */ -//public interface WidgetsBundleRepository extends CrudRepository { -public interface WidgetsBundleRepository extends JpaRepository, JpaSpecificationExecutor { +@ConditionalOnProperty(prefix = "sql", value = "enabled", havingValue = "true", matchIfMissing = false) +public interface WidgetsBundleRepository extends CrudRepository { WidgetsBundleEntity findWidgetsBundleByTenantIdAndAlias(UUID tenantId, String alias); diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java new file mode 100644 index 0000000000..2515618829 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java @@ -0,0 +1,55 @@ +package org.thingsboard.server.dao.sql.tenant; + +import com.datastax.driver.core.utils.UUIDs; +import com.github.springtestdbunit.annotation.DatabaseSetup; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.dao.AbstractJpaDaoTest; +import org.thingsboard.server.dao.tenant.TenantDao; + +import java.util.List; + +import static org.junit.Assert.*; + +/** + * Created by Valerii Sosliuk on 4/30/2017. + */ +public class JpaTenantDaoTest extends AbstractJpaDaoTest { + + @Autowired + private TenantDao tenantDao; + + @Test + @DatabaseSetup("classpath:dbunit/empty_dataset.xml") + public void testFindTenantsByRegion() { + createTenants(); + assertEquals(60, tenantDao.find().size()); + List tenants1 = tenantDao.findTenantsByRegion("REGION_1", new TextPageLink(20,"title")); + assertEquals(20, tenants1.size()); + List tenants2 = tenantDao.findTenantsByRegion("REGION_1", + new TextPageLink(20,"title", tenants1.get(19).getId().getId(), null)); + assertEquals(10, tenants2.size()); + List tenants3 = tenantDao.findTenantsByRegion("REGION_1", + new TextPageLink(20,"title", tenants2.get(9).getId().getId(), null)); + assertEquals(0, tenants3.size()); + } + + private void createTenants() { + for (int i = 0; i < 30; i++) { + createTenant("REGION_1", "TITLE", i); + createTenant("REGION_2", "TITLE", i); + } + } + + private void createTenant(String region, String title, int index) { + Tenant tenant = new Tenant(); + tenant.setId(new TenantId(UUIDs.timeBased())); + tenant.setRegion(region); + tenant.setTitle(title + "_" + index); + tenantDao.save(tenant); + } + +} diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserDaoTest.java index 5bd254fa67..fe540fa017 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserDaoTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.sql.user; +import com.datastax.driver.core.utils.UUIDs; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.springtestdbunit.annotation.DatabaseSetup; @@ -24,6 +25,7 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.dao.AbstractJpaDaoTest; import org.thingsboard.server.dao.user.UserDao; @@ -51,7 +53,7 @@ public class JpaUserDaoTest extends AbstractJpaDaoTest { @Test @DatabaseSetup("classpath:dbunit/users.xml") - public void findByEmail() { + public void testFindByEmail() { User user = userDao.findByEmail("sysadm@thingsboard.org"); assertNotNull("User is expected to be not null", user); assertEquals("9cb58ba0-27c1-11e7-93ae-92361f002671", user.getId().toString()); @@ -63,6 +65,40 @@ public class JpaUserDaoTest extends AbstractJpaDaoTest { assertEquals("{\"key\":\"value-0\"}", user.getAdditionalInfo().toString()); } + @Test + @DatabaseSetup("classpath:dbunit/empty_dataset.xml") + public void testFindTenantAdmins() { + UUID tenantId = UUIDs.timeBased(); + UUID customerId = UUIDs.timeBased(); + create30Adminsand60Users(tenantId, customerId); + assertEquals(90, userDao.find().size()); + List tenantAdmins1 = userDao.findTenantAdmins(tenantId, new TextPageLink(20)); + assertEquals(20, tenantAdmins1.size()); + List tenantAdmins2 = userDao.findTenantAdmins(tenantId, + new TextPageLink(20, null, tenantAdmins1.get(19).getId().getId(), null)); + assertEquals(10, tenantAdmins2.size()); + List tenantAdmins3 = userDao.findTenantAdmins(tenantId, + new TextPageLink(20, null, tenantAdmins2.get(9).getId().getId(), null)); + assertEquals(0, tenantAdmins3.size()); + } + + @Test + @DatabaseSetup("classpath:dbunit/empty_dataset.xml") + public void testFindCustomerUsers() { + UUID tenantId = UUIDs.timeBased(); + UUID customerId = UUIDs.timeBased(); + create30Adminsand60Users(tenantId, customerId); + assertEquals(90, userDao.find().size()); + List customerUsers1 = userDao.findCustomerUsers(tenantId, customerId, new TextPageLink(40)); + assertEquals(40, customerUsers1.size()); + List customerUsers2 = userDao.findCustomerUsers(tenantId, customerId, + new TextPageLink(20, null, customerUsers1.get(39).getId().getId(), null)); + assertEquals(20, customerUsers2.size()); + List customerUsers3 = userDao.findCustomerUsers(tenantId, customerId, + new TextPageLink(20, null, customerUsers2.get(19).getId().getId(), null)); + assertEquals(0, customerUsers3.size()); + } + @Test @DatabaseSetup("classpath:dbunit/users.xml") public void testSave() throws IOException { @@ -82,4 +118,30 @@ public class JpaUserDaoTest extends AbstractJpaDaoTest { User savedUser = userDao.findByEmail("user@thingsboard.org"); assertNotNull(savedUser); } + + private void create30Adminsand60Users(UUID tenantId, UUID customerId) { + // Create 30 tenant admins and 60 customer users + for (int i = 0; i < 30; i++) { + saveUser(tenantId, null); + saveUser(tenantId, customerId); + saveUser(tenantId, customerId); + } + } + + private void saveUser(UUID tenantId, UUID customerId) { + User user = new User(); + UUID id = UUIDs.timeBased(); + user.setId(new UserId(id)); + user.setTenantId(new TenantId(tenantId)); + if (customerId == null) { + user.setAuthority(Authority.TENANT_ADMIN); + } else { + user.setCustomerId(new CustomerId(customerId)); + user.setAuthority(Authority.CUSTOMER_USER); + } + String idString = id.toString(); + String email = idString.substring(0, idString.indexOf('-')) + "@thingsboard.org"; + user.setEmail(email); + userDao.save(user); + } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java new file mode 100644 index 0000000000..c41a7c5495 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java @@ -0,0 +1,40 @@ +package org.thingsboard.server.dao.sql.widget; + +import com.datastax.driver.core.utils.UUIDs; +import com.github.springtestdbunit.annotation.DatabaseSetup; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.server.common.data.widget.WidgetType; +import org.thingsboard.server.dao.AbstractJpaDaoTest; +import org.thingsboard.server.dao.widget.WidgetTypeDao; + +import java.util.List; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; + +/** + * Created by Valerii Sosliuk on 4/30/2017. + */ +public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { + + @Autowired + private WidgetTypeDao widgetTypeDao; + + @Test + @DatabaseSetup(("classpath:dbunit/widget_type.xml")) + public void testFindByTenantIdAndBundleAlias() { + UUID tenantId = UUID.fromString("2b7e4c90-2dfe-11e7-94aa-f7f6dbfb4833"); + List widgetTypes = widgetTypeDao.findWidgetTypesByTenantIdAndBundleAlias(tenantId, "BUNDLE_ALIAS_1"); + assertEquals(3, widgetTypes.size()); + } + + @Test + @DatabaseSetup(("classpath:dbunit/widget_type.xml")) + public void testFindByTenantIdAndBundleAliasAndAlias() { + UUID tenantId = UUID.fromString("2b7e4c90-2dfe-11e7-94aa-f7f6dbfb4833"); + WidgetType widgetType = widgetTypeDao.findByTenantIdBundleAliasAndAlias(tenantId, "BUNDLE_ALIAS_1", "ALIAS3"); + UUID id = UUID.fromString("2b7e4c93-2dfe-11e7-94aa-f7f6dbfb4833"); + assertEquals(id, widgetType.getId().getId()); + } +} diff --git a/dao/src/test/resources/dbunit/users.xml b/dao/src/test/resources/dbunit/users.xml index 644a6e982d..b1e51dde3e 100644 --- a/dao/src/test/resources/dbunit/users.xml +++ b/dao/src/test/resources/dbunit/users.xml @@ -11,7 +11,6 @@ /> + + + + + + \ No newline at end of file