diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a1b3789..781797d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 2.1.4-rc.2(2024-01-28) + +### ⭐ New Features + +- 优化苏标附件服务器的支持 +- 支持位置附加项列表注解 `@RequestFieldAlias.LocationMsgExtraItemMapping()` +- 新增 `@RequestField#conditionalOn()` 属性 +- 内置几个和苏标相关的实体类 + ## 2.1.4-beta1(2024-01-14) ### ⭐ New Features diff --git a/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/handler/AttachmentFileHandler.java b/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/handler/AttachmentFileHandler.java index 41e5ec35..321b8bfb 100644 --- a/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/handler/AttachmentFileHandler.java +++ b/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/handler/AttachmentFileHandler.java @@ -14,7 +14,6 @@ import io.github.hylexus.jt.jt808.spec.session.Jt808Session; import io.github.hylexus.jt.jt808.support.annotation.handler.Jt808RequestHandler; import io.github.hylexus.jt.jt808.support.annotation.handler.Jt808RequestHandlerMapping; -import io.github.hylexus.jt.jt808.support.extension.attachment.AttachmentJt808SessionManager; import io.github.hylexus.jt.jt808.support.extension.attachment.impl.SimpleAttachmentJt808RequestProcessor; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; @@ -39,14 +38,8 @@ public class AttachmentFileHandler { .expireAfterWrite(Duration.ofMinutes(5)) .build(); - // !!!如果需要用 session 的话,附件相关的几个 808 指令对应的 session 应该从 AttachmentJt808SessionManager 中获取 - // !!!而不是从普通的 Jt808SessionManager 中获取 - // !!!因为 附件上传 和 普通指令 是不同的 TCP 连接 - private final AttachmentJt808SessionManager sessionManager; - - public AttachmentFileHandler(AttachmentFileService attachmentFileService, AttachmentJt808SessionManager sessionManager) { + public AttachmentFileHandler(AttachmentFileService attachmentFileService) { this.attachmentFileService = attachmentFileService; - this.sessionManager = sessionManager; } @Jt808RequestHandlerMapping(msgType = 0x1210, versions = Jt808ProtocolVersion.AUTO_DETECTION) @@ -124,9 +117,7 @@ private void warnLogIfNecessary(Jt808Request request, String msg) { if (request.session() == null) { return; } - if (sessionManager.findByTerminalId(request.terminalId()).orElseThrow() != request.session()) { - log.error("session invalid"); - } + if (request.session().role() == Jt808Session.Role.INSTRUCTION) { log.warn(msg); } diff --git a/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/handler/LocationMsgHandler.java b/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/handler/LocationMsgHandler.java index 2975502c..c9dadf94 100644 --- a/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/handler/LocationMsgHandler.java +++ b/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/handler/LocationMsgHandler.java @@ -1,10 +1,10 @@ package io.github.hylexus.jt.demos.jt808.handler; import io.github.hylexus.jt.demos.jt808.msg.req.LocationBatchUploadMsgV2019; -import io.github.hylexus.jt.demos.jt808.msg.req.LocationUploadMsgV2019; import io.github.hylexus.jt.demos.jt808.service.LocationMsgService; import io.github.hylexus.jt.jt808.spec.Jt808RequestEntity; -import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg0200V2013Alias; +import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg0200V2013AliasV2; +import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg0200V2019AliasV2; import io.github.hylexus.jt.jt808.spec.builtin.msg.resp.BuiltinServerCommonReplyMsg; import io.github.hylexus.jt.jt808.spec.session.Jt808Session; import io.github.hylexus.jt.jt808.support.annotation.handler.Jt808RequestHandler; @@ -43,8 +43,8 @@ public BuiltinServerCommonReplyMsg processLocationBatchUploadMsgV2019(Jt808Reque } @Jt808RequestHandlerMapping(msgType = 0x0200, versions = VERSION_2019) - public BuiltinServerCommonReplyMsg processLocationUploadMsgV2019(Jt808RequestEntity request, Jt808Session session) { - final LocationUploadMsgV2019 body = request.body(); + public BuiltinServerCommonReplyMsg processLocationUploadMsgV2019(Jt808RequestEntity request, Jt808Session session) { + final BuiltinMsg0200V2019AliasV2 body = request.body(); log.info("LocationUpload -- V2019 -- {}", body); locationMsgService.processLocationMsg(request.session(), body); @@ -53,11 +53,11 @@ public BuiltinServerCommonReplyMsg processLocationUploadMsgV2019(Jt808RequestEnt } @Jt808RequestHandlerMapping(msgType = 0x0200, versions = VERSION_2013) - public BuiltinServerCommonReplyMsg processLocationUploadMsgV2013(Jt808RequestEntity request, Jt808Session session) { - final BuiltinMsg0200V2013Alias body = request.body(); + public BuiltinServerCommonReplyMsg processLocationUploadMsgV2013(Jt808RequestEntity request, Jt808Session session) { + final BuiltinMsg0200V2013AliasV2 body = request.body(); log.info("LocationUpload -- V2013 -- {}", body); - locationMsgService.processLocationMsg(body, request.session()); + locationMsgService.processLocationMsg(request.session(), body); return BuiltinServerCommonReplyMsg.success(request.msgId(), request.flowId()); } diff --git a/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/service/AttachmentFileService.java b/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/service/AttachmentFileService.java index 934b3666..7ae993f8 100644 --- a/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/service/AttachmentFileService.java +++ b/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/service/AttachmentFileService.java @@ -1,6 +1,7 @@ package io.github.hylexus.jt.demos.jt808.service; import io.github.hylexus.jt.demos.jt808.configuration.pros.Jt808AppProps; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.AlarmIdentifierAlias; import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg1210Alias; import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg30316364Alias; import io.github.hylexus.jt.jt808.spec.session.Jt808Session; @@ -9,8 +10,8 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; -import java.text.SimpleDateFormat; -import java.util.Date; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; @Service public class AttachmentFileService { @@ -22,12 +23,15 @@ public AttachmentFileService(Jt808AppProps appProps) { } public void writeDataFragment(Jt808Session session, BuiltinMsg30316364Alias body, BuiltinMsg1210Alias group) { + final AlarmIdentifierAlias alarmIdentifier = group.getAlarmIdentifier(); + final LocalDateTime localDateTime = alarmIdentifier.getTime(); // 这里就瞎写了一个路径 看你需求随便改 final String filePath = appProps.getAttachment().getTemporaryPath() + File.separator + + DateTimeFormatter.ofPattern("yyyyMMddHH").format(localDateTime) + File.separator + session.terminalId() + File.separator - + new SimpleDateFormat("yyyy-MM-dd HH").format(new Date()) + File.separator + group.getMessageType() + File.separator - + group.getAlarmNo() + File.separator + // + group.getAlarmNo() + File.separator + + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(localDateTime) + "-" + group.getAlarmNo() + File.separator + body.getFileName().trim(); final File tempFile = new File(filePath); diff --git a/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/service/LocationMsgService.java b/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/service/LocationMsgService.java index 8406894c..9b33e64c 100644 --- a/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/service/LocationMsgService.java +++ b/demos/jt-demo-808-server-webflux-boot3/src/main/java/io/github/hylexus/jt/demos/jt808/service/LocationMsgService.java @@ -1,12 +1,11 @@ package io.github.hylexus.jt.demos.jt808.service; import io.github.hylexus.jt.demos.jt808.configuration.pros.Jt808AppProps; -import io.github.hylexus.jt.demos.jt808.msg.req.LocationUploadMsgV2019; import io.github.hylexus.jt.jt808.spec.Jt808CommandKey; import io.github.hylexus.jt.jt808.spec.Jt808CommandSender; -import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.BuiltinMsg64; -import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg0200V2013Alias; -import io.github.hylexus.jt.jt808.spec.builtin.msg.req.extra.ExtraItemSupport; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.*; +import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg0200V2013AliasV2; +import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg0200V2019AliasV2; import io.github.hylexus.jt.jt808.spec.builtin.msg.resp.BuiltinMsg9208Alias; import io.github.hylexus.jt.jt808.spec.impl.BuiltinJt808MsgType; import io.github.hylexus.jt.jt808.spec.session.Jt808Session; @@ -18,9 +17,9 @@ import org.springframework.util.CollectionUtils; import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.stream.Collectors; @Slf4j @Service @@ -29,6 +28,7 @@ public class LocationMsgService { private final Jt808CommandSender commandSender; private final Jt808AppProps appProps; private final int attachmentServerPortTcp; + private static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(4); public LocationMsgService(Jt808CommandSender commandSender, Jt808AppProps appProps, @Value("${jt808.attachment-server.port}") int portTcp) { this.commandSender = commandSender; @@ -36,47 +36,96 @@ public LocationMsgService(Jt808CommandSender commandSender, Jt808AppProps appPro this.attachmentServerPortTcp = portTcp; } - public void processLocationMsg(Jt808Session session, LocationUploadMsgV2019 body) { - if (!CollectionUtils.isEmpty(body.getExtraItemList())) { - final Map groupById = body.getExtraItemList().stream().collect(Collectors.toMap(LocationUploadMsgV2019.ExtraItem::getId, Function.identity())); - this.processExtraItemList(session, groupById); + public void processLocationMsg(Jt808Session session, BuiltinMsg0200V2019AliasV2 body) { + final Map extraItemMap = body.getExtraItemMap(); + // 处理附加项列表 + if (!CollectionUtils.isEmpty(extraItemMap)) { + this.processExtraItemList(session, extraItemMap); } + // 处理其他消息属性... } - public void processLocationMsg(BuiltinMsg0200V2013Alias body, Jt808Session session) { - if (!CollectionUtils.isEmpty(body.getExtraItemList())) { - final Map groupById = body.getExtraItemList().stream().collect(Collectors.toMap(BuiltinMsg0200V2013Alias.ExtraItem::getId, Function.identity())); - this.processExtraItemList(session, groupById); + public void processLocationMsg(Jt808Session session, BuiltinMsg0200V2013AliasV2 body) { + final Map extraItemMap = body.getExtraItemMap(); + // 处理附加项列表 + if (!CollectionUtils.isEmpty(extraItemMap)) { + this.processExtraItemList(session, extraItemMap); } + // 处理其他消息属性... } - private void processExtraItemList(Jt808Session session, Map groupById) { + private void processExtraItemList(Jt808Session session, Map groupById) { // 苏标: 高级驾驶辅助系统报警信息,定义见表 4-15 - this.process0x64IfNecessary(session, groupById.get(0x64)); + // ADAS模块视频通道 + this.process0x64IfNecessary(session, (BuiltinMsg64Alias) groupById.get(0x64)); + + // 苏标: 驾驶员状态监测系统报警信息,定义见表 4-17 + // DSM模块视频通道 + this.process0x65IfNecessary(session, (BuiltinMsg65Alias) groupById.get(0x65)); + + // 苏标: 胎压监测系统报警信息,定义见表 4-18 + this.process0x66IfNecessary(session, (BuiltinMsg66Alias) groupById.get(0x66)); + + // 苏标: 盲区监测系统报警信息,定义见表 4-20 + this.process0x67IfNecessary(session, (BuiltinMsg67Alias) groupById.get(0x67)); } - private void process0x64IfNecessary(Jt808Session session, ExtraItemSupport extraItem) { - if (extraItem == null) { + private void process0x67IfNecessary(Jt808Session session, BuiltinMsg67Alias msg67) { + if (msg67 == null) { return; } - final BuiltinMsg64 msg64 = new BuiltinMsg64(extraItem.getContent()); + log.info("ExtraItem-67==>AlarmIdentifier: {}", msg67.getAlarmIdentifier()); + this.doSendMsg9208(session, msg67.getAlarmIdentifier()); + } + + private void process0x66IfNecessary(Jt808Session session, BuiltinMsg66Alias msg66) { + if (msg66 == null) { + return; + } + + log.info("ExtraItem-66==>AlarmIdentifier: {}", msg66.getAlarmIdentifier()); + this.doSendMsg9208(session, msg66.getAlarmIdentifier()); + } + + private void process0x65IfNecessary(Jt808Session session, BuiltinMsg65Alias msg65) { + if (msg65 == null) { + return; + } + + log.info("ExtraItem-65==>AlarmIdentifier: {}", msg65.getAlarmIdentifier()); + this.doSendMsg9208(session, msg65.getAlarmIdentifier()); + } + + private void process0x64IfNecessary(Jt808Session session, BuiltinMsg64Alias msg64) { + if (msg64 == null) { + return; + } + + log.info("ExtraItem-64==>AlarmIdentifier: {}", msg64.getAlarmIdentifier()); + this.doSendMsg9208(session, msg64.getAlarmIdentifier()); + } + + private void doSendMsg9208(Jt808Session session, AlarmIdentifierAlias alarmIdentifier) { final BuiltinMsg9208Alias msg9208 = new BuiltinMsg9208Alias(); msg9208.setAttachmentServerIp(appProps.getServerIp()); msg9208.setAttachmentServerIpLength((short) appProps.getServerIp().length()); msg9208.setAttachmentServerPortTcp(attachmentServerPortTcp); msg9208.setAttachmentServerPortUdp(0); - msg9208.setAlarmIdentifier(msg64.getAlarmIdentifiers()); + msg9208.setAlarmIdentifier(alarmIdentifier); msg9208.setAlarmNo(Randoms.randomString(32)); msg9208.setReservedByte16(""); - final Jt808CommandKey commandKey = Jt808CommandKey.of(session.terminalId(), BuiltinJt808MsgType.SERVER_MSG_9208, session.nextFlowId()); - try { - final Object resp = this.commandSender.sendCommandAndWaitingForReply(commandKey, msg9208, 20L, TimeUnit.SECONDS); - log.info("RESP <-- 0x9208: {}", resp); - } catch (Throwable e) { - log.error("下发 0x9208 异常", e); - throw new RuntimeException(e); - } + EXECUTOR.submit(() -> { + final Jt808CommandKey commandKey = Jt808CommandKey.of(session.terminalId(), BuiltinJt808MsgType.CLIENT_COMMON_REPLY, session.nextFlowId()); + try { + log.info("Waiting for <{}>", commandKey); + final Object resp = this.commandSender.sendCommandAndWaitingForReply(commandKey, msg9208, 20L, TimeUnit.SECONDS); + log.info("RESP <-- 0x9208: {}", resp); + } catch (Throwable e) { + log.error("下发 0x9208 异常", e); + throw new RuntimeException(e); + } + }); } } diff --git a/gradle.properties b/gradle.properties index ff539a0c..4d35ee1d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ projectGroup=io.github.hylexus.jt -projectVersion=2.1.4-beta1 +projectVersion=2.1.4-rc.2 # scm projectScmUrl=https://github.com/hylexus/jt-framework projectScmConnection=scm:git:git@github.com:hylexus/jt-framework.git diff --git a/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/config/configuration/Jt808AttachmentServerAutoConfiguration.java b/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/config/configuration/Jt808AttachmentServerAutoConfiguration.java index a20a96a1..7ccb8772 100644 --- a/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/config/configuration/Jt808AttachmentServerAutoConfiguration.java +++ b/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/config/configuration/Jt808AttachmentServerAutoConfiguration.java @@ -1,35 +1,30 @@ package io.github.hylexus.jt.jt808.boot.config.configuration; -import io.github.hylexus.jt.core.OrderedComponent; import io.github.hylexus.jt.jt808.boot.props.Jt808ServerProps; import io.github.hylexus.jt.jt808.boot.props.attachment.AttachmentServerProps; +import io.github.hylexus.jt.jt808.boot.props.attachment.IdleStateHandlerProps; import io.github.hylexus.jt.jt808.boot.props.msg.processor.MsgProcessorExecutorGroupProps; -import io.github.hylexus.jt.jt808.spec.session.Jt808FlowIdGeneratorFactory; -import io.github.hylexus.jt.jt808.spec.session.Jt808SessionEventListener; -import io.github.hylexus.jt.jt808.support.annotation.codec.Jt808AnnotationBasedEncoder; +import io.github.hylexus.jt.jt808.spec.session.Jt808SessionManager; import io.github.hylexus.jt.jt808.support.codec.Jt808MsgDecoder; -import io.github.hylexus.jt.jt808.support.codec.Jt808MsgEncoder; import io.github.hylexus.jt.jt808.support.codec.Jt808RequestRouteExceptionHandler; import io.github.hylexus.jt.jt808.support.dispatcher.Jt808DispatcherHandler; import io.github.hylexus.jt.jt808.support.dispatcher.Jt808RequestMsgDispatcher; import io.github.hylexus.jt.jt808.support.extension.attachment.*; -import io.github.hylexus.jt.jt808.support.extension.attachment.impl.DefaultAttachmentJt808CommandSender; -import io.github.hylexus.jt.jt808.support.extension.attachment.impl.DefaultAttachmentJt808SessionManager; +import io.github.hylexus.jt.jt808.support.extension.attachment.impl.DefaultJt808AttachmentServerNettyConfigure; import io.github.hylexus.jt.jt808.support.extension.attachment.impl.SimpleAttachmentJt808RequestProcessor; +import io.github.hylexus.jt.jt808.support.netty.InternalIdleStateHandlerProps; import io.netty.util.concurrent.DefaultEventExecutorGroup; import io.netty.util.concurrent.DefaultThreadFactory; import io.netty.util.concurrent.EventExecutorGroup; import io.netty.util.concurrent.RejectedExecutionHandlers; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; -import java.util.Comparator; - import static io.github.hylexus.jt.jt808.JtProtocolConstant.BEAN_NAME_JT808_ATTACHMENT_MSG_PROCESSOR_EVENT_EXECUTOR_GROUP; +import static io.github.hylexus.jt.jt808.JtProtocolConstant.BEAN_NAME_NETTY_HANDLER_NAME_ATTACHMENT_808_HEART_BEAT; @Slf4j @ConditionalOnProperty(prefix = "jt808.attachment-server", name = "enabled", havingValue = "true", matchIfMissing = false) @@ -40,27 +35,11 @@ public Jt808AttachmentServerAutoConfiguration(Jt808ServerProps instructionServer this.instructionServerProps = instructionServerProps; } - @Bean - @ConditionalOnMissingBean - public AttachmentJt808SessionManager attachmentJt808SessionManager(ObjectProvider listeners, Jt808FlowIdGeneratorFactory factory) { - final AttachmentJt808SessionManager manager = new DefaultAttachmentJt808SessionManager(factory); - listeners.stream().sorted(Comparator.comparing(OrderedComponent::getOrder)).forEach(manager::addListener); - return manager; - } - - @Bean - @ConditionalOnMissingBean - public AttachmentJt808CommandSender attachmentJt808CommandSender( - AttachmentJt808SessionManager sessionManager, Jt808MsgEncoder encoder, - Jt808AnnotationBasedEncoder annotationBasedEncoder) { - return new DefaultAttachmentJt808CommandSender(sessionManager, encoder, annotationBasedEncoder); - } - @Bean @ConditionalOnMissingBean(SimpleAttachmentJt808RequestProcessor.class) public SimpleAttachmentJt808RequestProcessor simpleAttachmentJt808RequestProcessor( Jt808MsgDecoder jt808MsgDecoder, - AttachmentJt808SessionManager sessionManager, + Jt808SessionManager sessionManager, Jt808RequestRouteExceptionHandler routeExceptionHandler, Jt808RequestMsgDispatcher msgDispatcher, Jt808DispatcherHandler dispatcherHandler) { @@ -83,29 +62,41 @@ public EventExecutorGroup eventExecutorGroup() { ); } + @Bean(BEAN_NAME_NETTY_HANDLER_NAME_ATTACHMENT_808_HEART_BEAT) + @ConditionalOnMissingBean(name = BEAN_NAME_NETTY_HANDLER_NAME_ATTACHMENT_808_HEART_BEAT) + public AttachmentJt808TerminalHeatBeatHandler heatBeatHandler() { + return new AttachmentJt808TerminalHeatBeatHandler(); + } + @Bean @ConditionalOnMissingBean - public AttachmentJt808DispatchChannelHandlerAdapter attachmentJt808DispatchChannelHandlerAdapter( - AttachmentJt808RequestProcessor requestProcessor, - AttachmentJt808SessionManager sessionManager) { - - return new AttachmentJt808DispatchChannelHandlerAdapter(requestProcessor, sessionManager); + public AttachmentJt808DispatchChannelHandlerAdapter attachmentJt808DispatchChannelHandlerAdapter(AttachmentJt808RequestProcessor requestProcessor) { + return new AttachmentJt808DispatchChannelHandlerAdapter(requestProcessor); } @Bean @ConditionalOnMissingBean public Jt808AttachmentServerNettyConfigure jt808AttachmentServerNettyConfigure( + AttachmentJt808TerminalHeatBeatHandler heatBeatHandler, AttachmentJt808DispatchChannelHandlerAdapter attachmentJt808DispatchChannelHandlerAdapter, @Qualifier(BEAN_NAME_JT808_ATTACHMENT_MSG_PROCESSOR_EVENT_EXECUTOR_GROUP) EventExecutorGroup executors) { final AttachmentServerProps attachmentServerProps = instructionServerProps.getAttachmentServer(); - return new Jt808AttachmentServerNettyConfigure.DefaultJt808AttachmentServerNettyConfigure( - new Jt808AttachmentServerNettyConfigure.DefaultJt808AttachmentServerNettyConfigure.BuiltInServerBootstrapProps( + final IdleStateHandlerProps idleStateHandler = attachmentServerProps.getIdleStateHandler(); + return new DefaultJt808AttachmentServerNettyConfigure( + new DefaultJt808AttachmentServerNettyConfigure.BuiltInServerBootstrapProps( instructionServerProps.getProtocol().getMaxFrameLength(), - attachmentServerProps.getMaxFrameLength() + attachmentServerProps.getMaxFrameLength(), + new InternalIdleStateHandlerProps( + idleStateHandler.isEnabled(), + idleStateHandler.getReaderIdleTime(), + idleStateHandler.getWriterIdleTime(), + idleStateHandler.getAllIdleTime() + ) ), attachmentJt808DispatchChannelHandlerAdapter, - executors + executors, + heatBeatHandler ); } diff --git a/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/config/configuration/codec/Jt808CodecAutoConfiguration.java b/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/config/configuration/codec/Jt808CodecAutoConfiguration.java index 6ae03b3c..7e434c8e 100644 --- a/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/config/configuration/codec/Jt808CodecAutoConfiguration.java +++ b/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/config/configuration/codec/Jt808CodecAutoConfiguration.java @@ -8,6 +8,7 @@ import io.github.hylexus.jt.jt808.spec.impl.DefaultJt808ProtocolVersionDetectorRegistry; import io.github.hylexus.jt.jt808.support.annotation.codec.Jt808AnnotationBasedDecoder; import io.github.hylexus.jt.jt808.support.annotation.codec.Jt808AnnotationBasedEncoder; +import io.github.hylexus.jt.jt808.support.annotation.codec.SimpleJt808MsgDecoder; import io.github.hylexus.jt.jt808.support.codec.*; import io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgBytesProcessor; import io.github.hylexus.jt.jt808.support.codec.impl.DefaultJt808MsgDecoder; @@ -102,4 +103,10 @@ public Jt808AnnotationBasedDecoder jt808AnnotationBasedDecoder(Jt808FieldDeseria public Jt808AnnotationBasedEncoder jt808AnnotationBasedEncoder(Jt808FieldSerializerRegistry fieldSerializerRegistry) { return new Jt808AnnotationBasedEncoder(fieldSerializerRegistry); } + + @Bean + @ConditionalOnMissingBean + public SimpleJt808MsgDecoder simpleJt808MsgDecoder(Jt808AnnotationBasedDecoder delegate) { + return new SimpleJt808MsgDecoder(delegate); + } } diff --git a/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/props/attachment/AttachmentServerProps.java b/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/props/attachment/AttachmentServerProps.java index d0c79336..7ca5f2f2 100644 --- a/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/props/attachment/AttachmentServerProps.java +++ b/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/props/attachment/AttachmentServerProps.java @@ -23,4 +23,8 @@ public class AttachmentServerProps { @NestedConfigurationProperty private MsgProcessorProps msgProcessor = new MsgProcessorProps(); + + @NestedConfigurationProperty + private IdleStateHandlerProps idleStateHandler = new IdleStateHandlerProps(); + } diff --git a/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/props/attachment/IdleStateHandlerProps.java b/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/props/attachment/IdleStateHandlerProps.java new file mode 100644 index 00000000..75b70901 --- /dev/null +++ b/jt-808-server-spring-boot-autoconfigure/src/main/java/io/github/hylexus/jt/jt808/boot/props/attachment/IdleStateHandlerProps.java @@ -0,0 +1,13 @@ +package io.github.hylexus.jt.jt808.boot.props.attachment; + +import lombok.Data; + +import java.time.Duration; + +@Data +public class IdleStateHandlerProps { + private boolean enabled = true; + private Duration readerIdleTime = Duration.ofMinutes(20); + private Duration writerIdleTime = Duration.ZERO; + private Duration allIdleTime = Duration.ZERO; +} \ No newline at end of file diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/JtProtocolConstant.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/JtProtocolConstant.java index 1a100f98..ac39c4d4 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/JtProtocolConstant.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/JtProtocolConstant.java @@ -17,8 +17,11 @@ public interface JtProtocolConstant { String BEAN_NAME_JT808_MSG_PROCESSOR_EVENT_EXECUTOR_GROUP = "jt808MsgProcessorEventExecutorGroup"; String BEAN_NAME_JT808_ATTACHMENT_MSG_PROCESSOR_EVENT_EXECUTOR_GROUP = "jt808AttachmentMsgProcessorEventExecutorGroup"; String BEAN_NAME_NETTY_HANDLER_NAME_808_HEART_BEAT = "Jt808NettyHeartBeatHandler"; + String BEAN_NAME_NETTY_HANDLER_NAME_ATTACHMENT_808_HEART_BEAT = "AttachmentJt808NettyHeartBeatHandler"; String NETTY_HANDLER_NAME_808_IDLE_STATE = "Jt808NettyIdleStateHandler"; + String NETTY_HANDLER_NAME_ATTACHMENT_808_IDLE_STATE = "AttachmentJt808NettyIdleStateHandler"; String NETTY_HANDLER_NAME_808_FRAME = "Jt808NettyHandler"; + String NETTY_HANDLER_NAME_ATTACHMENT_808_FRAME = "AttachmentJt808NettyHandler"; String NETTY_HANDLER_NAME_808_MSG_DISPATCHER_ADAPTER = "Jt808NettyHandlerAdapter"; } diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/Jt808Request.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/Jt808Request.java index 4b4179ae..b26b921c 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/Jt808Request.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/Jt808Request.java @@ -22,6 +22,9 @@ @BuiltinComponent public interface Jt808Request { + /** + * @since 2.1.4 + */ Jt808Session session(); /** diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/BuiltinMsg64.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/BuiltinMsg64.java deleted file mode 100644 index 350b6419..00000000 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/BuiltinMsg64.java +++ /dev/null @@ -1,78 +0,0 @@ -package io.github.hylexus.jt.jt808.spec.builtin.msg.extension; - -import io.github.hylexus.jt.common.Jt808ByteReader; -import lombok.Data; - -@Data -public class BuiltinMsg64 { - - public BuiltinMsg64(byte[] content) { - this.initFromBytes(content); - } - - private void initFromBytes(byte[] content) { - Jt808ByteReader.doWithReader(content, reader -> { - this.offset0 = reader.readUnsignedDword(); - this.offset4 = reader.readByte(); - this.offset5 = reader.readByte(); - this.offset6 = reader.readByte(); - this.offset7 = reader.readByte(); - this.offset8 = reader.readByte(); - this.offset9 = reader.readByte(); - this.offset10 = reader.readByte(); - this.offset11 = reader.readByte(); - this.offset12 = reader.readByte(); - this.offset13 = reader.readUnsignedWord(); - this.offset15 = reader.readUnsignedDword(); - this.offset19 = reader.readUnsignedDword(); - this.offset23 = reader.readBcd(6); - this.offset29 = reader.readUnsignedWord(); - this.offset31 = reader.readBytes(16); - }); - } - - // offset[0,4) 报警 ID: 按照报警先后,从0开始循环累加,不区分报警类型。 - private long offset0; - - // offset[4,5) 标志状态 - // 0x00:不可用 - // 0x01:开始标志 - // 0x02:结束标志 - // 该字段仅适用于有开始和结束标志类型的报警或事件,报警类型或事件类型无开始和结束标志,则该位不可用,填入0x00即可。 - private byte offset4; - // offset[5,6) 报警/事件类型 - private byte offset5; - // offset[6,7) 报警级别 - private byte offset6; - // offset[7,8) 前车车速 - private byte offset7; - // offset[8,9) 前车/行人距离 - private byte offset8; - // offset[9,10) 偏离类型 - private byte offset9; - - // offset[10,11) 道路标志识别类型 - private byte offset10; - // offset[11,12) 道路标志识别数据 - private byte offset11; - // offset[12,13) 车速 - private byte offset12; - // offset[13,15) 高程 - private int offset13; - - // offset[15,19) 纬度 - private long offset15; - - // offset[19,23) 经度 - private long offset19; - // offset[23,29) 日期时间 - private String offset23; - // offset[29,31] 车辆状态 - private int offset29; - // offset[31,31+16) 报警标识号 - private byte[] offset31; - - public String getAlarmIdentifiers() { - return new String(this.offset31); - } -} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/AlarmIdentifierAlias.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/AlarmIdentifierAlias.java new file mode 100644 index 00000000..6f729395 --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/AlarmIdentifierAlias.java @@ -0,0 +1,42 @@ +package io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location; + +import io.github.hylexus.jt.jt808.support.annotation.msg.req.RequestFieldAlias; +import io.github.hylexus.jt.jt808.support.annotation.msg.resp.ResponseFieldAlias; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + * 苏标-表-4-16 报警标识号格式 + * + * @author hylexus + */ +@Data +@Accessors(chain = true) +public class AlarmIdentifierAlias { + // 终端ID BYTE[7] 7个字节,由大写字母和数字组成 + @RequestFieldAlias.String(order = 10, length = 7) + @ResponseFieldAlias.String(order = 10) + private String terminalId; + + // 时间 BCD[6] YY-MM-DD-hh-mm-ss (GMT+8时间) + @RequestFieldAlias.BcdDateTime(order = 20) + @ResponseFieldAlias.BcdDateTime(order = 20) + private LocalDateTime time; + + // 序号 BYTE 同一时间点报警的序号,从0循环累加 + @RequestFieldAlias.Byte(order = 30) + @ResponseFieldAlias.Byte(order = 30) + private short sequence; + + // 附件数量 BYTE 表示该报警对应的附件数量 + @RequestFieldAlias.Byte(order = 40) + @ResponseFieldAlias.Byte(order = 40) + private short attachmentCount; + + // 预留 BYTE + @RequestFieldAlias.Byte(order = 50) + @ResponseFieldAlias.Byte(order = 50) + private short reserved = 0; +} \ No newline at end of file diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/BuiltinMsg64Alias.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/BuiltinMsg64Alias.java new file mode 100644 index 00000000..0cfbee22 --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/BuiltinMsg64Alias.java @@ -0,0 +1,85 @@ +package io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location; + +import io.github.hylexus.jt.jt808.support.annotation.msg.req.RequestFieldAlias; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 苏标-表-4-15 高级驾驶辅助报警信息数据格式 + * + * @author hylexus + */ +@Data +public class BuiltinMsg64Alias { + + // offset[0,4) DWORD 报警 ID: 按照报警先后,从0开始循环累加,不区分报警类型。 + @RequestFieldAlias.Dword(order = 10) + private long alarmId; + + // offset[4,5) BYTE 标志状态 + // 0x00:不可用 + // 0x01:开始标志 + // 0x02:结束标志 + // 该字段仅适用于有开始和结束标志类型的报警或事件,报警类型或事件类型无开始和结束标志,则该位不可用,填入0x00即可。 + @RequestFieldAlias.Byte(order = 20) + private short status; + + // offset[5,6) BYTE 报警/事件类型 + @RequestFieldAlias.Byte(order = 30) + private short alarmType; + + // offset[6,7) BYTE 报警级别 + @RequestFieldAlias.Byte(order = 40) + private short alarmLevel; + + // offset[7,8) BYTE 前车车速 + // Front vehicle speed + @RequestFieldAlias.Byte(order = 50) + private short speedOfFrontObject; + + // offset[8,9) BYTE 前车/行人距离 + @RequestFieldAlias.Byte(order = 60) + private short distanceToFrontObject; + + // offset[9,10) BYTE 偏离类型 + @RequestFieldAlias.Byte(order = 70) + private short deviationType; + + // offset[10,11) BYTE 道路标志识别类型 + @RequestFieldAlias.Byte(order = 80) + private short roadSignType; + + // offset[11,12) BYTE 道路标志识别数据 + @RequestFieldAlias.Byte(order = 90) + private short roadSignData; + + // offset[12,13) BYTE 车速 + @RequestFieldAlias.Byte(order = 100) + private short speed; + + // offset[13,15) WORD 高程 + @RequestFieldAlias.Word(order = 110) + private int height; + + // offset[15,19) DWORD 纬度 + @RequestFieldAlias.Dword(order = 120) + private long latitude; + + // offset[19,23) DWORD 经度 + @RequestFieldAlias.Dword(order = 130) + private long longitude; + + // offset[23,29) BCD[6] 日期时间 + @RequestFieldAlias.BcdDateTime(order = 140) + private LocalDateTime datetime; + + // offset[29,31] WORD 车辆状态 + @RequestFieldAlias.Word(order = 150) + private int vehicleStatus; + // offset[31,31+16) BYTE[16] 报警标识号 + // 报警识别号定义见表4-16 + @RequestFieldAlias.Object(order = 160, length = 16) + private AlarmIdentifierAlias alarmIdentifier; + +} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/BuiltinMsg65Alias.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/BuiltinMsg65Alias.java new file mode 100644 index 00000000..665852c4 --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/BuiltinMsg65Alias.java @@ -0,0 +1,70 @@ +package io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location; + +import io.github.hylexus.jt.jt808.support.annotation.msg.req.RequestFieldAlias; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 苏标-表-4-17 驾驶状态监测系统报警信息数据格式 + * + * @author hylexus + */ +@Data +public class BuiltinMsg65Alias { + + // offset[0,4) 报警 ID: 按照报警先后,从0开始循环累加,不区分报警类型。 + @RequestFieldAlias.Dword(order = 10) + private long alarmId; + + // 0x00:不可用 + // 0x01:开始标志 + // 0x02:结束标志 + // 该字段仅适用于有开始和结束标志类型的报警或事件,报警类型或事件类型无开始和结束标志,则该位不可用,填入0x00即可 + @RequestFieldAlias.Byte(order = 20) + private short status; + + // offset[5,6) 报警/事件类型 + @RequestFieldAlias.Byte(order = 30) + private short alarmType; + + // offset[6,7) 报警级别 + @RequestFieldAlias.Byte(order = 40) + private short alarmLevel; + + // offset[7,8) 疲劳程度 范围1~10。数值越大表示疲劳程度越严重,仅在报警类型为0x01时有效 + @RequestFieldAlias.Byte(order = 50) + private short fatigueLevel; + + // offset[8,12) BYTE[4] 预留 + @RequestFieldAlias.Bytes(order = 60, length = 4) + private byte[] reservedOffset8; + + // offset[12,13) BYTE 车速 + @RequestFieldAlias.Byte(order = 100) + private short speed; + + // offset[13,15) WORD 高程 + @RequestFieldAlias.Word(order = 110) + private int height; + + // offset[15,19) DWORD 纬度 + @RequestFieldAlias.Dword(order = 120) + private long latitude; + + // offset[19,23) DWORD 经度 + @RequestFieldAlias.Dword(order = 130) + private long longitude; + + // offset[23,29) BCD[6] 日期时间 + @RequestFieldAlias.BcdDateTime(order = 140) + private LocalDateTime datetime; + + // offset[29,31] WORD 车辆状态 + @RequestFieldAlias.Word(order = 150) + private int vehicleStatus; + // offset[31,31+16) BYTE[16] 报警标识号 + // 报警识别号定义见表4-16 + @RequestFieldAlias.Object(order = 160, length = 16) + private AlarmIdentifierAlias alarmIdentifier; +} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/BuiltinMsg66Alias.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/BuiltinMsg66Alias.java new file mode 100644 index 00000000..c3672557 --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/BuiltinMsg66Alias.java @@ -0,0 +1,98 @@ +package io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location; + +import io.github.hylexus.jt.jt808.support.annotation.msg.req.RequestFieldAlias; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 苏标-表-4-18 胎压监测系统报警信息数据格式 + * + * @author hylexus + */ +@Slf4j +@Data +public class BuiltinMsg66Alias { + + // offset[0,4) DWORD 报警 ID: 按照报警先后,从0开始循环累加,不区分报警类型。 + @RequestFieldAlias.Dword(order = 10) + private long alarmId; + + // offset[4,5) BYTE 标志状态 + // 0x00:不可用 + // 0x01:开始标志 + // 0x02:结束标志 + // 该字段仅适用于有开始和结束标志类型的报警或事件,报警类型或事件类型无开始和结束标志,则该位不可用,填入0x00即可 + @RequestFieldAlias.Byte(order = 20) + private short status; + + // offset[12,13) BYTE 车速 + @RequestFieldAlias.Byte(order = 100) + private short speed; + + // offset[13,15) WORD 高程 + @RequestFieldAlias.Word(order = 110) + private int height; + + // offset[15,19) DWORD 纬度 + @RequestFieldAlias.Dword(order = 120) + private long latitude; + + // offset[19,23) DWORD 经度 + @RequestFieldAlias.Dword(order = 130) + private long longitude; + + // offset[23,29) BCD[6] 日期时间 + @RequestFieldAlias.BcdDateTime(order = 140) + private LocalDateTime datetime; + + // offset[29,31] WORD 车辆状态 + @RequestFieldAlias.Word(order = 150) + private int vehicleStatus; + // offset[31,31+16) BYTE[16] 报警标识号 + // 报警识别号定义见表4-16 + @RequestFieldAlias.Object(order = 160, length = 16) + private AlarmIdentifierAlias alarmIdentifier; + + // offset[39, 40) BYTE 报警/事件列表总数 + @RequestFieldAlias.Byte(order = 170) + private short eventItemCount; + + // 报警/事件信息列表 + @RequestFieldAlias.List(order = 180, lengthExpression = "#ctx.msgBodyLength() - 40", conditionalOn = "#this.getEventItemCount() > 0") + private List eventItemList; + + @Data + public static class EventItem { + // 胎压报警位置 BYTE 报警轮胎位置编号(从左前轮开始以Z字形从00依次编号,编号与是否安装TPMS无关) + @RequestFieldAlias.Byte(order = 10) + private short offset0; + + // 报警/事件类型 WORD 0表示无报警,1表示有报警 + // bit0:胎压(定时上报) + // bit1:胎压过高报警 + // bit2:胎压过低报警 + // bit3:胎温过高报警 + // bit4:传感器异常报警 + // bit5:胎压不平衡报警 + // bit6:慢漏气报警 + // bit7:电池电量低报警 + // bit8~bit15:自定义 + @RequestFieldAlias.Word(order = 20) + private int offset2; + + // 胎压 WORD 单位 Kpa + @RequestFieldAlias.Word(order = 30) + private int offset4; + + // 胎温 WORD 单位 ℃ + @RequestFieldAlias.Word(order = 40) + private int offset6; + + // 电池电量 WORD 单位 % + @RequestFieldAlias.Word(order = 50) + private int offset8; + } +} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/BuiltinMsg67Alias.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/BuiltinMsg67Alias.java new file mode 100644 index 00000000..f959435e --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/extension/location/BuiltinMsg67Alias.java @@ -0,0 +1,63 @@ +package io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location; + +import io.github.hylexus.jt.jt808.support.annotation.msg.req.RequestFieldAlias; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 苏标-表-4-20 盲区监测系统报警定义数据格式 + * + * @author hylexus + */ +@Data +public class BuiltinMsg67Alias { + + // offset[0,4) DWORD 报警ID 按照报警先后,从0开始循环累加,不区分报警类型。 + @RequestFieldAlias.Dword(order = 10) + private long alarmId; + + // offset[4,5) BYTE + // 0x00:不可用 + // 0x01:开始标志 + // 0x02:结束标志 + // 该字段仅适用于有开始和结束标志类型的报警或事件,报警类型或事件类型无开始和结束标志,则该位不可用,填入0x00即可。 + @RequestFieldAlias.Byte(order = 20) + private short status; + + // offset[5,6) BYTE 报警/事件类型 + // 0x01:后方接近报警 + // 0x02:左侧后方接近报警 + // 0x03:右侧后方接近报警 + @RequestFieldAlias.Byte(order = 30) + private short alarmType; + + // offset[12,13) BYTE 车速 + @RequestFieldAlias.Byte(order = 100) + private short speed; + + // offset[13,15) WORD 高程 + @RequestFieldAlias.Word(order = 110) + private int height; + + // offset[15,19) DWORD 纬度 + @RequestFieldAlias.Dword(order = 120) + private long latitude; + + // offset[19,23) DWORD 经度 + @RequestFieldAlias.Dword(order = 130) + private long longitude; + + // offset[23,29) BCD[6] 日期时间 + @RequestFieldAlias.BcdDateTime(order = 140) + private LocalDateTime datetime; + + // offset[29,31] WORD 车辆状态 + @RequestFieldAlias.Word(order = 150) + private int vehicleStatus; + // offset[31,31+16) BYTE[16] 报警标识号 + // 报警识别号定义见表4-16 + @RequestFieldAlias.Object(order = 160, length = 16) + private AlarmIdentifierAlias alarmIdentifier; + +} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg0200V2013AliasV2.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg0200V2013AliasV2.java new file mode 100644 index 00000000..3e938d5f --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg0200V2013AliasV2.java @@ -0,0 +1,100 @@ +package io.github.hylexus.jt.jt808.spec.builtin.msg.req; + +import io.github.hylexus.jt.annotation.BuiltinComponent; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.BuiltinMsg64Alias; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.BuiltinMsg65Alias; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.BuiltinMsg66Alias; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.BuiltinMsg67Alias; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.Jt808RequestBody; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.RequestFieldAlias; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.SlicedFrom; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.extensions.ValueDescriptor; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.extensions.KeyValueMapping; +import io.github.hylexus.jt.jt808.support.data.MsgDataType; +import io.github.hylexus.jt.jt808.support.data.type.byteseq.ByteArrayContainer; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Map; + +/** + * @author hylexus + */ +@Data +@Accessors(chain = true) +@Jt808RequestBody +@BuiltinComponent +public class BuiltinMsg0200V2013AliasV2 { + // (1). byte[0,4) DWORD 报警标志 + @RequestFieldAlias.Dword(order = 1) + private long alarmFlag; + + // (2). byte[4,8) DWORD 状态 + @RequestFieldAlias.Dword(order = 2) + private long status; + + // 将上面的 status 字段的第0位取出转为 int 类型 + @SlicedFrom(sourceFieldName = "status", bitIndex = 0) + private int accIntStatus; + // 将上面的 status 字段的第0位取出转为 boolean 类型 + @SlicedFrom(sourceFieldName = "status", bitIndex = 0) + private Boolean accBooleanStatus; + // 0 北纬;1 南纬 + // 将上面的 status 字段的第2位取出转为 int 类型 + @SlicedFrom(sourceFieldName = "status", bitIndex = 2) + private int latType; + + // (3). byte[8,12) DWORD 纬度 + @RequestFieldAlias.Dword(order = 3) + private long lat; + + // (4). byte[12,16) DWORD 经度 + @RequestFieldAlias.Dword(order = 4) + private long lng; + + // (5). byte[16,18) WORD 高度 + @RequestFieldAlias.Word(order = 5) + private Integer height; + + // (6). byte[18,20) WORD 速度 + @RequestFieldAlias.Word(order = 6) + private int speed; + + // (7). byte[20,22) WORD 方向 + @RequestFieldAlias.Word(order = 7) + private Integer direction; + + // (8). byte[22,28) BCD[6] 时间 + @RequestFieldAlias.Bcd(order = 8, length = 6) + private String time; + + // (9). byte[28,n) 附加项列表 + @RequestFieldAlias.LocationMsgExtraItemMapping( + order = 9, + lengthExpression = "#ctx.msgBodyLength() - 28", + keyValueMappings = { + // 基础类型 + @KeyValueMapping(key = 0x01, value = @ValueDescriptor(source = MsgDataType.DWORD, target = Long.class), desc = "里程,DWORD,1/10km,对应车上里程表读数"), + @KeyValueMapping(key = 0x02, value = @ValueDescriptor(source = MsgDataType.WORD, target = Integer.class), desc = "油量,WORD,1/10L,对应车上油量表读数"), + @KeyValueMapping(key = 0x03, value = @ValueDescriptor(source = MsgDataType.WORD, target = Integer.class), desc = "行驶记录功能获取的速度,WORD,1/10km/h"), + @KeyValueMapping(key = 0x04, value = @ValueDescriptor(source = MsgDataType.WORD, target = Integer.class), desc = "需要人工确认报警事件的 ID,WORD,从 1 开始计数"), + @KeyValueMapping(key = 0x11, value = @ValueDescriptor(source = MsgDataType.BYTES, target = byte[].class), desc = "长度1或5;超速报警附加信息见 表 28"), + @KeyValueMapping(key = 0x25, value = @ValueDescriptor(source = MsgDataType.DWORD, target = Integer.class), desc = "扩展车辆信号状态位,定义见 表 31"), + @KeyValueMapping(key = 0x2A, value = @ValueDescriptor(source = MsgDataType.WORD, target = Integer.class), desc = "IO状态位,定义见 表 32"), + @KeyValueMapping(key = 0x2B, value = @ValueDescriptor(source = MsgDataType.DWORD, target = Long.class), desc = "模拟量,bit0-15,AD0;bit16-31,AD1"), + @KeyValueMapping(key = 0x30, value = @ValueDescriptor(source = MsgDataType.BYTE, target = Short.class), desc = "BYTE,无线通信网络信号强度"), + @KeyValueMapping(key = 0x31, value = @ValueDescriptor(source = MsgDataType.BYTE, target = Integer.class), desc = "BYTE,GNSS 定位卫星数"), + // 嵌套类型 + @KeyValueMapping(key = 0x64, value = @ValueDescriptor(source = MsgDataType.OBJECT, target = BuiltinMsg64Alias.class), desc = "苏标: 高级驾驶辅助报警信息,定义见表 4-15"), + // 嵌套类型 + @KeyValueMapping(key = 0x65, value = @ValueDescriptor(source = MsgDataType.OBJECT, target = BuiltinMsg65Alias.class), desc = "苏标: 驾驶员状态监测系统报警信息,定义见表 4-17"), + // 嵌套类型 + @KeyValueMapping(key = 0x66, value = @ValueDescriptor(source = MsgDataType.OBJECT, target = BuiltinMsg66Alias.class), desc = "苏标: 胎压监测系统报警信息,定义见表 4-18"), + // 嵌套类型 + @KeyValueMapping(key = 0x67, value = @ValueDescriptor(source = MsgDataType.OBJECT, target = BuiltinMsg67Alias.class), desc = "苏标: 盲区监测系统报警信息,定义见表 4-20"), + }, + // keyValueMappings 中没有指定的key, 都会以该属性描述符指定的格式解析 + defaultKeyValueMapping = @ValueDescriptor(source = MsgDataType.BYTES, target = ByteArrayContainer.class) + ) + private Map extraItemMap; +} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg0200V2019AliasV2.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg0200V2019AliasV2.java new file mode 100644 index 00000000..1edab75a --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg0200V2019AliasV2.java @@ -0,0 +1,124 @@ +package io.github.hylexus.jt.jt808.spec.builtin.msg.req; + +import io.github.hylexus.jt.annotation.BuiltinComponent; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.BuiltinMsg64Alias; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.BuiltinMsg65Alias; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.BuiltinMsg66Alias; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.BuiltinMsg67Alias; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.Jt808RequestBody; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.RequestFieldAlias; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.SlicedFrom; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.extensions.ValueDescriptor; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.extensions.KeyValueMapping; +import io.github.hylexus.jt.jt808.support.data.MsgDataType; +import io.github.hylexus.jt.jt808.support.data.type.byteseq.ByteArrayContainer; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Map; + +/** + * @author hylexus + */ +@Data +@Accessors(chain = true) +@Jt808RequestBody +@BuiltinComponent +public class BuiltinMsg0200V2019AliasV2 { + // (1). byte[0,4) DWORD 报警标志 + @RequestFieldAlias.Dword(order = 1) + private long alarmFlag; + // @RequestFieldAlias.Dword(order = 1) + // private BitOperator bitOperator; + + // (2). byte[4,8) DWORD 状态 + @RequestFieldAlias.Dword(order = 2) + private long status; + + // 将上面的 status 字段的第0位取出转为 int 类型 + @SlicedFrom(sourceFieldName = "status", bitIndex = 0) + private int accIntStatus; + // 将上面的 status 字段的第0位取出转为 boolean 类型 + @SlicedFrom(sourceFieldName = "status", bitIndex = 0) + private Boolean accBooleanStatus; + // 0 北纬;1 南纬 + // 将上面的 status 字段的第2位取出转为 int 类型 + @SlicedFrom(sourceFieldName = "status", bitIndex = 2) + private int latType; + + // (3). byte[8,12) DWORD 纬度 + @RequestFieldAlias.Dword(order = 3) + private long lat; + + // (4). byte[12,16) DWORD 经度 + @RequestFieldAlias.Dword(order = 4) + private long lng; + + // (5). byte[16,18) WORD 高度 + @RequestFieldAlias.Word(order = 5) + private Integer height; + + // (6). byte[18,20) WORD 速度 + @RequestFieldAlias.Word(order = 6) + private int speed; + + // (7). byte[20,22) WORD 方向 + @RequestFieldAlias.Word(order = 7) + private Integer direction; + + // (8). byte[22,28) BCD[6] 时间 + @RequestFieldAlias.Bcd(order = 8, length = 6) + private String time; + + // (9). byte[28,n) 附加项列表 + // @RequestField(order = 9, startIndex = 28, dataType = LIST, lengthExpression = "#request.msgBodyLength() - 28") + // @RequestFieldAlias.List(order = 9, lengthExpression = "#ctx.msgBodyLength() - 28") + // private List extraItemList; + + // (9). byte[28,n) 附加项列表 + @RequestFieldAlias.LocationMsgExtraItemMapping( + order = 9, + lengthExpression = "#ctx.msgBodyLength() - 28", + keyValueMappings = { + // 基础类型 + @KeyValueMapping(key = 0x01, value = @ValueDescriptor(source = MsgDataType.DWORD, target = Long.class), desc = "里程,DWORD,1/10km,对应车上里程表读数"), + @KeyValueMapping(key = 0x02, value = @ValueDescriptor(source = MsgDataType.WORD, target = Integer.class), desc = "油量,WORD,1/10L,对应车上油量表读数"), + @KeyValueMapping(key = 0x03, value = @ValueDescriptor(source = MsgDataType.WORD, target = Integer.class), desc = "行驶记录功能获取的速度,WORD,1/10km/h"), + @KeyValueMapping(key = 0x04, value = @ValueDescriptor(source = MsgDataType.WORD, target = Integer.class), desc = "需要人工确认报警事件的 ID,WORD,从 1 开始计数"), + @KeyValueMapping(key = 0x11, value = @ValueDescriptor(source = MsgDataType.BYTES, target = byte[].class), desc = "长度1或5;超速报警附加信息见 表 28"), + @KeyValueMapping(key = 0x25, value = @ValueDescriptor(source = MsgDataType.DWORD, target = Integer.class), desc = "扩展车辆信号状态位,定义见 表 31"), + @KeyValueMapping(key = 0x2A, value = @ValueDescriptor(source = MsgDataType.WORD, target = Integer.class), desc = "IO状态位,定义见 表 32"), + @KeyValueMapping(key = 0x2B, value = @ValueDescriptor(source = MsgDataType.DWORD, target = Long.class), desc = "模拟量,bit0-15,AD0;bit16-31,AD1"), + @KeyValueMapping(key = 0x30, value = @ValueDescriptor(source = MsgDataType.BYTE, target = Short.class), desc = "BYTE,无线通信网络信号强度"), + @KeyValueMapping(key = 0x31, value = @ValueDescriptor(source = MsgDataType.BYTE, target = Integer.class), desc = "BYTE,GNSS 定位卫星数"), + // 嵌套类型 + @KeyValueMapping(key = 0x64, value = @ValueDescriptor(source = MsgDataType.OBJECT, target = BuiltinMsg64Alias.class), desc = "苏标: 高级驾驶辅助报警信息,定义见表 4-15"), + // 嵌套类型 + @KeyValueMapping(key = 0x65, value = @ValueDescriptor(source = MsgDataType.OBJECT, target = BuiltinMsg65Alias.class), desc = "苏标: 驾驶员状态监测系统报警信息,定义见表 4-17"), + // 嵌套类型 + @KeyValueMapping(key = 0x66, value = @ValueDescriptor(source = MsgDataType.OBJECT, target = BuiltinMsg66Alias.class), desc = "苏标: 胎压监测系统报警信息,定义见表 4-18"), + // 嵌套类型 + @KeyValueMapping(key = 0x67, value = @ValueDescriptor(source = MsgDataType.OBJECT, target = BuiltinMsg67Alias.class), desc = "苏标: 盲区监测系统报警信息,定义见表 4-20"), + }, + // keyValueMappings 中没有指定的key, 都会以该属性描述符指定的格式解析 + defaultKeyValueMapping = @ValueDescriptor(source = MsgDataType.BYTES, target = ByteArrayContainer.class) + ) + private Map extraItemMap; + + @Data + public static class ExtraItem { + // 附加信息ID + @RequestFieldAlias.Byte(order = 0) + private int id; + + // 附加信息长度 + @RequestFieldAlias.Byte(order = 1) + private int contentLength; + + // 附加信息内容 + @RequestFieldAlias.Bytes(order = 3, lengthExpression = "#this.contentLength") + // private byte[] content; + private ByteArrayContainer content; + // private ByteBufContainer content; + } +} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg1210Alias.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg1210Alias.java index 67eb4cac..7c59c44a 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg1210Alias.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg1210Alias.java @@ -1,6 +1,7 @@ package io.github.hylexus.jt.jt808.spec.builtin.msg.req; import io.github.hylexus.jt.annotation.BuiltinComponent; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.AlarmIdentifierAlias; import io.github.hylexus.jt.jt808.support.annotation.msg.req.Jt808RequestBody; import io.github.hylexus.jt.jt808.support.annotation.msg.req.RequestField; import io.github.hylexus.jt.jt808.support.annotation.msg.req.RequestFieldAlias; @@ -26,8 +27,8 @@ public class BuiltinMsg1210Alias { private String terminalId; // byte[7,23) - @RequestFieldAlias.Bytes(order = 20, length = 16) - private String alarmIdentifier; + @RequestFieldAlias.Object(order = 20, length = 16) + private AlarmIdentifierAlias alarmIdentifier; // byte[23,55) @RequestFieldAlias.Bytes(order = 30, length = 32) diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinTerminalCommonReplyMsg.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinTerminalCommonReplyMsg.java index e8197b12..9ff25beb 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinTerminalCommonReplyMsg.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinTerminalCommonReplyMsg.java @@ -3,6 +3,7 @@ import io.github.hylexus.jt.annotation.BuiltinComponent; import io.github.hylexus.jt.jt808.support.annotation.msg.req.Jt808RequestBody; import io.github.hylexus.jt.jt808.support.annotation.msg.req.RequestField; +import io.github.hylexus.jt.utils.FormatUtils; import lombok.Data; import lombok.experimental.Accessors; @@ -43,4 +44,13 @@ public class BuiltinTerminalCommonReplyMsg { public static BuiltinTerminalCommonReplyMsg success(int serverMsgId, int serverFlowId) { return new BuiltinTerminalCommonReplyMsg().setServerMsgId(serverMsgId).setServerFlowId(serverFlowId).setResult(RESULT_SUCCESS); } + + @Override + public String toString() { + return "BuiltinTerminalCommonReplyMsg{" + + "serverFlowId=" + serverFlowId + + ", serverMsgId=" + serverMsgId + "(0x" + FormatUtils.toHexString(serverMsgId) + ")" + + ", result=" + result + + '}'; + } } diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/resp/BuiltinMsg9208Alias.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/resp/BuiltinMsg9208Alias.java index 1cae4400..f5c3a4c1 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/resp/BuiltinMsg9208Alias.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/builtin/msg/resp/BuiltinMsg9208Alias.java @@ -1,5 +1,6 @@ package io.github.hylexus.jt.jt808.spec.builtin.msg.resp; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.AlarmIdentifierAlias; import io.github.hylexus.jt.jt808.support.annotation.msg.resp.Jt808ResponseBody; import io.github.hylexus.jt.jt808.support.annotation.msg.resp.ResponseFieldAlias; import lombok.Data; @@ -30,8 +31,8 @@ public class BuiltinMsg9208Alias { private int attachmentServerPortUdp; // BYTE[16] - @ResponseFieldAlias.Bytes(order = 50) - private String alarmIdentifier; + @ResponseFieldAlias.Object(order = 50) + private AlarmIdentifierAlias alarmIdentifier; // BYTE[32] @ResponseFieldAlias.Bytes(order = 60) @@ -39,5 +40,5 @@ public class BuiltinMsg9208Alias { // BYTE[16] @ResponseFieldAlias.Bytes(order = 70) - private String reservedByte16; + private String reservedByte16 = "0000000000000000"; } diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/session/DefaultJt808SessionManager.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/session/DefaultJt808SessionManager.java index 8fd092d5..3cda00b6 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/session/DefaultJt808SessionManager.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/session/DefaultJt808SessionManager.java @@ -74,6 +74,11 @@ public Jt808Session generateSession(String terminalId, Jt808ProtocolVersion vers return buildSession(terminalId, version, channel, flowIdGenerator); } + @Override + public Jt808Session generateSession(String terminalId, Jt808ProtocolVersion version, Channel channel, Jt808Session.Role role) { + return ((DefaultJt808Session) this.generateSession(terminalId, version, channel)).role(role); + } + protected DefaultJt808Session buildSession(String terminalId, Jt808ProtocolVersion version, Channel channel, Jt808FlowIdGenerator flowIdGenerator) { final DefaultJt808Session session = new DefaultJt808Session(flowIdGenerator); session.channel(channel); diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/session/InternalJt808SessionManager.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/session/InternalJt808SessionManager.java index c0b0c1da..f581f57b 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/session/InternalJt808SessionManager.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/spec/session/InternalJt808SessionManager.java @@ -93,6 +93,13 @@ default String generateSessionId(Channel channel) { */ Jt808Session generateSession(String terminalId, Jt808ProtocolVersion version, Channel channel); + /** + * @since 2.1.4 + */ + default Jt808Session generateSession(String terminalId, Jt808ProtocolVersion version, Channel channel, Jt808Session.Role role) { + return this.generateSession(terminalId, version, channel); + } + /** * @param terminalId 终端号(手机号) * @param version 协议版本号 diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/codec/Jt808AnnotationBasedDecoder.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/codec/Jt808AnnotationBasedDecoder.java index 0c6de0ff..faf642ae 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/codec/Jt808AnnotationBasedDecoder.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/codec/Jt808AnnotationBasedDecoder.java @@ -17,11 +17,13 @@ import io.github.hylexus.jt.utils.Assertions; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.expression.EvaluationContext; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; +import javax.annotation.Nullable; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; @@ -50,14 +52,16 @@ public T decode(Jt808Request request, Class cls) throws Jt808AnnotationAr return result; } - public Object decode(Class cls, Object instance, ByteBuf byteBuf, Jt808Request request) throws Jt808AnnotationArgumentResolveException { + public Object decode(Class cls, Object instance, ByteBuf byteBuf, @Nullable Jt808Request request) throws Jt808AnnotationArgumentResolveException { this.processAwareMethod(instance, request); final EvaluationContext evaluationContext = new StandardEvaluationContext(instance); evaluationContext.setVariable("this", instance); - evaluationContext.setVariable("request", request); - evaluationContext.setVariable("header", request.header()); + if (request != null) { + evaluationContext.setVariable("request", request); + evaluationContext.setVariable("header", request.header()); + } final AnnotationDecoderContext context = new AnnotationDecoderContext(byteBuf.readableBytes(), byteBuf); evaluationContext.setVariable("ctx", context); evaluationContext.setVariable("context", context); @@ -80,12 +84,16 @@ public Object decode(Class cls, Object instance, ByteBuf byteBuf, Jt808Reques private void processBasicField( EvaluationContext evaluationContext, Class cls, Object instance, JavaBeanFieldMetadata fieldMetadata, - ByteBuf bodyDataBuf, Jt808Request request) { + ByteBuf bodyDataBuf, @Nullable Jt808Request request) { final RequestField annotation = fieldMetadata.getAnnotation(RequestField.class); final MsgDataType jtDataType = annotation.dataType(); final Class javaDataType = fieldMetadata.getFieldType(); + if (this.shouldSkip(evaluationContext, annotation)) { + return; + } + // v2.1.1 开始可以不再返回 `startIndex` 这个偏移量(2.x 中是按照 ByteBuf 顺序读取的,用不到1.x中遗留的 `startIndex` 逻辑) final int startIndex = getBasicFieldStartIndex(evaluationContext, cls, instance, annotation, fieldMetadata); // Assertions.assertThat(startIndex >= 0, "field offset < 0 : [ " + fieldMetadata.getField() + " ]"); @@ -98,7 +106,7 @@ private void processBasicField( final Field field = fieldMetadata.getField(); if (converterClass != Jt808FieldDeserializer.PlaceholderFieldDeserializer.class) { final Jt808FieldDeserializer fieldDeserializer = getFieldDeserializer(converterClass); - deserialize(bodyDataBuf, instance, field, fieldDeserializer, jtDataType, startIndex, length, fieldMetadata); + deserialize(bodyDataBuf, instance, field, fieldDeserializer, jtDataType, startIndex, length, fieldMetadata, request); return; } @@ -141,15 +149,26 @@ private void processBasicField( .orElseThrow(() -> new Jt808AnnotationArgumentResolveException( "No Jt808FieldDeserializer found, Unsupported expectedTargetClassType " + javaDataType + " for field " + field)); - deserialize(bodyDataBuf, instance, field, deserializer, jtDataType, startIndex, length, fieldMetadata); + deserialize(bodyDataBuf, instance, field, deserializer, jtDataType, startIndex, length, fieldMetadata, request); + } + + private boolean shouldSkip(EvaluationContext evaluationContext, RequestField annotation) { + if (StringUtils.isEmpty(annotation.conditionalOn())) { + return false; + } + final Boolean condition = this.parser.parseExpression(annotation.conditionalOn()).getValue(evaluationContext, Boolean.class); + if (condition == null) { + return false; + } + return !condition; } private void deserialize( ByteBuf byteBuf, Object instance, Field field, - Jt808FieldDeserializer deserializer, MsgDataType jtDataType, int offset, int length, JavaBeanFieldMetadata fieldMetadata) { + Jt808FieldDeserializer deserializer, MsgDataType jtDataType, int offset, int length, JavaBeanFieldMetadata fieldMetadata, Jt808Request request) { final Object value = deserializer.deserialize(byteBuf, jtDataType, offset, length, - new Jt808FieldDeserializer.DefaultInternalDecoderContext(fieldMetadata)); + new Jt808FieldDeserializer.DefaultInternalDecoderContext(fieldMetadata, this, request)); if (log.isDebugEnabled()) { log.debug("Deserialize field [{}#{}] by {}, result : {}", @@ -276,4 +295,10 @@ private void processAwareMethod(Object instance, Jt808Request request) { } + /** + * @since 2.1.4 + */ + public Jt808FieldDeserializerRegistry basicFieldDeserializerRegistry() { + return this.jt808FieldDeserializerRegistry; + } } diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/codec/SimpleJt808MsgDecoder.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/codec/SimpleJt808MsgDecoder.java new file mode 100644 index 00000000..9d10fd33 --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/codec/SimpleJt808MsgDecoder.java @@ -0,0 +1,46 @@ +package io.github.hylexus.jt.jt808.support.annotation.codec; + +import io.github.hylexus.jt.common.JtCommonUtils; +import io.github.hylexus.jt.jt808.support.utils.ReflectionUtils; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; + +import java.util.function.Supplier; + +/** + * @author hylexus + * @since 2.1.4 + */ +public class SimpleJt808MsgDecoder { + private final Jt808AnnotationBasedDecoder delegate; + + private final ByteBufAllocator allocator = ByteBufAllocator.DEFAULT; + + public SimpleJt808MsgDecoder(Jt808AnnotationBasedDecoder delegate) { + this.delegate = delegate; + } + + public T decode(byte[] byteStream, Class cls) { + return this.decode(byteStream, cls, () -> ReflectionUtils.createInstance(cls)); + } + + public T decode(byte[] byteStream, Class cls, Supplier instanceSupplier) { + ByteBuf byteBuf = null; + try { + byteBuf = allocator.buffer(byteStream.length).writeBytes(byteStream); + return this.decode(byteBuf, cls, instanceSupplier); + } finally { + JtCommonUtils.release(byteBuf); + } + } + + public T decode(ByteBuf byteStream, Class cls) { + return this.decode(byteStream, cls, () -> ReflectionUtils.createInstance(cls)); + } + + public T decode(ByteBuf byteStream, Class cls, Supplier instanceSupplier) { + @SuppressWarnings("unchecked") final T result = (T) this.delegate.decode(cls, instanceSupplier.get(), byteStream, null); + return result; + } + +} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/RequestField.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/RequestField.java index 588fb023..2d205d4d 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/RequestField.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/RequestField.java @@ -103,4 +103,10 @@ Class> customerFieldDeserializerClass() default Jt808FieldDeserializer.PlaceholderFieldDeserializer.class; String desc() default ""; + + /** + * @return SpEL(Spring Expression Language); 解析之后的结果为true时才会反序列化该字段。 + * @since 2.1.4 + */ + String conditionalOn() default ""; } diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/RequestFieldAlias.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/RequestFieldAlias.java index f28b3379..14036d33 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/RequestFieldAlias.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/RequestFieldAlias.java @@ -1,8 +1,12 @@ package io.github.hylexus.jt.jt808.support.annotation.msg.req; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.extensions.ValueDescriptor; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.extensions.KeyValueMapping; import io.github.hylexus.jt.jt808.support.data.MsgDataType; import io.github.hylexus.jt.jt808.support.data.deserialize.extension.ExtendedJt808FieldDeserializerBcdTime; import io.github.hylexus.jt.jt808.support.data.deserialize.extension.ExtendedJt808FieldDeserializerGeoPoint; +import io.github.hylexus.jt.jt808.support.data.deserialize.extension.ExtendedJt808FieldDeserializerLocationExtraItem; +import io.github.hylexus.jt.jt808.support.data.type.byteseq.ByteArrayContainer; import org.springframework.core.annotation.AliasFor; import java.lang.annotation.*; @@ -24,6 +28,9 @@ @AliasFor(annotation = RequestField.class, attribute = "order") int order(); + @AliasFor(annotation = RequestField.class, attribute = "conditionalOn") + java.lang.String conditionalOn() default ""; + @AliasFor(annotation = RequestField.class, attribute = "desc") java.lang.String desc() default ""; } @@ -36,6 +43,9 @@ @AliasFor(annotation = RequestField.class, attribute = "order") int order(); + @AliasFor(annotation = RequestField.class, attribute = "conditionalOn") + java.lang.String conditionalOn() default ""; + @AliasFor(annotation = RequestField.class, attribute = "desc") java.lang.String desc() default ""; } @@ -48,6 +58,9 @@ @AliasFor(annotation = RequestField.class, attribute = "order") int order(); + @AliasFor(annotation = RequestField.class, attribute = "conditionalOn") + java.lang.String conditionalOn() default ""; + @AliasFor(annotation = RequestField.class, attribute = "length") int length() default -1; @@ -70,6 +83,9 @@ @AliasFor(annotation = RequestField.class, attribute = "order") int order(); + @AliasFor(annotation = RequestField.class, attribute = "conditionalOn") + java.lang.String conditionalOn() default ""; + @AliasFor(annotation = RequestField.class, attribute = "desc") java.lang.String desc() default ""; } @@ -91,6 +107,9 @@ @AliasFor(annotation = RequestField.class, attribute = "lengthMethod") java.lang.String lengthMethod() default ""; + @AliasFor(annotation = RequestField.class, attribute = "conditionalOn") + java.lang.String conditionalOn() default ""; + @AliasFor(annotation = RequestField.class, attribute = "desc") java.lang.String desc() default ""; } @@ -103,6 +122,9 @@ @AliasFor(annotation = RequestField.class, attribute = "order") int order(); + @AliasFor(annotation = RequestField.class, attribute = "conditionalOn") + java.lang.String conditionalOn() default ""; + @AliasFor(annotation = RequestField.class, attribute = "desc") java.lang.String desc() default ""; } @@ -115,6 +137,9 @@ @AliasFor(annotation = RequestField.class, attribute = "order") int order(); + @AliasFor(annotation = RequestField.class, attribute = "conditionalOn") + java.lang.String conditionalOn() default ""; + @AliasFor(annotation = RequestField.class, attribute = "length") int length() default -1; @@ -137,6 +162,9 @@ @AliasFor(annotation = RequestField.class, attribute = "charset") java.lang.String charset() default "GBK"; + @AliasFor(annotation = RequestField.class, attribute = "conditionalOn") + java.lang.String conditionalOn() default ""; + @AliasFor(annotation = RequestField.class, attribute = "order") int order(); @@ -170,6 +198,9 @@ @AliasFor(annotation = RequestField.class, attribute = "lengthMethod") java.lang.String lengthMethod() default ""; + @AliasFor(annotation = RequestField.class, attribute = "conditionalOn") + java.lang.String conditionalOn() default ""; + @AliasFor(annotation = RequestField.class, attribute = "desc") java.lang.String desc() default ""; } @@ -182,7 +213,45 @@ @AliasFor(annotation = RequestField.class, attribute = "order") int order(); + @AliasFor(annotation = RequestField.class, attribute = "conditionalOn") + java.lang.String conditionalOn() default ""; + + @AliasFor(annotation = RequestField.class, attribute = "desc") + java.lang.String desc() default ""; + } + + /** + * 位置附加项 + * + * @since 2.1.4 + */ + @Target({ElementType.FIELD}) + @Retention(RetentionPolicy.RUNTIME) + @Documented + @RequestField(dataType = MsgDataType.OBJECT, order = -1, customerFieldDeserializerClass = ExtendedJt808FieldDeserializerLocationExtraItem.class) + @interface LocationMsgExtraItemMapping { + + @AliasFor(annotation = RequestField.class, attribute = "order") + int order(); + + @AliasFor(annotation = RequestField.class, attribute = "conditionalOn") + java.lang.String conditionalOn() default ""; + + @AliasFor(annotation = RequestField.class, attribute = "length") + int length() default -1; + + @AliasFor(annotation = RequestField.class, attribute = "lengthExpression") + java.lang.String lengthExpression() default ""; + + @AliasFor(annotation = RequestField.class, attribute = "lengthMethod") + java.lang.String lengthMethod() default ""; + @AliasFor(annotation = RequestField.class, attribute = "desc") java.lang.String desc() default ""; + + KeyValueMapping[] keyValueMappings(); + + ValueDescriptor defaultKeyValueMapping() default @ValueDescriptor(source = MsgDataType.BYTES, target = ByteArrayContainer.class); + } } diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/extensions/KeyValueMapping.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/extensions/KeyValueMapping.java new file mode 100644 index 00000000..6d414e5b --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/extensions/KeyValueMapping.java @@ -0,0 +1,10 @@ +package io.github.hylexus.jt.jt808.support.annotation.msg.req.extensions; + +public @interface KeyValueMapping { + + int key(); + + ValueDescriptor value(); + + String desc() default ""; +} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/extensions/ValueDescriptor.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/extensions/ValueDescriptor.java new file mode 100644 index 00000000..3ecab481 --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/annotation/msg/req/extensions/ValueDescriptor.java @@ -0,0 +1,10 @@ +package io.github.hylexus.jt.jt808.support.annotation.msg.req.extensions; + +import io.github.hylexus.jt.jt808.support.data.MsgDataType; + +public @interface ValueDescriptor { + + MsgDataType source(); + + Class target(); +} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/data/deserialize/Jt808FieldDeserializer.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/data/deserialize/Jt808FieldDeserializer.java index f9591fd8..dfa70287 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/data/deserialize/Jt808FieldDeserializer.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/data/deserialize/Jt808FieldDeserializer.java @@ -1,11 +1,14 @@ package io.github.hylexus.jt.jt808.support.data.deserialize; import io.github.hylexus.jt.core.ReplaceableComponent; +import io.github.hylexus.jt.jt808.spec.Jt808Request; +import io.github.hylexus.jt.jt808.support.annotation.codec.Jt808AnnotationBasedDecoder; import io.github.hylexus.jt.jt808.support.data.MsgDataType; import io.github.hylexus.jt.jt808.support.data.RequestMsgConvertibleMetadata; import io.github.hylexus.jt.jt808.support.data.meta.JavaBeanFieldMetadata; import io.netty.buffer.ByteBuf; +import javax.annotation.Nullable; import java.util.Set; /** @@ -31,20 +34,46 @@ default T deserialize(ByteBuf byteBuf, MsgDataType msgDataType, int start, int l interface Context { JavaBeanFieldMetadata fieldMetadata(); + + /** + * @since 2.1.4 + */ + @Nullable + Jt808AnnotationBasedDecoder delegate(); + + /** + * @since 2.1.4 + */ + @Nullable + Jt808Request request(); } class DefaultInternalDecoderContext implements Context { private final JavaBeanFieldMetadata fieldMetadata; + private final Jt808AnnotationBasedDecoder delegate; + private final Jt808Request request; - public DefaultInternalDecoderContext(JavaBeanFieldMetadata fieldMetadata) { + public DefaultInternalDecoderContext(JavaBeanFieldMetadata fieldMetadata, Jt808AnnotationBasedDecoder delegate, Jt808Request request) { this.fieldMetadata = fieldMetadata; + this.delegate = delegate; + this.request = request; } @Override public JavaBeanFieldMetadata fieldMetadata() { return this.fieldMetadata; } + + @Override + public Jt808AnnotationBasedDecoder delegate() { + return this.delegate; + } + + @Override + public Jt808Request request() { + return this.request; + } } @Override diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/data/deserialize/extension/ExtendedJt808FieldDeserializerLocationExtraItem.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/data/deserialize/extension/ExtendedJt808FieldDeserializerLocationExtraItem.java new file mode 100644 index 00000000..78d4763d --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/data/deserialize/extension/ExtendedJt808FieldDeserializerLocationExtraItem.java @@ -0,0 +1,90 @@ +package io.github.hylexus.jt.jt808.support.data.deserialize.extension; + +import io.github.hylexus.jt.common.JtCommonUtils; +import io.github.hylexus.jt.exception.JtIllegalStateException; +import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg0200V2019AliasV2; +import io.github.hylexus.jt.jt808.support.annotation.codec.Jt808AnnotationBasedDecoder; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.RequestFieldAlias; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.extensions.KeyValueMapping; +import io.github.hylexus.jt.jt808.support.annotation.msg.req.extensions.ValueDescriptor; +import io.github.hylexus.jt.jt808.support.data.MsgDataType; +import io.github.hylexus.jt.jt808.support.data.RequestMsgConvertibleMetadata; +import io.github.hylexus.jt.jt808.support.data.deserialize.Jt808FieldDeserializer; +import io.github.hylexus.jt.jt808.support.utils.ReflectionUtils; +import io.netty.buffer.ByteBuf; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; + +/** + * @see RequestFieldAlias.LocationMsgExtraItemMapping + * @see BuiltinMsg0200V2019AliasV2#getExtraItemMap() + */ +public class ExtendedJt808FieldDeserializerLocationExtraItem extends AbstractExtendedJt808FieldDeserializer { + + private final Map defaultMapping = new HashMap<>(); + private final Map> keyValueMappingCache = new HashMap<>(); + + @Override + public Object deserialize(ByteBuf byteBuf, MsgDataType msgDataType, int start, int length, Context context) { + final Jt808AnnotationBasedDecoder annotationBasedDecoder = context.delegate(); + if (annotationBasedDecoder == null) { + throw new JtIllegalStateException("Jt808AnnotationBasedDecoder is null"); + } + + final Map result = new LinkedHashMap<>(); + while (byteBuf.isReadable()) { + final int key = byteBuf.readUnsignedByte(); + final int valueLength = byteBuf.readUnsignedByte(); + final ByteBuf valueContent = byteBuf.readBytes(valueLength); + try { + final RequestMsgConvertibleMetadata convertibleMetadata = getValueType(context, key); + final Optional> basicConverter = annotationBasedDecoder.basicFieldDeserializerRegistry().getConverter(convertibleMetadata); + + final Object decodedValue; + if (basicConverter.isPresent()) { + decodedValue = basicConverter.get().deserialize(valueContent, convertibleMetadata.getSourceDataType(), 0, valueLength); + } else { + decodedValue = annotationBasedDecoder.decode(convertibleMetadata.getTargetClass(), ReflectionUtils.createInstance(convertibleMetadata.getTargetClass()), valueContent, context.request()); + } + result.put(key, decodedValue); + } finally { + JtCommonUtils.release(valueContent); + } + } + + return result; + } + + private RequestMsgConvertibleMetadata getValueType(Context context, int key) { + final Field field = context.fieldMetadata().getField(); + Map map = keyValueMappingCache.get(field); + if (map == null) { + this.initMetadata(context, field); + map = keyValueMappingCache.get(field); + } + final RequestMsgConvertibleMetadata metadata = map.get(key); + if (metadata == null) { + return Optional.ofNullable(defaultMapping.get(field)) + .orElseGet(() -> RequestMsgConvertibleMetadata.forJt808RequestMsgDataType(MsgDataType.BYTES, byte[].class)); + } + return metadata; + } + + private void initMetadata(Context context, Field currentField) { + final RequestFieldAlias.LocationMsgExtraItemMapping annotation = (RequestFieldAlias.LocationMsgExtraItemMapping) context.fieldMetadata().getAnnotationCache().get(RequestFieldAlias.LocationMsgExtraItemMapping.class); + final KeyValueMapping[] valueTypeMappings = annotation.keyValueMappings(); + for (final KeyValueMapping valueTypeMapping : valueTypeMappings) { + final int key = valueTypeMapping.key(); + final ValueDescriptor valueDescriptor = valueTypeMapping.value(); + final Map cache = keyValueMappingCache.computeIfAbsent(currentField, field -> new HashMap<>()); + cache.put(key, RequestMsgConvertibleMetadata.forJt808RequestMsgDataType(valueDescriptor.source(), valueDescriptor.target())); + } + + defaultMapping.put(currentField, RequestMsgConvertibleMetadata.forJt808RequestMsgDataType(annotation.defaultKeyValueMapping().source(), annotation.defaultKeyValueMapping().target())); + } + +} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/dispatcher/handler/builtin/BuiltinCommonHandler.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/dispatcher/handler/builtin/BuiltinCommonHandler.java index 760c3f95..12fde63a 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/dispatcher/handler/builtin/BuiltinCommonHandler.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/dispatcher/handler/builtin/BuiltinCommonHandler.java @@ -21,7 +21,7 @@ public class BuiltinCommonHandler { @Jt808RequestHandlerMapping(msgType = 0x0002) public BuiltinServerCommonReplyMsg processTerminalHeartBeatMsg(Jt808RequestEntity request) { - log.info("TerminalHeartBeatMsg, terminalId={}, flowId={}", request.terminalId(), request.flowId()); + log.info("TerminalHeartBeatMsg, terminalId={}, flowId={}, role={}", request.terminalId(), request.flowId(), request.session().role()); return BuiltinServerCommonReplyMsg.success(request.msgType().getMsgId(), request.flowId()); } diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808CommandSender.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808CommandSender.java deleted file mode 100644 index 8746deaf..00000000 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808CommandSender.java +++ /dev/null @@ -1,6 +0,0 @@ -package io.github.hylexus.jt.jt808.support.extension.attachment; - -import io.github.hylexus.jt.jt808.spec.Jt808CommandSenderInternal; - -public interface AttachmentJt808CommandSender extends Jt808CommandSenderInternal { -} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808DispatchChannelHandlerAdapter.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808DispatchChannelHandlerAdapter.java index 52967bf8..4096ef8c 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808DispatchChannelHandlerAdapter.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808DispatchChannelHandlerAdapter.java @@ -2,6 +2,7 @@ import io.github.hylexus.jt.jt808.support.netty.InternalJt808DispatchChannelHandlerAdapter; import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; import lombok.extern.slf4j.Slf4j; /** @@ -12,8 +13,19 @@ @ChannelHandler.Sharable public class AttachmentJt808DispatchChannelHandlerAdapter extends InternalJt808DispatchChannelHandlerAdapter { - public AttachmentJt808DispatchChannelHandlerAdapter(AttachmentJt808RequestProcessor requestProcessor, AttachmentJt808SessionManager sessionManager) { - super(requestProcessor, sessionManager); + public AttachmentJt808DispatchChannelHandlerAdapter(AttachmentJt808RequestProcessor requestProcessor) { + super(requestProcessor, null); } + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + log.error("[exceptionCaught]", cause); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (log.isDebugEnabled()) { + log.debug("channelInactive, address={} ", ctx.channel().remoteAddress()); + } + } } diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808SessionManager.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808SessionManager.java deleted file mode 100644 index ba8b4a78..00000000 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808SessionManager.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.github.hylexus.jt.jt808.support.extension.attachment; - -import io.github.hylexus.jt.jt808.spec.session.InternalJt808SessionManager; -import io.github.hylexus.jt.jt808.spec.session.Jt808SessionEventListener; - -import java.util.List; - -public interface AttachmentJt808SessionManager extends InternalJt808SessionManager { - - AttachmentJt808SessionManager addListener(Jt808SessionEventListener listener); - - List getListeners(); -} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808TerminalHeatBeatHandler.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808TerminalHeatBeatHandler.java new file mode 100644 index 00000000..caee25a6 --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/AttachmentJt808TerminalHeatBeatHandler.java @@ -0,0 +1,36 @@ +package io.github.hylexus.jt.jt808.support.extension.attachment; + +import io.github.hylexus.jt.annotation.BuiltinComponent; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.timeout.IdleStateEvent; +import lombok.extern.slf4j.Slf4j; + +/** + * @author hylexus + */ +@Slf4j +@ChannelHandler.Sharable +@BuiltinComponent +public class AttachmentJt808TerminalHeatBeatHandler extends ChannelInboundHandlerAdapter { + + public AttachmentJt808TerminalHeatBeatHandler() { + } + + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (!(evt instanceof IdleStateEvent)) { + super.userEventTriggered(ctx, evt); + return; + } + + try { + ctx.channel().close(); + } catch (Exception ignored) { + // ignored + } + + } +} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/Jt808AttachmentServerNettyConfigure.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/Jt808AttachmentServerNettyConfigure.java index 7a08181d..8901cbcd 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/Jt808AttachmentServerNettyConfigure.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/Jt808AttachmentServerNettyConfigure.java @@ -1,54 +1,7 @@ package io.github.hylexus.jt.jt808.support.extension.attachment; -import io.github.hylexus.jt.annotation.BuiltinComponent; import io.github.hylexus.jt.netty.JtServerNettyConfigure; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.socket.SocketChannel; -import io.netty.util.concurrent.EventExecutorGroup; -import lombok.Data; - -import static io.github.hylexus.jt.jt808.JtProtocolConstant.NETTY_HANDLER_NAME_808_FRAME; -import static io.github.hylexus.jt.jt808.JtProtocolConstant.NETTY_HANDLER_NAME_808_MSG_DISPATCHER_ADAPTER; public interface Jt808AttachmentServerNettyConfigure extends JtServerNettyConfigure { - @BuiltinComponent - class DefaultJt808AttachmentServerNettyConfigure implements Jt808AttachmentServerNettyConfigure { - private final DefaultJt808AttachmentServerNettyConfigure.BuiltInServerBootstrapProps serverBootstrapProps; - private final ChannelInboundHandlerAdapter jt808DispatchChannelHandlerAdapter; - private final EventExecutorGroup eventExecutorGroup; - - public DefaultJt808AttachmentServerNettyConfigure( - DefaultJt808AttachmentServerNettyConfigure.BuiltInServerBootstrapProps serverBootstrapProps, - ChannelInboundHandlerAdapter channelHandlerAdapter, - EventExecutorGroup eventExecutorGroup) { - - this.serverBootstrapProps = serverBootstrapProps; - this.jt808DispatchChannelHandlerAdapter = channelHandlerAdapter; - this.eventExecutorGroup = eventExecutorGroup; - } - - @Override - public void configureSocketChannel(SocketChannel ch) { - ch.pipeline().addLast( - NETTY_HANDLER_NAME_808_FRAME, - new DelimiterAndLengthFieldBasedByteToMessageDecoder( - serverBootstrapProps.getDelimiterBasedFrameMaxFrameLength(), - serverBootstrapProps.getLengthFieldBasedFrameMaxFrameLength() - ) - ); - ch.pipeline().addLast(this.eventExecutorGroup, NETTY_HANDLER_NAME_808_MSG_DISPATCHER_ADAPTER, jt808DispatchChannelHandlerAdapter); - } - - @Data - public static class BuiltInServerBootstrapProps { - final int delimiterBasedFrameMaxFrameLength; - final int lengthFieldBasedFrameMaxFrameLength; - - public BuiltInServerBootstrapProps(int delimiterBasedFrameMaxFrameLength, int lengthFieldBasedFrameMaxFrameLength) { - this.delimiterBasedFrameMaxFrameLength = delimiterBasedFrameMaxFrameLength; - this.lengthFieldBasedFrameMaxFrameLength = lengthFieldBasedFrameMaxFrameLength; - } - } - } } diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/DefaultAttachmentJt808CommandSender.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/DefaultAttachmentJt808CommandSender.java deleted file mode 100644 index 9b610b90..00000000 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/DefaultAttachmentJt808CommandSender.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.github.hylexus.jt.jt808.support.extension.attachment.impl; - -import io.github.hylexus.jt.jt808.spec.Jt808Response; -import io.github.hylexus.jt.jt808.spec.impl.AbstractJt808CommandSender; -import io.github.hylexus.jt.jt808.spec.session.Jt808Session; -import io.github.hylexus.jt.jt808.support.annotation.codec.Jt808AnnotationBasedEncoder; -import io.github.hylexus.jt.jt808.support.codec.Jt808MsgEncoder; -import io.github.hylexus.jt.jt808.support.exception.Jt808EncodeException; -import io.github.hylexus.jt.jt808.support.extension.attachment.AttachmentJt808CommandSender; -import io.github.hylexus.jt.jt808.support.extension.attachment.AttachmentJt808SessionManager; -import io.netty.buffer.ByteBuf; - -public class DefaultAttachmentJt808CommandSender extends AbstractJt808CommandSender implements AttachmentJt808CommandSender { - private final Jt808MsgEncoder msgEncoder; - private final Jt808AnnotationBasedEncoder annotationBasedEncoder; - - public DefaultAttachmentJt808CommandSender(AttachmentJt808SessionManager sessionManager, Jt808MsgEncoder msgEncoder, Jt808AnnotationBasedEncoder annotationBasedEncoder) { - super(sessionManager); - this.msgEncoder = msgEncoder; - this.annotationBasedEncoder = annotationBasedEncoder; - } - - @Override - protected ByteBuf encode(Jt808Session session, Jt808Response response) throws Jt808EncodeException { - return this.msgEncoder.encode(response, session); - } - - @Override - protected ByteBuf encode(Jt808Session session, Object response, int serverFlowId) throws Jt808EncodeException { - final Jt808Response jt808Response = this.annotationBasedEncoder.encode(response, session, serverFlowId); - return this.encode(session, jt808Response); - } -} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/DefaultAttachmentJt808SessionManager.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/DefaultAttachmentJt808SessionManager.java deleted file mode 100644 index cd0964ac..00000000 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/DefaultAttachmentJt808SessionManager.java +++ /dev/null @@ -1,195 +0,0 @@ -package io.github.hylexus.jt.jt808.support.extension.attachment.impl; - -import io.github.hylexus.jt.annotation.BuiltinComponent; -import io.github.hylexus.jt.jt808.Jt808ProtocolVersion; -import io.github.hylexus.jt.jt808.spec.session.*; -import io.github.hylexus.jt.jt808.support.extension.attachment.AttachmentJt808SessionManager; -import io.netty.channel.Channel; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.stream.Stream; - -// TODO 重构两个 SessionManager -@Slf4j -@BuiltinComponent -public class DefaultAttachmentJt808SessionManager implements AttachmentJt808SessionManager { - - private final Jt808FlowIdGeneratorFactory flowIdGeneratorFactory; - - private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - // - private final Map sessionMap = new ConcurrentHashMap<>(); - // - private final Map sessionIdTerminalIdMapping = new ConcurrentHashMap<>(); - - private final List listeners = new ArrayList<>(); - - public DefaultAttachmentJt808SessionManager(Jt808FlowIdGeneratorFactory flowIdGeneratorFactory) { - this.flowIdGeneratorFactory = flowIdGeneratorFactory; - } - - public Stream list() { - this.lock.readLock().lock(); - try { - return sessionMap.values().stream(); - } finally { - this.lock.readLock().unlock(); - } - } - - public long count() { - return sessionMap.size(); - } - - @Override - public long count(Predicate filter) { - return this.sessionMap.values().stream().filter(filter).count(); - } - - @Override - public Jt808Session generateSession(String terminalId, Jt808ProtocolVersion version, Channel channel) { - final Jt808FlowIdGenerator flowIdGenerator = this.flowIdGeneratorFactory.create(); - return buildSession(terminalId, version, channel, flowIdGenerator); - } - - protected DefaultJt808Session buildSession(String terminalId, Jt808ProtocolVersion version, Channel channel, Jt808FlowIdGenerator flowIdGenerator) { - final DefaultJt808Session session = new DefaultJt808Session(flowIdGenerator); - session.channel(channel); - session.id(generateSessionId(channel)); - session.terminalId(terminalId); - session.lastCommunicateTimestamp(System.currentTimeMillis()); - session.protocolVersion(version); - session.role(Jt808Session.Role.ATTACHMENT); - return session; - } - - @Override - public Optional findBySessionId(String sessionId) { - String terminalId = sessionIdTerminalIdMapping.get(sessionId); - if (StringUtils.isEmpty(terminalId)) { - return Optional.empty(); - } - return findByTerminalId(terminalId, false); - } - - @Override - public Jt808Session persistenceIfNecessary(String terminalId, Jt808ProtocolVersion version, Channel channel, boolean updateLastCommunicateTime) { - final Optional session = findByTerminalId(terminalId, updateLastCommunicateTime); - if (session.isPresent()) { - Jt808Session oldSession = session.get(); - if (oldSession.channel() != channel) { - log.warn("replace channel for terminal({}), new:{}, old:{}", terminalId, channel.remoteAddress(), oldSession.channel().remoteAddress()); - // 单个终端一般来说不会有高并发的问题,这里就不加锁了 - // 有必要的话,可以自己复写该方法或实现自己的SessionManager - oldSession.channel(channel); - } - return oldSession; - } - final Jt808Session newSession = generateSession(terminalId, version, channel); - persistence(newSession); - return newSession; - } - - @Override - public void persistence(Jt808Session session) { - lock.writeLock().lock(); - try { - this.sessionMap.put(session.terminalId(), session); - sessionIdTerminalIdMapping.put(session.id(), session.terminalId()); - } finally { - lock.writeLock().unlock(); - } - this.invokeListeners(listener -> listener.onSessionAdd(session)); - } - - private void invokeListeners(Consumer consumer) { - for (Jt808SessionEventListener listener : this.listeners) { - try { - consumer.accept(listener); - } catch (Throwable e) { - log.error("An error occurred while invoke Jt808SessionManagerEventListener", e); - } - } - } - - @Override - public Jt808Session removeBySessionId(String sessionId) { - lock.writeLock().lock(); - try { - final String terminalId = sessionIdTerminalIdMapping.remove(sessionId); - if (terminalId != null) { - final Jt808Session session = sessionMap.remove(terminalId); - this.invokeListeners(listener -> listener.onSessionRemove(session)); - return session; - } - } finally { - lock.writeLock().unlock(); - } - - return null; - } - - @Override - public void removeBySessionIdAndClose(String sessionId, SessionCloseReason reason) { - lock.writeLock().lock(); - try { - final Jt808Session session = this.removeBySessionId(sessionId); - if (session != null) { - invokeListeners(listener -> listener.onSessionClose(session, reason)); - session.channel().close(); - } - } finally { - lock.writeLock().unlock(); - } - } - - @Override - public Optional findByTerminalId(String terminalId, boolean updateLastCommunicateTime) { - final Jt808Session session = sessionMap.get(terminalId); - if (session == null) { - return Optional.empty(); - } - - if (updateLastCommunicateTime) { - session.lastCommunicateTimestamp(System.currentTimeMillis()); - } - - if (!this.checkStatus(session)) { - return Optional.empty(); - } - - return Optional.of(session); - } - - private boolean checkStatus(Jt808Session session) { - // if (!session.getChannel().isOpen()) { - if (!session.channel().isActive()) { - if (log.isDebugEnabled()) { - log.debug("Remove session [{}], because channel !isActive() ", session.terminalId()); - } - this.removeBySessionIdAndClose(session.id(), DefaultSessionCloseReason.CHANNEL_INACTIVE); - return false; - } - return true; - } - - @Override - public synchronized AttachmentJt808SessionManager addListener(Jt808SessionEventListener listener) { - this.listeners.add(listener); - return this; - } - - @Override - public List getListeners() { - return listeners; - } -} diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/DefaultJt808AttachmentServerNettyConfigure.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/DefaultJt808AttachmentServerNettyConfigure.java new file mode 100644 index 00000000..462bf1e8 --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/DefaultJt808AttachmentServerNettyConfigure.java @@ -0,0 +1,72 @@ +package io.github.hylexus.jt.jt808.support.extension.attachment.impl; + +import io.github.hylexus.jt.annotation.BuiltinComponent; +import io.github.hylexus.jt.jt808.support.extension.attachment.AttachmentJt808TerminalHeatBeatHandler; +import io.github.hylexus.jt.jt808.support.extension.attachment.DelimiterAndLengthFieldBasedByteToMessageDecoder; +import io.github.hylexus.jt.jt808.support.extension.attachment.Jt808AttachmentServerNettyConfigure; +import io.github.hylexus.jt.jt808.support.netty.InternalIdleStateHandlerProps; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.timeout.IdleStateHandler; +import io.netty.util.concurrent.EventExecutorGroup; +import lombok.Data; + +import java.util.concurrent.TimeUnit; + +import static io.github.hylexus.jt.jt808.JtProtocolConstant.*; + +@BuiltinComponent +public class DefaultJt808AttachmentServerNettyConfigure implements Jt808AttachmentServerNettyConfigure { + + private final DefaultJt808AttachmentServerNettyConfigure.BuiltInServerBootstrapProps serverBootstrapProps; + private final ChannelInboundHandlerAdapter jt808DispatchChannelHandlerAdapter; + private final EventExecutorGroup eventExecutorGroup; + private final AttachmentJt808TerminalHeatBeatHandler heatBeatHandler; + + public DefaultJt808AttachmentServerNettyConfigure( + DefaultJt808AttachmentServerNettyConfigure.BuiltInServerBootstrapProps serverBootstrapProps, + ChannelInboundHandlerAdapter channelHandlerAdapter, + EventExecutorGroup eventExecutorGroup, AttachmentJt808TerminalHeatBeatHandler heatBeatHandler) { + + this.serverBootstrapProps = serverBootstrapProps; + this.jt808DispatchChannelHandlerAdapter = channelHandlerAdapter; + this.eventExecutorGroup = eventExecutorGroup; + this.heatBeatHandler = heatBeatHandler; + } + + @Override + public void configureSocketChannel(SocketChannel ch) { + if (serverBootstrapProps.getIdleStateHandlerProps().isEnabled()) { + final long readerIdleTime = serverBootstrapProps.getIdleStateHandlerProps().getReaderIdleTime().toMillis(); + final long writerIdleTime = serverBootstrapProps.getIdleStateHandlerProps().getWriterIdleTime().toMillis(); + final long allIdleTime = serverBootstrapProps.getIdleStateHandlerProps().getAllIdleTime().toMillis(); + ch.pipeline().addLast( + NETTY_HANDLER_NAME_ATTACHMENT_808_IDLE_STATE, + new IdleStateHandler(readerIdleTime, writerIdleTime, allIdleTime, TimeUnit.MILLISECONDS) + ); + } + ch.pipeline().addLast(BEAN_NAME_NETTY_HANDLER_NAME_ATTACHMENT_808_HEART_BEAT, heatBeatHandler); + ch.pipeline().addLast( + NETTY_HANDLER_NAME_ATTACHMENT_808_FRAME, + new DelimiterAndLengthFieldBasedByteToMessageDecoder( + serverBootstrapProps.getDelimiterBasedFrameMaxFrameLength(), + serverBootstrapProps.getLengthFieldBasedFrameMaxFrameLength() + ) + ); + + ch.pipeline().addLast(this.eventExecutorGroup, NETTY_HANDLER_NAME_808_MSG_DISPATCHER_ADAPTER, jt808DispatchChannelHandlerAdapter); + } + + @Data + public static class BuiltInServerBootstrapProps { + final int delimiterBasedFrameMaxFrameLength; + final int lengthFieldBasedFrameMaxFrameLength; + final InternalIdleStateHandlerProps idleStateHandlerProps; + + public BuiltInServerBootstrapProps(int delimiterBasedFrameMaxFrameLength, int lengthFieldBasedFrameMaxFrameLength, InternalIdleStateHandlerProps idleStateHandlerProps) { + this.delimiterBasedFrameMaxFrameLength = delimiterBasedFrameMaxFrameLength; + this.lengthFieldBasedFrameMaxFrameLength = lengthFieldBasedFrameMaxFrameLength; + this.idleStateHandlerProps = idleStateHandlerProps; + } + } +} \ No newline at end of file diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/SimpleAttachmentJt808RequestProcessor.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/SimpleAttachmentJt808RequestProcessor.java index 3ae30429..f587323c 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/SimpleAttachmentJt808RequestProcessor.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/extension/attachment/impl/SimpleAttachmentJt808RequestProcessor.java @@ -6,13 +6,13 @@ import io.github.hylexus.jt.jt808.spec.impl.DefaultJt808ServerExchange; import io.github.hylexus.jt.jt808.spec.impl.response.DefaultJt808Response; import io.github.hylexus.jt.jt808.spec.session.Jt808Session; +import io.github.hylexus.jt.jt808.spec.session.Jt808SessionManager; import io.github.hylexus.jt.jt808.support.codec.Jt808MsgDecoder; import io.github.hylexus.jt.jt808.support.codec.Jt808RequestRouteExceptionHandler; import io.github.hylexus.jt.jt808.support.dispatcher.Jt808DispatcherHandler; import io.github.hylexus.jt.jt808.support.dispatcher.Jt808RequestMsgDispatcher; import io.github.hylexus.jt.jt808.support.exception.Jt808UnknownMsgException; import io.github.hylexus.jt.jt808.support.extension.attachment.AttachmentJt808RequestProcessor; -import io.github.hylexus.jt.jt808.support.extension.attachment.AttachmentJt808SessionManager; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.util.AttributeKey; @@ -27,11 +27,11 @@ public class SimpleAttachmentJt808RequestProcessor implements AttachmentJt808Req private final Jt808RequestMsgDispatcher msgDispatcher; private final Jt808DispatcherHandler dispatcherHandler; - private final AttachmentJt808SessionManager sessionManager; + private final Jt808SessionManager sessionManager; public SimpleAttachmentJt808RequestProcessor( Jt808MsgDecoder decoder, - AttachmentJt808SessionManager sessionManager, + Jt808SessionManager sessionManager, Jt808RequestRouteExceptionHandler routeExceptionHandler, Jt808RequestMsgDispatcher msgDispatcher, Jt808DispatcherHandler dispatcherHandler) { @@ -100,6 +100,7 @@ private void handleRequest(Jt808Request originalRequest, Jt808Session jt808Sessi exchange = new DefaultJt808ServerExchange(originalRequest, originalResponse, jt808Session); dispatcherHandler.handleRequest(exchange); } finally { + originalRequest.release(); if (exchange != null && exchange.response() != originalResponse) { originalResponse.release(); } @@ -111,9 +112,11 @@ private void handleRequest(Jt808Request originalRequest, Jt808Session jt808Sessi private Jt808Session persistenceSessionIfNecessary(Channel channel, Jt808Request request) { final Jt808Session session = this.getSession(channel); if (session != null) { - return session; + return session.lastCommunicateTimestamp(System.currentTimeMillis()); } - final Jt808Session attachmentSession = sessionManager.persistenceIfNecessary(request.terminalId(), request.version(), channel); + final Jt808Session attachmentSession = sessionManager.generateSession(request.terminalId(), request.version(), channel, Jt808Session.Role.ATTACHMENT); + + // sessionManager.persistenceIfNecessary(request.terminalId(), request.version(), channel); channel.attr(SESSION_ATTR_KEY).set(attachmentSession); return attachmentSession; } diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/netty/InternalIdleStateHandlerProps.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/netty/InternalIdleStateHandlerProps.java new file mode 100644 index 00000000..2b499352 --- /dev/null +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/netty/InternalIdleStateHandlerProps.java @@ -0,0 +1,20 @@ +package io.github.hylexus.jt.jt808.support.netty; + +import lombok.Data; + +import java.time.Duration; + +@Data +public class InternalIdleStateHandlerProps { + private boolean enabled; + private Duration readerIdleTime; + private Duration writerIdleTime; + private Duration allIdleTime; + + public InternalIdleStateHandlerProps(boolean enabled, Duration readerIdleTime, Duration writerIdleTime, Duration allIdleTime) { + this.enabled = enabled; + this.readerIdleTime = readerIdleTime; + this.writerIdleTime = writerIdleTime; + this.allIdleTime = allIdleTime; + } +} \ No newline at end of file diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/netty/Jt808ServerNettyConfigure.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/netty/Jt808ServerNettyConfigure.java index 93453cae..52216182 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/netty/Jt808ServerNettyConfigure.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/netty/Jt808ServerNettyConfigure.java @@ -68,14 +68,6 @@ public DefaultJt808ServerNettyConfigure( this.eventExecutorGroup = eventExecutorGroup; } - @Override - public void configureServerBootstrap(ServerBootstrap serverBootstrap) { - serverBootstrap - .option(ChannelOption.SO_BACKLOG, 2048) - .option(ChannelOption.SO_REUSEADDR, true) - .childOption(ChannelOption.SO_KEEPALIVE, true); - } - @Override public void configureSocketChannel(SocketChannel ch) { if (serverBootstrapProps.getIdleStateHandlerProps().isEnabled()) { diff --git a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/utils/JavaBeanMetadataUtils.java b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/utils/JavaBeanMetadataUtils.java index 101b1d3f..6b227a11 100644 --- a/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/utils/JavaBeanMetadataUtils.java +++ b/jt-808-server-support/src/main/java/io/github/hylexus/jt/jt808/support/utils/JavaBeanMetadataUtils.java @@ -79,7 +79,9 @@ private static JavaBeanMetadata buildClassMetadata(Class cls) { javaBeanFieldMetadata.setRequestFieldLengthExtractor(RequestFieldLengthExtractor.createFor(fieldType, annotation.dataType(), annotation)); javaBeanFieldMetadata.setFieldCharset(Charset.forName(annotation.charset())); javaBeanMetadata.getRequestFieldMetadataList().add(javaBeanFieldMetadata); - } else if (javaBeanFieldMetadata.isAnnotationPresent(ResponseField.class)) { + } + + if (javaBeanFieldMetadata.isAnnotationPresent(ResponseField.class)) { final ResponseField annotation = javaBeanFieldMetadata.getAnnotation(ResponseField.class); javaBeanFieldMetadata.setOrder(annotation.order()); javaBeanMetadata.getResponseFieldMetadataList().add(javaBeanFieldMetadata); diff --git a/jt-808-server-support/src/test/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg0200V2Test.java b/jt-808-server-support/src/test/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg0200V2Test.java new file mode 100644 index 00000000..2fc66003 --- /dev/null +++ b/jt-808-server-support/src/test/java/io/github/hylexus/jt/jt808/spec/builtin/msg/req/BuiltinMsg0200V2Test.java @@ -0,0 +1,14 @@ +package io.github.hylexus.jt.jt808.spec.builtin.msg.req; + +import io.github.hylexus.jt.jt808.spec.builtin.msg.BaseReqRespMsgTest; +import org.junit.jupiter.api.Test; + +class BuiltinMsg0200V2Test extends BaseReqRespMsgTest { + final String hex = "7e0200409C0100000000014499999999002800000002004C01C302161B5F077365DF006407BF000024012811312801040000005D020201F1030207BF04020000051ED3D4D5D6D3D4D5D3D4D5DDDEDFDDDEDFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0602001E1101002504000000002A0200002B0400000000300108310109642F000000890001013232000000C600640216196B077363EB240128113118040169643030303033240128113123000400A37e"; + + @Test + void test2019Alias() { + final BuiltinMsg0200V2019AliasV2 msg = decode(hex, BuiltinMsg0200V2019AliasV2.class); + final BuiltinMsg0200V2019AliasV2 msg1 = decode(hex, BuiltinMsg0200V2019AliasV2.class); + } +} \ No newline at end of file diff --git a/jt-808-server-support/src/test/java/io/github/hylexus/jt/jt808/spec/builtin/msg/resp/BuiltinMsg9208AliasTest.java b/jt-808-server-support/src/test/java/io/github/hylexus/jt/jt808/spec/builtin/msg/resp/BuiltinMsg9208AliasTest.java new file mode 100644 index 00000000..d6bbe207 --- /dev/null +++ b/jt-808-server-support/src/test/java/io/github/hylexus/jt/jt808/spec/builtin/msg/resp/BuiltinMsg9208AliasTest.java @@ -0,0 +1,38 @@ +package io.github.hylexus.jt.jt808.spec.builtin.msg.resp; + +import io.github.hylexus.jt.jt808.Jt808ProtocolVersion; +import io.github.hylexus.jt.jt808.spec.builtin.msg.BaseReqRespMsgTest; +import io.github.hylexus.jt.jt808.spec.builtin.msg.extension.location.AlarmIdentifierAlias; +import io.github.hylexus.jt.jt808.spec.impl.BuiltinJt808MsgType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; + +public class BuiltinMsg9208AliasTest extends BaseReqRespMsgTest { + @Test + void test() { + + final String serverIp = "192.168.71.119"; + final BuiltinMsg9208Alias msg = new BuiltinMsg9208Alias() + .setAttachmentServerIpLength((short) serverIp.getBytes(StandardCharsets.UTF_8).length) + .setAttachmentServerIp(serverIp) + .setAttachmentServerPortTcp(6808) + .setAttachmentServerPortUdp(0) + .setAlarmIdentifier(new AlarmIdentifierAlias() + .setTerminalId("id00003") + .setTime(LocalDateTime.of(2024, 1, 1, 12, 12, 12)) + .setSequence((short) 0) + .setAttachmentCount((short) 4) + ) + .setAlarmNo("lbt9kpl93jlq6krtlvwqi8b7bmpt9111"); + + final String hexString = this.encode(msg, builder -> + builder.version(Jt808ProtocolVersion.VERSION_2019) + .terminalId("00000000014499999999") + .msgId(BuiltinJt808MsgType.SERVER_MSG_9208) + ); + Assertions.assertEquals("7E92084053010000000001449999999900000E3139322E3136382E37312E3131391A980000696430303030332401011212120004006C6274396B706C39336A6C71366B72746C76777169386237626D70743931313130303030303030303030303030303030507E", hexString); + } +} diff --git a/jt-808-server-support/src/test/java/io/github/hylexus/jt/jt808/support/data/deserialize/extension/ExtendedJt808FieldDeserializerBcdTimeTest.java b/jt-808-server-support/src/test/java/io/github/hylexus/jt/jt808/support/data/deserialize/extension/ExtendedJt808FieldDeserializerBcdTimeTest.java index a4a078b5..50cb4918 100644 --- a/jt-808-server-support/src/test/java/io/github/hylexus/jt/jt808/support/data/deserialize/extension/ExtendedJt808FieldDeserializerBcdTimeTest.java +++ b/jt-808-server-support/src/test/java/io/github/hylexus/jt/jt808/support/data/deserialize/extension/ExtendedJt808FieldDeserializerBcdTimeTest.java @@ -71,7 +71,7 @@ void doWithBcd(String hex, Consumer consumer) { private static Jt808FieldDeserializer.Context createContext(String field) { final JavaBeanFieldMetadata fieldMetadata = JavaBeanMetadataUtils.getBeanMetadata(Placeholder.class).getFieldMapping().get(field); - return new Jt808FieldDeserializer.DefaultInternalDecoderContext(fieldMetadata); + return new Jt808FieldDeserializer.DefaultInternalDecoderContext(fieldMetadata, null, null); } } diff --git a/samples/jt-808-server-sample-debug/src/main/java/io/github/hylexus/jt/jt808/samples/debug/handler/AttachmentFileHandler.java b/samples/jt-808-server-sample-debug/src/main/java/io/github/hylexus/jt/jt808/samples/debug/handler/AttachmentFileHandler.java index a721e339..dfb6d4dd 100644 --- a/samples/jt-808-server-sample-debug/src/main/java/io/github/hylexus/jt/jt808/samples/debug/handler/AttachmentFileHandler.java +++ b/samples/jt-808-server-sample-debug/src/main/java/io/github/hylexus/jt/jt808/samples/debug/handler/AttachmentFileHandler.java @@ -1,20 +1,15 @@ package io.github.hylexus.jt.jt808.samples.debug.handler; import io.github.hylexus.jt.jt808.Jt808ProtocolVersion; -import io.github.hylexus.jt.jt808.spec.Jt808MsgBuilder; import io.github.hylexus.jt.jt808.spec.Jt808Request; import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg1210Alias; import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg1211Alias; import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg1212Alias; import io.github.hylexus.jt.jt808.spec.builtin.msg.req.BuiltinMsg30316364Alias; -import io.github.hylexus.jt.jt808.spec.builtin.msg.resp.BuiltinMsg9212Alias; import io.github.hylexus.jt.jt808.spec.builtin.msg.resp.BuiltinServerCommonReplyMsg; import io.github.hylexus.jt.jt808.spec.session.Jt808Session; import io.github.hylexus.jt.jt808.support.annotation.handler.Jt808RequestHandler; import io.github.hylexus.jt.jt808.support.annotation.handler.Jt808RequestHandlerMapping; -import io.github.hylexus.jt.jt808.support.extension.attachment.AttachmentJt808CommandSender; -import io.github.hylexus.jt.jt808.support.extension.attachment.AttachmentJt808SessionManager; -import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; @@ -23,18 +18,8 @@ @Component @Jt808RequestHandler public class AttachmentFileHandler { - // !!!如果需要用 session 的话,附件相关的几个 808 指令对应的 session 应该从 AttachmentJt808SessionManager 中获取 - // !!!而不是从普通的 Jt808SessionManager 中获取 - // !!!因为附件上传和普通指令是不同的 TCP 连接 - private final AttachmentJt808SessionManager sessionManager; - // AttachmentJt808CommandSender 和 Jt808CommandSender 类似 - // 只不过 AttachmentJt808CommandSender 是针对于附件消息的 - private final AttachmentJt808CommandSender attachmentJt808CommandSender; - - public AttachmentFileHandler(AttachmentJt808SessionManager sessionManager, AttachmentJt808CommandSender attachmentJt808CommandSender) { - this.sessionManager = sessionManager; - this.attachmentJt808CommandSender = attachmentJt808CommandSender; + public AttachmentFileHandler() { } @Jt808RequestHandlerMapping(msgType = 0x1210, versions = Jt808ProtocolVersion.AUTO_DETECTION) @@ -81,21 +66,6 @@ private void warnLogIfNecessary(Jt808Request request, String msg) { if (request.session().role() == Jt808Session.Role.INSTRUCTION) { log.warn(msg); } - sessionManager.findByTerminalId(request.terminalId()).ifPresent(session -> { - if (session != request.session()) { - log.error("session invalid"); - } - }); } - public void sendMsg9212(String terminalId, BuiltinMsg9212Alias body) { - final Jt808Session session = this.sessionManager.findByTerminalId(terminalId).orElseThrow(); - - final ByteBuf byteBuf = Jt808MsgBuilder.newEntityBuilder(session) - .version(session.protocolVersion()) - .terminalId(terminalId) - .body(body) - .build(); - session.sendMsgToClient(byteBuf); - } }