Commit 08c8482f0630d9e72ed6fd7e2159881881fca6be

Authored by Igor Kulikov
1 parent f84c4fe3

Revert "Handle Device service transactional methods exceptions (fix exception ha…

…ndling for devices with same name)"

This reverts commit b67f454b
... ... @@ -30,6 +30,7 @@ import org.springframework.cache.annotation.Cacheable;
30 30 import org.springframework.cache.annotation.Caching;
31 31 import org.springframework.context.annotation.Lazy;
32 32 import org.springframework.stereotype.Service;
  33 +import org.springframework.transaction.annotation.Transactional;
33 34 import org.springframework.util.CollectionUtils;
34 35 import org.springframework.util.StringUtils;
35 36 import org.thingsboard.common.util.JacksonUtil;
... ... @@ -81,7 +82,6 @@ import org.thingsboard.server.dao.service.DataValidator;
81 82 import org.thingsboard.server.dao.service.PaginatedRemover;
82 83 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
83 84 import org.thingsboard.server.dao.tenant.TenantDao;
84   -import org.thingsboard.server.dao.tx.TransactionHandler;
85 85
86 86 import javax.annotation.Nullable;
87 87 import java.util.ArrayList;
... ... @@ -141,9 +141,6 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
141 141 @Autowired
142 142 private OtaPackageService otaPackageService;
143 143
144   - @Autowired
145   - private TransactionHandler transactionHandler;
146   -
147 144 @Override
148 145 public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) {
149 146 log.trace("Executing findDeviceInfoById [{}]", deviceId);
... ... @@ -187,13 +184,10 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
187 184 @CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.name}"),
188 185 @CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.id}")
189 186 })
  187 + @Transactional
190 188 @Override
191 189 public Device saveDeviceWithAccessToken(Device device, String accessToken) {
192   - try {
193   - return transactionHandler.runInTransaction(() -> doSaveDevice(device, accessToken, true));
194   - } catch (Exception t) {
195   - throw handleDeviceSaveException(device, t);
196   - }
  190 + return doSaveDevice(device, accessToken, true);
197 191 }
198 192
199 193 @Caching(evict= {
... ... @@ -218,32 +212,26 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
218 212 @CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.name}"),
219 213 @CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.id}")
220 214 })
  215 + @Transactional
221 216 @Override
222   - public Device saveDeviceWithCredentials(Device toSave, DeviceCredentials deviceCredentials) {
223   - try {
224   - return transactionHandler.runInTransaction(() -> {
225   - Device device = toSave;
226   - if (device.getId() == null) {
227   - Device deviceWithName = this.findDeviceByTenantIdAndName(device.getTenantId(), device.getName());
228   - device = deviceWithName == null ? device : deviceWithName.updateDevice(device);
229   - }
230   - Device savedDevice = this.saveDeviceWithoutCredentials(device, true);
231   - deviceCredentials.setDeviceId(savedDevice.getId());
232   - if (device.getId() == null) {
233   - deviceCredentialsService.createDeviceCredentials(savedDevice.getTenantId(), deviceCredentials);
234   - } else {
235   - DeviceCredentials foundDeviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), savedDevice.getId());
236   - if (foundDeviceCredentials == null) {
237   - deviceCredentialsService.createDeviceCredentials(savedDevice.getTenantId(), deviceCredentials);
238   - } else {
239   - deviceCredentialsService.updateDeviceCredentials(device.getTenantId(), deviceCredentials);
240   - }
241   - }
242   - return savedDevice;
243   - });
244   - } catch (Exception t) {
245   - throw handleDeviceSaveException(toSave, t);
  217 + public Device saveDeviceWithCredentials(Device device, DeviceCredentials deviceCredentials) {
  218 + if (device.getId() == null) {
  219 + Device deviceWithName = this.findDeviceByTenantIdAndName(device.getTenantId(), device.getName());
  220 + device = deviceWithName == null ? device : deviceWithName.updateDevice(device);
  221 + }
  222 + Device savedDevice = this.saveDeviceWithoutCredentials(device, true);
  223 + deviceCredentials.setDeviceId(savedDevice.getId());
  224 + if (device.getId() == null) {
  225 + deviceCredentialsService.createDeviceCredentials(savedDevice.getTenantId(), deviceCredentials);
  226 + } else {
  227 + DeviceCredentials foundDeviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), savedDevice.getId());
  228 + if (foundDeviceCredentials == null) {
  229 + deviceCredentialsService.createDeviceCredentials(savedDevice.getTenantId(), deviceCredentials);
  230 + } else {
  231 + deviceCredentialsService.updateDeviceCredentials(device.getTenantId(), deviceCredentials);
  232 + }
246 233 }
  234 + return savedDevice;
247 235 }
248 236
249 237 private Device doSaveDevice(Device device, String accessToken, boolean doValidate) {
... ... @@ -282,7 +270,15 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
282 270 device.setDeviceData(syncDeviceData(deviceProfile, device.getDeviceData()));
283 271 return deviceDao.save(device.getTenantId(), device);
284 272 } catch (Exception t) {
285   - throw handleDeviceSaveException(device, t);
  273 + ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
  274 + if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_name_unq_key")) {
  275 + // remove device from cache in case null value cached in the distributed redis.
  276 + removeDeviceFromCacheByName(device.getTenantId(), device.getName());
  277 + removeDeviceFromCacheById(device.getTenantId(), device.getId());
  278 + throw new DataValidationException("Device with such name already exists!");
  279 + } else {
  280 + throw t;
  281 + }
286 282 }
287 283 }
288 284
... ... @@ -368,17 +364,16 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
368 364 }
369 365
370 366 private void removeDeviceFromCacheByName(TenantId tenantId, String name) {
371   - if (tenantId != null && !StringUtils.isEmpty(name)) {
372   - Cache cache = cacheManager.getCache(DEVICE_CACHE);
373   - cache.evict(Arrays.asList(tenantId, name));
374   - }
  367 + Cache cache = cacheManager.getCache(DEVICE_CACHE);
  368 + cache.evict(Arrays.asList(tenantId, name));
375 369 }
376 370
377 371 private void removeDeviceFromCacheById(TenantId tenantId, DeviceId deviceId) {
378   - if (tenantId != null && deviceId != null) {
379   - Cache cache = cacheManager.getCache(DEVICE_CACHE);
380   - cache.evict(Arrays.asList(tenantId, deviceId));
  372 + if (deviceId == null) {
  373 + return;
381 374 }
  375 + Cache cache = cacheManager.getCache(DEVICE_CACHE);
  376 + cache.evict(Arrays.asList(tenantId, deviceId));
382 377 }
383 378
384 379 @Override
... ... @@ -565,93 +560,84 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
565 560 }, MoreExecutors.directExecutor());
566 561 }
567 562
  563 + @Transactional
568 564 @Override
569 565 public Device assignDeviceToTenant(TenantId tenantId, Device device) {
570 566 log.trace("Executing assignDeviceToTenant [{}][{}]", tenantId, device);
  567 +
571 568 try {
572   - return transactionHandler.runInTransaction(() -> {
573   - try {
574   - List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), device.getId()).get();
575   - if (!CollectionUtils.isEmpty(entityViews)) {
576   - throw new DataValidationException("Can't assign device that has entity views to another tenant!");
577   - }
578   - } catch (ExecutionException | InterruptedException e) {
579   - log.error("Exception while finding entity views for deviceId [{}]", device.getId(), e);
580   - throw new RuntimeException("Exception while finding entity views for deviceId [" + device.getId() + "]", e);
581   - }
  569 + List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), device.getId()).get();
  570 + if (!CollectionUtils.isEmpty(entityViews)) {
  571 + throw new DataValidationException("Can't assign device that has entity views to another tenant!");
  572 + }
  573 + } catch (ExecutionException | InterruptedException e) {
  574 + log.error("Exception while finding entity views for deviceId [{}]", device.getId(), e);
  575 + throw new RuntimeException("Exception while finding entity views for deviceId [" + device.getId() + "]", e);
  576 + }
582 577
583   - eventService.removeEvents(device.getTenantId(), device.getId());
  578 + eventService.removeEvents(device.getTenantId(), device.getId());
584 579
585   - relationService.removeRelations(device.getTenantId(), device.getId());
  580 + relationService.removeRelations(device.getTenantId(), device.getId());
586 581
587   - TenantId oldTenantId = device.getTenantId();
  582 + TenantId oldTenantId = device.getTenantId();
588 583
589   - device.setTenantId(tenantId);
590   - device.setCustomerId(null);
591   - Device savedDevice = doSaveDevice(device, null, true);
  584 + device.setTenantId(tenantId);
  585 + device.setCustomerId(null);
  586 + Device savedDevice = doSaveDevice(device, null, true);
592 587
593   - // explicitly remove device with previous tenant id from cache
594   - // result device object will have different tenant id and will not remove entity from cache
595   - removeDeviceFromCacheByName(oldTenantId, device.getName());
596   - removeDeviceFromCacheById(oldTenantId, device.getId());
  588 + // explicitly remove device with previous tenant id from cache
  589 + // result device object will have different tenant id and will not remove entity from cache
  590 + removeDeviceFromCacheByName(oldTenantId, device.getName());
  591 + removeDeviceFromCacheById(oldTenantId, device.getId());
597 592
598   - return savedDevice;
599   - });
600   - } catch (Exception t) {
601   - throw handleDeviceSaveException(device, t);
602   - }
  593 + return savedDevice;
603 594 }
604 595
605 596 @Override
606 597 @CacheEvict(cacheNames = DEVICE_CACHE, key = "{#profile.tenantId, #provisionRequest.deviceName}")
  598 + @Transactional
607 599 public Device saveDevice(ProvisionRequest provisionRequest, DeviceProfile profile) {
608 600 Device device = new Device();
609   - try {
610   - return transactionHandler.runInTransaction(() -> {
611   - device.setName(provisionRequest.getDeviceName());
612   - device.setType(profile.getName());
613   - device.setTenantId(profile.getTenantId());
614   - Device savedDevice = saveDevice(device);
615   - if (!StringUtils.isEmpty(provisionRequest.getCredentialsData().getToken()) ||
616   - !StringUtils.isEmpty(provisionRequest.getCredentialsData().getX509CertHash()) ||
617   - !StringUtils.isEmpty(provisionRequest.getCredentialsData().getUsername()) ||
618   - !StringUtils.isEmpty(provisionRequest.getCredentialsData().getPassword()) ||
619   - !StringUtils.isEmpty(provisionRequest.getCredentialsData().getClientId())) {
620   - DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedDevice.getTenantId(), savedDevice.getId());
621   - if (deviceCredentials == null) {
622   - deviceCredentials = new DeviceCredentials();
623   - }
624   - deviceCredentials.setDeviceId(savedDevice.getId());
625   - deviceCredentials.setCredentialsType(provisionRequest.getCredentialsType());
626   - switch (provisionRequest.getCredentialsType()) {
627   - case ACCESS_TOKEN:
628   - deviceCredentials.setCredentialsId(provisionRequest.getCredentialsData().getToken());
629   - break;
630   - case MQTT_BASIC:
631   - BasicMqttCredentials mqttCredentials = new BasicMqttCredentials();
632   - mqttCredentials.setClientId(provisionRequest.getCredentialsData().getClientId());
633   - mqttCredentials.setUserName(provisionRequest.getCredentialsData().getUsername());
634   - mqttCredentials.setPassword(provisionRequest.getCredentialsData().getPassword());
635   - deviceCredentials.setCredentialsValue(JacksonUtil.toString(mqttCredentials));
636   - break;
637   - case X509_CERTIFICATE:
638   - deviceCredentials.setCredentialsValue(provisionRequest.getCredentialsData().getX509CertHash());
639   - break;
640   - case LWM2M_CREDENTIALS:
641   - break;
642   - }
643   - try {
644   - deviceCredentialsService.updateDeviceCredentials(savedDevice.getTenantId(), deviceCredentials);
645   - } catch (Exception e) {
646   - throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name());
647   - }
648   - }
649   - removeDeviceFromCacheById(savedDevice.getTenantId(), savedDevice.getId()); // eviction by name is described as annotation @CacheEvict above
650   - return savedDevice;
651   - });
652   - } catch (Exception t) {
653   - throw handleDeviceSaveException(device, t);
  601 + device.setName(provisionRequest.getDeviceName());
  602 + device.setType(profile.getName());
  603 + device.setTenantId(profile.getTenantId());
  604 + Device savedDevice = saveDevice(device);
  605 + if (!StringUtils.isEmpty(provisionRequest.getCredentialsData().getToken()) ||
  606 + !StringUtils.isEmpty(provisionRequest.getCredentialsData().getX509CertHash()) ||
  607 + !StringUtils.isEmpty(provisionRequest.getCredentialsData().getUsername()) ||
  608 + !StringUtils.isEmpty(provisionRequest.getCredentialsData().getPassword()) ||
  609 + !StringUtils.isEmpty(provisionRequest.getCredentialsData().getClientId())) {
  610 + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedDevice.getTenantId(), savedDevice.getId());
  611 + if (deviceCredentials == null) {
  612 + deviceCredentials = new DeviceCredentials();
  613 + }
  614 + deviceCredentials.setDeviceId(savedDevice.getId());
  615 + deviceCredentials.setCredentialsType(provisionRequest.getCredentialsType());
  616 + switch (provisionRequest.getCredentialsType()) {
  617 + case ACCESS_TOKEN:
  618 + deviceCredentials.setCredentialsId(provisionRequest.getCredentialsData().getToken());
  619 + break;
  620 + case MQTT_BASIC:
  621 + BasicMqttCredentials mqttCredentials = new BasicMqttCredentials();
  622 + mqttCredentials.setClientId(provisionRequest.getCredentialsData().getClientId());
  623 + mqttCredentials.setUserName(provisionRequest.getCredentialsData().getUsername());
  624 + mqttCredentials.setPassword(provisionRequest.getCredentialsData().getPassword());
  625 + deviceCredentials.setCredentialsValue(JacksonUtil.toString(mqttCredentials));
  626 + break;
  627 + case X509_CERTIFICATE:
  628 + deviceCredentials.setCredentialsValue(provisionRequest.getCredentialsData().getX509CertHash());
  629 + break;
  630 + case LWM2M_CREDENTIALS:
  631 + break;
  632 + }
  633 + try {
  634 + deviceCredentialsService.updateDeviceCredentials(savedDevice.getTenantId(), deviceCredentials);
  635 + } catch (Exception e) {
  636 + throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name());
  637 + }
654 638 }
  639 + removeDeviceFromCacheById(savedDevice.getTenantId(), savedDevice.getId()); // eviction by name is described as annotation @CacheEvict above
  640 + return savedDevice;
655 641 }
656 642
657 643 @Override
... ... @@ -832,20 +818,4 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
832 818 unassignDeviceFromCustomer(tenantId, new DeviceId(entity.getUuidId()));
833 819 }
834 820 };
835   -
836   - private RuntimeException handleDeviceSaveException(Device device, Exception t) {
837   - ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
838   - if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_name_unq_key")) {
839   - // remove device from cache in case null value cached in the distributed redis.
840   - if (device != null) {
841   - removeDeviceFromCacheByName(device.getTenantId(), device.getName());
842   - removeDeviceFromCacheById(device.getTenantId(), device.getId());
843   - }
844   - return new DataValidationException("Device with such name already exists!");
845   - } else if (t instanceof RuntimeException) {
846   - return (RuntimeException)t;
847   - } else {
848   - return new RuntimeException("Failed to save device!", t);
849   - }
850   - }
851 821 }
... ...
1   -/**
2   - * Copyright © 2016-2021 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.dao.tx;
17   -
18   -import org.springframework.stereotype.Service;
19   -import org.springframework.transaction.annotation.Propagation;
20   -import org.springframework.transaction.annotation.Transactional;
21   -
22   -import java.util.function.Supplier;
23   -
24   -@Service
25   -public class TransactionHandler {
26   -
27   - @Transactional(propagation = Propagation.REQUIRED)
28   - public <T> T runInTransaction(Supplier<T> supplier) {
29   - return supplier.get();
30   - }
31   -
32   - @Transactional(propagation = Propagation.REQUIRES_NEW)
33   - public <T> T runInNewTransaction(Supplier<T> supplier) {
34   - return supplier.get();
35   - }
36   -}