Merge branch 'master' into feature/TB-65

This commit is contained in:
Igor Kulikov 2017-06-30 16:40:52 +03:00
commit e11dc50a7f
24 changed files with 124 additions and 66 deletions

1
.mvn/jvm.config Normal file
View File

@ -0,0 +1 @@
-Xmx4096m -Xms1024m

View File

@ -28,6 +28,7 @@ import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg;
import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg;
import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
import org.thingsboard.server.extensions.api.plugins.msg.*;
@ -60,7 +61,9 @@ public class DeviceActor extends ContextAwareActor {
} else if (msg instanceof ToDeviceRpcRequestPluginMsg) {
processor.processRpcRequest(context(), (ToDeviceRpcRequestPluginMsg) msg);
} else if (msg instanceof DeviceCredentialsUpdateNotificationMsg){
processor.processCredentialsUpdate(context(), (DeviceCredentialsUpdateNotificationMsg) msg);
processor.processCredentialsUpdate();
} else if (msg instanceof DeviceNameOrTypeUpdateMsg){
processor.processNameOrTypeUpdate((DeviceNameOrTypeUpdateMsg) msg);
}
} else if (msg instanceof TimeoutMsg) {
processor.processTimeout(context(), (TimeoutMsg) msg);

View File

@ -37,10 +37,7 @@ import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionType;
import org.thingsboard.server.common.msg.session.ToDeviceMsg;
import org.thingsboard.server.extensions.api.device.DeviceAttributes;
import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg;
import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg;
import org.thingsboard.server.extensions.api.device.DeviceMetaData;
import org.thingsboard.server.extensions.api.device.*;
import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse;
import org.thingsboard.server.extensions.api.plugins.msg.RpcError;
import org.thingsboard.server.extensions.api.plugins.msg.TimeoutIntMsg;
@ -372,11 +369,16 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
}
}
public void processCredentialsUpdate(ActorContext context, DeviceCredentialsUpdateNotificationMsg msg) {
public void processCredentialsUpdate() {
sessions.forEach((k, v) -> {
sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(new SessionCloseNotification(), k), v.getServer());
});
attributeSubscriptions.clear();
rpcSubscriptions.clear();
}
public void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) {
this.deviceName = msg.getDeviceName();
this.deviceType = msg.getDeviceType();
}
}

View File

@ -31,4 +31,6 @@ public interface ActorService extends SessionMsgProcessor, WebSocketMsgProcessor
void onRuleStateChange(TenantId tenantId, RuleId ruleId, ComponentLifecycleEvent state);
void onCredentialsUpdate(TenantId tenantId, DeviceId deviceId);
void onDeviceNameOrTypeUpdate(TenantId tenantId, DeviceId deviceId, String deviceName, String deviceType);
}

View File

@ -20,8 +20,6 @@ import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.Terminated;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.server.actors.ActorSystemContext;
@ -42,13 +40,13 @@ import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg;
import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg;
import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
import org.thingsboard.server.extensions.api.plugins.msg.ToPluginActorMsg;
import org.thingsboard.server.extensions.api.plugins.rest.PluginRestMsg;
import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg;
import org.thingsboard.server.extensions.api.plugins.ws.msg.PluginWebsocketMsg;
import org.thingsboard.server.service.cluster.discovery.DiscoveryService;
import org.thingsboard.server.service.cluster.discovery.ServerInstance;
@ -238,6 +236,18 @@ public class DefaultActorService implements ActorService {
}
}
@Override
public void onDeviceNameOrTypeUpdate(TenantId tenantId, DeviceId deviceId, String deviceName, String deviceType) {
log.trace("[{}] Processing onDeviceNameOrTypeUpdate event, deviceName: {}, deviceType: {}", deviceId, deviceName, deviceType);
DeviceNameOrTypeUpdateMsg msg = new DeviceNameOrTypeUpdateMsg(tenantId, deviceId, deviceName, deviceType);
Optional<ServerAddress> address = actorContext.getRoutingService().resolveById(deviceId);
if (address.isPresent()) {
rpcService.tell(address.get(), msg);
} else {
onMsg(msg);
}
}
public void broadcast(ToAllNodesMsg msg) {
rpcService.broadcast(msg);
appActor.tell(msg, ActorRef.noSender());

View File

@ -61,7 +61,14 @@ public class DeviceController extends BaseController {
public Device saveDevice(@RequestBody Device device) throws ThingsboardException {
try {
device.setTenantId(getCurrentUser().getTenantId());
return checkNotNull(deviceService.saveDevice(device));
Device savedDevice = checkNotNull(deviceService.saveDevice(device));
actorService
.onDeviceNameOrTypeUpdate(
savedDevice.getTenantId(),
savedDevice.getId(),
savedDevice.getName(),
savedDevice.getType());
return savedDevice;
} catch (Exception e) {
throw handleException(e);
}
@ -174,7 +181,7 @@ public class DeviceController extends BaseController {
try {
TenantId tenantId = getCurrentUser().getTenantId();
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
if (type != null && type.trim().length()>0) {
if (type != null && type.trim().length() > 0) {
return checkNotNull(deviceService.findDevicesByTenantIdAndType(tenantId, type, pageLink));
} else {
return checkNotNull(deviceService.findDevicesByTenantId(tenantId, pageLink));
@ -213,7 +220,7 @@ public class DeviceController extends BaseController {
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId);
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
if (type != null && type.trim().length()>0) {
if (type != null && type.trim().length() > 0) {
return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
} else {
return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerId(tenantId, customerId, pageLink));

View File

@ -105,9 +105,11 @@ coap:
adaptor: "${COAP_ADAPTOR_NAME:JsonCoapAdaptor}"
timeout: "${COAP_TIMEOUT:10000}"
database:
type: "${DATABASE_TYPE:cassandra}" # cassandra OR postgres
# Cassandra driver configuration parameters
cassandra:
enabled: "${CASSANDRA_ENABLED:false}"
# Thingsboard cluster name
cluster_name: "${CASSANDRA_CLUSTER_NAME:Thingsboard Cluster}"
# Thingsboard keyspace name
@ -200,7 +202,7 @@ updates:
# Enable/disable updates checking.
enabled: "${UPDATES_ENABLED:true}"
# spring CORS configuration
# spring CORS configuration
spring.mvc.cors:
mappings:
# Intercept path
@ -223,8 +225,6 @@ spring.mvc.cors:
allow-credentials: "true"
# SQL DAO Configuration
sql:
enabled: "${SQL_ENABLED:true}"
spring:
data:

View File

@ -34,6 +34,6 @@ public class ControllerTestSuite {
Arrays.asList(
new ClassPathCQLDataSet("cassandra/schema.cql", false, false),
new ClassPathCQLDataSet("cassandra/system-data.cql", false, false),
new ClassPathCQLDataSet("system-test.cql", false, false)),
new ClassPathCQLDataSet("cassandra/system-test.cql", false, false)),
"cassandra-test.yaml", 30000l);
}

View File

@ -18,19 +18,15 @@ package org.thingsboard.server.dao.sql;
import com.datastax.driver.core.utils.UUIDs;
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.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.BaseEntity;
import org.thingsboard.server.dao.model.SearchTextEntity;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Executors;
import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW;
@ -46,9 +42,7 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
protected abstract CrudRepository<E, UUID> getCrudRepository();
protected boolean isSearchTextDao() {
return false;
}
protected void setSearchText(E entity) {}
@Override
@Transactional(propagation = REQUIRES_NEW)
@ -60,9 +54,7 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
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()) {
((SearchTextEntity) entity).setSearchText(((SearchTextEntity) entity).getSearchTextSource().toLowerCase());
}
setSearchText(entity);
log.debug("Saving entity {}", entity);
if (entity.getId() == null) {
entity.setId(UUIDs.timeBased());

View File

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.sql;
import org.thingsboard.server.dao.model.BaseEntity;
import org.thingsboard.server.dao.model.SearchTextEntity;
/**
* Created by Valerii Sosliuk on 5/6/2017.
@ -23,7 +24,7 @@ import org.thingsboard.server.dao.model.BaseEntity;
public abstract class JpaAbstractSearchTextDao <E extends BaseEntity<D>, D> extends JpaAbstractDao<E, D> {
@Override
protected boolean isSearchTextDao() {
return true;
protected void setSearchText(E entity) {
((SearchTextEntity) entity).setSearchText(((SearchTextEntity) entity).getSearchTextSource().toLowerCase());
}
}

View File

@ -16,16 +16,14 @@
package org.thingsboard.server.dao.sql.user;
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.User;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.model.sql.UserCredentialsEntity;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
import org.thingsboard.server.dao.user.UserCredentialsDao;
import org.thingsboard.server.dao.util.SqlDao;
import java.util.UUID;
@ -33,7 +31,7 @@ import java.util.UUID;
* Created by Valerii Sosliuk on 4/22/2017.
*/
@Component
@ConditionalOnProperty(prefix="sql", value="enabled",havingValue = "true", matchIfMissing = false)
@SqlDao
public class JpaUserCredentialsDao extends JpaAbstractDao<UserCredentialsEntity, UserCredentials> implements UserCredentialsDao {
@Autowired

View File

@ -15,16 +15,16 @@
*/
package org.thingsboard.server.dao.sql.user;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.repository.CrudRepository;
import org.thingsboard.server.dao.model.sql.UserCredentialsEntity;
import org.thingsboard.server.dao.util.SqlDao;
import java.util.UUID;
/**
* Created by Valerii Sosliuk on 4/22/2017.
*/
@ConditionalOnProperty(prefix="sql", value="enabled",havingValue = "true", matchIfMissing = false)
@SqlDao
public interface UserCredentialsRepository extends CrudRepository<UserCredentialsEntity, UUID> {
UserCredentialsEntity findByUserId(UUID userId);

View File

@ -17,6 +17,6 @@ package org.thingsboard.server.dao.util;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ConditionalOnProperty(prefix = "cassandra", value = "enabled", havingValue = "true")
@ConditionalOnProperty(prefix = "database", value = "type", havingValue = "cassandra")
public @interface NoSqlDao {
}

View File

@ -17,6 +17,6 @@ package org.thingsboard.server.dao.util;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ConditionalOnProperty(prefix = "sql", value = "enabled", havingValue = "true")
@ConditionalOnProperty(prefix = "database", value = "type", havingValue = "postgres")
public @interface SqlDao {
}

View File

@ -24,8 +24,7 @@ import java.util.Arrays;
@RunWith(ClasspathSuite.class)
@ClassnameFilters({
// "org.thingsboard.server.dao.sql.alarm.",
"org.thingsboard.server.dao.sql.*Test",
"org.thingsboard.server.dao.sql.*Test"
})
public class JpaDaoTestSuite {

View File

@ -34,7 +34,7 @@ public class NoSqlDaoServiceTestSuite {
new CustomCassandraCQLUnit(
Arrays.asList(new ClassPathCQLDataSet("cassandra/schema.cql", false, false),
new ClassPathCQLDataSet("cassandra/system-data.cql", false, false),
new ClassPathCQLDataSet("system-test.cql", false, false)),
new ClassPathCQLDataSet("cassandra/system-test.cql", false, false)),
"cassandra-test.yaml", 30000L);
}

View File

@ -30,7 +30,7 @@ public class SqlDaoServiceTestSuite {
@ClassRule
public static CustomPostgresUnit postgresUnit = new CustomPostgresUnit(
Arrays.asList("postgres/schema.sql", "postgres/system-data.sql", "system-test.sql"),
Arrays.asList("postgres/schema.sql", "postgres/system-data.sql", "postgres/system-test.sql"),
"postgres-embedded-test.properties");
}

View File

@ -1,2 +1 @@
sql.enabled=false
cassandra.enabled=true
database.type=cassandra

View File

@ -1,5 +1,4 @@
cassandra.enabled=false
sql.enabled=true
database.type=postgres
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=validate
@ -7,7 +6,3 @@ spring.jpa.hibernate.ddl-auto=validate
spring.datasource.url=jdbc:postgresql://localhost:5433/thingsboard-test
spring.datasource.username=postgres
spring.datasource.password=postgres
#spring.datasource.url=jdbc:h2:mem:test;MODE=PostgreSQL
#spring.datasource.schema=classpath:postgres/schema.sql
#spring.datasource.data=classpath:postgres/system-data.sql;classpath:system-test.sql

View File

@ -0,0 +1,30 @@
/**
* 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
*
* 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.extensions.api.device;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
@Data
@AllArgsConstructor
public class DeviceNameOrTypeUpdateMsg implements ToDeviceActorNotificationMsg {
private final TenantId tenantId;
private final DeviceId deviceId;
private final String deviceName;
private final String deviceType;
}

View File

@ -892,10 +892,10 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
}
}
function getRelatedEntities(rootEntityId, entityType, entitySubTypes, maxLevel, keys, typeTranslatePrefix) {
function getRelatedEntities(rootEntityId, entityType, entitySubTypes, maxLevel, keys, typeTranslatePrefix, relationType) {
var deferred = $q.defer();
var entitySearchQuery = constructRelatedEntitiesSearchQuery(rootEntityId, entityType, entitySubTypes, maxLevel);
var entitySearchQuery = constructRelatedEntitiesSearchQuery(rootEntityId, entityType, entitySubTypes, maxLevel, relationType);
if (!entitySearchQuery) {
deferred.reject();
} else {
@ -930,12 +930,12 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
return deferred.promise;
}
function saveRelatedEntity(relatedEntity, parentEntityId, keys) {
function saveRelatedEntity(relatedEntity, parentEntityId, keys, relation) {
var deferred = $q.defer();
if (relatedEntity.id.id) {
updateRelatedEntity(relatedEntity, keys, deferred);
updateRelatedEntity(relatedEntity, keys, deferred, relation);
} else {
addRelatedEntity(relatedEntity, parentEntityId, keys, deferred);
addRelatedEntity(relatedEntity, parentEntityId, keys, deferred, relation);
}
return deferred.promise;
}
@ -1073,7 +1073,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
}
}
function addRelatedEntity(relatedEntity, parentEntityId, keys, deferred) {
function addRelatedEntity(relatedEntity, parentEntityId, keys, deferred, relation) {
var entity = {};
entity.id = relatedEntity.id;
entity.name = relatedEntity.name;
@ -1081,14 +1081,18 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
saveEntityPromise(entity).then(
function success(entity) {
relatedEntity.id = entity.id;
var relation = {
if (!relation) {
relation = {
from: parentEntityId,
to: relatedEntity.id,
type: types.entityRelationType.contains
};
} else {
relation.to = relatedEntity.id;
}
entityRelationService.saveRelation(relation).then(
function success() {
updateEntity(entity, relatedEntity, keys, deferred);
updateEntity(entity, relatedEntity, keys, deferred, relation);
},
function fail() {
deferred.reject();
@ -1101,15 +1105,27 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
);
}
function updateRelatedEntity(relatedEntity, keys, deferred) {
function updateRelatedEntity(relatedEntity, keys, deferred, relation) {
getEntityPromise(relatedEntity.id.entityType, relatedEntity.id.id, {ignoreLoading: true}).then(
function success(entity) {
if (relation) {
relation.to = relatedEntity.id;
entityRelationService.saveRelation(relation).then(
function success() {
updateEntity(entity, relatedEntity, keys, deferred);
},
function fail() {
deferred.reject();
}
);
} else {
updateEntity(entity, relatedEntity, keys, deferred);
}
},
function fail() {
deferred.reject();
}
);
}
function updateEntity(entity, relatedEntity, keys, deferred) {
@ -1146,7 +1162,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
);
}
function constructRelatedEntitiesSearchQuery(rootEntityId, entityType, entitySubTypes, maxLevel) {
function constructRelatedEntitiesSearchQuery(rootEntityId, entityType, entitySubTypes, maxLevel, relationType) {
var searchQuery = {
parameters: {
@ -1154,8 +1170,11 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
rootType: rootEntityId.entityType,
direction: types.entitySearchDirection.from
},
relationType: types.entityRelationType.contains
relationType: relationType
};
if (!relationType) {
searchQuery.relationType = types.entityRelationType.contains;
}
if (maxLevel) {
searchQuery.parameters.maxLevel = maxLevel;

View File

@ -125,7 +125,7 @@
</md-table-container>
<md-table-pagination md-limit="vm.query.limit" md-limit-options="[5, 10, 15]"
md-page="vm.query.page" md-total="{{vm.relationsCount}}"
md-on-paginate="onPaginate" md-page-select>
md-on-paginate="vm.onPaginate" md-page-select>
</md-table-pagination>
</div>
</md-content>