-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Problem Statement
Entities extending IdentifiedObject have inconsistent implementations for Atom <link rel="related"> elements, causing compilation errors and architectural inconsistency.
Current State:
IdentifiedObjectdefinesrelatedLinksasList<LinkType>(3-column structure: rel, href, type)- 13 entity-specific related_links tables use single-column VARCHAR(1024) structure
- Attempting to add custom
List<String> relatedLinksfields causes compilation errors - Entities cannot use bidirectional Atom links as required by NAESB ESPI 4.0
Compilation Errors:
[ERROR] name clash: setRelatedLinks(java.util.List<java.lang.String>) in CustomerAgreementEntity
and setRelatedLinks(java.util.List<LinkType>) in IdentifiedObject have the same erasure
[ERROR] return type java.util.List<java.lang.String> is not compatible with
java.util.List<org.greenbuttonalliance.espi.common.domain.common.LinkType>
Root Cause
Database schema design for *_related_links tables is inconsistent with IdentifiedObject:
IdentifiedObject expects (CORRECT):
CREATE TABLE identified_object_related_links (
identified_object_id CHAR(36) NOT NULL,
rel VARCHAR(255), -- Relationship type: "related", "self", "up"
href VARCHAR(1024), -- Link URL
link_type VARCHAR(255) -- ESPI type: "espi-entry/UsagePoint" or "espi-feed/UsagePoint"
);Entity-specific tables currently have (WRONG):
CREATE TABLE customer_agreement_related_links (
customer_agreement_id CHAR(36) NOT NULL,
related_links VARCHAR(1024) -- Single column storing only href
);Affected Entities and Tables
Usage Domain (4 entities - V1 migration)
| Entity | Table | Extends IdentifiedObject | Custom relatedLinks Field |
|---|---|---|---|
| ApplicationInformationEntity | application_information_related_links |
✅ Yes | ❌ No |
| AuthorizationEntity | authorization_related_links |
✅ Yes | ❌ No |
| ReadingTypeEntity | reading_type_related_links |
✅ Yes | ❌ No |
| ElectricPowerQualitySummaryEntity | electric_power_quality_summary_related_links |
✅ Yes | ❌ No |
Customer Domain (9 entities - V3 migration)
| Entity | Table | Extends IdentifiedObject | Custom relatedLinks Field |
|---|---|---|---|
| CustomerEntity | customer_related_links |
✅ Yes | ❌ No |
| CustomerAgreementEntity | customer_agreement_related_links |
✅ Yes | |
| CustomerAccountEntity | customer_account_related_links |
✅ Yes | ❌ No |
| ServiceLocationEntity | service_location_related_links |
✅ Yes | |
| ServiceSupplierEntity | service_supplier_related_links |
✅ Yes | |
| EndDeviceEntity | end_device_related_links |
✅ Yes | |
| MeterEntity | meter_related_links |
✅ Yes (via EndDevice) | |
| ProgramDateIdMappingsEntity | program_date_id_mapping_related_links |
✅ Yes | |
| StatementEntity | statement_related_links |
✅ Yes | ❌ No |
Total: 13 tables need standardization
Usage Entities Without relatedLinks Tables
These entities extend IdentifiedObject but have NO related_links tables:
- IntervalBlockEntity ✅
- MeterReadingEntity ✅
- UsagePointEntity ✅
- UsageSummaryEntity ✅
- TimeConfigurationEntity ✅
ESPI Link Type Values
CRITICAL: Link type= attribute is NOT a media type. It uses ESPI-specific format.
Usage Domain Resources (usage.xsd)
<!-- href ends with identifier → single entry -->
<link rel="related"
href="https://api.example.com/resource/IntervalBlock/123"
type="espi-entry/IntervalBlock"/>
<!-- href ends with ResourceName → collection/feed -->
<link rel="related"
href="https://api.example.com/resource/UsagePoint/456/MeterReading"
type="espi-feed/MeterReading"/>Customer Domain Resources (customer.xsd)
<!-- href ends with identifier → single entry -->
<link rel="related"
href="https://api.example.com/resource/CustomerAgreement/789"
type="cust-entry/CustomerAgreement"/>
<!-- href ends with ResourceName → collection/feed -->
<link rel="related"
href="https://api.example.com/resource/ServiceLocation/abc/EndDevice"
type="cust-feed/EndDevice"/>Link Type Determination (Marshalling Concern)
The -entry vs -feed distinction is determined during XML marshalling (Java → XML):
Rule: Examine the href= attribute value:
- If
hrefends with ResourceName →type="{prefix}-feed/{ResourceName}" - If
hrefends with identifier →type="{prefix}-entry/{ResourceName}"
Examples:
href="https://api.example.com/resource/UsagePoint/123/MeterReading"
↑ ends with "MeterReading" → type="espi-feed/MeterReading"
href="https://api.example.com/resource/MeterReading/456"
↑ ends with "456" (identifier) → type="espi-entry/MeterReading"
During unmarshalling (XML → Java):
- The type value is already provided in the XML
- Simply store it in
LinkType.typefield
Proposed Solution
Phase 1: Update Existing Flyway Scripts
IMPORTANT: Since this is a development system not yet deployed, we can update V1 and V3 scripts directly.
Update 13 related_links tables to use 3-column structure (rel, href, link_type) instead of single-column (related_links).
See full implementation details in ISSUE_DRAFT_RELATED_LINKS_STANDARDIZATION.md
Phase 2: Revert Phase A0 Changes
Remove the List<String> relatedLinks fields from 5 entities causing compilation errors.
Phase 3: Add @AssociationOverride Annotations
All 13 entities should override IdentifiedObject's relatedLinks table name via @AssociationOverride.
Phase 4: Service Layer Usage
Services create links with rel and href, marshalling layer determines type based on href pattern.
Phase 5: Marshalling Layer Logic
Add determineEspiLinkType() helper method to DtoExportService.
Implementation Tasks
- Update V1 Flyway script (4 tables)
- Update V3 Flyway script (10 tables)
- Revert Phase A0 changes (5 entities)
- Add @AssociationOverride annotations (13 entities)
- Add marshalling logic
- Update CLAUDE.md documentation
- Update tests
- Build and integration tests
Success Criteria
- All compilation errors resolved
- All 13 related_links tables use 3-column structure
- All entities inherit relatedLinks from IdentifiedObject
- All tests passing (~760+ tests)
- XML output has correct ESPI type values
- Phase 17 can proceed without blockers
Dependencies
Blocks: Issue #28 Phase 17: ProgramDateIdMappings implementation
Requires: Phase A0 branch must be reverted
Estimated Effort
Total: ~13-16 hours
Priority
CRITICAL - Blocks Phase 17 implementation and prevents build from succeeding.