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

Last change on this file since 6083 was 6083, checked in by bastiK, 11 years ago

see #8902 - Small performance enhancements (patch by shinigami)

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