From e5d8b1738b8eeb465975c60da295b67354e203a6 Mon Sep 17 00:00:00 2001 From: Jesper Zedlitz <jesper@zedlitz.de> Date: Sat, 27 Nov 2021 08:55:48 +0100 Subject: [PATCH] Refactored to support HEAD requests --- .gitlab-ci.yml | 2 +- pom.xml | 12 +- .../landsh/opendata/coronardeck/CoronaData.g4 | 2 +- .../de/landsh/opendata/dataproxy/App.java | 57 ++++-- .../dataproxy/CachingDataConverter.java | 19 -- .../dataproxy/CachingDataResponser.java | 72 ++++++++ .../opendata/dataproxy/CoronaRdEck.java | 78 +++----- .../landsh/opendata/dataproxy/StrassenSH.java | 86 +++++++++ .../dataproxy/StrassenSH2Geojson.java | 111 ------------ .../opendata/dataproxy/CoronaDataTest.java | 79 +++++++++ .../dataproxy/StrassenSH2GeojsonTest.java | 28 +++ src/test/resources/2021-11-12_100007.json | 167 ++++++++++++++++++ 12 files changed, 512 insertions(+), 201 deletions(-) delete mode 100644 src/main/java/de/landsh/opendata/dataproxy/CachingDataConverter.java create mode 100644 src/main/java/de/landsh/opendata/dataproxy/CachingDataResponser.java create mode 100644 src/main/java/de/landsh/opendata/dataproxy/StrassenSH.java delete mode 100644 src/main/java/de/landsh/opendata/dataproxy/StrassenSH2Geojson.java create mode 100644 src/test/java/de/landsh/opendata/dataproxy/CoronaDataTest.java create mode 100644 src/test/java/de/landsh/opendata/dataproxy/StrassenSH2GeojsonTest.java create mode 100644 src/test/resources/2021-11-12_100007.json diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 808c596..6eb0171 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,5 +15,5 @@ build: script: "mvn clean package -B" artifacts: paths: - - target/*-jar-with-dependencies.jar + - target/data-proxy-jar-with-dependencies.jar diff --git a/pom.xml b/pom.xml index ea819ec..1c40ddb 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,7 @@ <jena.version>4.2.0</jena.version> </properties> <build> + <finalName>data-proxy</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -26,7 +27,7 @@ <plugin> <groupId>org.antlr</groupId> <artifactId>antlr4-maven-plugin</artifactId> - <version>4.5</version> + <version>4.9.3</version> <executions> <execution> <goals> @@ -85,7 +86,14 @@ <dependency> <groupId>org.antlr</groupId> <artifactId>antlr4-runtime</artifactId> - <version>4.5</version> + <version>4.9.3</version> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.13.2</version> + <scope>test</scope> </dependency> </dependencies> </project> diff --git a/src/main/antlr4/de/landsh/opendata/coronardeck/CoronaData.g4 b/src/main/antlr4/de/landsh/opendata/coronardeck/CoronaData.g4 index aec2ba3..d4f212c 100644 --- a/src/main/antlr4/de/landsh/opendata/coronardeck/CoronaData.g4 +++ b/src/main/antlr4/de/landsh/opendata/coronardeck/CoronaData.g4 @@ -12,7 +12,7 @@ pair: NAME ':' VALUE ; NAME: [a-z_]+ ; WS : [ \t\r\n]+ -> skip ; // Define whitespace rule, toss it out -QUOTE: [\'\"] ; +QUOTE: ['"] ; ARS: '010' [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] ; VALUE: [0-9]+ '.'? [0-9]* ; diff --git a/src/main/java/de/landsh/opendata/dataproxy/App.java b/src/main/java/de/landsh/opendata/dataproxy/App.java index 77ed16f..b78c91a 100644 --- a/src/main/java/de/landsh/opendata/dataproxy/App.java +++ b/src/main/java/de/landsh/opendata/dataproxy/App.java @@ -1,26 +1,57 @@ package de.landsh.opendata.dataproxy; -import fi.iki.elonen.router.RouterNanoHTTPD; +import fi.iki.elonen.NanoHTTPD; import fi.iki.elonen.util.ServerRunner; -public class App extends RouterNanoHTTPD { - public static final int PORT = 8081; +public class App extends NanoHTTPD { + public static int port = 8080; - @Override - public void addMappings() { - super.addMappings(); - addRoute("/strassen-sh.geojson", StrassenSH2Geojson.class); - addRoute("/corona-rd-eck.json", CoronaRdEck.class); - - } + private final StrassenSH strassenSH = new StrassenSH(); + private final CoronaRdEck coronaRdEck = new CoronaRdEck(); public App() { - super(PORT); - addMappings(); - System.out.println("\nRunning! Point your browser to http://localhost:" + PORT + "/ \n"); + super(port); + System.out.println("\nRunning! Point your browser to http://localhost:" + port + "/ \n"); } public static void main(String[] args) { + + if( args.length > 0) { + try { + App.port = Integer.parseInt(args[0]); + } catch (NumberFormatException ignore) { + System.err.println("Usage: java -jar data-proxy.jar [PORT]"); + System.exit(1); + } + } + ServerRunner.run(App.class); } + + @Override + public Response serve(IHTTPSession session) { + + final CachingDataResponser responder; + if ("/strassen-sh.geojson".equals(session.getUri())) { + responder = strassenSH; + } else if ("/corona-rd-eck.json".equals(session.getUri())) { + responder = coronaRdEck; + } else { + responder = null; + } + + if (responder == null) { + return newFixedLengthResponse(Response.Status.NOT_FOUND, "text/plain", "Not Found"); + } else { + if (session.getMethod() == Method.GET) { + return responder.get(); + } else if (session.getMethod() == Method.HEAD) { + return responder.head(); + } else { + return newFixedLengthResponse(Response.Status.METHOD_NOT_ALLOWED, "text/plain", "Method not allowed"); + + } + } + + } } diff --git a/src/main/java/de/landsh/opendata/dataproxy/CachingDataConverter.java b/src/main/java/de/landsh/opendata/dataproxy/CachingDataConverter.java deleted file mode 100644 index bb37308..0000000 --- a/src/main/java/de/landsh/opendata/dataproxy/CachingDataConverter.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.landsh.opendata.dataproxy; - -import fi.iki.elonen.NanoHTTPD; -import fi.iki.elonen.router.RouterNanoHTTPD; - -import java.io.IOException; - -public abstract class CachingDataConverter extends RouterNanoHTTPD.DefaultHandler { - - - /** - * Return the update interval in milliseconds; - */ - abstract int getUpdateInterval(); - - abstract String loadData() throws IOException; - - -} diff --git a/src/main/java/de/landsh/opendata/dataproxy/CachingDataResponser.java b/src/main/java/de/landsh/opendata/dataproxy/CachingDataResponser.java new file mode 100644 index 0000000..9665b47 --- /dev/null +++ b/src/main/java/de/landsh/opendata/dataproxy/CachingDataResponser.java @@ -0,0 +1,72 @@ +package de.landsh.opendata.dataproxy; + +import fi.iki.elonen.NanoHTTPD; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +public abstract class CachingDataResponser { + + private String data = "{}"; + private long lastUpdate = -1; + private NanoHTTPD.Response.Status status = NanoHTTPD.Response.Status.INTERNAL_ERROR; + + /** + * Returns the update interval in milliseconds. + */ + abstract int getUpdateInterval(); + + /** + * Returns the MIME type for a successful response. + */ + abstract String getMimeType(); + + /** + * Load data from the original source. + */ + abstract String loadData() throws IOException; + + private void loadDataIfNecessary() { + if (System.currentTimeMillis() - getUpdateInterval() > lastUpdate) { + System.out.println("Loading data for " + getClass().getName()); + + try { + data = loadData(); + status = NanoHTTPD.Response.Status.OK; + } catch (IOException e) { + data = "{}"; + status = NanoHTTPD.Response.Status.INTERNAL_ERROR; + } + lastUpdate = System.currentTimeMillis(); + } + } + + /** + * Handle GET requests. + */ + public NanoHTTPD.Response get() { + loadDataIfNecessary(); + + NanoHTTPD.Response response = NanoHTTPD.newFixedLengthResponse(status, getMimeType(), data); + response.addHeader("Access-Control-Allow-Origin", "*"); + return response; + } + + /** + * Handle HEAD requests. + */ + public NanoHTTPD.Response head() { + loadDataIfNecessary(); + NanoHTTPD.Response response = new HeadResponse(status, getMimeType(), data.length()); + response.addHeader("Access-Control-Allow-Origin", "*"); + return response; + } + + static class HeadResponse extends NanoHTTPD.Response { + + protected HeadResponse(IStatus status, String mimeType, long totalBytes) { + super(status, mimeType, new ByteArrayInputStream(new byte[0]), totalBytes); + } + } + +} diff --git a/src/main/java/de/landsh/opendata/dataproxy/CoronaRdEck.java b/src/main/java/de/landsh/opendata/dataproxy/CoronaRdEck.java index 686274a..7c25109 100644 --- a/src/main/java/de/landsh/opendata/dataproxy/CoronaRdEck.java +++ b/src/main/java/de/landsh/opendata/dataproxy/CoronaRdEck.java @@ -2,8 +2,6 @@ package de.landsh.opendata.dataproxy; import de.landsh.opendata.coronardeck.CoronaDataLexer; import de.landsh.opendata.coronardeck.CoronaDataParser; -import fi.iki.elonen.NanoHTTPD; -import fi.iki.elonen.router.RouterNanoHTTPD; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.tree.ParseTree; @@ -14,30 +12,40 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.net.URL; -import java.util.Map; -public class CoronaRdEck implements RouterNanoHTTPD.UriResponder { - public static final int UPDATE_INTERVAL = 600000; // 10 minutes - private static String data = "{}"; - private static long lastUpdate = -1; - private static NanoHTTPD.Response.Status status = NanoHTTPD.Response.Status.INTERNAL_ERROR; +public class CoronaRdEck extends CachingDataResponser { + + private final String originalURL; + + public CoronaRdEck() { + originalURL = "https://covid19dashboardrdeck.aco/daten/daten.js"; + } + + CoronaRdEck(String url) { + originalURL = url; + } + + @Override + int getUpdateInterval() { + return 600000; // 10 minutes + } + + @Override + String getMimeType() { + return "application/json"; + } String loadData() throws IOException { - InputStream inputStream = new URL("https://covid19dashboardrdeck.aco/daten/daten.js").openStream(); + final InputStream inputStream = new URL(originalURL).openStream(); final ANTLRInputStream input = new ANTLRInputStream(inputStream); - final CoronaDataLexer lexer = new CoronaDataLexer(input); - final CommonTokenStream tokens = new CommonTokenStream(lexer); - final CoronaDataParser parser = new CoronaDataParser(tokens); - final ParseTree tree = parser.data(); - final ParseTreeWalker walker = new ParseTreeWalker(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream out = new PrintStream(baos); + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final PrintStream out = new PrintStream(baos); walker.walk(new CoronaRdEckWalker(out), tree); out.close(); @@ -47,42 +55,4 @@ public class CoronaRdEck implements RouterNanoHTTPD.UriResponder { } - @Override - public NanoHTTPD.Response get(RouterNanoHTTPD.UriResource uriResource, Map<String, String> urlParams, NanoHTTPD.IHTTPSession session) { - if (System.currentTimeMillis() - UPDATE_INTERVAL > lastUpdate) { - System.out.println("Loading data for " + getClass().getName()); - - try { - data = loadData(); - status = NanoHTTPD.Response.Status.OK; - } catch (IOException e) { - data = "{}"; - status = NanoHTTPD.Response.Status.INTERNAL_ERROR; - } - lastUpdate = System.currentTimeMillis(); - } - return NanoHTTPD.newFixedLengthResponse(status, "application/json", data); - } - - @Override - public NanoHTTPD.Response put(RouterNanoHTTPD.UriResource uriResource, Map<String, String> map, NanoHTTPD.IHTTPSession ihttpSession) { - return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.METHOD_NOT_ALLOWED, "text/plain", "method not allowed"); - } - - @Override - public NanoHTTPD.Response post(RouterNanoHTTPD.UriResource uriResource, Map<String, String> map, NanoHTTPD.IHTTPSession ihttpSession) { - return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.METHOD_NOT_ALLOWED, "text/plain", "method not allowed"); - } - - @Override - public NanoHTTPD.Response delete(RouterNanoHTTPD.UriResource uriResource, Map<String, String> map, NanoHTTPD.IHTTPSession ihttpSession) { - return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.METHOD_NOT_ALLOWED, "text/plain", "method not allowed"); - } - - @Override - public NanoHTTPD.Response other(String s, RouterNanoHTTPD.UriResource uriResource, Map<String, String> map, NanoHTTPD.IHTTPSession ihttpSession) { - return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.METHOD_NOT_ALLOWED, "text/plain", "method not allowed"); - } - - } diff --git a/src/main/java/de/landsh/opendata/dataproxy/StrassenSH.java b/src/main/java/de/landsh/opendata/dataproxy/StrassenSH.java new file mode 100644 index 0000000..bfa6bbf --- /dev/null +++ b/src/main/java/de/landsh/opendata/dataproxy/StrassenSH.java @@ -0,0 +1,86 @@ +package de.landsh.opendata.dataproxy; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.json.JSONTokener; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +public class StrassenSH extends CachingDataResponser { + + private final String baseURL; + + public StrassenSH() { + baseURL = "https://strassen-sh.de/proxy/geojson/los/"; + } + + StrassenSH(String baseURL) { + this.baseURL = baseURL; + } + + @Override + int getUpdateInterval() { + return 180000; // 3 minutes + } + + @Override + String getMimeType() { + return "application/geo+json"; + } + + String loadData() throws IOException { + System.out.println("Loading data from strassen-sh.de..."); + + final JSONObject featureCollection = new JSONObject(); + featureCollection.put("type", "FeatureCollection"); + processQuery(featureCollection, new URL(baseURL + "2/100").openStream(), "frei"); + processQuery(featureCollection, new URL(baseURL + "6/100").openStream(), "gestaut"); + processQuery(featureCollection, new URL(baseURL + "4/100").openStream(), "dicht"); + processQuery(featureCollection, new URL(baseURL + "5/100").openStream(), "zähfließend"); + processQuery(featureCollection, new URL(baseURL + "9/100").openStream(), "Datenausfall"); + + return featureCollection.toString(); + } + + private void processQuery(JSONObject featureCollection, InputStream in, String status) { + if (!featureCollection.has("features")) { + featureCollection.put("features", new JSONArray()); + } + + final JSONObject json = new JSONObject(new JSONTokener(in)); + final JSONArray featuresOut = featureCollection.getJSONArray("features"); + final JSONArray featuresIn = json.getJSONArray("features"); + for (int i = 0; i < featuresIn.length(); i++) { + final JSONObject featureIn = featuresIn.getJSONObject(i); + final JSONObject featureOut = convertFeature(featureIn); + featureOut.getJSONObject("properties").put("status", status); + featuresOut.put(featureOut); + } + + if (json.has("properties")) { + featureCollection.put("properties", json.getJSONObject("properties")); + } + } + + JSONObject convertFeature(JSONObject feature) { + final JSONObject result = new JSONObject(); + result.put("type", "Feature"); + + final JSONObject geometry = new JSONObject(); + final JSONObject properties = feature.getJSONObject("properties"); + final String type = feature.getString("type"); + final JSONArray coordinates = feature.getJSONArray("coordinates"); + + result.put("properties", properties); + // result.put("id", coordinates.hashCode()); + geometry.put("type", type); + geometry.put("coordinates", coordinates); + result.put("geometry", geometry); + + return result; + } + + +} diff --git a/src/main/java/de/landsh/opendata/dataproxy/StrassenSH2Geojson.java b/src/main/java/de/landsh/opendata/dataproxy/StrassenSH2Geojson.java deleted file mode 100644 index 920e093..0000000 --- a/src/main/java/de/landsh/opendata/dataproxy/StrassenSH2Geojson.java +++ /dev/null @@ -1,111 +0,0 @@ -package de.landsh.opendata.dataproxy; - -import fi.iki.elonen.NanoHTTPD; -import fi.iki.elonen.router.RouterNanoHTTPD; -import org.json.JSONArray; -import org.json.JSONObject; -import org.json.JSONTokener; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Map; - -public class StrassenSH2Geojson implements RouterNanoHTTPD.UriResponder { - public static final int UPDATE_INTERVAL = 180000; // 3 minutes - private static String data = "{}"; - private static long lastUpdate = -1; - private static NanoHTTPD.Response.Status status = NanoHTTPD.Response.Status.INTERNAL_ERROR; - - String loadData() throws IOException { - System.out.println("Loading data from strassen-sh.de..."); - - final JSONObject featureCollection = new JSONObject(); - featureCollection.put("type", "FeatureCollection"); - processQuery(featureCollection, new URL("https://strassen-sh.de/proxy/geojson/los/2/100").openStream(), "frei"); - processQuery(featureCollection, new URL("https://strassen-sh.de/proxy/geojson/los/6/100").openStream(), "gestaut"); - processQuery(featureCollection, new URL("https://strassen-sh.de/proxy/geojson/los/4/100").openStream(), "dicht"); - processQuery(featureCollection, new URL("https://strassen-sh.de/proxy/geojson/los/5/100").openStream(), "zähfließend"); - processQuery(featureCollection, new URL("https://strassen-sh.de/proxy/geojson/los/9/100").openStream(), "Datenausfall"); - - return featureCollection.toString(); - } - - private void processQuery(JSONObject featureCollection, InputStream in, String status) { - if (!featureCollection.has("features")) { - featureCollection.put("features", new JSONArray()); - } - - final JSONObject json = new JSONObject(new JSONTokener(in)); - final JSONArray featuresOut = featureCollection.getJSONArray("features"); - final JSONArray featuresIn = json.getJSONArray("features"); - for (int i = 0; i < featuresIn.length(); i++) { - final JSONObject featureIn = featuresIn.getJSONObject(i); - final JSONObject featureOut = convertFeature(featureIn); - featureOut.getJSONObject("properties").put("status", status); - featuresOut.put(featureOut); - } - - if (json.has("properties")) { - featureCollection.put("properties", json.getJSONObject("properties")); - } - } - - JSONObject convertFeature(JSONObject feature) { - final JSONObject result = new JSONObject(); - result.put("type", "Feature"); - - final JSONObject geometry = new JSONObject(); - final JSONObject properties = feature.getJSONObject("properties"); - final String type = feature.getString("type"); - final JSONArray coordinates = feature.getJSONArray("coordinates"); - - result.put("properties", properties); - // result.put("id", coordinates.hashCode()); - geometry.put("type", type); - geometry.put("coordinates", coordinates); - result.put("geometry", geometry); - - return result; - } - - @Override - public NanoHTTPD.Response get(RouterNanoHTTPD.UriResource uriResource, Map<String, String> urlParams, NanoHTTPD.IHTTPSession session) { - if (System.currentTimeMillis() - UPDATE_INTERVAL > lastUpdate) { - System.out.println("Loading data for " + getClass().getName()); - - try { - data = loadData(); - status = NanoHTTPD.Response.Status.OK; - } catch (IOException e) { - data = "{}"; - status = NanoHTTPD.Response.Status.INTERNAL_ERROR; - } - lastUpdate = System.currentTimeMillis(); - } - return NanoHTTPD.newFixedLengthResponse(status, "application/geo+json", data); - } - - - @Override - public NanoHTTPD.Response put(RouterNanoHTTPD.UriResource uriResource, Map<String, String> map, NanoHTTPD.IHTTPSession ihttpSession) { - return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.METHOD_NOT_ALLOWED, "text/plain", "method not allowed"); - } - - @Override - public NanoHTTPD.Response post(RouterNanoHTTPD.UriResource uriResource, Map<String, String> map, NanoHTTPD.IHTTPSession ihttpSession) { - return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.METHOD_NOT_ALLOWED, "text/plain", "method not allowed"); - } - - @Override - public NanoHTTPD.Response delete(RouterNanoHTTPD.UriResource uriResource, Map<String, String> map, NanoHTTPD.IHTTPSession ihttpSession) { - return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.METHOD_NOT_ALLOWED, "text/plain", "method not allowed"); - } - - @Override - public NanoHTTPD.Response other(String s, RouterNanoHTTPD.UriResource uriResource, Map<String, String> map, NanoHTTPD.IHTTPSession ihttpSession) { - return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.METHOD_NOT_ALLOWED, "text/plain", "method not allowed"); - } - - -} diff --git a/src/test/java/de/landsh/opendata/dataproxy/CoronaDataTest.java b/src/test/java/de/landsh/opendata/dataproxy/CoronaDataTest.java new file mode 100644 index 0000000..596b3df --- /dev/null +++ b/src/test/java/de/landsh/opendata/dataproxy/CoronaDataTest.java @@ -0,0 +1,79 @@ +package de.landsh.opendata.dataproxy; + +import de.landsh.opendata.coronardeck.CoronaDataLexer; +import de.landsh.opendata.coronardeck.CoronaDataParser; +import org.antlr.v4.runtime.*; +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +/** + * Unit test for simple CoronaData. + */ +public class CoronaDataTest { + + @Test + public void invalidData() { + final CharStream input = CharStreams.fromString("var data = {\n" + + "'010580005005: { amount_pt: 2.1037868162693, amount_t: 206, amount_i: 21, amount_d: 3, amount_h: 182 },\n}"); + + CoronaDataLexer lexer = new CoronaDataLexer(input); + CommonTokenStream tokens = new CommonTokenStream(lexer); + CoronaDataParser parser = new CoronaDataParser(tokens); + + parser.addErrorListener(new BaseErrorListener() { + @Override + public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + throw new RuntimeException(msg); + } + }); + + try { + parser.data(); + fail(); + } catch (RuntimeException ignore) { + // ok + } + } + + @Test + public void oneEntry() { + final CharStream input = CharStreams.fromString("var data = {\n" + + "'010580005005': { amount_pt: 2.1037868162693, amount_t: 206, amount_i: 21, amount_d: 3, amount_h: 182 },\n}"); + + CoronaDataLexer lexer = new CoronaDataLexer(input); + CommonTokenStream tokens = new CommonTokenStream(lexer); + CoronaDataParser parser = new CoronaDataParser(tokens); + + parser.addErrorListener(new BaseErrorListener() { + @Override + public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + throw new RuntimeException(msg); + } + }); + + parser.data(); + + + } + + @Test + public void test() throws IOException { + final InputStream inputStream = getClass().getResourceAsStream("/2021-11-12_100007.json"); + assertNotNull(inputStream); + final CharStream input = CharStreams.fromStream(inputStream); + + CoronaDataLexer lexer = new CoronaDataLexer(input); + + CommonTokenStream tokens = new CommonTokenStream(lexer); + + CoronaDataParser parser = new CoronaDataParser(tokens); + + parser.data(); + + } +} diff --git a/src/test/java/de/landsh/opendata/dataproxy/StrassenSH2GeojsonTest.java b/src/test/java/de/landsh/opendata/dataproxy/StrassenSH2GeojsonTest.java new file mode 100644 index 0000000..044853c --- /dev/null +++ b/src/test/java/de/landsh/opendata/dataproxy/StrassenSH2GeojsonTest.java @@ -0,0 +1,28 @@ +package de.landsh.opendata.dataproxy; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class StrassenSH2GeojsonTest { + + StrassenSH strassenSH2Geojson = new StrassenSH(); + + @Test + public void convertFeature() { + String json = "{\"properties\":{},\"type\":\"LineString\",\"coordinates\":[[11.1348821,54.42609306],[11.12938639,54.42167313],[11.12450702,54.41677863],[11.12069621,54.4118541],[11.11344491,54.40078343]]}"; + + JSONObject in = new JSONObject(json); + JSONObject result = strassenSH2Geojson.convertFeature(in); + + assertTrue(result.has("properties")); + JSONObject geometry = result.getJSONObject("geometry"); + assertNotNull(geometry); + assertEquals("LineString", geometry.getString("type")); + JSONArray coordinates = geometry.getJSONArray("coordinates"); + assertNotNull(coordinates); + assertEquals(5, coordinates.length()); + } +} diff --git a/src/test/resources/2021-11-12_100007.json b/src/test/resources/2021-11-12_100007.json new file mode 100644 index 0000000..4c4de49 --- /dev/null +++ b/src/test/resources/2021-11-12_100007.json @@ -0,0 +1,167 @@ +var data = { +'010580005005': { amount_pt: 2.1037868162693, amount_t: 207, amount_i: 21, amount_d: 3, amount_h: 183 }, +'010580034034': { amount_pt: 0.67107659860033, amount_t: 219, amount_i: 7, amount_d: 2, amount_h: 210 }, +'010580043043': { amount_pt: 0.96480749793256, amount_t: 457, amount_i: 21, amount_d: 8, amount_h: 428 }, +'010580092092': { amount_pt: 1.0036801605888, amount_t: 224, amount_i: 12, amount_d: 1, amount_h: 211 }, +'010580135135': { amount_pt: 1.7367744624683, amount_t: 1256, amount_i: 50, amount_d: 16, amount_h: 1190 }, +'010580169169': { amount_pt: 3.0395136778116, amount_t: 35, amount_i: 7, amount_d: 0, amount_h: 28 }, +'010585803001': { amount_pt: 0, amount_t: 14, amount_i: 0, amount_d: 0, amount_h: 14 }, +'010585803028': { amount_pt: 3.2851511169514, amount_t: 19, amount_i: 5, amount_d: 0, amount_h: 14 }, +'010585803050': { amount_pt: 1.4058106841612, amount_t: 39, amount_i: 3, amount_d: 0, amount_h: 36 }, +'010585803093': { amount_pt: 0, amount_t: 9, amount_i: 0, amount_d: 0, amount_h: 9 }, +'010585803104': { amount_pt: 0.53995680345572, amount_t: 34, amount_i: 1, amount_d: 0, amount_h: 33 }, +'010585803126': { amount_pt: 1.0526315789474, amount_t: 27, amount_i: 1, amount_d: 0, amount_h: 26 }, +'010585803130': { amount_pt: 1.7064846416382, amount_t: 25, amount_i: 3, amount_d: 0, amount_h: 22 }, +'010585803171': { amount_pt: 1.2730744748568, amount_t: 23, amount_i: 2, amount_d: 0, amount_h: 21 }, +'010585822037': { amount_pt: 2.326182476092, amount_t: 80, amount_i: 9, amount_d: 0, amount_h: 71 }, +'010585822116': { amount_pt: 1.1547344110855, amount_t: 11, amount_i: 1, amount_d: 0, amount_h: 10 }, +'010585822150': { amount_pt: 0, amount_t: 34, amount_i: 0, amount_d: 0, amount_h: 34 }, +'010585822157': { amount_pt: 1.3440860215054, amount_t: 14, amount_i: 2, amount_d: 0, amount_h: 12 }, +'010585824051': { amount_pt: 1.6820857863751, amount_t: 22, amount_i: 2, amount_d: 0, amount_h: 20 }, +'010585824058': { amount_pt: 2.119486024639, amount_t: 89, amount_i: 16, amount_d: 1, amount_h: 72 }, +'010585824096': { amount_pt: 5.1094890510949, amount_t: 18, amount_i: 7, amount_d: 0, amount_h: 11 }, +'010585824110': { amount_pt: 0, amount_t: 11, amount_i: 0, amount_d: 0, amount_h: 11 }, +'010585824112': { amount_pt: 0, amount_t: 17, amount_i: 0, amount_d: 0, amount_h: 17 }, +'010585824121': { amount_pt: 0.79396585946804, amount_t: 26, amount_i: 2, amount_d: 0, amount_h: 24 }, +'010585824142': { amount_pt: 2.9644268774704, amount_t: 10, amount_i: 3, amount_d: 0, amount_h: 7 }, +'010585824165': { amount_pt: 0, amount_t: 14, amount_i: 0, amount_d: 1, amount_h: 13 }, +'010585830019': { amount_pt: 0, amount_t: 0, amount_i: 0, amount_d: 0, amount_h: 0 }, +'010585830053': { amount_pt: 0.83114004709794, amount_t: 107, amount_i: 6, amount_d: 0, amount_h: 101 }, +'010585830145': { amount_pt: 0, amount_t: 3, amount_i: 0, amount_d: 0, amount_h: 3 }, +'010585830160': { amount_pt: 0, amount_t: 1, amount_i: 0, amount_d: 0, amount_h: 1 }, +'010585833003': { amount_pt: 2.1108179419525, amount_t: 35, amount_i: 4, amount_d: 0, amount_h: 31 }, +'010585833054': { amount_pt: 3.9701445132603, amount_t: 157, amount_i: 25, amount_d: 1, amount_h: 131 }, +'010585833118': { amount_pt: 0, amount_t: 36, amount_i: 0, amount_d: 1, amount_h: 35 }, +'010585833136': { amount_pt: 2.9296875, amount_t: 11, amount_i: 3, amount_d: 0, amount_h: 8 }, +'010585847010': { amount_pt: 0, amount_t: 0, amount_i: 0, amount_d: 0, amount_h: 0 }, +'010585847029': { amount_pt: 0, amount_t: 22, amount_i: 0, amount_d: 0, amount_h: 22 }, +'010585847036': { amount_pt: 0, amount_t: 5, amount_i: 0, amount_d: 0, amount_h: 5 }, +'010585847047': { amount_pt: 0, amount_t: 24, amount_i: 0, amount_d: 0, amount_h: 24 }, +'010585847055': { amount_pt: 0, amount_t: 0, amount_i: 0, amount_d: 0, amount_h: 0 }, +'010585847056': { amount_pt: 0, amount_t: 2, amount_i: 0, amount_d: 0, amount_h: 2 }, +'010585847070': { amount_pt: 0, amount_t: 50, amount_i: 0, amount_d: 0, amount_h: 50 }, +'010585847078': { amount_pt: 1.6535758577925, amount_t: 38, amount_i: 4, amount_d: 0, amount_h: 34 }, +'010585847089': { amount_pt: 0, amount_t: 0, amount_i: 0, amount_d: 0, amount_h: 0 }, +'010585847097': { amount_pt: 0, amount_t: 1, amount_i: 0, amount_d: 0, amount_h: 1 }, +'010585847129': { amount_pt: 0, amount_t: 7, amount_i: 0, amount_d: 0, amount_h: 7 }, +'010585847154': { amount_pt: 0, amount_t: 5, amount_i: 0, amount_d: 0, amount_h: 5 }, +'010585853031': { amount_pt: 0, amount_t: 0, amount_i: 0, amount_d: 0, amount_h: 0 }, +'010585853048': { amount_pt: 0, amount_t: 2, amount_i: 0, amount_d: 0, amount_h: 2 }, +'010585853068': { amount_pt: 0, amount_t: 15, amount_i: 0, amount_d: 0, amount_h: 15 }, +'010585853071': { amount_pt: 0, amount_t: 9, amount_i: 0, amount_d: 1, amount_h: 8 }, +'010585853075': { amount_pt: 0, amount_t: 0, amount_i: 0, amount_d: 0, amount_h: 0 }, +'010585853086': { amount_pt: 0.30111412225233, amount_t: 26, amount_i: 1, amount_d: 0, amount_h: 25 }, +'010585853101': { amount_pt: 0, amount_t: 9, amount_i: 0, amount_d: 0, amount_h: 9 }, +'010585853148': { amount_pt: 0, amount_t: 8, amount_i: 0, amount_d: 0, amount_h: 8 }, +'010585853155': { amount_pt: 0, amount_t: 1, amount_i: 0, amount_d: 0, amount_h: 1 }, +'010585853172': { amount_pt: 0.9954210631097, amount_t: 90, amount_i: 5, amount_d: 0, amount_h: 85 }, +'010585859018': { amount_pt: 2.8490028490028, amount_t: 20, amount_i: 2, amount_d: 0, amount_h: 18 }, +'010585859105': { amount_pt: 4.3859649122807, amount_t: 39, amount_i: 6, amount_d: 0, amount_h: 33 }, +'010585859107': { amount_pt: 0.59654006760787, amount_t: 57, amount_i: 3, amount_d: 1, amount_h: 53 }, +'010585859138': { amount_pt: 0, amount_t: 6, amount_i: 0, amount_d: 0, amount_h: 6 }, +'010585859139': { amount_pt: 0, amount_t: 6, amount_i: 0, amount_d: 0, amount_h: 6 }, +'010585859141': { amount_pt: 0, amount_t: 4, amount_i: 0, amount_d: 1, amount_h: 3 }, +'010585864011': { amount_pt: 5.5788005578801, amount_t: 21, amount_i: 4, amount_d: 0, amount_h: 17 }, +'010585864021': { amount_pt: 0, amount_t: 6, amount_i: 0, amount_d: 0, amount_h: 6 }, +'010585864023': { amount_pt: 0, amount_t: 5, amount_i: 0, amount_d: 0, amount_h: 5 }, +'010585864027': { amount_pt: 5.7803468208092, amount_t: 8, amount_i: 2, amount_d: 0, amount_h: 6 }, +'010585864038': { amount_pt: 0, amount_t: 16, amount_i: 0, amount_d: 0, amount_h: 16 }, +'010585864045': { amount_pt: 0, amount_t: 1, amount_i: 0, amount_d: 0, amount_h: 1 }, +'010585864046': { amount_pt: 0, amount_t: 10, amount_i: 0, amount_d: 0, amount_h: 10 }, +'010585864049': { amount_pt: 0, amount_t: 27, amount_i: 0, amount_d: 0, amount_h: 27 }, +'010585864059': { amount_pt: 0.85178875638842, amount_t: 4, amount_i: 1, amount_d: 0, amount_h: 3 }, +'010585864065': { amount_pt: 0, amount_t: 16, amount_i: 0, amount_d: 1, amount_h: 15 }, +'010585864091': { amount_pt: 0, amount_t: 4, amount_i: 0, amount_d: 0, amount_h: 4 }, +'010585864094': { amount_pt: 0, amount_t: 27, amount_i: 0, amount_d: 0, amount_h: 27 }, +'010585864117': { amount_pt: 1.1682242990654, amount_t: 142, amount_i: 8, amount_d: 3, amount_h: 131 }, +'010585864120': { amount_pt: 0, amount_t: 3, amount_i: 0, amount_d: 0, amount_h: 3 }, +'010585864147': { amount_pt: 1.3071895424837, amount_t: 7, amount_i: 1, amount_d: 0, amount_h: 6 }, +'010585864163': { amount_pt: 0, amount_t: 30, amount_i: 0, amount_d: 0, amount_h: 30 }, +'010585864168': { amount_pt: 1.4577259475219, amount_t: 5, amount_i: 1, amount_d: 0, amount_h: 4 }, +'010585888026': { amount_pt: 3.6563071297989, amount_t: 17, amount_i: 4, amount_d: 0, amount_h: 13 }, +'010585888073': { amount_pt: 0, amount_t: 2, amount_i: 0, amount_d: 0, amount_h: 2 }, +'010585888122': { amount_pt: 5.1457975986278, amount_t: 15, amount_i: 3, amount_d: 0, amount_h: 12 }, +'010585888124': { amount_pt: 0.9788566953798, amount_t: 101, amount_i: 5, amount_d: 0, amount_h: 96 }, +'010585888132': { amount_pt: 0, amount_t: 0, amount_i: 0, amount_d: 0, amount_h: 0 }, +'010585888140': { amount_pt: 1.2484394506866, amount_t: 126, amount_i: 6, amount_d: 1, amount_h: 119 }, +'010585888146': { amount_pt: 0, amount_t: 3, amount_i: 0, amount_d: 0, amount_h: 3 }, +'010585889016': { amount_pt: 6.2111801242236, amount_t: 1, amount_i: 1, amount_d: 0, amount_h: 0 }, +'010585889022': { amount_pt: 0.9085009733939, amount_t: 157, amount_i: 7, amount_d: 5, amount_h: 145 }, +'010585889033': { amount_pt: 0, amount_t: 22, amount_i: 0, amount_d: 1, amount_h: 21 }, +'010585889063': { amount_pt: 0, amount_t: 1, amount_i: 0, amount_d: 0, amount_h: 1 }, +'010585889064': { amount_pt: 0, amount_t: 3, amount_i: 0, amount_d: 0, amount_h: 3 }, +'010585889076': { amount_pt: 0, amount_t: 2, amount_i: 0, amount_d: 0, amount_h: 2 }, +'010585889098': { amount_pt: 0, amount_t: 2, amount_i: 0, amount_d: 0, amount_h: 2 }, +'010585889108': { amount_pt: 0, amount_t: 11, amount_i: 0, amount_d: 0, amount_h: 11 }, +'010585889109': { amount_pt: 0, amount_t: 2, amount_i: 0, amount_d: 0, amount_h: 2 }, +'010585889133': { amount_pt: 0, amount_t: 4, amount_i: 0, amount_d: 0, amount_h: 4 }, +'010585889143': { amount_pt: 0, amount_t: 5, amount_i: 0, amount_d: 0, amount_h: 5 }, +'010585889144': { amount_pt: 0, amount_t: 7, amount_i: 0, amount_d: 0, amount_h: 7 }, +'010585889153': { amount_pt: 0, amount_t: 1, amount_i: 0, amount_d: 0, amount_h: 1 }, +'010585889170': { amount_pt: 0, amount_t: 27, amount_i: 0, amount_d: 1, amount_h: 26 }, +'010585890008': { amount_pt: 1.0277492291881, amount_t: 36, amount_i: 1, amount_d: 4, amount_h: 31 }, +'010585890024': { amount_pt: 0, amount_t: 24, amount_i: 0, amount_d: 1, amount_h: 23 }, +'010585890030': { amount_pt: 0, amount_t: 9, amount_i: 0, amount_d: 0, amount_h: 9 }, +'010585890035': { amount_pt: 0, amount_t: 12, amount_i: 0, amount_d: 0, amount_h: 12 }, +'010585890039': { amount_pt: 4.8192771084337, amount_t: 7, amount_i: 2, amount_d: 0, amount_h: 5 }, +'010585890066': { amount_pt: 5.4858934169279, amount_t: 16, amount_i: 7, amount_d: 0, amount_h: 9 }, +'010585890069': { amount_pt: 1.779359430605, amount_t: 9, amount_i: 1, amount_d: 0, amount_h: 8 }, +'010585890080': { amount_pt: 3.8699690402477, amount_t: 16, amount_i: 5, amount_d: 0, amount_h: 11 }, +'010585890081': { amount_pt: 0, amount_t: 1, amount_i: 0, amount_d: 0, amount_h: 1 }, +'010585890083': { amount_pt: 0, amount_t: 8, amount_i: 0, amount_d: 0, amount_h: 8 }, +'010585890088': { amount_pt: 0, amount_t: 1, amount_i: 0, amount_d: 0, amount_h: 1 }, +'010585890111': { amount_pt: 0, amount_t: 9, amount_i: 0, amount_d: 0, amount_h: 9 }, +'010585890123': { amount_pt: 3.9370078740157, amount_t: 19, amount_i: 4, amount_d: 1, amount_h: 14 }, +'010585890127': { amount_pt: 0.27277686852155, amount_t: 87, amount_i: 1, amount_d: 1, amount_h: 85 }, +'010585890152': { amount_pt: 0, amount_t: 14, amount_i: 0, amount_d: 0, amount_h: 14 }, +'010585890175': { amount_pt: 0, amount_t: 5, amount_i: 0, amount_d: 0, amount_h: 5 }, +'010585893004': { amount_pt: 0, amount_t: 5, amount_i: 0, amount_d: 0, amount_h: 5 }, +'010585893012': { amount_pt: 3.2509752925878, amount_t: 30, amount_i: 5, amount_d: 0, amount_h: 25 }, +'010585893032': { amount_pt: 0, amount_t: 2, amount_i: 0, amount_d: 0, amount_h: 2 }, +'010585893040': { amount_pt: 0, amount_t: 20, amount_i: 0, amount_d: 0, amount_h: 20 }, +'010585893042': { amount_pt: 0, amount_t: 10, amount_i: 0, amount_d: 0, amount_h: 10 }, +'010585893052': { amount_pt: 2.3062730627306, amount_t: 28, amount_i: 5, amount_d: 0, amount_h: 23 }, +'010585893057': { amount_pt: 1.8832391713748, amount_t: 13, amount_i: 1, amount_d: 0, amount_h: 12 }, +'010585893067': { amount_pt: 1.3774104683196, amount_t: 15, amount_i: 1, amount_d: 0, amount_h: 14 }, +'010585893082': { amount_pt: 0, amount_t: 5, amount_i: 0, amount_d: 0, amount_h: 5 }, +'010585893084': { amount_pt: 0, amount_t: 6, amount_i: 0, amount_d: 0, amount_h: 6 }, +'010585893087': { amount_pt: 0, amount_t: 4, amount_i: 0, amount_d: 0, amount_h: 4 }, +'010585893090': { amount_pt: 0, amount_t: 11, amount_i: 0, amount_d: 0, amount_h: 11 }, +'010585893099': { amount_pt: 2.4301336573512, amount_t: 17, amount_i: 2, amount_d: 0, amount_h: 15 }, +'010585893102': { amount_pt: 0, amount_t: 21, amount_i: 0, amount_d: 0, amount_h: 21 }, +'010585893137': { amount_pt: 0.36845983787767, amount_t: 56, amount_i: 1, amount_d: 1, amount_h: 54 }, +'010585893162': { amount_pt: 2.5906735751295, amount_t: 3, amount_i: 1, amount_d: 0, amount_h: 2 }, +'010585893166': { amount_pt: 0, amount_t: 33, amount_i: 0, amount_d: 1, amount_h: 32 }, +'010585893173': { amount_pt: 0, amount_t: 12, amount_i: 0, amount_d: 0, amount_h: 12 }, +'010585893174': { amount_pt: 0, amount_t: 14, amount_i: 0, amount_d: 0, amount_h: 14 }, +'010585895007': { amount_pt: 0, amount_t: 10, amount_i: 0, amount_d: 1, amount_h: 9 }, +'010585895009': { amount_pt: 0, amount_t: 63, amount_i: 0, amount_d: 0, amount_h: 63 }, +'010585895013': { amount_pt: 10.791366906475, amount_t: 13, amount_i: 3, amount_d: 0, amount_h: 10 }, +'010585895014': { amount_pt: 0, amount_t: 5, amount_i: 0, amount_d: 0, amount_h: 5 }, +'010585895015': { amount_pt: 1.3422818791946, amount_t: 48, amount_i: 1, amount_d: 1, amount_h: 46 }, +'010585895025': { amount_pt: 0, amount_t: 1, amount_i: 0, amount_d: 0, amount_h: 1 }, +'010585895044': { amount_pt: 1.6447368421053, amount_t: 9, amount_i: 1, amount_d: 0, amount_h: 8 }, +'010585895061': { amount_pt: 0, amount_t: 19, amount_i: 0, amount_d: 0, amount_h: 19 }, +'010585895062': { amount_pt: 0, amount_t: 5, amount_i: 0, amount_d: 0, amount_h: 5 }, +'010585895072': { amount_pt: 2.7036160865157, amount_t: 65, amount_i: 8, amount_d: 2, amount_h: 55 }, +'010585895074': { amount_pt: 0, amount_t: 0, amount_i: 0, amount_d: 0, amount_h: 0 }, +'010585895077': { amount_pt: 1.3062138458668, amount_t: 167, amount_i: 7, amount_d: 2, amount_h: 158 }, +'010585895085': { amount_pt: 0, amount_t: 0, amount_i: 0, amount_d: 0, amount_h: 0 }, +'010585895100': { amount_pt: 0, amount_t: 6, amount_i: 0, amount_d: 1, amount_h: 5 }, +'010585895103': { amount_pt: 0, amount_t: 1, amount_i: 0, amount_d: 0, amount_h: 1 }, +'010585895106': { amount_pt: 4.2735042735043, amount_t: 6, amount_i: 1, amount_d: 0, amount_h: 5 }, +'010585895113': { amount_pt: 0, amount_t: 16, amount_i: 0, amount_d: 0, amount_h: 16 }, +'010585895115': { amount_pt: 0, amount_t: 6, amount_i: 0, amount_d: 0, amount_h: 6 }, +'010585895119': { amount_pt: 0, amount_t: 2, amount_i: 0, amount_d: 0, amount_h: 2 }, +'010585895125': { amount_pt: 0, amount_t: 12, amount_i: 0, amount_d: 0, amount_h: 12 }, +'010585895128': { amount_pt: 1.1771630370806, amount_t: 22, amount_i: 2, amount_d: 0, amount_h: 20 }, +'010585895131': { amount_pt: 0, amount_t: 0, amount_i: 0, amount_d: 0, amount_h: 0 }, +'010585895134': { amount_pt: 2.3201856148492, amount_t: 10, amount_i: 1, amount_d: 0, amount_h: 9 }, +'010585895151': { amount_pt: 0, amount_t: 2, amount_i: 0, amount_d: 0, amount_h: 2 }, +'010585895156': { amount_pt: 0, amount_t: 6, amount_i: 0, amount_d: 0, amount_h: 6 }, +'010585895158': { amount_pt: 0, amount_t: 0, amount_i: 0, amount_d: 0, amount_h: 0 }, +'010585895159': { amount_pt: 0, amount_t: 0, amount_i: 0, amount_d: 0, amount_h: 0 }, +'010585895161': { amount_pt: 0, amount_t: 8, amount_i: 0, amount_d: 0, amount_h: 8 }, +'010585895164': { amount_pt: 1.9607843137255, amount_t: 21, amount_i: 2, amount_d: 0, amount_h: 19 }, +'010585895167': { amount_pt: 0, amount_t: 8, amount_i: 0, amount_d: 1, amount_h: 7 }, +} -- GitLab