Skip to content

Commit a16ad0b

Browse files
authored
45 bug metadata are not returned (#46)
* refactor: decouple MetadataService file handling with new MetaDataProvider interface - Replaced direct file handling logic in `MetadataService` with the `MetaDataProvider` interface. - Introduced `FileMetaDataProvider` for file-based metadata loading, improving testability. - Adjusted ImportService to use configurable `paikka.version` property. - Added comprehensive unit tests for metadata loading logic. * fix: correct variable name typo in `MetadataServiceTest`
1 parent 70fc17f commit a16ad0b

8 files changed

Lines changed: 154 additions & 49 deletions

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* This file is part of paikka.
3+
*
4+
* Paikka is free software: you can redistribute it and/or
5+
* modify it under the terms of the GNU Affero General Public License
6+
* as published by the Free Software Foundation, either version 3 or
7+
* any later version.
8+
*
9+
* Paikka is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied
11+
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
* See the GNU Affero General Public License for more details.
13+
* You should have received a copy of the GNU Affero General Public License
14+
* along with Paikka. If not, see <https://www.gnu.org/licenses/>.
15+
*/
16+
17+
package com.dedicatedcode.paikka.service;
18+
19+
import com.dedicatedcode.paikka.config.PaikkaConfiguration;
20+
import org.springframework.stereotype.Service;
21+
22+
import java.io.FileInputStream;
23+
import java.io.FileNotFoundException;
24+
import java.io.InputStream;
25+
import java.nio.file.Path;
26+
import java.nio.file.Paths;
27+
28+
@Service
29+
public class FileMetaDataProvider implements MetaDataProvider {
30+
private static final String METADATA_FILE_NAME = "paikka_metadata.json";
31+
32+
private final PaikkaConfiguration configuration;
33+
private final Path metadataPath;
34+
35+
public FileMetaDataProvider(PaikkaConfiguration configuration) {
36+
this.configuration = configuration;
37+
this.metadataPath = Paths.get(configuration.getDataDir(), METADATA_FILE_NAME);
38+
}
39+
40+
@Override
41+
public boolean exists() {
42+
return false;
43+
}
44+
45+
@Override
46+
public InputStream get() throws FileNotFoundException {
47+
return new FileInputStream(metadataPath.toFile());
48+
}
49+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* This file is part of paikka.
3+
*
4+
* Paikka is free software: you can redistribute it and/or
5+
* modify it under the terms of the GNU Affero General Public License
6+
* as published by the Free Software Foundation, either version 3 or
7+
* any later version.
8+
*
9+
* Paikka is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied
11+
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
* See the GNU Affero General Public License for more details.
13+
* You should have received a copy of the GNU Affero General Public License
14+
* along with Paikka. If not, see <https://www.gnu.org/licenses/>.
15+
*/
16+
17+
package com.dedicatedcode.paikka.service;
18+
19+
import java.io.FileNotFoundException;
20+
import java.io.InputStream;
21+
22+
public interface MetaDataProvider {
23+
boolean exists();
24+
25+
InputStream get() throws FileNotFoundException;
26+
}

src/main/java/com/dedicatedcode/paikka/service/MetadataService.java

Lines changed: 12 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.dedicatedcode.paikka.service;
1818

19-
import com.dedicatedcode.paikka.config.PaikkaConfiguration;
2019
import com.fasterxml.jackson.databind.ObjectMapper;
2120
import jakarta.annotation.PostConstruct;
2221
import org.slf4j.Logger;
@@ -25,11 +24,7 @@
2524
import org.springframework.stereotype.Service;
2625

2726
import java.io.IOException;
28-
import java.nio.file.Files;
29-
import java.nio.file.Path;
30-
import java.nio.file.Paths;
31-
import java.time.Instant;
32-
import java.time.format.DateTimeParseException;
27+
import java.io.InputStream;
3328
import java.util.Collections;
3429
import java.util.HashMap;
3530
import java.util.Map;
@@ -40,17 +35,16 @@
4035
public class MetadataService {
4136

4237
private static final Logger logger = LoggerFactory.getLogger(MetadataService.class);
43-
private static final String METADATA_FILE_NAME = "paikka_metadata.json";
4438

45-
private final PaikkaConfiguration config;
4639
private final ObjectMapper objectMapper;
40+
private final MetaDataProvider provider;
4741

4842
private volatile PaikkaMetadata metadata; // Change type to PaikkaMetadata
4943

50-
public MetadataService(PaikkaConfiguration config, ObjectMapper objectMapper) {
51-
this.config = config;
44+
public MetadataService(MetaDataProvider provider, ObjectMapper objectMapper) {
45+
this.provider = provider;
5246
this.objectMapper = objectMapper;
53-
this.metadata = null; // Initialize with null, will be loaded in @PostConstruct
47+
this.metadata = null;
5448
}
5549

5650
@PostConstruct
@@ -62,20 +56,18 @@ public void init() {
6256
* Loads the metadata from the paikka_metadata.json file.
6357
* This method is synchronized to prevent race conditions during reload.
6458
*/
65-
public synchronized void loadMetadata() {
66-
Path metadataPath = Paths.get(config.getDataDir(), METADATA_FILE_NAME);
67-
68-
if (!Files.exists(metadataPath)) {
69-
logger.warn("Metadata file not found at {}. Running without metadata.", metadataPath);
59+
private synchronized void loadMetadata() {
60+
if (!provider.exists()) {
61+
logger.warn("Metadata file not!. Running without metadata.");
7062
this.metadata = null; // Set to null if file not found
7163
return;
7264
}
7365

74-
try {
75-
this.metadata = objectMapper.readValue(metadataPath.toFile(), PaikkaMetadata.class); // Deserialize to PaikkaMetadata
76-
logger.info("Metadata loaded successfully from {}", metadataPath);
66+
try (InputStream is = provider.get()) {
67+
this.metadata = objectMapper.readValue(is, PaikkaMetadata.class); // Deserialize to PaikkaMetadata
68+
logger.info("Metadata loaded successfully");
7769
} catch (IOException e) {
78-
logger.error("Failed to load metadata from {}: {}", metadataPath, e.getMessage());
70+
logger.error("Failed to load metadata:", e);
7971
this.metadata = null; // Set to null on error
8072
}
8173
}
@@ -115,30 +107,4 @@ public Map<String, Object> getMetadata() {
115107
metadataMap.put("paikkaVersion", metadata.paikkaVersion());
116108
return Collections.unmodifiableMap(metadataMap);
117109
}
118-
119-
/**
120-
* Returns the import timestamp as an Instant.
121-
* If metadata is not available or timestamp is invalid, returns Optional.empty().
122-
*/
123-
public Optional<Instant> getImportTimestamp() {
124-
return Optional.ofNullable(metadata)
125-
.map(PaikkaMetadata::importTimestamp)
126-
.flatMap(timestampStr -> {
127-
try {
128-
return Optional.of(Instant.parse(timestampStr));
129-
} catch (DateTimeParseException e) {
130-
logger.warn("Invalid importTimestamp format in metadata: {}", timestampStr);
131-
return Optional.empty();
132-
}
133-
});
134-
}
135-
136-
/**
137-
* Returns the PAIKKA application version that generated the data.
138-
*/
139-
public String getPaikkaVersion() {
140-
return Optional.ofNullable(metadata)
141-
.map(PaikkaMetadata::paikkaVersion)
142-
.orElse("unknown");
143-
}
144110
}

src/main/java/com/dedicatedcode/paikka/service/importer/ImportService.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.locationtech.jts.geom.*;
3737
import org.locationtech.jts.io.WKBWriter;
3838
import org.rocksdb.*;
39+
import org.springframework.beans.factory.annotation.Value;
3940
import org.springframework.stereotype.Service;
4041

4142
import java.io.IOException;
@@ -65,6 +66,7 @@ public class ImportService {
6566
private final S2Helper s2Helper;
6667
private final GeometrySimplificationService geometrySimplificationService;
6768
private final PaikkaConfiguration config;
69+
private final String version;
6870

6971
private final Map<String, String> tagCache = new ConcurrentHashMap<>(1000);
7072

@@ -73,10 +75,11 @@ public class ImportService {
7375
private final AtomicLong sequence = new AtomicLong(0);
7476
private final AtomicLong buildingSequence = new AtomicLong(0);
7577

76-
public ImportService(S2Helper s2Helper, GeometrySimplificationService geometrySimplificationService, PaikkaConfiguration config) {
78+
public ImportService(S2Helper s2Helper, GeometrySimplificationService geometrySimplificationService, PaikkaConfiguration config, @Value("${paikka.version:1.0.0}") String version) {
7779
this.s2Helper = s2Helper;
7880
this.geometrySimplificationService = geometrySimplificationService;
7981
this.config = config;
82+
this.version = version;
8083
this.fileReadWindowSize = calculateFileReadWindowSize();
8184
}
8285

@@ -289,7 +292,7 @@ private void writeMetadataFile(List<Path> pbfFiles, Path dataDirectory) throws I
289292
String importTimestamp = DateTimeFormatter.ISO_INSTANT.format(now);
290293
String dataVersion = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss").withZone(ZoneOffset.UTC).format(now);
291294
ObjectMapper objectMapper = new ObjectMapper();
292-
PaikkaMetadata metadata = new PaikkaMetadata(importTimestamp, dataVersion, pbfFiles.stream().map(path -> path.getFileName().toString()).toList(), S2Helper.GRID_LEVEL, "1.0.0");
295+
PaikkaMetadata metadata = new PaikkaMetadata(importTimestamp, dataVersion, pbfFiles.stream().map(path -> path.getFileName().toString()).toList(), S2Helper.GRID_LEVEL, version);
293296

294297
objectMapper.writeValue(metadataPath.toFile(), metadata);
295298
System.out.println("\n\033[1;32mMetadata file written to: " + metadataPath + "\033[0m");

src/main/resources/application.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ spring.web.resources.cache.cachecontrol.cache-public=true
1212
spring.web.resources.chain.strategy.content.enabled=true
1313
spring.web.resources.chain.strategy.content.paths=/css/**,/js/**,/img/**,/fonts/**
1414

15+
paikka.version=1.1.7
1516
paikka.data-dir=./data
1617
paikka.import.threads=16
1718
paikka.import.chunk-size=100000

src/test/java/com/dedicatedcode/paikka/service/ImportServiceTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ void setUp() throws Exception {
6868
GeometrySimplificationService geometrySimplificationService = new GeometrySimplificationService();
6969

7070
S2Helper s2Helper = new S2Helper();
71-
ImportService importService = new ImportService(s2Helper, geometrySimplificationService, config);
71+
ImportService importService = new ImportService(s2Helper, geometrySimplificationService, config, "1.0.0");
7272
importService.importData(Collections.singletonList(tempImportFile.toString()), tempDataDir.toString());
7373
}
7474

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* This file is part of paikka.
3+
*
4+
* Paikka is free software: you can redistribute it and/or
5+
* modify it under the terms of the GNU Affero General Public License
6+
* as published by the Free Software Foundation, either version 3 or
7+
* any later version.
8+
*
9+
* Paikka is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied
11+
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
* See the GNU Affero General Public License for more details.
13+
* You should have received a copy of the GNU Affero General Public License
14+
* along with Paikka. If not, see <https://www.gnu.org/licenses/>.
15+
*/
16+
17+
package com.dedicatedcode.paikka.service;
18+
19+
import com.fasterxml.jackson.databind.ObjectMapper;
20+
import org.junit.jupiter.api.Test;
21+
22+
import java.io.FileNotFoundException;
23+
import java.io.InputStream;
24+
import java.util.List;
25+
import java.util.Map;
26+
27+
import static org.junit.jupiter.api.Assertions.assertEquals;
28+
import static org.junit.jupiter.api.Assertions.assertNotNull;
29+
30+
class MetadataServiceTest {
31+
@SuppressWarnings("unchecked")
32+
@Test
33+
void shouldLoadMetadata() {
34+
MetadataService candidate = new MetadataService(new MetaDataProvider() {
35+
@Override
36+
public boolean exists() {
37+
return true;
38+
}
39+
40+
@Override
41+
public InputStream get() throws FileNotFoundException {
42+
return getClass().getResourceAsStream("/metadata.json");
43+
}
44+
}, new ObjectMapper());
45+
candidate.reload();
46+
47+
Map<String, Object> loaded = candidate.getMetadata();
48+
assertNotNull(loaded);
49+
assertEquals("2026-05-17T07:47:51.028675223Z", loaded.get("importTimestamp"));
50+
assertEquals("20260517-074751", loaded.get("dataVersion"));
51+
assertEquals(12, loaded.get("gridLevel"));
52+
assertEquals("1.0.0", loaded.get("paikkaVersion"));
53+
List<String> files = (List<String>) loaded.get("files");
54+
assertNotNull(files);
55+
assertEquals(2, files.size());
56+
assertEquals("planet-filtered.pbf", files.get(0));
57+
assertEquals("test.pbf", files.get(1));
58+
}
59+
}

src/test/resources/metadata.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"importTimestamp":"2026-05-17T07:47:51.028675223Z","dataVersion":"20260517-074751","file":["planet-filtered.pbf", "test.pbf"],"gridLevel":12,"paikkaVersion":"1.0.0"}

0 commit comments

Comments
 (0)