commit 1bd6c58c8c6d6d733d8a8051c22826620eb353d1
Author: Simon Legner <Simon.Legner@gmail.com>
Date: 2020-02-29 23:51:15 +0100
fix #18164 - Migrate OverpassTurboQueryWizard to overpass-wizard-server
diff --git a/src/org/openstreetmap/josm/gui/download/OverpassQueryWizardDialog.java b/src/org/openstreetmap/josm/gui/download/OverpassQueryWizardDialog.java
index 891c991c1..5de809442 100644
a
|
b
|
|
5 | 5 | |
6 | 6 | import java.awt.GridBagLayout; |
7 | 7 | import java.awt.event.ActionEvent; |
| 8 | import java.io.IOException; |
8 | 9 | import java.util.ArrayList; |
9 | 10 | import java.util.Arrays; |
10 | 11 | import java.util.Collections; |
… |
… |
private void saveHistory() {
|
143 | 144 | private Optional<String> tryParseSearchTerm(String searchTerm) { |
144 | 145 | try { |
145 | 146 | return Optional.of(overpassQueryBuilder.constructQuery(searchTerm)); |
146 | | } catch (UncheckedParseException | IllegalStateException ex) { |
| 147 | } catch (IOException | UncheckedParseException ex) { |
147 | 148 | Logging.error(ex); |
148 | 149 | JOptionPane.showMessageDialog( |
149 | 150 | dsPanel.getParent(), |
diff --git a/src/org/openstreetmap/josm/tools/OverpassTurboQueryWizard.java b/src/org/openstreetmap/josm/tools/OverpassTurboQueryWizard.java
index fc4c340f8..4f7b17f1d 100644
a
|
b
|
|
2 | 2 | package org.openstreetmap.josm.tools; |
3 | 3 | |
4 | 4 | import java.io.IOException; |
5 | | import java.io.Reader; |
| 5 | import java.net.URL; |
6 | 6 | |
7 | | import javax.script.Invocable; |
8 | | import javax.script.ScriptEngine; |
9 | | import javax.script.ScriptException; |
10 | | |
11 | | import org.openstreetmap.josm.io.CachedFile; |
12 | 7 | import org.openstreetmap.josm.spi.preferences.Config; |
13 | 8 | |
14 | 9 | /** |
15 | 10 | * Uses <a href="https://github.com/tyrasd/overpass-wizard/">Overpass Turbo query wizard</a> code (MIT Licensed) |
16 | 11 | * to build an Overpass QL from a {@link org.openstreetmap.josm.actions.search.SearchAction} like query. |
17 | 12 | * |
18 | | * Requires a JavaScript {@link ScriptEngine}. |
| 13 | * This involves a HTTP request to an overpass-wizard-server. |
19 | 14 | * @since 8744 |
20 | 15 | */ |
21 | 16 | public final class OverpassTurboQueryWizard { |
22 | 17 | |
23 | 18 | private static OverpassTurboQueryWizard instance; |
24 | | private final ScriptEngine engine = Utils.getJavaScriptEngine(); |
25 | 19 | |
26 | 20 | /** |
27 | 21 | * Replies the unique instance of this class. |
… |
… |
public static synchronized OverpassTurboQueryWizard getInstance() {
|
35 | 29 | return instance; |
36 | 30 | } |
37 | 31 | |
38 | | private OverpassTurboQueryWizard() { |
39 | | try (CachedFile file = new CachedFile("resource://data/overpass-wizard.js"); |
40 | | Reader reader = file.getContentReader()) { |
41 | | if (engine != null) { |
42 | | engine.eval("var console = {error: " + Logging.class.getCanonicalName() + ".warn};"); |
43 | | engine.eval("var global = {};"); |
44 | | engine.eval(reader); |
45 | | engine.eval("var overpassWizardJOSM = function(query) {" + |
46 | | " return overpassWizard(query, {" + |
47 | | " comment: false," + |
48 | | " timeout: " + Config.getPref().getInt("overpass.wizard.timeout", 90) + "," + |
49 | | " outputFormat: 'xml'," + |
50 | | " outputMode: 'recursive_meta'" + |
51 | | " });" + |
52 | | "}"); |
53 | | } |
54 | | } catch (ScriptException | IOException ex) { |
55 | | throw new IllegalStateException("Failed to initialize OverpassTurboQueryWizard", ex); |
56 | | } |
57 | | } |
58 | | |
59 | 32 | /** |
60 | 33 | * Builds an Overpass QL from a {@link org.openstreetmap.josm.actions.search.SearchAction} like query. |
61 | 34 | * @param search the {@link org.openstreetmap.josm.actions.search.SearchAction} like query |
62 | 35 | * @return an Overpass QL query |
63 | 36 | * @throws UncheckedParseException when the parsing fails |
| 37 | * @throws IOException in case of I/O error |
64 | 38 | */ |
65 | | public String constructQuery(String search) { |
66 | | if (engine == null) { |
67 | | throw new IllegalStateException("Failed to retrieve JavaScript engine"); |
68 | | } |
69 | | try { |
70 | | final Object result = ((Invocable) engine).invokeFunction("overpassWizardJOSM", search); |
71 | | if (Boolean.FALSE.equals(result)) { |
72 | | throw new UncheckedParseException(); |
73 | | } |
74 | | return (String) result; |
75 | | } catch (NoSuchMethodException e) { |
76 | | throw new IllegalStateException(e); |
77 | | } catch (ScriptException e) { |
78 | | throw new UncheckedParseException("Failed to execute OverpassTurboQueryWizard", e); |
| 39 | public String constructQuery(String search) throws UncheckedParseException, IOException { |
| 40 | String url = Config.getPref().get("overpass.wizard.server", "https://overpass-wizard.josm.eu/overpass-wizard/") |
| 41 | + "?search=" + Utils.encodeUrl(search) |
| 42 | + "&comment=false" |
| 43 | + "&timeout=" + Config.getPref().getInt("overpass.wizard.timeout", 90) |
| 44 | + "&outputFormat=xml" |
| 45 | + "&outputMode=recursive_meta"; |
| 46 | final String query = HttpClient.create(new URL(url)) |
| 47 | .connect() |
| 48 | .fetchContent(); |
| 49 | if ("false".equals(query)) { |
| 50 | throw new UncheckedParseException(); |
79 | 51 | } |
| 52 | return query; |
80 | 53 | } |
81 | 54 | } |
diff --git a/test/unit/org/openstreetmap/josm/io/OverpassDownloadReaderTest.java b/test/unit/org/openstreetmap/josm/io/OverpassDownloadReaderTest.java
index 8c2d6831e..fe96ccca0 100644
a
|
b
|
|
10 | 10 | import static org.junit.Assert.assertNull; |
11 | 11 | import static org.junit.Assert.assertTrue; |
12 | 12 | |
| 13 | import java.io.IOException; |
13 | 14 | import java.io.StringReader; |
14 | 15 | import java.time.LocalDateTime; |
15 | 16 | import java.util.regex.Matcher; |
… |
… |
public void setUp() {
|
57 | 58 | NameFinder.NOMINATIM_URL_PROP.put("http://localhost:" + wireMockRule.port() + NOMINATIM_URL_PATH); |
58 | 59 | } |
59 | 60 | |
60 | | private String getExpandedQuery(String search) { |
| 61 | private String getExpandedQuery(String search) throws IOException { |
61 | 62 | final String query = OverpassTurboQueryWizard.getInstance().constructQuery(search); |
62 | 63 | final String request = new OverpassDownloadReader(new Bounds(1, 2, 3, 4), null, query) |
63 | 64 | .getRequestForBbox(1, 2, 3, 4) |
… |
… |
private String getExpandedQuery(String search) {
|
69 | 70 | * Tests evaluating the extended query feature {@code bbox}. |
70 | 71 | */ |
71 | 72 | @Test |
72 | | public void testBbox() { |
| 73 | public void testBbox() throws IOException { |
73 | 74 | final String query = getExpandedQuery("amenity=drinking_water"); |
74 | 75 | assertEquals("" + |
75 | 76 | "[out:xml][timeout:90][bbox:2.0,1.0,4.0,3.0];\n" + |
… |
… |
public void testDate() {
|
118 | 119 | * Tests evaluating the extended query feature {@code date} through {@code newer:} operator. |
119 | 120 | */ |
120 | 121 | @Test |
121 | | public void testDateNewer() { |
| 122 | public void testDateNewer() throws IOException { |
122 | 123 | final String query = getExpandedQuery("type:node and newer:3minutes"); |
123 | 124 | String statement = query.substring(query.indexOf("node(newer:\"") + 12, query.lastIndexOf("\");")); |
124 | 125 | assertNotNull(DateUtils.fromString(statement)); |
… |
… |
public void testDateNewer() {
|
128 | 129 | * Tests evaluating the extended query feature {@code geocodeArea}. |
129 | 130 | */ |
130 | 131 | @Test |
131 | | public void testGeocodeArea() { |
| 132 | public void testGeocodeArea() throws IOException { |
132 | 133 | stubNominatim("London"); |
133 | 134 | final String query = getExpandedQuery("amenity=drinking_water in London"); |
134 | 135 | assertEquals("" + |
diff --git a/test/unit/org/openstreetmap/josm/tools/OverpassTurboQueryWizardTest.java b/test/unit/org/openstreetmap/josm/tools/OverpassTurboQueryWizardTest.java
index 90a3a2a65..899ae0b7e 100644
a
|
b
|
|
3 | 3 | |
4 | 4 | import static org.junit.Assert.assertEquals; |
5 | 5 | |
| 6 | import java.io.IOException; |
| 7 | |
6 | 8 | import org.junit.Ignore; |
7 | 9 | import org.junit.Rule; |
8 | 10 | import org.junit.Test; |
… |
… |
|
25 | 27 | * Test {@code key=value}. |
26 | 28 | */ |
27 | 29 | @Test |
28 | | public void testKeyValue() { |
| 30 | public void testKeyValue() throws IOException { |
29 | 31 | final String query = OverpassTurboQueryWizard.getInstance().constructQuery("amenity=drinking_water"); |
30 | 32 | assertEquals("" + |
31 | 33 | "[out:xml][timeout:90][bbox:{{bbox}}];\n" + |
… |
… |
public void testKeyValue() {
|
40 | 42 | * Test {@code key!=value}. |
41 | 43 | */ |
42 | 44 | @Test |
43 | | public void testKeyNotValue() { |
| 45 | public void testKeyNotValue() throws IOException { |
44 | 46 | final String query = OverpassTurboQueryWizard.getInstance().constructQuery("amenity!=drinking_water"); |
45 | 47 | assertEquals("" + |
46 | 48 | "[out:xml][timeout:90][bbox:{{bbox}}];\n" + |
… |
… |
public void testKeyNotValue() {
|
55 | 57 | * Test {@code foo=bar and baz=42}. |
56 | 58 | */ |
57 | 59 | @Test |
58 | | public void testBooleanAnd() { |
| 60 | public void testBooleanAnd() throws IOException { |
59 | 61 | final String expected = "" + |
60 | 62 | "[out:xml][timeout:90][bbox:{{bbox}}];\n" + |
61 | 63 | "(\n" + |
… |
… |
public void testBooleanAnd() {
|
72 | 74 | * Test {@code foo=bar or baz=42}. |
73 | 75 | */ |
74 | 76 | @Test |
75 | | public void testBooleanOr() { |
| 77 | public void testBooleanOr() throws IOException { |
76 | 78 | final String expected = "" + |
77 | 79 | "[out:xml][timeout:90][bbox:{{bbox}}];\n" + |
78 | 80 | "(\n" + |
… |
… |
public void testBooleanOr() {
|
90 | 92 | * Test {@code (foo=* or bar=*) and (asd=* or fasd=*)}. |
91 | 93 | */ |
92 | 94 | @Test |
93 | | public void testBoolean() { |
| 95 | public void testBoolean() throws IOException { |
94 | 96 | final String query = OverpassTurboQueryWizard.getInstance().constructQuery("(foo=* or bar=*) and (asd=* or fasd=*)"); |
95 | 97 | assertEquals("" + |
96 | 98 | "[out:xml][timeout:90][bbox:{{bbox}}];\n" + |
… |
… |
public void testBoolean() {
|
108 | 110 | * Test {@code foo=bar and (type:node or type:way)}. |
109 | 111 | */ |
110 | 112 | @Test |
111 | | public void testType() { |
| 113 | public void testType() throws IOException { |
112 | 114 | final String query = OverpassTurboQueryWizard.getInstance().constructQuery("foo=bar and (type:node or type:way)"); |
113 | 115 | assertEquals("" + |
114 | 116 | "[out:xml][timeout:90][bbox:{{bbox}}];\n" + |
… |
… |
public void testType() {
|
124 | 126 | * Test {@code user:foo or uid:42}. |
125 | 127 | */ |
126 | 128 | @Test |
127 | | public void testUser() { |
| 129 | public void testUser() throws IOException { |
128 | 130 | final String query = OverpassTurboQueryWizard.getInstance().constructQuery("user:foo or uid:42"); |
129 | 131 | assertEquals("" + |
130 | 132 | "[out:xml][timeout:90][bbox:{{bbox}}];\n" + |
… |
… |
public void testUser() {
|
140 | 142 | * Test {@code foo=bar and (type:node or type:way)}. |
141 | 143 | */ |
142 | 144 | @Test |
143 | | public void testEmpty() { |
| 145 | public void testEmpty() throws IOException { |
144 | 146 | final String query = OverpassTurboQueryWizard.getInstance().constructQuery("foo='' and type:way"); |
145 | 147 | assertEquals("" + |
146 | 148 | "[out:xml][timeout:90][bbox:{{bbox}}];\n" + |
… |
… |
public void testEmpty() {
|
155 | 157 | * Test geocodeArea. |
156 | 158 | */ |
157 | 159 | @Test |
158 | | public void testInArea() { |
| 160 | public void testInArea() throws IOException { |
159 | 161 | final String query = OverpassTurboQueryWizard.getInstance().constructQuery("foo=bar in Josmland"); |
160 | 162 | assertEquals("" + |
161 | 163 | "[out:xml][timeout:90];\n" + |
… |
… |
public void testInArea() {
|
172 | 174 | */ |
173 | 175 | @Test |
174 | 176 | @Ignore("preset handling not implemented") |
175 | | public void testPreset() { |
| 177 | public void testPreset() throws IOException { |
176 | 178 | final String query = OverpassTurboQueryWizard.getInstance().constructQuery("Hospital"); |
177 | 179 | assertEquals("" + |
178 | 180 | "[out:xml][timeout:90];\n" + |
… |
… |
public void testPreset() {
|
187 | 189 | * Test erroneous value. |
188 | 190 | */ |
189 | 191 | @Test(expected = UncheckedParseException.class) |
190 | | public void testErroneous() { |
| 192 | public void testErroneous() throws IOException { |
191 | 193 | OverpassTurboQueryWizard.getInstance().constructQuery("foo"); |
192 | 194 | } |
193 | 195 | } |