现在学习thingsboard源码,从设备的保存开始分析.
整个保存方法如下:
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device", method = RequestMethod.POST)
@ResponseBody
public Device saveDevice(@RequestBody Device device,
@RequestParam(name = "accessToken", required = false) String accessToken) throws ThingsboardException {
try {
device.setTenantId(getCurrentUser().getTenantId());
checkEntity(device.getId(), device, Resource.DEVICE);
Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken));
tbClusterService.onDeviceChange(savedDevice, null);
tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(),
savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null);
tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(),
device.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
logEntityAction(savedDevice.getId(), savedDevice,
savedDevice.getCustomerId(),
device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
if (device.getId() == null) {
deviceStateService.onDeviceAdded(savedDevice);
} else {
deviceStateService.onDeviceUpdated(savedDevice);
}
return savedDevice;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.DEVICE), device,
null, device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
tb使用了spring security进行权限验证和控制,这里就通过PreAuthorize来判断登陆人是否具有TENANT_ADMIN(租户管理员)和CUSTOMER_USER(用户)的权限。
设置设备的租户ID,因为设备有所属的租户ID
device.setTenantId(getCurrentUser().getTenantId());
检查设备entity数据是否正确
checkEntity(device.getId(), device, Resource.DEVICE);
//检查设备数据
protected <I extends EntityId, T extends HasTenantId> void checkEntity(I entityId, T entity, Resource resource) throws ThingsboardException {
if (entityId == null) {
accessControlService
.checkPermission(getCurrentUser(), resource, Operation.CREATE, null, entity);
} else {
checkEntityId(entityId, Operation.WRITE);
}
}
protected void checkEntityId(EntityId entityId, Operation operation) throws ThingsboardException {
try {
//判断是否为Null
checkNotNull(entityId);
//这里和后面的检查重复了,都是检查id是否正确
validateId(entityId.getId(), "Incorrect entityId " + entityId);
switch (entityId.getEntityType()) {
case ALARM:
checkAlarmId(new AlarmId(entityId.getId()), operation);
return;
case DEVICE:
//设备属性,走这里
checkDeviceId(new DeviceId(entityId.getId()), operation);
return;
case DEVICE_PROFILE:
checkDeviceProfileId(new DeviceProfileId(entityId.getId()), operation);
return;
case CUSTOMER:
checkCustomerId(new CustomerId(entityId.getId()), operation);
return;
case TENANT:
checkTenantId(new TenantId(entityId.getId()), operation);
return;
case TENANT_PROFILE:
checkTenantProfileId(new TenantProfileId(entityId.getId()), operation);
return;
case RULE_CHAIN:
checkRuleChain(new RuleChainId(entityId.getId()), operation);
return;
case RULE_NODE:
checkRuleNode(new RuleNodeId(entityId.getId()), operation);
return;
case ASSET:
checkAssetId(new AssetId(entityId.getId()), operation);
return;
case DASHBOARD:
checkDashboardId(new DashboardId(entityId.getId()), operation);
return;
case USER:
checkUserId(new UserId(entityId.getId()), operation);
return;
case ENTITY_VIEW:
checkEntityViewId(new EntityViewId(entityId.getId()), operation);
return;
case WIDGETS_BUNDLE:
checkWidgetsBundleId(new WidgetsBundleId(entityId.getId()), operation);
return;
case WIDGET_TYPE:
checkWidgetTypeId(new WidgetTypeId(entityId.getId()), operation);
return;
default:
throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType());
}
} catch (Exception e) {
throw handleException(e, false);
}
}
//检查设备属性数据
Device checkDeviceId(DeviceId deviceId, Operation operation) throws ThingsboardException {
try {
//判断设备属性是否正确
validateId(deviceId, "Incorrect deviceId " + deviceId);
//根据管理员Id和设备id查找设备信息
Device device = deviceService.findDeviceById(getCurrentUser().getTenantId(), deviceId);
checkNotNull(device);
//检查当前管理员权限是否正确
accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, operation, deviceId, device);
return device;
} catch (Exception e) {
throw handleException(e, false);
}
}
保存设备信息
Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken));
//缓存
@CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.name}")
@Override
public Device saveDeviceWithAccessToken(Device device, String accessToken) {
return doSaveDevice(device, accessToken);
}
//真正保存操作
private Device doSaveDevice(Device device, String accessToken) {
log.trace("Executing saveDevice [{}]", device);
deviceValidator.validate(device, Device::getTenantId);
Device savedDevice;
try {
DeviceProfile deviceProfile;
if (device.getDeviceProfileId() == null) {
if (!StringUtils.isEmpty(device.getType())) {
deviceProfile = this.deviceProfileService.findOrCreateDeviceProfile(device.getTenantId(), device.getType());
} else {
deviceProfile = this.deviceProfileService.findDefaultDeviceProfile(device.getTenantId());
}
device.setDeviceProfileId(new DeviceProfileId(deviceProfile.getId().getId()));
} else {
deviceProfile = this.deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId());
if (deviceProfile == null) {
throw new DataValidationException("Device is referencing non existing device profile!");
}
}
device.setType(deviceProfile.getName());
device.setDeviceData(syncDeviceData(deviceProfile, device.getDeviceData()));
savedDevice = deviceDao.save(device.getTenantId(), device);
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_name_unq_key")) {
// remove device from cache in case null value cached in the distributed redis.
removeDeviceFromCache(device.getTenantId(), device.getName());
throw new DataValidationException("Device with such name already exists!");
} else {
throw t;
}
}
if (device.getId() == null) {
DeviceCredentials deviceCredentials = new DeviceCredentials();
deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId()));
deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
deviceCredentials.setCredentialsId(!StringUtils.isEmpty(accessToken) ? accessToken : RandomStringUtils.randomAlphanumeric(20));
deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials);
}
return savedDevice;
}
private DeviceData syncDeviceData(DeviceProfile deviceProfile, DeviceData deviceData) {
if (deviceData == null) {
deviceData = new DeviceData();
}
if (deviceData.getConfiguration() == null || !deviceProfile.getType().equals(deviceData.getConfiguration().getType())) {
switch (deviceProfile.getType()) {
case DEFAULT:
deviceData.setConfiguration(new DefaultDeviceConfiguration());
break;
}
}
if (deviceData.getTransportConfiguration() == null || !deviceProfile.getTransportType().equals(deviceData.getTransportConfiguration().getType())) {
switch (deviceProfile.getTransportType()) {
case DEFAULT:
deviceData.setTransportConfiguration(new DefaultDeviceTransportConfiguration());
break;
case MQTT:
deviceData.setTransportConfiguration(new MqttDeviceTransportConfiguration());
break;
case LWM2M:
deviceData.setTransportConfiguration(new Lwm2mDeviceTransportConfiguration());
break;
case COAP:
deviceData.setTransportConfiguration(new CoapDeviceTransportConfiguration());
break;
}
}
return deviceData;
}
//真正保存方法
@Override
@Transactional
public D save(TenantId tenantId, D domain) {
E entity;
try {
entity = getEntityClass().getConstructor(domain.getClass()).newInstance(domain);
} 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);
}
setSearchText(entity);
log.debug("Saving entity {}", entity);
if (entity.getUuid() == null) {
UUID uuid = Uuids.timeBased();
entity.setUuid(uuid);
entity.setCreatedTime(Uuids.unixTimestamp(uuid));
}
entity = getCrudRepository().save(entity);
return DaoUtil.getData(entity);
}