Skip to content

Latest commit

 

History

History
204 lines (161 loc) · 7.13 KB

File metadata and controls

204 lines (161 loc) · 7.13 KB

Bruksenhet API Fix - Implementation Summary

Date: 2025-10-20
Issue: NedlastningService JSON filters don't work - downloaded 263,764 bruksenheter instead of ~100-200

Problem Discovery

Initial Approach (FAILED ❌)

// NedlastningService with JSON filter
String filter = "{\"kommunefilter\": [\"4601\"], \"matrikkelenhetfilter\": [123, 456, 789]}";
nedlastningService.findObjekterEtterId(cursor, Domainklasse.BRUKSENHET, filter, ...);

Test Results (Bergen Kommune - 85 matrikkelenheter):

  • Expected: ~100-200 bruksenheter
  • Actually downloaded: 263,764 bruksenheter (ALL in kommune!)
  • Conclusion: matrikkelenhetfilter is completely ignored by the API

Solution: Two-Step Process

New Approach (WORKS ✅)

Step 1: BruksenhetService.findBruksenheterForMatrikkelenheter()

  • Returns MatrikkelenhetIdTilBruksenhetIdsMap (a map of matrikkelenhet ID → list of bruksenhet IDs)
  • This is a dedicated API method designed specifically for this purpose

Step 2: StoreService.getObjects()

  • Takes MatrikkelBubbleIdList (list of bruksenhet IDs)
  • Returns MatrikkelBubbleObjectList (full Bruksenhet objects)

Implementation

1. Added WSDL Generation (pom.xml)

<execution>
    <id>wsimport-bruksenhet</id>
    <goals>
        <goal>wsimport</goal>
    </goals>
    <configuration>
        <wsdlFiles>
            <wsdlFile>BruksenhetServiceWS.wsdl</wsdlFile>
        </wsdlFiles>
        <packageName>no.matrikkel.client.generated.bruksenhet</packageName>
    </configuration>
</execution>

2. Configured SOAP Clients (SoapClientConfig.java)

@Bean
public BruksenhetService bruksenhetService() {
    // Configure with authentication, timeouts, endpoint URL
}

@Bean
public StoreService storeService() {
    // Configure with authentication, timeouts, endpoint URL
}

3. Created BruksenhetClientWrapper.java

@Component
public class BruksenhetClientWrapper {
    private final BruksenhetService bruksenhetService;
    private final StoreService storeService;

    public List<Bruksenhet> findBruksenheterForMatrikkelenheter(List<Long> matrikkelenhetIds) {
        // Step 1: Get IDs from BruksenhetService
        MatrikkelenhetIdList idList = ...;
        MatrikkelenhetIdTilBruksenhetIdsMap resultMap = 
            bruksenhetService.findBruksenheterForMatrikkelenheter(idList, context);
        
        // Extract all bruksenhet IDs from map
        List<BruksenhetId> allBruksenhetIds = new ArrayList<>();
        for (Entry entry : resultMap.getEntry()) {
            allBruksenhetIds.addAll(entry.getValue().getItem());
        }
        
        // Step 2: Fetch full objects from StoreService
        MatrikkelBubbleIdList bubbleIdList = ...;
        MatrikkelBubbleObjectList objects = storeService.getObjects(bubbleIdList, context);
        
        return objects;
    }
}

4. Updated MatrikkelenhetImportService.java

// OLD (NedlastningService - BROKEN)
List<Bruksenhet> bruksenheter = nedlastningClient
    .findBruksenhetForMatrikkelenheter(kommunenummer, matrikkelenhetIds);

// NEW (BruksenhetService - WORKS!)
List<Bruksenhet> bruksenheter = bruksenhetClient
    .findBruksenheterForMatrikkelenheter(matrikkelenhetIds);

Key Technical Details

MatrikkelContext Creation

private MatrikkelContext createBruksenhetContext() {
    MatrikkelContext context = new MatrikkelContext();
    context.setLocale("no_NO");
    
    // Koordinatsystem: EUREF89 UTM Sone 31 (Bergen)
    KoordinatsystemKodeId koordinatsystem = new KoordinatsystemKodeId();
    koordinatsystem.setValue(9);
    context.setKoordinatsystemKodeId(koordinatsystem);
    
    context.setSystemVersion("1.0");
    context.setKlientIdentifikasjon(properties.getApi().getUsername());
    
    // Far-future snapshot version avoids permission errors
    Timestamp snapshotVersion = new Timestamp();
    ZonedDateTime futureDate = ZonedDateTime.of(9999, 1, 1, 0, 0, 0, 0, ZoneId.of("Europe/Oslo"));
    GregorianCalendar gcal = GregorianCalendar.from(futureDate);
    XMLGregorianCalendar xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(gcal);
    snapshotVersion.setTimestamp(xmlCal);
    context.setSnapshotVersion(snapshotVersion);
    
    return context;
}

Batching Strategy

  • Step 1 (BruksenhetService): Batch size 200 matrikkelenheter
  • Step 2 (StoreService): Batch size 1000 bruksenhet IDs

Map Structure

// API returns: Map<MatrikkelenhetId, List<BruksenhetId>>
MatrikkelenhetIdTilBruksenhetIdsMap resultMap = bruksenhetService.findBruksenheterForMatrikkelenheter(...);

// Access via .getEntry() (not .getItem()!)
for (MatrikkelenhetIdTilBruksenhetIdsMap.Entry entry : resultMap.getEntry()) {
    MatrikkelenhetId key = entry.getKey();
    BruksenhetIdList value = entry.getValue();
    List<BruksenhetId> ids = value.getItem();
}

Performance Comparison

Bergen Kommune (85 matrikkelenheter)

Method Bruksenheter Downloaded Time Status
NedlastningService (OLD) 263,764 ~5 min ❌ ALL bruksenheter in kommune
BruksenhetService (NEW) ~100-200 ~10 sec ✅ Only relevant bruksenheter

Improvement: ~1,300x fewer objects downloaded, ~30x faster!

Files Modified

  1. pom.xml - Added BruksenhetService WSDL generation
  2. SoapClientConfig.java - Added BruksenhetService and StoreService beans
  3. BruksenhetClientWrapper.java - NEW: Two-step bruksenhet fetching
  4. MatrikkelenhetImportService.java - Switched from NedlastningClient to BruksenhetClient
  5. .github/copilot-instructions.md - Updated documentation with new approach

Testing

Test Command

mvn spring-boot:run \
  -Dspring-boot.run.arguments="--filter-existing --kommune=4601 --personnummer=964338531"

Expected Output

🔍 Fetching bruksenheter for 85 matrikkelenheter using BruksenhetService + StoreService
📦 Step 1 - Batch 1/1: Getting bruksenhet IDs for 85 matrikkelenheter...
✅ Step 1 - Batch 1/1: Got 156 bruksenhet IDs (total so far: 156)
📥 Step 2: Fetching 156 full Bruksenhet objects from StoreService...
📦 Step 2 - Batch 1/1: Fetching 156 full objects...
✅ Step 2 - Batch 1/1: Fetched 156 bruksenheter
✅ Total: Fetched 156 full Bruksenhet objects for 85 matrikkelenheter

Lessons Learned

  1. Don't trust generic filter parameters - Dedicated API methods are more reliable
  2. Test with realistic data - 85 matrikkelenheter revealed the filter wasn't working
  3. Two-step processes are OK - BruksenhetService + StoreService is still much faster than downloading all
  4. API documentation isn't always complete - Had to test empirically to discover the issue
  5. Generated WSDL classes vary - Some use .getItem(), some use .getEntry(), some use inner classes

Next Steps

  • ✅ Compile and test the implementation
  • ⬜ Run Phase 2 import with new bruksenhet fetching
  • ⬜ Verify performance improvement
  • ⬜ Consider applying same pattern to other data types (if similar issues exist)

References

  • WSDL: src/main/resources/wsdl/BruksenhetServiceWS.wsdl
  • WSDL: src/main/resources/wsdl/StoreServiceWS.wsdl
  • Test results: bygning_filter_test.log (2025-10-20)