Commit 08c8482f0630d9e72ed6fd7e2159881881fca6be
1 parent
f84c4fe3
Revert "Handle Device service transactional methods exceptions (fix exception ha…
…ndling for devices with same name)" This reverts commit b67f454b
Showing
2 changed files
with
97 additions
and
163 deletions
... | ... | @@ -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 | } | ... | ... |
dao/src/main/java/org/thingsboard/server/dao/tx/TransactionHandler.java
deleted
100644 → 0
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 | -} |