Extend the IoT Hub install dialog so installing a rule chain can also set
it as the Default rule chain on a Device or Asset profile in one step.
The confirm step shows three actions: Cancel, Install (creates the chain
without targeting any profile), and Set for profile (opens a picker step).
The picker step has Cancel, Back, and Install — confirming with a profile
that already has a non-null defaultRuleChainId routes through a
confirm-overwrite step before replacing it. CALCULATED_FIELD keeps its
existing single-button flow unchanged.
Backend:
* RuleChainInstalledItemDescriptor gains a nullable EntityId
targetProfileId field, persisted in the existing descriptor JSON column
(no schema migration; @JsonIgnoreProperties(ignoreUnknown=true) handles
pre-existing rows).
* DefaultIotHubService.installRuleChain() now accepts SecurityUser and
JsonNode data; a new setAsDefaultRuleChain() helper applies the chain
as Default rule chain on the selected DEVICE_PROFILE or ASSET_PROFILE
via the existing tbDeviceProfileService / tbAssetProfileService save
paths (so the change shows up in the tenant audit log as a normal
profile update).
Frontend:
* iot-hub-install-dialog.component grows a per-ItemType selectEntityConfig
map, a 'confirm-overwrite' state, and the methods
installAsEntityProfileDefault, selectEntityBack, resolveOverwrite,
confirmOverwriteReplace, confirmOverwriteCancel.
* tb-entity-select gets a 512px min-width above the gt-sm breakpoint so
the picker renders at a consistent width regardless of the prompt text
length (mirrors the pattern in recipient-notification-dialog).
* New i18n keys: rule-chain-install-desc, rule-chain-install-as-default,
select-profile-for-rule-chain, rule-chain-overwrite-title,
rule-chain-overwrite-body, rule-chain-overwrite-replace.
SimpleCalculatedFieldState.formatResult cast the double result down to
int via TbUtils.toInt when "Decimals by default" was 0 (the UI default).
BigDecimal.intValue() returns only the low-order 32 bits, so a sum
above ~2.1B wrapped to a negative number (e.g. 3,980,173,734 ->
-314,793,562).
Add TbUtils.toLong(double) alongside toInt (toInt is left untouched to
preserve TBEL script behavior), switch the CF precision=0 path to it,
and add a Long branch in createResultJson so the JSON node is emitted
as a numeric long
- Group tomcat, commons-lang3 version properties under spring-boot.version
- Drop thymeleaf override (PE-only dependency, not present in CE)
- Drop lz4 plumbing: kafka-clients 3.9.2 and cassandra-all 5.0.7 now transitively ship at.yawk.lz4:lz4-java, making the Dec 2025 CVE hack obsolete
AbstractTbQueueConsumerTemplate.poll() returned emptyList() immediately
when partitions was empty, bypassing both doPoll() and the secondary
sleep guard (which is also skipped for backends that report
isLongPollingSupported()==true, e.g. Kafka). The result was a
permanent CPU-burning loop on consumers whose partition assignment
ended up empty after a rebalance cascade — observed on 26
ie-downlink-consumer threads (~244% total CPU) until container restart.
Route the empty-partition path through sleepAndReturnEmpty() so the
caller honors durationInMillis regardless of long-polling support.
Moved NioEventLoopGroup allocations into the try block so that a
constructor failure for the second group no longer leaks the first.
Channel close failures during cleanup now attach via addSuppressed
instead of replacing the original BindException. Narrowed the outer
catch from Throwable to Exception, removing the brittle (Error) cast
that would have masked any direct Throwable subclass.
* Feature/iot hub alarm rules (#15539)
* feat(iot-hub): scaffold ALARM_RULE item type and CREATOR_VISIBLE_ITEM_TYPES
* feat(iot-hub): wire ALARM_RULE through browse, item card, detail dialog, installed items, and install dialog
* feat(iot-hub): reorder home cards, hide Dashboards, add Alarm Rules
* feat(iot-hub): scaffold ALARM_RULE descriptor and reject install with v4.3 upgrade hint
Registers AlarmRuleInstalledItemDescriptor in the Jackson polymorphism so
4.2 can browse Alarm Rule items from the marketplace without descriptor
deserialization failures.
The install handler explicitly rejects ALARM_RULE with a friendly message
asking the user to upgrade to v4.3+. The full install/update/delete
implementation depends on CalculatedFieldType.ALARM (added in v4.3) and
will land once master is merged into this branch.
* feat(iot-hub): hide redundant Type filter on Alarm Rules browse
* feat(iot-hub): show v4.3 update info dialog directly when installing an Alarm Rule
* feat(iot-hub): implement ALARM_RULE install / update / delete handlers
Replaces the temporary v4.3-upgrade-required rejection with the actual
backend handlers. Alarm rules install as CalculatedField entities with
type=ALARM, mirroring the CALCULATED_FIELD path:
- installAlarmRule parses the alarm-rule JSON, validates type==ALARM,
saves via tbCalculatedFieldService, and returns
AlarmRuleInstalledItemDescriptor with calculatedFieldId + entityId.
- updateAlarmRule re-saves the existing CF with new name, type, and
configuration.
- Delete branch removes the underlying calculated field on installed-item
delete.
- Checksum dispatch unifies CF and ALARM_RULE through a shared
calculateCalculatedFieldChecksum(CalculatedFieldId) helper.
Frontend: drops the v4.3 info-dialog interception in IotHubActionsService
(install now actually runs); restores the select-entity branch for
ALARM_RULE in the install dialog so users can pick a parent device.
Removes the now-unused alarm-rule-install-update-required* locale keys.
* feat(iot-hub): scaffold ALARM_RULE item type and CREATOR_VISIBLE_ITEM_TYPES
* feat(iot-hub): wire ALARM_RULE through browse, item card, detail dialog, installed items, and install dialog
* feat(iot-hub): reorder home cards, hide Dashboards, add Alarm Rules
* feat(iot-hub): scaffold ALARM_RULE descriptor and reject install with v4.3 upgrade hint
Registers AlarmRuleInstalledItemDescriptor in the Jackson polymorphism so
4.2 can browse Alarm Rule items from the marketplace without descriptor
deserialization failures.
The install handler explicitly rejects ALARM_RULE with a friendly message
asking the user to upgrade to v4.3+. The full install/update/delete
implementation depends on CalculatedFieldType.ALARM (added in v4.3) and
will land once master is merged into this branch.
* feat(iot-hub): hide redundant Type filter on Alarm Rules browse
* feat(iot-hub): show v4.3 update info dialog directly when installing an Alarm Rule
- Introduce HasAppliedToEntity interface used by CreatedAlarmRuleInfo and
CreatedCalculatedFieldInfo to share the entity page-link logic and
cover DEVICE / ASSET in addition to the profile types.
- Add static from(EntityId, name, CalculatedField) factories to both
records; SolutionInstallContext now uses them and detects ALARM
calculated fields via type instead of the previous TODO/hardcoded
false.
- AlarmSeverity and CalculatedFieldType expose display names used when
formatting created-alarm-rule severities and CF type column.
- DefaultSolutionService switches the CF arguments check from
BaseCalculatedFieldConfiguration to ArgumentsBasedCalculatedFieldConfiguration
and throws ThingsboardRuntimeException for missing references.
SolutionTemplateInstalledItemDescriptor and SolutionInstallResponse now
carry tenantTelemetryKeys and tenantAttributeKeys lists. SolutionService
.deleteSolution takes the full descriptor (instead of just the
created-entity list) so uninstall can also clean up tenant-scoped
telemetry/attributes. Update IotHub install descriptor population and
delete call sites; force-update path logs and continues if delete throws.
PathChildrenCache invoked EnsureContainers internally during start(), so
the parent znode existed when publishCurrentServer ran. CuratorCache does
not, so on a fresh ZK creatingParentsIfNeeded reaches ZKPaths.mkdirs with
the trailing-slash forPath argument and fails with
"Path must not end with / character", aborting Spring startup.
Switches the ZooKeeper-based service discovery from the deprecated
org.apache.curator.framework.recipes.cache.PathChildrenCache to the
modern CuratorCache replacement (Curator 5.x).
- ZkDiscoveryService: field type, construction, listener registration
and child-event handler migrated to the new API. parentPathFilter
and zkNodesDir guard preserve the original direct-children semantics
against the recursive-by-default behaviour of CuratorCache.
- ZkDiscoveryServiceTest: mock type and event construction adapted to
the new listener signature; existing assertions unchanged.
Eliminates 11 [WARNING] lines for PathChildrenCache deprecation on
lts-4.2 (targeted Tier 3 slice of #15481): repo-wide [WARNING] count
843 -> 832, [ERROR] count 0 -> 0.
Routes get/set/del/scan/getSet/hGet/hSet/hDel/lRange/zRem/getRange calls
through stringCommands()/keyCommands()/hashCommands()/listCommands()/
zSetCommands() instead of the deprecated shortcut methods on
DefaultedRedisConnection. Behavior-preserving — Spring Data Redis
delegates the deprecated overloads to these same typed commands.
Eliminates 70 deprecation warnings across RedisOtaPackageDataCache, five
Leshan-forked lwm2m stores (TbLwM2mRedisRegistrationStore,
TbLwM2mRedisSecurityStore, TbRedisLwM2MClientStore,
TbRedisLwM2MModelConfigStore, TbLwM2mRedisClientOtaInfoStore,
TbLwM2MDtlsSessionRedisStore) and the TbRedisLwM2MClientStoreTest unit
test, which now uses Answers.RETURNS_DEEP_STUBS to mock the typed
command chain.
Part of #15481 Tier 3 cleanup.
Added @Builder.Default to 5 fields with initializers in
MobileLayoutConfig (pages) and DefaultTenantProfileConfiguration
(maxCalculatedFieldsPerEntity, maxArgumentsPerCF, maxStateSizeInKBytes,
maxSingleValueArgumentSizeInKBytes). Dropped the redundant `= 0` on
Task.attempt (int default is already 0) to clear the same anomaly on
@SuperBuilder.
Eliminates 6 "@Builder/@SuperBuilder will ignore the initializing
expression" warnings from #15481 Tier 2. `[WARNING]` total drops
843 -> 837, `[ERROR]` unchanged at 0.
Creates missing system images from application/src/main/data/resources/images
during LTS patch startup, mirroring the upgrade-path loadSystemResources logic.
Existing system images in the DB are left untouched.
- Mark force-added entity-field filter mappings as ignored under OR so
EntityDataAdapter keeps the response shape identical to AND (applied
to both findEntityDataByQuery and validateEntityCountQuery paths).
- Skip the ON-clause filter in toLatestJoin when forceLeftJoin=true to
avoid duplicating the predicate that buildQuery already emits at the
middle layer under OR (different bound parameter names, same filter).
- Document the empty-predicate drop in buildQuery (safe under AND,
narrowing under OR) and the defensive vacuously-true return in
RepositoryUtils.checkKeyFilters.
- Explain why validateEntityCountQuery uses the nullable
getKeyFiltersOperation() rather than the OrDefault helper.
- Add regression test asserting latest[ENTITY_FIELD] under OR only
contains keys declared in entityFields.
Prevents UnrecognizedPropertyException during rolling upgrades when a
newer node writes a cached entity with an added field and an older node
reads it back. The Redis-backed TbJsonRedisSerializer now uses
JacksonUtil.IGNORE_UNKNOWN_PROPERTIES_JSON_MAPPER instead of the strict
OBJECT_MAPPER used by JacksonUtil.fromBytes.
Store install state (form values, entity outputs, selected connectivity)
in DeviceInstalledItemDescriptor during registration. Installed Items
info icon for DEVICE type re-fetches the ZIP and opens the wizard in
read-only review mode:
- All stepper steps clickable (jump to any step)
- Form fields populated with stored values and disabled
- Entity progress shows all items as completed
- Markdown instructions rendered with resolved variables
- Download buttons and image galleries still work
- Single "Close" button in footer
Backend: add selectedConnectivity and installState fields to descriptor
Test: verify installState deserialization round-trip
The admin settings endpoint requires SYS_ADMIN authority but the device
install wizard runs as TENANT_ADMIN.
Fix: add getConnectivityInfo(baseUrl) to DeviceConnectivityService which
resolves host/port with baseUrl fallback (reusing existing getHost/getPort
logic). Expose via new TENANT_ADMIN endpoint GET /api/iot-hub/connectivity.
Remove AdminService dependency from the dialog component.