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

Revision 3530, 8.6 KB checked in by stoecker, 21 months ago (diff)

fix array preferences

  • Property svn:eol-style set to native
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.data.Version;
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.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 * {@see #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 {@see 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 = (HttpURLConnection)capabilitiesUrl.openConnection();
185            }
186            connection.setDoInput(true);
187            connection.setDoOutput(false);
188            connection.setRequestMethod("GET");
189            connection.setRequestProperty("User-Agent", Version.getInstance().getAgentString());
190            connection.setRequestProperty("Host", connection.getURL().getHost());
191            connection.connect();
192
193            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
194                alertInvalidServerResult(connection.getResponseCode());
195                return;
196            }
197            StringBuilder changesets = new StringBuilder();
198            bin = new BufferedReader(new InputStreamReader(connection.getInputStream()));
199            String line;
200            while ((line = bin.readLine()) != null) {
201                changesets.append(line).append("\n");
202            }
203            if (! (changesets.toString().contains("<osm") && changesets.toString().contains("</osm>"))) {
204                // heuristic: if there isn't an opening and closing "<osm>" tag in the returned content,
205                // then we didn't get a list of changesets in return. Could be replaced by explicitly parsing
206                // the result but currently not worth the effort.
207                alertInvalidChangesetList();
208                return;
209            }
210            success = true;
211        } catch(IOException e) {
212            if (canceled)
213                // ignore exceptions
214                return;
215            e.printStackTrace();
216            alertConnectionFailed();
217            return;
218        } finally {
219            if (bin != null) {
220                try {
221                    bin.close();
222                } catch(IOException e){/* ignore */}
223            }
224        }
225    }
226
227    public boolean isCanceled() {
228        return canceled;
229    }
230
231    public boolean isSuccess() {
232        return success;
233    }
234}
Note: See TracBrowser for help on using the repository browser.