Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* This file is part of paikka.
*
* Paikka is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation, either version 3 or
* any later version.
*
* Paikka is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with Paikka. If not, see <https://www.gnu.org/licenses/>.
*/

package com.dedicatedcode.paikka.service;

import com.dedicatedcode.paikka.config.PaikkaConfiguration;
import org.springframework.stereotype.Service;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;

@Service
public class FileMetaDataProvider implements MetaDataProvider {
private static final String METADATA_FILE_NAME = "paikka_metadata.json";

private final PaikkaConfiguration configuration;
private final Path metadataPath;

public FileMetaDataProvider(PaikkaConfiguration configuration) {
this.configuration = configuration;
this.metadataPath = Paths.get(configuration.getDataDir(), METADATA_FILE_NAME);
}

@Override
public boolean exists() {
return false;
}

@Override
public InputStream get() throws FileNotFoundException {
return new FileInputStream(metadataPath.toFile());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* This file is part of paikka.
*
* Paikka is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation, either version 3 or
* any later version.
*
* Paikka is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with Paikka. If not, see <https://www.gnu.org/licenses/>.
*/

package com.dedicatedcode.paikka.service;

import java.io.FileNotFoundException;
import java.io.InputStream;

public interface MetaDataProvider {
boolean exists();

InputStream get() throws FileNotFoundException;
}
58 changes: 12 additions & 46 deletions src/main/java/com/dedicatedcode/paikka/service/MetadataService.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package com.dedicatedcode.paikka.service;

import com.dedicatedcode.paikka.config.PaikkaConfiguration;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
Expand All @@ -25,11 +24,7 @@
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.format.DateTimeParseException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -40,17 +35,16 @@
public class MetadataService {

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

private final PaikkaConfiguration config;
private final ObjectMapper objectMapper;
private final MetaDataProvider provider;

private volatile PaikkaMetadata metadata; // Change type to PaikkaMetadata

public MetadataService(PaikkaConfiguration config, ObjectMapper objectMapper) {
this.config = config;
public MetadataService(MetaDataProvider provider, ObjectMapper objectMapper) {
this.provider = provider;
this.objectMapper = objectMapper;
this.metadata = null; // Initialize with null, will be loaded in @PostConstruct
this.metadata = null;
}

@PostConstruct
Expand All @@ -62,20 +56,18 @@ public void init() {
* Loads the metadata from the paikka_metadata.json file.
* This method is synchronized to prevent race conditions during reload.
*/
public synchronized void loadMetadata() {
Path metadataPath = Paths.get(config.getDataDir(), METADATA_FILE_NAME);

if (!Files.exists(metadataPath)) {
logger.warn("Metadata file not found at {}. Running without metadata.", metadataPath);
private synchronized void loadMetadata() {
if (!provider.exists()) {
logger.warn("Metadata file not!. Running without metadata.");
this.metadata = null; // Set to null if file not found
return;
}

try {
this.metadata = objectMapper.readValue(metadataPath.toFile(), PaikkaMetadata.class); // Deserialize to PaikkaMetadata
logger.info("Metadata loaded successfully from {}", metadataPath);
try (InputStream is = provider.get()) {
this.metadata = objectMapper.readValue(is, PaikkaMetadata.class); // Deserialize to PaikkaMetadata
logger.info("Metadata loaded successfully");
} catch (IOException e) {
logger.error("Failed to load metadata from {}: {}", metadataPath, e.getMessage());
logger.error("Failed to load metadata:", e);
this.metadata = null; // Set to null on error
}
}
Expand Down Expand Up @@ -115,30 +107,4 @@ public Map<String, Object> getMetadata() {
metadataMap.put("paikkaVersion", metadata.paikkaVersion());
return Collections.unmodifiableMap(metadataMap);
}

/**
* Returns the import timestamp as an Instant.
* If metadata is not available or timestamp is invalid, returns Optional.empty().
*/
public Optional<Instant> getImportTimestamp() {
return Optional.ofNullable(metadata)
.map(PaikkaMetadata::importTimestamp)
.flatMap(timestampStr -> {
try {
return Optional.of(Instant.parse(timestampStr));
} catch (DateTimeParseException e) {
logger.warn("Invalid importTimestamp format in metadata: {}", timestampStr);
return Optional.empty();
}
});
}

/**
* Returns the PAIKKA application version that generated the data.
*/
public String getPaikkaVersion() {
return Optional.ofNullable(metadata)
.map(PaikkaMetadata::paikkaVersion)
.orElse("unknown");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.WKBWriter;
import org.rocksdb.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
Expand Down Expand Up @@ -65,6 +66,7 @@ public class ImportService {
private final S2Helper s2Helper;
private final GeometrySimplificationService geometrySimplificationService;
private final PaikkaConfiguration config;
private final String version;

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

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

public ImportService(S2Helper s2Helper, GeometrySimplificationService geometrySimplificationService, PaikkaConfiguration config) {
public ImportService(S2Helper s2Helper, GeometrySimplificationService geometrySimplificationService, PaikkaConfiguration config, @Value("${paikka.version:1.0.0}") String version) {
this.s2Helper = s2Helper;
this.geometrySimplificationService = geometrySimplificationService;
this.config = config;
this.version = version;
this.fileReadWindowSize = calculateFileReadWindowSize();
}

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

objectMapper.writeValue(metadataPath.toFile(), metadata);
System.out.println("\n\033[1;32mMetadata file written to: " + metadataPath + "\033[0m");
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ spring.web.resources.cache.cachecontrol.cache-public=true
spring.web.resources.chain.strategy.content.enabled=true
spring.web.resources.chain.strategy.content.paths=/css/**,/js/**,/img/**,/fonts/**

paikka.version=1.1.7
paikka.data-dir=./data
paikka.import.threads=16
paikka.import.chunk-size=100000
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ void setUp() throws Exception {
GeometrySimplificationService geometrySimplificationService = new GeometrySimplificationService();

S2Helper s2Helper = new S2Helper();
ImportService importService = new ImportService(s2Helper, geometrySimplificationService, config);
ImportService importService = new ImportService(s2Helper, geometrySimplificationService, config, "1.0.0");
importService.importData(Collections.singletonList(tempImportFile.toString()), tempDataDir.toString());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* This file is part of paikka.
*
* Paikka is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation, either version 3 or
* any later version.
*
* Paikka is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with Paikka. If not, see <https://www.gnu.org/licenses/>.
*/

package com.dedicatedcode.paikka.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

class MetadataServiceTest {
@SuppressWarnings("unchecked")
@Test
void shouldLoadMetadata() {
MetadataService candidate = new MetadataService(new MetaDataProvider() {
@Override
public boolean exists() {
return true;
}

@Override
public InputStream get() throws FileNotFoundException {
return getClass().getResourceAsStream("/metadata.json");
}
}, new ObjectMapper());
candidate.reload();

Map<String, Object> loaded = candidate.getMetadata();
assertNotNull(loaded);
assertEquals("2026-05-17T07:47:51.028675223Z", loaded.get("importTimestamp"));
assertEquals("20260517-074751", loaded.get("dataVersion"));
assertEquals(12, loaded.get("gridLevel"));
assertEquals("1.0.0", loaded.get("paikkaVersion"));
List<String> files = (List<String>) loaded.get("files");
assertNotNull(files);
assertEquals(2, files.size());
assertEquals("planet-filtered.pbf", files.get(0));
assertEquals("test.pbf", files.get(1));
}
}
1 change: 1 addition & 0 deletions src/test/resources/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"importTimestamp":"2026-05-17T07:47:51.028675223Z","dataVersion":"20260517-074751","file":["planet-filtered.pbf", "test.pbf"],"gridLevel":12,"paikkaVersion":"1.0.0"}
Loading