source: josm/trunk/src/org/openstreetmap/josm/gui/preferences/server/ApiUrlTestTask.java@ 7037

Last change on this file since 7037 was 7037, checked in by Don-vip, 10 years ago

see #8465 - last batch of try-with-resources

  • Property svn:eol-style set to native
File size: 8.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.preferences.server;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.io.BufferedReader;
8import java.io.IOException;
9import java.io.InputStreamReader;
10import java.net.HttpURLConnection;
11import java.net.MalformedURLException;
12import java.net.URL;
13
14import javax.swing.JOptionPane;
15
16import org.openstreetmap.josm.Main;
17import org.openstreetmap.josm.gui.HelpAwareOptionPane;
18import org.openstreetmap.josm.gui.PleaseWaitRunnable;
19import org.openstreetmap.josm.gui.help.HelpUtil;
20import org.openstreetmap.josm.io.OsmTransferException;
21import org.openstreetmap.josm.tools.CheckParameterUtil;
22import org.openstreetmap.josm.tools.Utils;
23import org.xml.sax.SAXException;
24
25/**
26 * This is an asynchronous task for testing whether an URL points to an OSM API server.
27 * It tries to retrieve a list of changesets from the given URL. If it succeeds, the method
28 * {@link #isSuccess()} replies true, otherwise false.
29 *
30 * Note: it fetches a list of changesets instead of the much smaller capabilities because - strangely enough -
31 * an OSM server "https://x.y.y/api/0.6" not only responds to "https://x.y.y/api/0.6/capabilities" but also
32 * to "https://x.y.y/api/0/capabilities" or "https://x.y.y/a/capabilities" with valid capabilities. If we get
33 * valid capabilities with an URL we therefore can't be sure that the base URL is valid API URL.
34 *
35 */
36public class ApiUrlTestTask extends PleaseWaitRunnable{
37
38 private String url;
39 private boolean canceled;
40 private boolean success;
41 private Component parent;
42 private HttpURLConnection connection;
43
44 /**
45 * Creates the task
46 *
47 * @param parent the parent component relative to which the {@link PleaseWaitRunnable}-Dialog is displayed
48 * @param url the url. Must not be null.
49 * @throws IllegalArgumentException thrown if url is null.
50 */
51 public ApiUrlTestTask(Component parent, String url) throws IllegalArgumentException {
52 super(parent, tr("Testing OSM API URL ''{0}''", url), false /* don't ignore exceptions */);
53 CheckParameterUtil.ensureParameterNotNull(url,"url");
54 this.parent = parent;
55 this.url = url;
56 }
57
58 protected void alertInvalidUrl(String url) {
59 HelpAwareOptionPane.showOptionDialog(
60 parent,
61 tr("<html>"
62 + "''{0}'' is not a valid OSM API URL.<br>"
63 + "Please check the spelling and validate again."
64 + "</html>",
65 url
66 ),
67 tr("Invalid API URL"),
68 JOptionPane.ERROR_MESSAGE,
69 HelpUtil.ht("/Preferences/Connection#InvalidAPIUrl")
70 );
71 }
72
73 protected void alertInvalidChangesetUrl(String url) {
74 HelpAwareOptionPane.showOptionDialog(
75 parent,
76 tr("<html>"
77 + "Failed to build URL ''{0}'' for validating the OSM API server.<br>"
78 + "Please check the spelling of ''{1}'' and validate again."
79 +"</html>",
80 url,
81 getNormalizedApiUrl()
82 ),
83 tr("Invalid API URL"),
84 JOptionPane.ERROR_MESSAGE,
85 HelpUtil.ht("/Preferences/Connection#InvalidAPIGetChangesetsUrl")
86 );
87 }
88
89 protected void alertConnectionFailed() {
90 HelpAwareOptionPane.showOptionDialog(
91 parent,
92 tr("<html>"
93 + "Failed to connect to the URL ''{0}''.<br>"
94 + "Please check the spelling of ''{1}'' and your Internet connection and validate again."
95 +"</html>",
96 url,
97 getNormalizedApiUrl()
98 ),
99 tr("Connection to API failed"),
100 JOptionPane.ERROR_MESSAGE,
101 HelpUtil.ht("/Preferences/Connection#ConnectionToAPIFailed")
102 );
103 }
104
105 protected void alertInvalidServerResult(int retCode) {
106 HelpAwareOptionPane.showOptionDialog(
107 parent,
108 tr("<html>"
109 + "Failed to retrieve a list of changesets from the OSM API server at<br>"
110 + "''{1}''. The server responded with the return code {0} instead of 200.<br>"
111 + "Please check the spelling of ''{1}'' and validate again."
112 + "</html>",
113 retCode,
114 getNormalizedApiUrl()
115 ),
116 tr("Connection to API failed"),
117 JOptionPane.ERROR_MESSAGE,
118 HelpUtil.ht("/Preferences/Connection#InvalidServerResult")
119 );
120 }
121
122 protected void alertInvalidChangesetList() {
123 HelpAwareOptionPane.showOptionDialog(
124 parent,
125 tr("<html>"
126 + "The OSM API server at ''{0}'' did not return a valid response.<br>"
127 + "It is likely that ''{0}'' is not an OSM API server.<br>"
128 + "Please check the spelling of ''{0}'' and validate again."
129 + "</html>",
130 getNormalizedApiUrl()
131 ),
132 tr("Connection to API failed"),
133 JOptionPane.ERROR_MESSAGE,
134 HelpUtil.ht("/Preferences/Connection#InvalidSettings")
135 );
136 }
137
138 @Override
139 protected void cancel() {
140 canceled = true;
141 synchronized(this) {
142 if (connection != null) {
143 connection.disconnect();
144 }
145 }
146 }
147
148 @Override
149 protected void finish() {}
150
151 /**
152 * Removes leading and trailing whitespace from the API URL and removes trailing
153 * '/'.
154 *
155 * @return the normalized API URL
156 */
157 protected String getNormalizedApiUrl() {
158 String apiUrl = url.trim();
159 while(apiUrl.endsWith("/")) {
160 apiUrl = apiUrl.substring(0, apiUrl.lastIndexOf('/'));
161 }
162 return apiUrl;
163 }
164
165 @Override
166 protected void realRun() throws SAXException, IOException, OsmTransferException {
167 try {
168 try {
169 new URL(getNormalizedApiUrl());
170 } catch(MalformedURLException e) {
171 alertInvalidUrl(getNormalizedApiUrl());
172 return;
173 }
174 URL capabilitiesUrl;
175 String getChangesetsUrl = getNormalizedApiUrl() + "/0.6/changesets";
176 try {
177 capabilitiesUrl = new URL(getChangesetsUrl);
178 } catch(MalformedURLException e) {
179 alertInvalidChangesetUrl(getChangesetsUrl);
180 return;
181 }
182
183 synchronized(this) {
184 connection = Utils.openHttpConnection(capabilitiesUrl);
185 }
186 connection.setDoInput(true);
187 connection.setDoOutput(false);
188 connection.setRequestMethod("GET");
189 connection.connect();
190
191 if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
192 alertInvalidServerResult(connection.getResponseCode());
193 return;
194 }
195 StringBuilder changesets = new StringBuilder();
196 try (BufferedReader bin = new BufferedReader(new InputStreamReader(connection.getInputStream(), Utils.UTF_8))) {
197 String line;
198 while ((line = bin.readLine()) != null) {
199 changesets.append(line).append("\n");
200 }
201 }
202 if (! (changesets.toString().contains("<osm") && changesets.toString().contains("</osm>"))) {
203 // heuristic: if there isn't an opening and closing "<osm>" tag in the returned content,
204 // then we didn't get a list of changesets in return. Could be replaced by explicitly parsing
205 // the result but currently not worth the effort.
206 alertInvalidChangesetList();
207 return;
208 }
209 success = true;
210 } catch(IOException e) {
211 if (canceled)
212 // ignore exceptions
213 return;
214 Main.error(e);
215 alertConnectionFailed();
216 return;
217 }
218 }
219
220 /**
221 * Determines if the test has been canceled.
222 * @return {@code true} if canceled, {@code false} otherwise
223 */
224 public boolean isCanceled() {
225 return canceled;
226 }
227
228 /**
229 * Determines if the test has succeeded.
230 * @return {@code true} if success, {@code false} otherwise
231 */
232 public boolean isSuccess() {
233 return success;
234 }
235}
Note: See TracBrowser for help on using the repository browser.