mirror of
https://gitee.com/pnoker/iot-dc3.git
synced 2026-08-29 06:31:14 +08:00
feat(driver,manager): broadcast driver metadata events and let drivers refresh on demand
Extends the existing point/device metadata refresh flow to drivers:
- MetadataEvent gains an optional targetServices set so manager-side
publishers can scope a metadata event to specific driver services
instead of broadcasting to every listener.
- New DRIVER value on MetadataTypeEnum, plus a new GetById RPC on
driver_driver.proto so drivers can re-fetch their registered metadata
without going through the full registration handshake again.
- DriverClient.refreshMetadata(driverId) calls the new RPC and reapplies
the returned device ids and attribute maps via a shared applyMetadata
helper.
- MetadataReceiver now handles MetadataTypeEnum.DRIVER:
DELETE -> clear DriverMetadata, DeviceMetadata, and PointMetadata
caches and flip status to OFFLINE
ADD/UPDATE -> driverClient.refreshMetadata(id)
- Manager-side MetadataEventListener forwards events to RabbitMQ keyed by
the target services in the event, falling back to broadcast when none
are specified.
- DeviceServiceImpl, DriverAttributeServiceImpl, PointAttributeServiceImpl,
and PointServiceImpl populate targetServices using the relevant driver
service names so changes only wake the drivers that own the affected
entity.
- DriverDriverServer.getById exposes the new RPC; new DriverDriverServerTest
covers it.
- MetadataReceiverTest gains driverUpdate / driverDelete cases;
MetadataEventListenerTest covers the per-service routing.
This commit is contained in:
@@ -22,6 +22,7 @@ package api.common.driver;
|
||||
import "api/common/r.proto";
|
||||
import "api/common/entity.proto";
|
||||
import "api/common/driver/driver_entity.proto";
|
||||
import "api/common/driver/driver_query.proto";
|
||||
|
||||
// Configuration options for code generation
|
||||
option java_package = "io.github.pnoker.api.common.driver";
|
||||
@@ -33,6 +34,9 @@ option java_multiple_files = true;
|
||||
service DriverApi {
|
||||
// Driver registration, used by the driver service to register itself with the platform
|
||||
rpc DriverRegister (GrpcDriverRegisterDTO) returns (GrpcRDriverRegisterDTO);
|
||||
|
||||
// Query the current registered driver metadata without re-registering it
|
||||
rpc GetById (GrpcDriverQuery) returns (GrpcRDriverRegisterDTO);
|
||||
}
|
||||
|
||||
// Driver registration response structure
|
||||
@@ -51,4 +55,4 @@ message GrpcRDriverRegisterDTO {
|
||||
|
||||
// List of point attribute configurations supported by the driver
|
||||
repeated GrpcPointAttributeDTO point_attributes = 5;
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -44,6 +44,11 @@ public enum MetadataTypeEnum {
|
||||
* Point metadata
|
||||
*/
|
||||
POINT((byte) 1, "point", "Point metadata"),
|
||||
|
||||
/**
|
||||
* Driver metadata
|
||||
*/
|
||||
DRIVER((byte) 2, "driver", "Driver metadata"),
|
||||
;
|
||||
|
||||
/**
|
||||
|
||||
+6
@@ -60,6 +60,12 @@ public class MetadataEventListener implements ApplicationListener<MetadataEvent>
|
||||
entityEvent.setMetadataType(MetadataTypeEnum.POINT);
|
||||
entityEvent.setOperateType(metadataEvent.getOperateType());
|
||||
driverCustomService.event(entityEvent);
|
||||
} else if (MetadataTypeEnum.DRIVER.equals(metadataType)) {
|
||||
MetadataEventDTO entityEvent = new MetadataEventDTO();
|
||||
entityEvent.setId(metadataEvent.getId());
|
||||
entityEvent.setMetadataType(MetadataTypeEnum.DRIVER);
|
||||
entityEvent.setOperateType(metadataEvent.getOperateType());
|
||||
driverCustomService.event(entityEvent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
@@ -22,6 +22,7 @@ import io.github.pnoker.api.common.GrpcDriverDTO;
|
||||
import io.github.pnoker.api.common.GrpcPointAttributeDTO;
|
||||
import io.github.pnoker.api.common.driver.DriverApiGrpc;
|
||||
import io.github.pnoker.api.common.driver.GrpcDriverRegisterDTO;
|
||||
import io.github.pnoker.api.common.driver.GrpcDriverQuery;
|
||||
import io.github.pnoker.api.common.driver.GrpcRDriverRegisterDTO;
|
||||
import io.github.pnoker.common.driver.entity.bo.DriverBO;
|
||||
import io.github.pnoker.common.driver.entity.bo.RegisterBO;
|
||||
@@ -33,6 +34,7 @@ import io.github.pnoker.common.driver.entity.dto.PointAttributeDTO;
|
||||
import io.github.pnoker.common.driver.metadata.DriverMetadata;
|
||||
import io.github.pnoker.common.enums.DriverStatusEnum;
|
||||
import io.github.pnoker.common.exception.RegisterException;
|
||||
import io.github.pnoker.common.exception.ServiceException;
|
||||
import io.github.pnoker.common.optional.CollectionOptional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -41,6 +43,7 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -98,6 +101,30 @@ public class DriverClient {
|
||||
throw new RegisterException(rDriverRegisterDTO.getResult().getMessage());
|
||||
}
|
||||
|
||||
applyMetadata(rDriverRegisterDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the current driver metadata from manager without submitting registration
|
||||
* properties again.
|
||||
*
|
||||
* @param driverId registered driver id
|
||||
*/
|
||||
public void refreshMetadata(Long driverId) {
|
||||
if (Objects.isNull(driverId) || driverId <= 0) {
|
||||
throw new ServiceException("Failed to refresh driver metadata: invalid driver id");
|
||||
}
|
||||
|
||||
GrpcDriverQuery query = GrpcDriverQuery.newBuilder().setDriverId(driverId).build();
|
||||
GrpcRDriverRegisterDTO rDriverRegisterDTO = driverApiBlockingStub.getById(query);
|
||||
if (!rDriverRegisterDTO.getResult().getOk()) {
|
||||
throw new ServiceException(rDriverRegisterDTO.getResult().getMessage());
|
||||
}
|
||||
|
||||
applyMetadata(rDriverRegisterDTO);
|
||||
}
|
||||
|
||||
private void applyMetadata(GrpcRDriverRegisterDTO rDriverRegisterDTO) {
|
||||
DriverBO driverBO = driverBuilder.buildDTOByGrpcDTO(rDriverRegisterDTO.getDriver());
|
||||
driverMetadata.setDriver(driverBO);
|
||||
|
||||
|
||||
+20
-3
@@ -116,8 +116,18 @@ public final class DeviceMetadata {
|
||||
* @param id device identifier
|
||||
*/
|
||||
public void loadCache(long id) {
|
||||
CompletableFuture<DeviceBO> future = CompletableFuture.supplyAsync(() -> deviceClient.getById(id));
|
||||
cache.put(id, future);
|
||||
CompletableFuture.supplyAsync(() -> deviceClient.getById(id))
|
||||
.whenComplete((device, throwable) -> {
|
||||
if (Objects.nonNull(throwable)) {
|
||||
log.error("Failed to reload device metadata, deviceId={}", id, throwable);
|
||||
return;
|
||||
}
|
||||
if (Objects.isNull(device)) {
|
||||
cache.synchronous().invalidate(id);
|
||||
return;
|
||||
}
|
||||
cache.put(id, CompletableFuture.completedFuture(device));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,7 +136,14 @@ public final class DeviceMetadata {
|
||||
* @param id device identifier
|
||||
*/
|
||||
public void removeCache(long id) {
|
||||
cache.put(id, CompletableFuture.completedFuture(null));
|
||||
cache.synchronous().invalidate(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all cached device metadata.
|
||||
*/
|
||||
public void clearCache() {
|
||||
cache.synchronous().invalidateAll();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+12
-2
@@ -76,12 +76,12 @@ public final class DriverMetadata {
|
||||
* Current driver status.
|
||||
*/
|
||||
@Setter
|
||||
private DriverStatusEnum driverStatus = DriverStatusEnum.OFFLINE;
|
||||
private volatile DriverStatusEnum driverStatus = DriverStatusEnum.OFFLINE;
|
||||
/**
|
||||
* Registered driver definition.
|
||||
*/
|
||||
@Setter
|
||||
private DriverBO driver;
|
||||
private volatile DriverBO driver;
|
||||
|
||||
private static <E> void replaceContents(Set<E> target, Set<E> source) {
|
||||
target.clear();
|
||||
@@ -117,4 +117,14 @@ public final class DriverMetadata {
|
||||
replaceContents(this.pointAttributeNameMap, pointAttributeNameMap);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
deviceIds.clear();
|
||||
driverAttributeIdMap.clear();
|
||||
driverAttributeNameMap.clear();
|
||||
pointAttributeIdMap.clear();
|
||||
pointAttributeNameMap.clear();
|
||||
driver = null;
|
||||
driverStatus = DriverStatusEnum.OFFLINE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-3
@@ -103,8 +103,18 @@ public final class PointMetadata {
|
||||
* @param id point identifier
|
||||
*/
|
||||
public void loadCache(long id) {
|
||||
CompletableFuture<PointBO> future = CompletableFuture.supplyAsync(() -> pointClient.getById(id));
|
||||
cache.put(id, future);
|
||||
CompletableFuture.supplyAsync(() -> pointClient.getById(id))
|
||||
.whenComplete((point, throwable) -> {
|
||||
if (throwable != null) {
|
||||
log.error("Failed to reload point metadata, pointId={}", id, throwable);
|
||||
return;
|
||||
}
|
||||
if (point == null) {
|
||||
cache.synchronous().invalidate(id);
|
||||
return;
|
||||
}
|
||||
cache.put(id, CompletableFuture.completedFuture(point));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,7 +123,14 @@ public final class PointMetadata {
|
||||
* @param id point identifier
|
||||
*/
|
||||
public void removeCache(long id) {
|
||||
cache.put(id, CompletableFuture.completedFuture(null));
|
||||
cache.synchronous().invalidate(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all cached point metadata.
|
||||
*/
|
||||
public void clearCache() {
|
||||
cache.synchronous().invalidateAll();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+17
@@ -19,6 +19,7 @@ package io.github.pnoker.common.driver.receiver.rabbit;
|
||||
|
||||
import com.rabbitmq.client.Channel;
|
||||
import io.github.pnoker.common.driver.event.metadata.MetadataEventPublisher;
|
||||
import io.github.pnoker.common.driver.grpc.client.DriverClient;
|
||||
import io.github.pnoker.common.driver.metadata.DeviceMetadata;
|
||||
import io.github.pnoker.common.driver.metadata.DriverMetadata;
|
||||
import io.github.pnoker.common.driver.metadata.PointMetadata;
|
||||
@@ -56,6 +57,8 @@ public class MetadataReceiver {
|
||||
|
||||
private final DeviceMetadata deviceMetadata;
|
||||
|
||||
private final DriverClient driverClient;
|
||||
|
||||
private final MetadataEventPublisher metadataEventPublisher;
|
||||
|
||||
/**
|
||||
@@ -112,6 +115,20 @@ public class MetadataReceiver {
|
||||
// Publish point metadata event
|
||||
metadataEventPublisher.publishEvent(
|
||||
new MetadataEvent(this, entityDTO.getId(), MetadataTypeEnum.POINT, entityDTO.getOperateType()));
|
||||
} else if (MetadataTypeEnum.DRIVER.equals(entityDTO.getMetadataType())) {
|
||||
if (MetadataOperateTypeEnum.DELETE.equals(entityDTO.getOperateType())) {
|
||||
log.info("Delete driver metadata: {}", entityDTO.getId());
|
||||
driverMetadata.clear();
|
||||
deviceMetadata.clearCache();
|
||||
pointMetadata.clearCache();
|
||||
} else if (MetadataOperateTypeEnum.ADD.equals(entityDTO.getOperateType())
|
||||
|| MetadataOperateTypeEnum.UPDATE.equals(entityDTO.getOperateType())) {
|
||||
log.info("Refresh driver metadata: {}", entityDTO.getId());
|
||||
driverClient.refreshMetadata(entityDTO.getId());
|
||||
}
|
||||
|
||||
metadataEventPublisher.publishEvent(
|
||||
new MetadataEvent(this, entityDTO.getId(), MetadataTypeEnum.DRIVER, entityDTO.getOperateType()));
|
||||
} else {
|
||||
log.error("Unsupported metadata type: {}", entityDTO.getMetadataType());
|
||||
RabbitAckUtil.reject(channel, deliveryTag);
|
||||
|
||||
+29
@@ -18,6 +18,7 @@
|
||||
package io.github.pnoker.common.driver.receiver.rabbit;
|
||||
|
||||
import com.rabbitmq.client.Channel;
|
||||
import io.github.pnoker.common.driver.entity.bo.DriverBO;
|
||||
import io.github.pnoker.common.driver.event.metadata.MetadataEventPublisher;
|
||||
import io.github.pnoker.common.driver.grpc.client.DriverClient;
|
||||
import io.github.pnoker.common.driver.metadata.DeviceMetadata;
|
||||
@@ -25,6 +26,7 @@ import io.github.pnoker.common.driver.metadata.DriverMetadata;
|
||||
import io.github.pnoker.common.driver.metadata.PointMetadata;
|
||||
import io.github.pnoker.common.entity.dto.MetadataEventDTO;
|
||||
import io.github.pnoker.common.entity.event.MetadataEvent;
|
||||
import io.github.pnoker.common.enums.DriverStatusEnum;
|
||||
import io.github.pnoker.common.enums.MetadataOperateTypeEnum;
|
||||
import io.github.pnoker.common.enums.MetadataTypeEnum;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -151,6 +153,33 @@ class MetadataReceiverTest {
|
||||
verify(channel).basicAck(eq(7L), eq(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void driverUpdateRefreshesDriverMetadata() throws Exception {
|
||||
MetadataEventDTO dto = event(MetadataTypeEnum.DRIVER, MetadataOperateTypeEnum.UPDATE, 7L);
|
||||
receiver.metadataReceive(channel, message, dto);
|
||||
verify(driverClient).refreshMetadata(7L);
|
||||
verify(metadataEventPublisher).publishEvent(org.mockito.ArgumentMatchers.any(MetadataEvent.class));
|
||||
verify(channel).basicAck(eq(7L), eq(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void driverDeleteClearsAllDriverSideCaches() throws Exception {
|
||||
driverMetadata.setDriver(new DriverBO());
|
||||
driverMetadata.setDriverStatus(DriverStatusEnum.ONLINE);
|
||||
|
||||
MetadataEventDTO dto = event(MetadataTypeEnum.DRIVER, MetadataOperateTypeEnum.DELETE, 7L);
|
||||
receiver.metadataReceive(channel, message, dto);
|
||||
|
||||
verify(deviceMetadata).clearCache();
|
||||
verify(pointMetadata).clearCache();
|
||||
assertThat(driverMetadata.getDeviceIds()).isEmpty();
|
||||
assertThat(driverMetadata.getDriver()).isNull();
|
||||
assertThat(driverMetadata.getDriverStatus()).isEqualTo(DriverStatusEnum.OFFLINE);
|
||||
verify(driverClient, never()).refreshMetadata(7L);
|
||||
verify(metadataEventPublisher).publishEvent(org.mockito.ArgumentMatchers.any(MetadataEvent.class));
|
||||
verify(channel).basicAck(eq(7L), eq(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nacksAndRequeuesOnPublisherFailure() throws Exception {
|
||||
MetadataEventDTO dto = event(MetadataTypeEnum.DEVICE, MetadataOperateTypeEnum.ADD, 10L);
|
||||
|
||||
+25
-5
@@ -26,12 +26,15 @@ import io.github.pnoker.common.manager.service.DriverService;
|
||||
import io.github.pnoker.common.utils.JsonUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.event.TransactionPhase;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Event listener that processes metadata change events.
|
||||
@@ -43,26 +46,40 @@ import java.util.List;
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class MetadataEventListener implements ApplicationListener<MetadataEvent> {
|
||||
public class MetadataEventListener {
|
||||
|
||||
private final DriverService driverService;
|
||||
|
||||
private final RabbitTemplate rabbitTemplate;
|
||||
|
||||
@Async
|
||||
@Override
|
||||
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, fallbackExecution = true)
|
||||
public void onApplicationEvent(MetadataEvent metadataEvent) {
|
||||
log.info("Metadata event listener received: {}", JsonUtil.toJsonString(metadataEvent));
|
||||
try {
|
||||
Long id = metadataEvent.getId();
|
||||
MetadataTypeEnum metadataType = metadataEvent.getMetadataType();
|
||||
MetadataEventDTO entityDTO = new MetadataEventDTO(id, metadataType, metadataEvent.getOperateType());
|
||||
if (CollectionUtils.isNotEmpty(metadataEvent.getTargetServices())) {
|
||||
metadataEvent.getTargetServices().forEach(service -> notifyDriver(service, entityDTO));
|
||||
return;
|
||||
}
|
||||
|
||||
if (MetadataTypeEnum.DEVICE.equals(metadataType)) {
|
||||
DriverBO entityBO = driverService.listByDeviceId(id);
|
||||
notifyDriver(entityBO.getServiceName(), entityDTO);
|
||||
if (Objects.nonNull(entityBO)) {
|
||||
notifyDriver(entityBO.getServiceName(), entityDTO);
|
||||
}
|
||||
} else if (MetadataTypeEnum.POINT.equals(metadataType)) {
|
||||
List<DriverBO> entityBOList = driverService.selectByPointId(id);
|
||||
entityBOList.forEach(entityBO -> notifyDriver(entityBO.getServiceName(), entityDTO));
|
||||
if (CollectionUtils.isNotEmpty(entityBOList)) {
|
||||
entityBOList.forEach(entityBO -> notifyDriver(entityBO.getServiceName(), entityDTO));
|
||||
}
|
||||
} else if (MetadataTypeEnum.DRIVER.equals(metadataType)) {
|
||||
DriverBO entityBO = driverService.getById(id);
|
||||
if (Objects.nonNull(entityBO)) {
|
||||
notifyDriver(entityBO.getServiceName(), entityDTO);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Metadata event listener failed, event={}", JsonUtil.toJsonString(metadataEvent), e);
|
||||
@@ -74,6 +91,9 @@ public class MetadataEventListener implements ApplicationListener<MetadataEvent>
|
||||
* @param entityDTO DriverTransferMetadataDTO
|
||||
*/
|
||||
private void notifyDriver(String service, MetadataEventDTO entityDTO) {
|
||||
if (Objects.isNull(service) || service.isBlank()) {
|
||||
return;
|
||||
}
|
||||
log.info("Notify driver[{}]: {}", service, JsonUtil.toJsonString(entityDTO));
|
||||
rabbitTemplate.convertAndSend(RabbitConstant.TOPIC_EXCHANGE_METADATA,
|
||||
RabbitConstant.ROUTING_DRIVER_METADATA_PREFIX + service, entityDTO);
|
||||
|
||||
+68
@@ -23,6 +23,7 @@ import io.github.pnoker.api.common.GrpcPointAttributeDTO;
|
||||
import io.github.pnoker.api.common.GrpcR;
|
||||
import io.github.pnoker.api.common.driver.DriverApiGrpc;
|
||||
import io.github.pnoker.api.common.driver.GrpcDriverRegisterDTO;
|
||||
import io.github.pnoker.api.common.driver.GrpcDriverQuery;
|
||||
import io.github.pnoker.api.common.driver.GrpcRDriverRegisterDTO;
|
||||
import io.github.pnoker.common.enums.ResponseEnum;
|
||||
import io.github.pnoker.common.manager.biz.DriverRegisterService;
|
||||
@@ -33,12 +34,17 @@ import io.github.pnoker.common.manager.grpc.builder.GrpcDriverAttributeBuilder;
|
||||
import io.github.pnoker.common.manager.grpc.builder.GrpcDriverBuilder;
|
||||
import io.github.pnoker.common.manager.grpc.builder.GrpcPointAttributeBuilder;
|
||||
import io.github.pnoker.common.manager.service.DeviceService;
|
||||
import io.github.pnoker.common.manager.service.DriverAttributeService;
|
||||
import io.github.pnoker.common.manager.service.DriverService;
|
||||
import io.github.pnoker.common.manager.service.PointAttributeService;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* gRPC server handling driver-to-manager driver requests.
|
||||
@@ -60,6 +66,12 @@ public class DriverDriverServer extends DriverApiGrpc.DriverApiImplBase {
|
||||
|
||||
private final DriverRegisterService driverRegisterService;
|
||||
|
||||
private final DriverService driverService;
|
||||
|
||||
private final DriverAttributeService driverAttributeService;
|
||||
|
||||
private final PointAttributeService pointAttributeService;
|
||||
|
||||
private final DeviceService deviceService;
|
||||
|
||||
@Override
|
||||
@@ -110,4 +122,60 @@ public class DriverDriverServer extends DriverApiGrpc.DriverApiImplBase {
|
||||
responseObserver.onCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getById(GrpcDriverQuery request, StreamObserver<GrpcRDriverRegisterDTO> responseObserver) {
|
||||
GrpcRDriverRegisterDTO.Builder builder = GrpcRDriverRegisterDTO.newBuilder();
|
||||
GrpcR.Builder rBuilder = GrpcR.newBuilder();
|
||||
|
||||
try {
|
||||
DriverBO entityBO = driverService.getById(request.getDriverId());
|
||||
if (Objects.isNull(entityBO)) {
|
||||
rBuilder.setOk(false);
|
||||
rBuilder.setCode(ResponseEnum.NO_RESOURCE.getCode());
|
||||
rBuilder.setMessage(ResponseEnum.NO_RESOURCE.getText());
|
||||
} else {
|
||||
buildMetadataResponse(builder, entityBO);
|
||||
|
||||
rBuilder.setOk(true);
|
||||
rBuilder.setCode(ResponseEnum.OK.getCode());
|
||||
rBuilder.setMessage(ResponseEnum.OK.getText());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
rBuilder.setOk(false);
|
||||
rBuilder.setCode(ResponseEnum.FAILURE.getCode());
|
||||
rBuilder.setMessage(e.getMessage());
|
||||
|
||||
log.error("Driver metadata gRPC query failed, driverId={}", request.getDriverId(), e);
|
||||
}
|
||||
|
||||
builder.setResult(rBuilder);
|
||||
responseObserver.onNext(builder.build());
|
||||
responseObserver.onCompleted();
|
||||
}
|
||||
|
||||
private void buildMetadataResponse(GrpcRDriverRegisterDTO.Builder builder, DriverBO entityBO) {
|
||||
builder.setDriver(grpcDriverBuilder.buildGrpcDTOByBO(entityBO));
|
||||
|
||||
List<GrpcDriverAttributeDTO> driverAttributeDTOList = Optional
|
||||
.ofNullable(driverAttributeService.listByDriverId(entityBO.getId()))
|
||||
.orElseGet(List::of)
|
||||
.stream()
|
||||
.filter(attribute -> Objects.equals(entityBO.getTenantId(), attribute.getTenantId()))
|
||||
.map(grpcDriverAttributeBuilder::buildGrpcDTOByBO)
|
||||
.toList();
|
||||
builder.addAllDriverAttributes(driverAttributeDTOList);
|
||||
|
||||
List<GrpcPointAttributeDTO> pointAttributeDTOList = Optional
|
||||
.ofNullable(pointAttributeService.listByDriverId(entityBO.getId()))
|
||||
.orElseGet(List::of)
|
||||
.stream()
|
||||
.filter(attribute -> Objects.equals(entityBO.getTenantId(), attribute.getTenantId()))
|
||||
.map(grpcPointAttributeBuilder::buildGrpcDTOByBO)
|
||||
.toList();
|
||||
builder.addAllPointAttributes(pointAttributeDTOList);
|
||||
|
||||
List<Long> idList = Optional.ofNullable(deviceService.listIdsByDriverId(entityBO.getId())).orElseGet(List::of);
|
||||
builder.addAllDeviceIds(idList);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+34
-5
@@ -122,6 +122,7 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
private final MetadataEventPublisher metadataEventPublisher;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void add(DeviceBO entityBO) {
|
||||
validateTenantRelations(entityBO);
|
||||
|
||||
@@ -139,7 +140,7 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
|
||||
//
|
||||
MetadataEvent metadataEvent = new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.DEVICE,
|
||||
MetadataOperateTypeEnum.ADD);
|
||||
MetadataOperateTypeEnum.ADD, driverServiceNames(entityDO.getDriverId()));
|
||||
metadataEventPublisher.publishEvent(metadataEvent);
|
||||
}
|
||||
|
||||
@@ -147,6 +148,7 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
@Transactional
|
||||
public void delete(Long id) {
|
||||
DeviceDO entityDO = getDOById(id, true);
|
||||
Set<String> targetServices = driverServiceNames(entityDO.getDriverId());
|
||||
|
||||
//
|
||||
profileBindService.removeByDeviceId(id);
|
||||
@@ -157,13 +159,15 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
|
||||
//
|
||||
MetadataEvent metadataEvent = new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.DEVICE,
|
||||
MetadataOperateTypeEnum.DELETE);
|
||||
MetadataOperateTypeEnum.DELETE, targetServices);
|
||||
metadataEventPublisher.publishEvent(metadataEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void update(DeviceBO entityBO) {
|
||||
DeviceDO entityDO = getDOById(entityBO.getId(), true);
|
||||
Long oldDriverId = entityDO.getDriverId();
|
||||
if (!Objects.equals(entityBO.getTenantId(), entityDO.getTenantId())) {
|
||||
throw new NotFoundException("Resource does not exist");
|
||||
}
|
||||
@@ -198,9 +202,16 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
entityBO.setDeviceName(deviceBO.getDeviceName());
|
||||
|
||||
//
|
||||
MetadataEvent metadataEvent = new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.DEVICE,
|
||||
MetadataOperateTypeEnum.UPDATE);
|
||||
metadataEventPublisher.publishEvent(metadataEvent);
|
||||
if (Objects.equals(oldDriverId, entityBO.getDriverId())) {
|
||||
MetadataEvent metadataEvent = new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.DEVICE,
|
||||
MetadataOperateTypeEnum.UPDATE, driverServiceNames(entityBO.getDriverId()));
|
||||
metadataEventPublisher.publishEvent(metadataEvent);
|
||||
} else {
|
||||
metadataEventPublisher.publishEvent(new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.DEVICE,
|
||||
MetadataOperateTypeEnum.DELETE, driverServiceNames(oldDriverId)));
|
||||
metadataEventPublisher.publishEvent(new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.DEVICE,
|
||||
MetadataOperateTypeEnum.ADD, driverServiceNames(entityBO.getDriverId())));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -610,6 +621,24 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
return !isUpdate || !one.getId().equals(entityBO.getId());
|
||||
}
|
||||
|
||||
private Set<String> driverServiceNames(Long... driverIds) {
|
||||
Set<String> services = new HashSet<>();
|
||||
if (Objects.isNull(driverIds)) {
|
||||
return services;
|
||||
}
|
||||
|
||||
for (Long driverId : driverIds) {
|
||||
if (Objects.isNull(driverId)) {
|
||||
continue;
|
||||
}
|
||||
DriverBO driverBO = driverService.getById(driverId);
|
||||
if (Objects.nonNull(driverBO) && StringUtils.isNotBlank(driverBO.getServiceName())) {
|
||||
services.add(driverBO.getServiceName());
|
||||
}
|
||||
}
|
||||
return services;
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary key ID
|
||||
*
|
||||
|
||||
+24
-1
@@ -23,6 +23,9 @@ import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapp
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.github.pnoker.common.constant.common.QueryWrapperConstant;
|
||||
import io.github.pnoker.common.entity.common.Pages;
|
||||
import io.github.pnoker.common.entity.event.MetadataEvent;
|
||||
import io.github.pnoker.common.enums.MetadataOperateTypeEnum;
|
||||
import io.github.pnoker.common.enums.MetadataTypeEnum;
|
||||
import io.github.pnoker.common.exception.AddException;
|
||||
import io.github.pnoker.common.exception.DeleteException;
|
||||
import io.github.pnoker.common.exception.DuplicateException;
|
||||
@@ -34,6 +37,7 @@ import io.github.pnoker.common.manager.entity.bo.DriverBO;
|
||||
import io.github.pnoker.common.manager.entity.builder.DriverAttributeBuilder;
|
||||
import io.github.pnoker.common.manager.entity.model.DriverAttributeDO;
|
||||
import io.github.pnoker.common.manager.entity.query.DriverAttributeQuery;
|
||||
import io.github.pnoker.common.manager.event.metadata.MetadataEventPublisher;
|
||||
import io.github.pnoker.common.manager.service.DriverAttributeService;
|
||||
import io.github.pnoker.common.manager.service.DriverService;
|
||||
import io.github.pnoker.common.utils.FieldUtil;
|
||||
@@ -46,6 +50,7 @@ import org.springframework.stereotype.Service;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Business service implementation for driver attribute operations.
|
||||
@@ -65,6 +70,8 @@ public class DriverAttributeServiceImpl implements DriverAttributeService {
|
||||
|
||||
private final DriverService driverService;
|
||||
|
||||
private final MetadataEventPublisher metadataEventPublisher;
|
||||
|
||||
@Override
|
||||
public void add(DriverAttributeBO entityBO) {
|
||||
validateTenantRelations(entityBO);
|
||||
@@ -76,15 +83,17 @@ public class DriverAttributeServiceImpl implements DriverAttributeService {
|
||||
if (!driverAttributeManager.save(entityDO)) {
|
||||
throw new AddException("Failed to create driver attribute");
|
||||
}
|
||||
publishDriverMetadataEvent(entityDO.getDriverId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Long id) {
|
||||
getDOById(id, true);
|
||||
DriverAttributeDO entityDO = getDOById(id, true);
|
||||
|
||||
if (!driverAttributeManager.removeById(id)) {
|
||||
throw new DeleteException("Failed to remove driver attribute");
|
||||
}
|
||||
publishDriverMetadataEvent(entityDO.getDriverId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,6 +113,7 @@ public class DriverAttributeServiceImpl implements DriverAttributeService {
|
||||
if (!driverAttributeManager.updateById(entityDO)) {
|
||||
throw new UpdateException("Failed to update driver attribute");
|
||||
}
|
||||
publishDriverMetadataEvent(entityDO.getDriverId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -140,6 +150,7 @@ public class DriverAttributeServiceImpl implements DriverAttributeService {
|
||||
if (!driverAttributeManager.saveBatch(doList)) {
|
||||
throw new AddException("Failed to batch create driver attributes");
|
||||
}
|
||||
entityBOList.stream().map(DriverAttributeBO::getDriverId).distinct().forEach(this::publishDriverMetadataEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -156,6 +167,7 @@ public class DriverAttributeServiceImpl implements DriverAttributeService {
|
||||
if (!driverAttributeManager.updateBatchById(doList)) {
|
||||
throw new UpdateException("Failed to batch update driver attributes");
|
||||
}
|
||||
entityBOList.stream().map(DriverAttributeBO::getDriverId).distinct().forEach(this::publishDriverMetadataEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -163,9 +175,11 @@ public class DriverAttributeServiceImpl implements DriverAttributeService {
|
||||
if (Objects.isNull(ids) || ids.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<DriverAttributeDO> entityDOList = driverAttributeManager.listByIds(ids);
|
||||
if (!driverAttributeManager.removeByIds(ids)) {
|
||||
throw new DeleteException("Failed to batch remove driver attributes");
|
||||
}
|
||||
entityDOList.stream().map(DriverAttributeDO::getDriverId).distinct().forEach(this::publishDriverMetadataEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -226,6 +240,15 @@ public class DriverAttributeServiceImpl implements DriverAttributeService {
|
||||
}
|
||||
}
|
||||
|
||||
private void publishDriverMetadataEvent(Long driverId) {
|
||||
DriverBO driverBO = driverService.getById(driverId);
|
||||
if (Objects.isNull(driverBO) || StringUtils.isBlank(driverBO.getServiceName())) {
|
||||
return;
|
||||
}
|
||||
metadataEventPublisher.publishEvent(new MetadataEvent(this, driverId, MetadataTypeEnum.DRIVER,
|
||||
MetadataOperateTypeEnum.UPDATE, Set.of(driverBO.getServiceName())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary key ID
|
||||
*
|
||||
|
||||
+24
-1
@@ -23,6 +23,9 @@ import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapp
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.github.pnoker.common.constant.common.QueryWrapperConstant;
|
||||
import io.github.pnoker.common.entity.common.Pages;
|
||||
import io.github.pnoker.common.entity.event.MetadataEvent;
|
||||
import io.github.pnoker.common.enums.MetadataOperateTypeEnum;
|
||||
import io.github.pnoker.common.enums.MetadataTypeEnum;
|
||||
import io.github.pnoker.common.exception.AddException;
|
||||
import io.github.pnoker.common.exception.DeleteException;
|
||||
import io.github.pnoker.common.exception.DuplicateException;
|
||||
@@ -34,6 +37,7 @@ import io.github.pnoker.common.manager.entity.bo.PointAttributeBO;
|
||||
import io.github.pnoker.common.manager.entity.builder.PointAttributeBuilder;
|
||||
import io.github.pnoker.common.manager.entity.model.PointAttributeDO;
|
||||
import io.github.pnoker.common.manager.entity.query.PointAttributeQuery;
|
||||
import io.github.pnoker.common.manager.event.metadata.MetadataEventPublisher;
|
||||
import io.github.pnoker.common.manager.service.DriverService;
|
||||
import io.github.pnoker.common.manager.service.PointAttributeService;
|
||||
import io.github.pnoker.common.utils.FieldUtil;
|
||||
@@ -46,6 +50,7 @@ import org.springframework.stereotype.Service;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Business service implementation for point attribute operations.
|
||||
@@ -65,6 +70,8 @@ public class PointAttributeServiceImpl implements PointAttributeService {
|
||||
|
||||
private final DriverService driverService;
|
||||
|
||||
private final MetadataEventPublisher metadataEventPublisher;
|
||||
|
||||
@Override
|
||||
public void add(PointAttributeBO entityBO) {
|
||||
validateTenantRelations(entityBO);
|
||||
@@ -74,15 +81,17 @@ public class PointAttributeServiceImpl implements PointAttributeService {
|
||||
if (!pointAttributeManager.save(entityDO)) {
|
||||
throw new AddException("Failed to create point attribute");
|
||||
}
|
||||
publishDriverMetadataEvent(entityDO.getDriverId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Long id) {
|
||||
getDOById(id, true);
|
||||
PointAttributeDO entityDO = getDOById(id, true);
|
||||
|
||||
if (!pointAttributeManager.removeById(id)) {
|
||||
throw new DeleteException("Failed to remove point attribute");
|
||||
}
|
||||
publishDriverMetadataEvent(entityDO.getDriverId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,6 +109,7 @@ public class PointAttributeServiceImpl implements PointAttributeService {
|
||||
if (!pointAttributeManager.updateById(entityDO)) {
|
||||
throw new UpdateException("Failed to update point attribute");
|
||||
}
|
||||
publishDriverMetadataEvent(entityDO.getDriverId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,6 +146,7 @@ public class PointAttributeServiceImpl implements PointAttributeService {
|
||||
if (!pointAttributeManager.saveBatch(doList)) {
|
||||
throw new AddException("Failed to batch create point attributes");
|
||||
}
|
||||
entityBOList.stream().map(PointAttributeBO::getDriverId).distinct().forEach(this::publishDriverMetadataEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -152,6 +163,7 @@ public class PointAttributeServiceImpl implements PointAttributeService {
|
||||
if (!pointAttributeManager.updateBatchById(doList)) {
|
||||
throw new UpdateException("Failed to batch update point attributes");
|
||||
}
|
||||
entityBOList.stream().map(PointAttributeBO::getDriverId).distinct().forEach(this::publishDriverMetadataEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -159,9 +171,11 @@ public class PointAttributeServiceImpl implements PointAttributeService {
|
||||
if (Objects.isNull(ids) || ids.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<PointAttributeDO> entityDOList = pointAttributeManager.listByIds(ids);
|
||||
if (!pointAttributeManager.removeByIds(ids)) {
|
||||
throw new DeleteException("Failed to batch remove point attributes");
|
||||
}
|
||||
entityDOList.stream().map(PointAttributeDO::getDriverId).distinct().forEach(this::publishDriverMetadataEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -227,6 +241,15 @@ public class PointAttributeServiceImpl implements PointAttributeService {
|
||||
}
|
||||
}
|
||||
|
||||
private void publishDriverMetadataEvent(Long driverId) {
|
||||
DriverBO driverBO = driverService.getById(driverId);
|
||||
if (Objects.isNull(driverBO) || StringUtils.isBlank(driverBO.getServiceName())) {
|
||||
return;
|
||||
}
|
||||
metadataEventPublisher.publishEvent(new MetadataEvent(this, driverId, MetadataTypeEnum.DRIVER,
|
||||
MetadataOperateTypeEnum.UPDATE, Set.of(driverBO.getServiceName())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary key ID
|
||||
*
|
||||
|
||||
+62
-11
@@ -37,6 +37,7 @@ import io.github.pnoker.common.manager.dal.PointAttributeConfigManager;
|
||||
import io.github.pnoker.common.manager.dal.PointManager;
|
||||
import io.github.pnoker.common.manager.dal.ProfileBindManager;
|
||||
import io.github.pnoker.common.manager.entity.bo.DeviceByPointBO;
|
||||
import io.github.pnoker.common.manager.entity.bo.DriverBO;
|
||||
import io.github.pnoker.common.manager.entity.bo.PointBO;
|
||||
import io.github.pnoker.common.manager.entity.bo.PointConfigByDeviceBO;
|
||||
import io.github.pnoker.common.manager.entity.bo.ProfileBO;
|
||||
@@ -49,6 +50,7 @@ import io.github.pnoker.common.manager.entity.query.PointQuery;
|
||||
import io.github.pnoker.common.manager.event.metadata.MetadataEventPublisher;
|
||||
import io.github.pnoker.common.manager.mapper.DeviceMapper;
|
||||
import io.github.pnoker.common.manager.mapper.PointMapper;
|
||||
import io.github.pnoker.common.manager.service.DriverService;
|
||||
import io.github.pnoker.common.manager.service.PointService;
|
||||
import io.github.pnoker.common.manager.service.ProfileBindService;
|
||||
import io.github.pnoker.common.manager.service.ProfileService;
|
||||
@@ -59,7 +61,9 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -98,7 +102,10 @@ public class PointServiceImpl implements PointService {
|
||||
|
||||
private final DeviceMapper deviceMapper;
|
||||
|
||||
private final DriverService driverService;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void add(PointBO entityBO) {
|
||||
validateTenantRelations(entityBO);
|
||||
checkDuplicate(entityBO, false, true);
|
||||
@@ -109,16 +116,19 @@ public class PointServiceImpl implements PointService {
|
||||
}
|
||||
|
||||
//
|
||||
metadataEventPublisher.publishEvent(
|
||||
new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.POINT, MetadataOperateTypeEnum.ADD));
|
||||
List<Long> deviceIds = profileBindService.listDeviceIdsByProfileId(entityDO.getProfileId());
|
||||
deviceIds.forEach(entityId -> metadataEventPublisher
|
||||
.publishEvent(new MetadataEvent(this, entityId, MetadataTypeEnum.DEVICE, MetadataOperateTypeEnum.UPDATE)));
|
||||
metadataEventPublisher.publishEvent(
|
||||
new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.POINT, MetadataOperateTypeEnum.ADD,
|
||||
driverServiceNamesByDeviceIds(deviceIds)));
|
||||
publishDeviceUpdateEvents(deviceIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void delete(Long id) {
|
||||
PointDO entityDO = getDOById(id, true);
|
||||
List<Long> deviceIds = profileBindService.listDeviceIdsByProfileId(entityDO.getProfileId());
|
||||
Set<String> targetServices = driverServiceNamesByDeviceIds(deviceIds);
|
||||
|
||||
if (!pointManager.removeById(id)) {
|
||||
throw new DeleteException("Failed to remove ");
|
||||
@@ -126,16 +136,16 @@ public class PointServiceImpl implements PointService {
|
||||
|
||||
//
|
||||
MetadataEvent metadataEvent = new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.POINT,
|
||||
MetadataOperateTypeEnum.DELETE);
|
||||
MetadataOperateTypeEnum.DELETE, targetServices);
|
||||
metadataEventPublisher.publishEvent(metadataEvent);
|
||||
List<Long> deviceIds = profileBindService.listDeviceIdsByProfileId(entityDO.getProfileId());
|
||||
deviceIds.forEach(entityId -> metadataEventPublisher
|
||||
.publishEvent(new MetadataEvent(this, entityId, MetadataTypeEnum.DEVICE, MetadataOperateTypeEnum.UPDATE)));
|
||||
publishDeviceUpdateEvents(deviceIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void update(PointBO entityBO) {
|
||||
PointDO current = getDOById(entityBO.getId(), true);
|
||||
List<Long> oldDeviceIds = profileBindService.listDeviceIdsByProfileId(current.getProfileId());
|
||||
if (!Objects.equals(entityBO.getTenantId(), current.getTenantId())) {
|
||||
throw new NotFoundException("Resource does not exist");
|
||||
}
|
||||
@@ -150,9 +160,19 @@ public class PointServiceImpl implements PointService {
|
||||
}
|
||||
|
||||
//
|
||||
MetadataEvent metadataEvent = new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.POINT,
|
||||
MetadataOperateTypeEnum.UPDATE);
|
||||
metadataEventPublisher.publishEvent(metadataEvent);
|
||||
if (Objects.equals(current.getProfileId(), entityDO.getProfileId())) {
|
||||
MetadataEvent metadataEvent = new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.POINT,
|
||||
MetadataOperateTypeEnum.UPDATE, driverServiceNamesByDeviceIds(oldDeviceIds));
|
||||
metadataEventPublisher.publishEvent(metadataEvent);
|
||||
} else {
|
||||
List<Long> newDeviceIds = profileBindService.listDeviceIdsByProfileId(entityDO.getProfileId());
|
||||
metadataEventPublisher.publishEvent(new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.POINT,
|
||||
MetadataOperateTypeEnum.DELETE, driverServiceNamesByDeviceIds(oldDeviceIds)));
|
||||
metadataEventPublisher.publishEvent(new MetadataEvent(this, entityDO.getId(), MetadataTypeEnum.POINT,
|
||||
MetadataOperateTypeEnum.ADD, driverServiceNamesByDeviceIds(newDeviceIds)));
|
||||
publishDeviceUpdateEvents(oldDeviceIds);
|
||||
publishDeviceUpdateEvents(newDeviceIds);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -370,6 +390,37 @@ public class PointServiceImpl implements PointService {
|
||||
}
|
||||
}
|
||||
|
||||
private void publishDeviceUpdateEvents(Collection<Long> deviceIds) {
|
||||
if (CollectionUtils.isEmpty(deviceIds)) {
|
||||
return;
|
||||
}
|
||||
deviceIds.forEach(deviceId -> metadataEventPublisher.publishEvent(
|
||||
new MetadataEvent(this, deviceId, MetadataTypeEnum.DEVICE, MetadataOperateTypeEnum.UPDATE,
|
||||
driverServiceNamesByDeviceId(deviceId))));
|
||||
}
|
||||
|
||||
private Set<String> driverServiceNamesByDeviceIds(Collection<Long> deviceIds) {
|
||||
if (CollectionUtils.isEmpty(deviceIds)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return deviceIds.stream()
|
||||
.map(this::driverServiceNamesByDeviceId)
|
||||
.flatMap(Set::stream)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Set<String> driverServiceNamesByDeviceId(Long deviceId) {
|
||||
if (Objects.isNull(deviceId)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
DriverBO driverBO = driverService.listByDeviceId(deviceId);
|
||||
if (Objects.isNull(driverBO) || StringUtils.isBlank(driverBO.getServiceName())) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return Set.of(driverBO.getServiceName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary key ID
|
||||
*
|
||||
|
||||
+26
@@ -33,6 +33,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@@ -107,6 +108,31 @@ class MetadataEventListenerTest {
|
||||
verifyNoInteractions(rabbitTemplate);
|
||||
}
|
||||
|
||||
@Test
|
||||
void eventWithTargetServicesBypassesOwnerLookup() {
|
||||
listener.onApplicationEvent(new MetadataEvent(this, 10L, MetadataTypeEnum.DEVICE,
|
||||
MetadataOperateTypeEnum.DELETE, Set.of("dc3-driver-old")));
|
||||
|
||||
verify(driverService, never()).listByDeviceId(10L);
|
||||
verify(rabbitTemplate).convertAndSend(
|
||||
eq(RabbitConstant.TOPIC_EXCHANGE_METADATA),
|
||||
eq(RabbitConstant.ROUTING_DRIVER_METADATA_PREFIX + "dc3-driver-old"),
|
||||
any(MetadataEventDTO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void driverEventNotifiesRegisteredDriverService() {
|
||||
when(driverService.getById(7L)).thenReturn(driver);
|
||||
|
||||
listener.onApplicationEvent(new MetadataEvent(this, 7L, MetadataTypeEnum.DRIVER,
|
||||
MetadataOperateTypeEnum.UPDATE));
|
||||
|
||||
verify(rabbitTemplate).convertAndSend(
|
||||
eq(RabbitConstant.TOPIC_EXCHANGE_METADATA),
|
||||
eq(RabbitConstant.ROUTING_DRIVER_METADATA_PREFIX + "dc3-driver-modbus-tcp"),
|
||||
any(MetadataEventDTO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void serviceFailureIsSwallowedSilently() {
|
||||
when(driverService.listByDeviceId(10L)).thenThrow(new RuntimeException("downstream offline"));
|
||||
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2016-present the IoT DC3 original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.github.pnoker.common.manager.grpc.server.driver;
|
||||
|
||||
import io.github.pnoker.api.common.GrpcDriverAttributeDTO;
|
||||
import io.github.pnoker.api.common.GrpcDriverDTO;
|
||||
import io.github.pnoker.api.common.GrpcPointAttributeDTO;
|
||||
import io.github.pnoker.api.common.driver.DriverApiGrpc;
|
||||
import io.github.pnoker.api.common.driver.GrpcDriverQuery;
|
||||
import io.github.pnoker.api.common.driver.GrpcRDriverRegisterDTO;
|
||||
import io.github.pnoker.common.enums.ResponseEnum;
|
||||
import io.github.pnoker.common.manager.biz.DriverRegisterService;
|
||||
import io.github.pnoker.common.manager.entity.bo.DriverAttributeBO;
|
||||
import io.github.pnoker.common.manager.entity.bo.DriverBO;
|
||||
import io.github.pnoker.common.manager.entity.bo.PointAttributeBO;
|
||||
import io.github.pnoker.common.manager.grpc.builder.GrpcDriverAttributeBuilder;
|
||||
import io.github.pnoker.common.manager.grpc.builder.GrpcDriverBuilder;
|
||||
import io.github.pnoker.common.manager.grpc.builder.GrpcPointAttributeBuilder;
|
||||
import io.github.pnoker.common.manager.service.DeviceService;
|
||||
import io.github.pnoker.common.manager.service.DriverAttributeService;
|
||||
import io.github.pnoker.common.manager.service.DriverService;
|
||||
import io.github.pnoker.common.manager.service.PointAttributeService;
|
||||
import io.grpc.ManagedChannel;
|
||||
import io.grpc.Server;
|
||||
import io.grpc.inprocess.InProcessChannelBuilder;
|
||||
import io.grpc.inprocess.InProcessServerBuilder;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class DriverDriverServerTest {
|
||||
|
||||
@Mock
|
||||
private GrpcDriverBuilder grpcDriverBuilder;
|
||||
|
||||
@Mock
|
||||
private GrpcDriverAttributeBuilder grpcDriverAttributeBuilder;
|
||||
|
||||
@Mock
|
||||
private GrpcPointAttributeBuilder grpcPointAttributeBuilder;
|
||||
|
||||
@Mock
|
||||
private DriverRegisterService driverRegisterService;
|
||||
|
||||
@Mock
|
||||
private DriverService driverService;
|
||||
|
||||
@Mock
|
||||
private DriverAttributeService driverAttributeService;
|
||||
|
||||
@Mock
|
||||
private PointAttributeService pointAttributeService;
|
||||
|
||||
@Mock
|
||||
private DeviceService deviceService;
|
||||
|
||||
private Server server;
|
||||
private ManagedChannel channel;
|
||||
private DriverApiGrpc.DriverApiBlockingStub stub;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
DriverDriverServer driverServer = new DriverDriverServer(grpcDriverBuilder, grpcDriverAttributeBuilder,
|
||||
grpcPointAttributeBuilder, driverRegisterService, driverService, driverAttributeService,
|
||||
pointAttributeService, deviceService);
|
||||
|
||||
String name = "dc3-driver-metadata-" + UUID.randomUUID();
|
||||
server = InProcessServerBuilder.forName(name).directExecutor().addService(driverServer).build().start();
|
||||
channel = InProcessChannelBuilder.forName(name).directExecutor().build();
|
||||
stub = DriverApiGrpc.newBlockingStub(channel);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
if (channel != null) {
|
||||
channel.shutdownNow();
|
||||
}
|
||||
if (server != null) {
|
||||
server.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByIdReturnsRegisteredMetadataSnapshot() {
|
||||
DriverBO driver = new DriverBO();
|
||||
driver.setId(7L);
|
||||
driver.setTenantId(100L);
|
||||
|
||||
DriverAttributeBO driverAttribute = new DriverAttributeBO();
|
||||
driverAttribute.setTenantId(100L);
|
||||
PointAttributeBO pointAttribute = new PointAttributeBO();
|
||||
pointAttribute.setTenantId(100L);
|
||||
|
||||
when(driverService.getById(7L)).thenReturn(driver);
|
||||
when(grpcDriverBuilder.buildGrpcDTOByBO(driver)).thenReturn(GrpcDriverDTO.newBuilder().build());
|
||||
when(driverAttributeService.listByDriverId(7L)).thenReturn(List.of(driverAttribute));
|
||||
when(pointAttributeService.listByDriverId(7L)).thenReturn(List.of(pointAttribute));
|
||||
when(grpcDriverAttributeBuilder.buildGrpcDTOByBO(driverAttribute))
|
||||
.thenReturn(GrpcDriverAttributeDTO.newBuilder().build());
|
||||
when(grpcPointAttributeBuilder.buildGrpcDTOByBO(pointAttribute))
|
||||
.thenReturn(GrpcPointAttributeDTO.newBuilder().build());
|
||||
when(deviceService.listIdsByDriverId(7L)).thenReturn(List.of(1L, 2L));
|
||||
|
||||
GrpcRDriverRegisterDTO response = stub.getById(GrpcDriverQuery.newBuilder().setDriverId(7L).build());
|
||||
|
||||
assertThat(response.getResult().getOk()).isTrue();
|
||||
assertThat(response.getResult().getCode()).isEqualTo(ResponseEnum.OK.getCode());
|
||||
assertThat(response.getDriverAttributesCount()).isEqualTo(1);
|
||||
assertThat(response.getPointAttributesCount()).isEqualTo(1);
|
||||
assertThat(response.getDeviceIdsList()).containsExactly(1L, 2L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByIdReturnsNoResourceWhenDriverMissing() {
|
||||
when(driverService.getById(404L)).thenReturn(null);
|
||||
|
||||
GrpcRDriverRegisterDTO response = stub.getById(GrpcDriverQuery.newBuilder().setDriverId(404L).build());
|
||||
|
||||
assertThat(response.getResult().getOk()).isFalse();
|
||||
assertThat(response.getResult().getCode()).isEqualTo(ResponseEnum.NO_RESOURCE.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByIdReturnsFailureWhenLookupThrows() {
|
||||
when(driverService.getById(7L)).thenThrow(new IllegalStateException("metadata unavailable"));
|
||||
|
||||
GrpcRDriverRegisterDTO response = stub.getById(GrpcDriverQuery.newBuilder().setDriverId(7L).build());
|
||||
|
||||
assertThat(response.getResult().getOk()).isFalse();
|
||||
assertThat(response.getResult().getCode()).isEqualTo(ResponseEnum.FAILURE.getCode());
|
||||
assertThat(response.getResult().getMessage()).isEqualTo("metadata unavailable");
|
||||
}
|
||||
}
|
||||
+27
@@ -22,6 +22,12 @@ import io.github.pnoker.common.enums.MetadataTypeEnum;
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Metadata event.
|
||||
*
|
||||
@@ -38,6 +44,8 @@ public class MetadataEvent extends ApplicationEvent {
|
||||
|
||||
private final MetadataOperateTypeEnum operateType;
|
||||
|
||||
private final Set<String> targetServices;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@@ -47,10 +55,29 @@ public class MetadataEvent extends ApplicationEvent {
|
||||
* @param operateType Metadata operation type
|
||||
*/
|
||||
public MetadataEvent(Object source, Long id, MetadataTypeEnum metadataType, MetadataOperateTypeEnum operateType) {
|
||||
this(source, id, metadataType, operateType, Collections.emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param source Event source object
|
||||
* @param id Metadata ID
|
||||
* @param metadataType Metadata type
|
||||
* @param operateType Metadata operation type
|
||||
* @param targetServices Driver services that must receive this event
|
||||
*/
|
||||
public MetadataEvent(Object source, Long id, MetadataTypeEnum metadataType, MetadataOperateTypeEnum operateType,
|
||||
Collection<String> targetServices) {
|
||||
super(source);
|
||||
this.id = id;
|
||||
this.metadataType = metadataType;
|
||||
this.operateType = operateType;
|
||||
this.targetServices = Objects.isNull(targetServices) ? Collections.emptySet()
|
||||
: targetServices.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(service -> !service.isBlank())
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user