Add the first driver integration test: spins a real PostgreSQL container and
verifies the shared JDBC read path returns stored values and that the write
path binds the point value as a parameter — a SQL-injection payload is stored
verbatim and cannot drop the table, confirming the parameterised-write fix
end-to-end. Set the Failsafe classesDirectory so integration tests run against
the plain compiled classes instead of the Spring Boot repackaged fat jar.
Add offline MockitoExtension tests for bacnet-ip, can, ethernet-ip, fins, http,
lwm2m, mysql, oracle, postgresql, serial, snmp, sqlserver, and tcp-udp. Each
covers configuration validation (validate/validatePoint flag missing required
attributes) and deterministic lifecycle behavior. Network/hardware paths
(read/write/getConnector) are deliberately excluded to keep the suite fast and
deterministic. Takes these drivers from zero tests to baseline coverage.
The shared JDBC driver base interpolated the point value into the write SQL via
writeQuery.replace("${value}", ...), allowing a crafted write command value to
alter the statement. Bind the value with PreparedStatement#setString against a
single ? placeholder instead. Update the mysql/oracle/postgresql/sqlserver
writeQuery attribute docs to the ? convention and add the module's first test.
The DLMS and IEC 104 drivers are work-in-progress skeletons whose protocol I/O
is unimplemented. They previously returned a null-valued ReadPointValue / cached
echo and reported write success, so the SDK emitted fabricated point values and
masked that the drivers do not work. Make read/write throw Read/WritePointException
so the SDK records failures and applies backoff. Remove the dead connection
scaffolding and add the drivers' first unit tests.
validate(driverConfig) required commandTopic/commandQos, but those are
per-point attributes read from pointConfig in write(), so driver-level
validation always failed. Drop the misplaced checks (and the now-unused
helper); this driver declares no required driver-level attributes.
Document 31 modules that had no README: dc3-center-agentic, dc3-e2e,
common modules (agentic, sql, test, resource-registrar) and the facade
subsystem (api/grpc/local-auth/local-data/local-manager), plus 21
drivers. Content is grounded in each module's pom/yaml/source; WIP
skeleton drivers (can, dlms, ethernet-ip, iec104, lwm2m, zigbee) are
flagged as such.
Move misclassified point attributes out of the driver-attribute tables
(modbus-tcp Slave ID, virtual Tag, listening-virtual), drop plcs7's
fabricated Data Length and add the required PLC Type, document
command/event attributes, and flag the mqtt driver as a WIP skeleton.
Part of the x-dc3-ai annotation-standard rollout. Complete method/param javadoc (TokenService, RepositoryService, RuleEngine, ...), flag work-in-progress utilities and drivers (X509Util, MQTT/CAN/DLMS/... ) with explicit WARNING notes, and remove redundant inline comments / blank lines from query/VO/ext/constant classes plus mapper indentation. Comment/doc only, no behavior change.
Replace the mixed-purpose ResponseEnum with a ResponseCode interface implemented
by SuccessCode (OK/ADD/DELETE/UPDATE) and ErrorCode (NOT_FOUND/UNAUTHORIZED/
TOKEN_INVALID/IP_INVALID/FORBIDDEN/PASSWORD_*/VALIDATION/OUT_OF_RANGE/FAILURE),
each carrying its HTTP status so the envelope body code and transport status no
longer diverge.
- Introduce abstract BusinessException carrying an ErrorCode; all 23 business
exceptions extend it and bind a fixed code. ExceptionConfig reads the carried
code to set both body code and HTTP status (404->R404, 401->R401, 422->R422).
- Add GrpcRFactory (ok/fail/notFound) and remove the hand-written GrpcR builder
boilerplate across 19 gRPC servers.
- Drop the dead @EnumValue index and ofIndex/ofCode/ofName lookups; OUT_OF_RANGE
is now carried by OutRangeException.
- Update R factory methods to accept ResponseCode; migrate 90+ controllers,
11 gRPC facades, OpenAPI specs and README to the split enums.
Also fix several pre-existing red tests surfaced by the full suite:
- OAuthMcpRuntimeServiceImplTest: setUp set @Value fields refactored into
OAuthProperties; inject the properties object instead.
- DriverReadServiceImplTest: reset leaked ConnectionBackoff static state via a
new clear() in @BeforeEach.
- modbus-rtu/tcp: make the static modbusFactory non-final so tests can swap it.
- ble: override no-arg health() to report OFFLINE before initialization.
- PlcS7/facade-local tests: expect the thrown exception / use the single-arg
overload matching production behaviour.
- Remove a duplicate dc3-common-constant dependency in dc3-common-data/pom.xml.
- Update test references to the renamed *TypeEnum/RuleStatusEnum.
- Add the new builder/PermissionProvider constructor args to the affected
service-impl test setups.
- Fix pre-existing failures unrelated to this work: String-vs-Long assertions
(DriverStatusServiceImplTest), save->saveBatch (EntityStateExpiryScannerTest),
List.of(null) NPE (AlarmRulePipelineServiceImplTest), and the cache/batch
refactor expectations (PointValueServiceImplTest).
Align the DO/BO/VO model and enums with the project domain-modeling rules:
- Rename 24 multi-valued *FlagEnum to *TypeEnum (closed classifications) and
RuleStateFlagEnum to RuleStatusEnum (state machine); keep true 0/1 toggles as
*FlagEnum (EnableFlagEnum/DefaultFlagEnum/ConfirmFlagEnum). Add the new
ConfirmFlagEnum.
- Give every enum the consistent triplet + ofIndex/ofCode/ofName (fill the two
Agentic enums) and switch underscore codes to hyphen-case.
- Replace bare Byte/Integer/String flag fields on VOs with their domain enums
(EventHistory, AlertItem, ...); centralize index/code<->enum conversion in the
MapStruct builders instead of services; drop ad-hoc (byte) enum casts.
- Stop leaking DO out of the data history services/controllers: the command /
point-command / event history services now return VO, converting inside the
service via the builder.
- Add @Schema (description + example/required, verified enum constants) across
VO/BO/Query DTOs and the entity/ext nested beans; @Schema the R<T> wrapper;
exclude credential fields from @ToString.
- Replace obsolete nexus-staging-maven-plugin with central-publishing-
maven-plugin in dc3-api and dc3-common
- Remove 20 redundant version declarations from dc3-coverage dependencies
- Fix snmp4j version from non-existent 3.8.3 to available 3.7.4
Add final to ~30 public static fields in RabbitConstant — without final,
any code could reassign exchange/queue/routing-key constants at runtime,
silently corrupting messaging routes across the entire distributed system.
Add final to ModbusFactory static fields in ModbusRtu/Tcp drivers and
Random field in OPC-DA Group class.
Replace System.setProperty-based tag isolation in RabbitmqEnvironmentConfig
with a static initializer block in RabbitConstant to preserve immutability.
- Replace e.getMessage() with exception object in 12 SLF4J log calls
across 8 files to preserve full stack traces
- Replace hardcoded date pattern in @JsonFormat with TimeConstant
reference in LatestPointValueVO and TimeseriesPointVO
- Standardize TopicVO: replace @Data with @Getter/@Setter/@ToString,
add @NoArgsConstructor/@AllArgsConstructor, @JsonInclude, Serializable
- Replace fully-qualified class names with imports in DashboardController
Replace string concatenation in SLF4J log calls with {} placeholders
across 13 driver implementations. Parameterized logging avoids string
construction when the log level is disabled, reducing CPU overhead.
Affected: listening-virtual (6 files), virtual, modbus-tcp, modbus-rtu,
opc-da, opc-ua, mqtt, coap.
Remove unused imports, dead constructors, redundant fields, and unreferenced
local variables across 16 protocol driver implementations and supporting
classes. Add type-specific Encodable creation for BACnet write operations.
Prevent PointValue double-scaling on write echo by adding a static
ofRawValue() factory method that skips the ReadPointValue.calculate()
pipeline. Write values are already in final device-level form and must
not have point scaling (base/multiple/decimal) re-applied.
Add ConnectionBackoff with per-device exponential backoff (1s initial,
2x multiplier, 5min cap) to prevent reconnection storms during device
or network recovery. Integrated transparently into DriverReadServiceImpl
and DriverWriteServiceImpl — applies to all driver types.
Add Modbus TCP connect/read timeout (5s via ModbusMaster.setTimeout)
replacing OS-level default 60-120s timeout that blocked Quartz threads.
Override health() in OPC UA and MQTT drivers to check live connectivity
rather than defaulting to ONLINE. OPC UA uses a 1-second connect() probe;
MQTT marks a TODO for Spring Integration CachingConnectionFactory access.
Remove DEFAULT_KEY and DEFAULT_PASSWORD constants from AlgorithmConstant.
Require DC3_SECURITY_KEY env var at startup — fail with IllegalStateException
if not configured instead of silently falling back to a well-known string.
Remove hardcoded default HMAC secret from HmacAuthProperties. Log a warning
when request signing is disabled in WebFilterConfig.
Require DC3_SECURITY_DEFAULT_PASSWORD for password reset operations instead
of falling back to the hardcoded 'dc3dc3dc3'.
Replace all YAML password fallback values (dc3dc3dc3) with empty defaults so
misconfigured deployments fail at connection time with a clear error rather
than silently connecting with a well-known password.
## Common Foundation
- dc3-common-sql: AbstractJdbcDriverCustomService base class with HikariCP
pool management and JDBC template methods
## Serial & General-Purpose (3)
- Serial: RS232/RS485/RS422 with configurable frame parsing (CRC16/XOR)
- HTTP: REST Client using Spring WebClient with JSON path extraction
- TCP/UDP Raw: generic socket driver with pluggable frame protocol
## Database Drivers (4)
- MySQL, PostgreSQL, Oracle (SID/ServiceName), SQL Server
## IoT & Wireless Protocols (3)
- LwM2M: Eclipse Leshan 2.0.0-M14 with CoAP server and device observation
- Zigbee: Z-Smart Systems 1.4.16.1 with Telegesis dongle support
- BLE: Sputnikdev Bluetooth Manager 1.5.3 with TinyB transport
## Building Automation & Smart Metering (2)
- BACnet IP: BACnet4J 6.0.1 with ReadProperty/WriteProperty support
- DLMS/COSEM: Gurux DLMS 4.0.79 for smart metering (TCP/Serial transport)
## Industrial & Power Protocols (4)
- IEC 104: OpenMUC j60870 1.7.2 for power telecontrol
- SNMP: SNMP4J 3.7.4 for network device monitoring
- EtherNet/IP: CIP Data Table Read/Write for Rockwell AB PLCs
- FINS: Omron PLC memory area read/write over TCP
## Automotive & Fieldbus (1)
- CAN Bus: SocketCAN interface with standard/extended frame support
## Build
- Register all 17 driver modules and dc3-common-sql in parent POMs
- Add version properties and dependencyManagement entries
Match incoming station addresses against device code/name, look up the
configured byte index per point, and ship element values through
DriverSenderService instead of only logging them. Load the xingshuangs
SL651 server and listener through reflection so the driver still starts
when the optional protocol library is absent, logging a warning instead
of failing.
Drop and dispose protocol connectors when read/write fails so the next
call rebuilds a fresh client for Modbus RTU/TCP, OPC DA, OPC UA, Melsec,
and PLC S7. Replace silent zero defaults with UnSupportException for
unknown Modbus function codes and reject null/empty config in CoAP and
listening-virtual paths. Make Netty TCP/UDP handlers Spring-managed
beans, release inbound ByteBuf references, unregister channels on
inactive, await write flush with a timeout, and bound-check every
configured byte slice. Skip MQTT/CoAP point values that lack
device/point identity and isolate event reporting failures.
feat: new driver modules
- dc3-driver-melsec: Mitsubishi Melsec MC (1E/3E/4E frame) driver via iot-communication
- dc3-driver-sl651: SL651-2014 hydrological telemetry server-side driver via iot-communication
- Bump iot-communication from 1.5.4 to 1.5.6 in dc3-driver-plcs7
- Relocate ias-releases repository from root pom.xml to dc3-driver/pom.xml
fix: code review fixes across driver implementations
- PlcS7PointVariable: only include bit offset in address when bit access and offset > 0
- OpcDaDriverCustomServiceImpl: disconnect server on device delete/update
- OpcUaDriverCustomServiceImpl: disconnect client on device delete/update
- ModbusTcpDriverCustomServiceImpl: remove duplicate FLOAT case in write value switch
refactor: eliminate magic numbers, consolidate statics, and normalize log formatting
- NettyServerHandler: replace magic numbers with named constants
- OpcUaDriverCustomServiceImpl: replace magic timeout numbers with named constants
- ModbusFactory: consolidate static block into private static final field
- VirtualDriverCustomServiceImpl: replace new Random() with ThreadLocalRandom
- KeyLoader: reorder fields so statics precede instance fields
- Normalize log format from string concat to {} placeholders across multiple drivers
- MqttDriverCustomServiceImpl: downgrade QoS fallback log warn→debug
- Remove unused imports
Introduce CommandAttribute/EventAttribute with config variants:
- REST controllers, MyBatis mappers, services, and DAL managers
- gRPC client/server builders and proto message definitions
- DTOs, BOs, DOs, VOs for type-safe data transfer layer
fix: add explicit ::text casts in json_build_object parameters
PostgreSQL cannot infer parameter types inside json_build_object()
calls. Add ::text casts to #{stateExtType} and #{stateDescription}
to resolve "could not determine data type of parameter $10" errors.
refactor: restructure driver gRPC client and metadata layer
- Rename GrpcStubConfig to DriverClientStubConfig with dedicated DTOs
- Extract attribute builders from inline gRPC conversion logic
- Consolidate driver metadata, register service, and command handling
- Update device state heartbeat and command result event handling
docs: add multilingual architecture diagram and sync READMEs
- Translate architecture SVG into zh, ja, vi variants
- Update README architecture image references per language
- Add missing service-level shortcut sections to ja/vi READMEs
- Replace two duplicate enums with single EntityStatusEnum (same index/code)
- Rename DB columns: state_flag→entity_state_flag, state_ext→entity_state_ext
- Add stateDescription field to DeviceStateDTO/DriverStateDTO for diagnostics
- Add description field to DeviceHealthState/DriverHealthState
- UPSERT SQL now writes stateDescription into entity_state_ext on heartbeat
- Remove EntityStateStatus interface (no longer needed with single enum)
- Update MQ layer, heartbeat services, status queries, gRPC, and all tests
Replace hand-written all-assignment constructors with Lombok
@RequiredArgsConstructor across controllers, services, config classes,
event listeners, and tool classes. No behavioral change.
Last batch of the cross-module refactor away from @Resource field
injection.
Production code:
- dc3-driver/* (8 driver modules): listening-virtual (4 files: Netty
handlers + driver custom impl), virtual, mqtt (2), coap (2),
modbus-tcp, plcs7, opc-da, opc-ua. Fields become private final;
jakarta.annotation.Resource imports are removed.
- NettyTcpServer/NettyUdpServer pass null to NettyTcpServerHandler /
NettyUdpServerHandler when adding the manually-created handler to the
Netty pipeline. Those handler instances are pure stubs that delegate
to the Spring-managed instance via the existing static self-reference,
so a null collaborator field on the stub is functionally equivalent to
the prior no-op default-constructor instance.
Test adaptations:
- 26 tests across dc3-common-mqtt, dc3-common-data, dc3-common-auth,
dc3-common-manager, dc3-common-facade-{local-manager,local-auth,
local-data}, and dc3-driver/* swap the no-args + reflection setup for
a direct constructor call that passes the Lombok-generated parameter
list. Reflection setters and the `injectField` helper are removed
where they only existed for refactor-affected fields; reflection
helpers that touch unrelated state (static factories, private cache
maps used as test seams) are kept.
- 3 dc3-common-driver tests (DeviceCommandReceiverTest,
MetadataReceiverTest, DriverRegisterServiceImplTest) get the same
treatment. MetadataReceiverTest also gains a DriverClient mock to
match the now-five-arg constructor.
- VirtualDriverCustomServiceImplTest and SessionServiceImplTest drop
their reflection-only @BeforeEach blocks: with final fields, Mockito
@InjectMocks now uses constructor injection automatically and matches
collaborators by type.
- PointServiceImplTest gains a missing DriverService @Mock so that
Mockito constructor injection can populate every parameter.
Six public/private static final fields used camelCase, in violation
of the standard Java naming convention for class-level constants:
MqttScheduleJob.messageLock -> MESSAGE_LOCK
MqttScheduleJob.messageCount -> MESSAGE_COUNT
MqttScheduleJob.messageSpeed -> MESSAGE_SPEED
MqttScheduleJob.mqttMessages -> MQTT_MESSAGES
NettyTcpServer.deviceChannelMap -> DEVICE_CHANNEL_MAP
RepositoryStrategyFactory.repositoryServiceMap -> REPOSITORY_SERVICE_MAP
The receiveBatch() method parameter mqttMessages is intentionally
kept as camelCase; only the static field is renamed.
Refresh module READMEs, AGENTS.md, CONTRIBUTING.md, and dc3/doc/
guides to reflect the unified Dockerfile, consolidated compose stacks,
and updated build instructions.
Replace 14 individual Dockerfiles with a single unified Dockerfile at
the repo root using multi-stage BuildKit targets. Maven build runs
inside the builder stage so no host JDK is required.
Update @since from 2022.1.0 to 2016.10.1 and @version from 2026.5.5
to 2026.5.17 across all Java source files to reflect the actual
project start date.