[SDK-568] Add stable cross-SDK identifiers to IterableDataRegion - #1081
[SDK-568] Add stable cross-SDK identifiers to IterableDataRegion#1081franco-zalamena-iterable wants to merge 6 commits into
Conversation
Phase 1 of the cross-platform data region parity effort (iOS SDK-609, RN SDK-610, Flutter SDK-611). Android already exposed a typed enum, so this hardens it into the shared reference shape rather than redesigning it. All changes are additive. Source compatibility was verified by compiling the pre-existing public call patterns (getEndpoint, valueOf, values, ordinal, enum switch, the deprecated constants) against the new classes. - Add getRegionCode() and getCode() as stable cross-SDK identifiers. Numeric codes are declared explicitly rather than derived from ordinal(), so adding a region cannot renumber the existing ones. - Add from(String) and from(int) factories for wrapper bridges. from(String) also accepts a full endpoint URL, so the iOS SDK's string-based region values resolve without translation. - Log and fall back to US on unrecognised, empty or null input instead of resolving silently, so a misconfigured region surfaces in the logs rather than quietly routing EU-destined data to the US data center. - setDataRegion(null) falls back to US with a warning instead of leaving the region unset. - Deprecate IterableConstants.BASE_URL_API and BASE_URL_LINKS: both are hardcoded to the US region and unused by the SDK, which resolves its endpoint from the configured region. - Drop a duplicated overrideUrl application in IterableRequestTask; getBaseUrl() already applies it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…URL constants An unnamed removal target is how BASE_URL_API survived as dead public API in the first place, so commit to a version clients can plan against.
…ored Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…a-region-parity # Conflicts: # CHANGELOG.md
| } | ||
| } | ||
|
|
||
| IterableLogger.w(TAG, "Unsupported data region \"" + value + "\", defaulting to " + US.regionCode |
There was a problem hiding this comment.
These warnings never reach logcat. IterableLogger.w checks Log.WARN >= getLogLevel(), and at the point from() and setDataRegion() run we are still building the config, so getLogLevel() reads the pre-init default IterableConfig whose logLevel is Log.ERROR.
That makes the check 5 >= 6, so the message is dropped.
Note this is not fixable by the integrator either: sharedInstance.config is only swapped for the customer's config in initialize() (IterableApi.java:817), so even .setLogLevel(Log.VERBOSE) in the same builder chain is too late.
I confirmed this with a probe test using Cursor, IterableLogger.w is gated out while IterableLogger.e reaches android.util.Log. Given the failure mode is EU-destined data silently going to the US data center, I would use IterableLogger.e for the unrecognised-region path and add a test asserting the log fires. Otherwise the CHANGELOG line about it no longer resolving silently is not true for anyone.
There was a problem hiding this comment.
thanks for the catch, this was a good finding and is now fixed.
One exception, from(null) / from("") stays at warning. That's the documented default rather than a misconfiguration, and ERROR there would fire for every wrapper app that never sets a region.
| @NonNull | ||
| public Builder setDataRegion(@NonNull IterableDataRegion dataRegion) { | ||
| if (dataRegion == null) { | ||
| IterableLogger.w("IterableConfig", "setDataRegion received null, defaulting to " + IterableDataRegion.US.getRegionCode()); |
There was a problem hiding this comment.
We can use the static final string TAG here instead of the "magic string"!
Log unrecognised data regions at error level so they survive the default log level, and use TAG in setDataRegion. Cover both with tests asserting the message actually reaches logcat. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
📝 Summary
Add stable cross-SDK identifiers and lookup factories to
IterableDataRegion, and log instead of silently falling back when a region is unrecognised.🎟️ Jira Ticket: SDK-568
📖 Description
SDK-568 asks for a typed data region across the SDKs. Android already had it —
IterableDataRegionhas been a Java enum withUS/EUsince 3.6.0 (MOB-6309),IterableConfigdefaults toUS, and the builder setter is@NonNull-typed. The divergence the epic describes lives on iOS (config.dataRegionis a rawString, so a typo compiles and misroutes data) and Web (isEuIterableServiceboolean).So this PR hardens Android into the shared reference shape rather than redesigning it. Everything is additive — no breaking change, and no action required from clients.
Deprecated
IterableConstants.BASE_URL_APIandBASE_URL_LINKS. Both are hardcoded to the US data region, are unused by the SDK (verified: zero references outside their own declarations), and contradict the configuredIterableDataRegion. They still resolve to the same values, so nothing breaks. Named 3.12.0 as the removal version in both the javadoc and the CHANGELOG — assuming this ships in 3.11.0, that's one minor of runway. Deliberately named rather than left as "a future major": the last Android major was 3.0.0 (2018), while public API does get removed in minors (3.5.5 droppedsetEncryptionEnforced, 3.8.0 dropped CBC encryption). An unnamed target is exactly howBASE_URL_APIsurvived this long as dead public API. If 3.11.0 isn't the release this lands in, the named version needs adjusting to keep the window intact.Reviewer notes
Not done deliberately:
setDataRegion(String)/setDataRegion(int)builder overloads. Adding them would make an existingsetDataRegion(null)call an ambiguous-overload compile error, sinceIterableDataRegionandStringare unrelated reference types — source-breaking. The staticfrom(...)factories give wrappers the same capability with no ambiguity.getEndpoint()stays public. Narrowing it is the one breaking change available here and it isn't worth it.Follow-up not in this PR: nothing in the repo will remind anyone to actually remove the constants at 3.12.0. That needs tracking in the 3.12.0 release scope, or it repeats the pattern it's meant to fix.
🧪 How to test?
Unit tests:
./gradlew :iterableapi:testDebugUnitTestNew coverage in
IterableDataRegionTest.kt(9 tests) — endpoints match the data centers, identifiers match the other SDKs,from()by region code / iOS-style endpoint URL / numeric code, case- and whitespace-insensitivity, unsupported-value fallback for both overloads, and identifier round-tripping.IterableConfigTest.ktaddsnullDataRegionFallsBackToUs(via reflection, since the null is only reachable from Java).Manual check of the logging path:
Expect a warning tagged
IterableDataRegionnaming the supported values (US (0), EU (1)) and a fallback toUS. Then confirmIterableDataRegion.from("EU")andfrom(1)both resolve toEUand that requests go tohttps://api.eu.iterable.com/api/.📚 Docs PR if applicable
TODO — the new identifiers/factories and the 3.12.0 deprecation are customer-facing and should be documented before release.