Skip to content

Commit

Permalink
Implement static data (shape file)
Browse files Browse the repository at this point in the history
  • Loading branch information
bertrik committed Jan 27, 2024
1 parent 2b256db commit dff33d1
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package nl.bertriksikken.geojson;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonProperty;

public final class FeatureCollection extends GeoJsonObject {

@JsonProperty("features")
Expand All @@ -22,6 +22,10 @@ public void add(Feature feature) {
features.add(feature);
}

public List<Feature> getFeatures() {
return List.copyOf(features);
}

public static final class Feature extends GeoJsonObject {
@JsonProperty("geometry")
private final GeoJsonGeometry geometry;
Expand All @@ -37,6 +41,10 @@ public Feature(GeoJsonGeometry geometry) {
public void addProperty(String name, Object value) {
properties.put(name, value);
}

public Map<String, Object> getProperties() {
return Map.copyOf(properties);
}
}

public static abstract class GeoJsonGeometry extends GeoJsonObject {
Expand All @@ -58,7 +66,7 @@ private PointGeometry() {

public PointGeometry(double latitude, double longitude) {
super(EGeometry.POINT);
coordinates = new double[] { longitude, latitude };
coordinates = new double[]{longitude, latitude};
}

public double getLatitude() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import jakarta.ws.rs.sse.OutboundSseEvent;
import jakarta.ws.rs.sse.Sse;
import jakarta.ws.rs.sse.SseEventSink;
import nl.bertriksikken.geojson.FeatureCollection;
import nl.bertriksikken.verkeersdrukte.traffic.AggregateMeasurement;
import nl.bertriksikken.verkeersdrukte.traffic.ITrafficHandler;
import nl.bertriksikken.verkeersdrukte.traffic.TrafficConfig;
Expand Down Expand Up @@ -52,18 +53,14 @@ public final class VerkeersDrukteResource {

@GET
@Path("/static")
public String getStatic() {
// return the entire shape file, FeatureCollection
LOG.info("getStatic()");
return "static";
public FeatureCollection getStatic() {
return handler.getStaticData();
}

@GET
@Path("/static/{location}")
public String getStatic(@PathParam("location") String location) {
// return part of the shape file, a single Feature
LOG.info("getStatic() for location {}", location);
return location;
public Optional<FeatureCollection.Feature> getStatic(@PathParam("location") String location) {
return Optional.ofNullable(handler.getStaticData(location));
}

@GET
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
package nl.bertriksikken.verkeersdrukte.traffic;

public interface ITrafficHandler {
import nl.bertriksikken.geojson.FeatureCollection;

public interface ITrafficHandler {

boolean isHealthy();

AggregateMeasurement getDynamicData(String location);

void subscribe(String clientId, INotifyData callback);
FeatureCollection getStaticData();

FeatureCollection.Feature getStaticData(String location);

void subscribe(String clientId, INotifyData callback);

void unsubscribe(String clientId);
void unsubscribe(String clientId);

public interface INotifyData {
interface INotifyData {
void notifyUpdate();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
import nl.bertriksikken.datex2.D2LogicalModel;
import nl.bertriksikken.datex2.MeasuredValue;
import nl.bertriksikken.datex2.SiteMeasurements;
import nl.bertriksikken.geojson.FeatureCollection;
import nl.bertriksikken.shapefile.EShapeType;
import nl.bertriksikken.shapefile.ShapeFile;
import nl.bertriksikken.shapefile.ShapeRecord;
import nl.bertriksikken.verkeersdrukte.ndw.FileResponse;
import nl.bertriksikken.verkeersdrukte.ndw.NdwClient;
import nl.bertriksikken.verkeersdrukte.ndw.NdwConfig;
Expand All @@ -16,6 +20,7 @@

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
Expand All @@ -34,15 +39,23 @@ public final class TrafficHandler implements ITrafficHandler, Managed {
private final NdwClient ndwClient;
private final ObjectMapper mapper;
private MeasurementCache measurementCache = new MeasurementCache(Instant.now());
private FeatureCollection shapeFile;

public TrafficHandler(NdwConfig config) {
this.ndwClient = NdwClient.create(config);
this.mapper = new XmlMapper();
}

@Override
public void start() {
public void start() throws IOException {
// read the shape file
LOG.info("Reading shape file ...");
InputStream shpStream = getClass().getClassLoader().getResourceAsStream("shapefile/Telpunten_WGS84.shp");
InputStream dbfStream = getClass().getClassLoader().getResourceAsStream("shapefile/Telpunten_WGS84.dbf");
shapeFile = readShapeFile(shpStream, dbfStream);

// schedule regular fetches, starting immediately
LOG.info("Schedule download ...");
executor.schedule(this::downloadTrafficSpeed, 0, TimeUnit.SECONDS);
}

Expand Down Expand Up @@ -142,6 +155,23 @@ public AggregateMeasurement getDynamicData(String location) {
return measurementCache.get(location);
}

@Override
public FeatureCollection getStaticData() {
return shapeFile;
}

@Override
public FeatureCollection.Feature getStaticData(String location) {
for (FeatureCollection.Feature feature : shapeFile.getFeatures()) {
String dlgLoc = feature.getProperties().get("dgl_loc").toString();
if (location.equals(dlgLoc)) {
return feature;
}
}
// not found
return null;
}

@Override
public void subscribe(String clientId, INotifyData callback) {
LOG.info("Subscribe: {}", clientId);
Expand Down Expand Up @@ -171,6 +201,21 @@ private void notifyClients() {
copy.forEach(subscription -> subscription.callback.notifyUpdate());
}

private FeatureCollection readShapeFile(InputStream shpStream, InputStream dbfStream) throws IOException {
ShapeFile shapeFile = ShapeFile.read(shpStream, dbfStream);
FeatureCollection collection = new FeatureCollection();
for (ShapeRecord record : shapeFile.getRecords()) {
if (record.getType() == EShapeType.Point) {
ShapeRecord.Point point = (ShapeRecord.Point) record;
FeatureCollection.GeoJsonGeometry geometry = new FeatureCollection.PointGeometry(point.y, point.x);
FeatureCollection.Feature feature = new FeatureCollection.Feature(geometry);
record.getProperties().forEach(feature::addProperty);
collection.add(feature);
}
}
return collection;
}

private static final class Subscription {
private final String clientId;
private final INotifyData callback;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,17 @@
import com.fasterxml.jackson.databind.ObjectWriter;
import nl.bertriksikken.geojson.FeatureCollection;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

public final class ShapeFileReaderTest {

private static final Logger LOG = LoggerFactory.getLogger(ShapeFileReaderTest.class);

@Test
public void testWriteGeoJson() throws IOException {
InputStream shpStream = getClass().getClassLoader().getResourceAsStream("Telpunten_WGS84.shp");
InputStream dbfStream = getClass().getClassLoader().getResourceAsStream("Telpunten_WGS84.dbf");
InputStream shpStream = getClass().getClassLoader().getResourceAsStream("shapefile/Telpunten_WGS84.shp");
InputStream dbfStream = getClass().getClassLoader().getResourceAsStream("shapefile/Telpunten_WGS84.dbf");
ShapeFile shapeFile = ShapeFile.read(shpStream, dbfStream);

FeatureCollection collection = new FeatureCollection();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,17 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public final class TrafficHandlerTest {

private static final Logger LOG = LoggerFactory.getLogger(TrafficHandlerTest.class);

public static void main(String[] args) throws InterruptedException {
public static void main(String[] args) throws IOException {
NdwConfig config = new NdwConfig();
TrafficHandler trafficHandler = new TrafficHandler(config);
trafficHandler.start();
try {
trafficHandler.subscribe("client", () -> notifyData());
} finally {
Thread.sleep(120_000L);
trafficHandler.stop();
}
trafficHandler.subscribe("client", TrafficHandlerTest::notifyData);
}

private static void notifyData() {
Expand Down

0 comments on commit dff33d1

Please sign in to comment.