- Timestamp:
- 2009-05-07T17:55:45+02:00 (16 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/io
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/io/OsmApi.java
r1578 r1581 23 23 import java.util.Properties; 24 24 import java.util.StringTokenizer; 25 import java.util.concurrent.FutureTask; 25 26 26 27 import javax.xml.parsers.SAXParserFactory; … … 33 34 import org.openstreetmap.josm.data.osm.Way; 34 35 import org.openstreetmap.josm.data.osm.visitor.CreateOsmChangeVisitor; 36 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 35 37 import org.xml.sax.Attributes; 36 38 import org.xml.sax.InputSource; … … 39 41 40 42 /** 41 * Class that encapsulates the communications with the OSM API. 42 * 43 * All interaction with the server-side OSM API should go through this class. 43 * Class that encapsulates the communications with the OSM API. 44 * 45 * All interaction with the server-side OSM API should go through this class. 44 46 * 45 47 * It is conceivable to extract this into an interface later and create various 46 48 * classes implementing the interface, to be able to talk to various kinds of servers. 47 * 49 * 48 50 */ 49 51 public class OsmApi extends OsmConnection { … … 63 65 */ 64 66 private String minVersion = null; 65 67 66 68 /** 67 69 * Maximum API version accepted by server, from capabilities response 68 70 */ 69 71 private String maxVersion = null; 70 72 71 73 /** 72 74 * Maximum downloadable area from server (degrees squared), from capabilities response … … 74 76 */ 75 77 private String maxArea = null; 76 78 77 79 /** 78 80 * true if successfully initialized 79 81 */ 80 82 private boolean initialized = false; 81 83 82 84 private StringWriter swriter = new StringWriter(); 83 85 private OsmWriter osmWriter = new OsmWriter(new PrintWriter(swriter), true, null); … … 108 110 return ""; 109 111 } 110 111 /** 112 113 /** 112 114 * Returns the OSM protocol version we use to talk to the server. 113 115 * @return protocol version, or null if not yet negotiated. … … 116 118 return version; 117 119 } 118 120 119 121 /** 120 122 * Returns true if the negotiated version supports changesets. … … 124 126 return ((version != null) && (version.compareTo("0.6")>=0)); 125 127 } 126 128 127 129 /** 128 130 * Initializes this component by negotiating a protocol version with the server. … … 141 143 } else { 142 144 System.err.println(tr("This version of JOSM is incompatible with the configured server.")); 143 System.err.println(tr("It supports protocol versions 0.5 and 0.6, while the server says it supports {0} to {1}.", 145 System.err.println(tr("It supports protocol versions 0.5 and 0.6, while the server says it supports {0} to {1}.", 144 146 minVersion, maxVersion)); 145 147 initialized = false; 146 148 } 147 System.out.println(tr("Communications with {0} established using protocol version {1}", 148 Main.pref.get("osm-server.url"), 149 System.out.println(tr("Communications with {0} established using protocol version {1}", 150 Main.pref.get("osm-server.url"), 149 151 version)); 150 152 osmWriter.setVersion(version); … … 154 156 } 155 157 } 156 158 157 159 /** 158 160 * Makes an XML string from an OSM primitive. Uses the OsmWriter class. … … 171 173 return swriter.toString(); 172 174 } 173 175 174 176 /** 175 177 * Helper that makes an int from the first whitespace separated token in a string. … … 183 185 return Integer.parseInt(t.nextToken()); 184 186 } catch (Exception x) { 185 throw new OsmTransferException( "Cannot read numeric value from response");187 throw new OsmTransferException(tr("Cannot read numeric value from response")); 186 188 } 187 189 } … … 198 200 return Long.parseLong(t.nextToken()); 199 201 } catch (Exception x) { 200 throw new OsmTransferException( "Cannot read numeric value from response");201 } 202 } 203 202 throw new OsmTransferException(tr("Cannot read numeric value from response")); 203 } 204 } 205 204 206 /** 205 207 * Returns the base URL for API requests, including the negotiated version number. … … 213 215 } 214 216 rv.append("/"); 215 // this works around a ruby (or lighttpd) bug where two consecutive slashes in 217 // this works around a ruby (or lighttpd) bug where two consecutive slashes in 216 218 // an URL will cause a "404 not found" response. 217 219 int p; while ((p = rv.indexOf("//", 6)) > -1) { rv.delete(p, p + 1); } … … 219 221 } 220 222 221 /** 223 /** 222 224 * Creates an OSM primitive on the server. The OsmPrimitive object passed in 223 225 * is modified by giving it the server-assigned id. 224 * 226 * 225 227 * @param osm the primitive 226 228 * @throws OsmTransferException if something goes wrong … … 230 232 osm.version = 1; 231 233 } 232 234 233 235 /** 234 236 * Modifies an OSM primitive on the server. For protocols greater than 0.5, 235 * the OsmPrimitive object passed in is modified by giving it the server-assigned 237 * the OsmPrimitive object passed in is modified by giving it the server-assigned 236 238 * version. 237 * 239 * 238 240 * @param osm the primitive 239 241 * @throws OsmTransferException if something goes wrong … … 247 249 osm.version = parseInt(sendRequest("PUT", which(osm)+"/" + osm.id, toXml(osm, true))); 248 250 } 249 } 250 251 } 252 251 253 /** 252 254 * Deletes an OSM primitive on the server. … … 257 259 // legacy mode does not require payload. normal mode (0.6 and up) requires payload for version matching. 258 260 sendRequest("DELETE", which(osm)+"/" + osm.id, version.equals("0.5") ? null : toXml(osm, false)); 259 } 260 261 } 262 261 263 /** 262 264 * Creates a new changeset on the server to use for subsequent calls. … … 276 278 /** 277 279 * Closes a changeset on the server. 278 * 280 * 279 281 * @throws OsmTransferException if something goes wrong. 280 282 */ … … 286 288 287 289 /** 288 * Uploads a list of changes in "diff" form the the server. 290 * Uploads a list of changes in "diff" form to the server. 291 * 289 292 * @param list the list of changed OSM Primitives 290 293 * @return list of processed primitives 291 * @throws OsmTransferException if something is wrong. 292 */ 293 public Collection<OsmPrimitive> uploadDiff(Collection<OsmPrimitive> list) throws OsmTransferException { 294 294 * @throws OsmTransferException if something is wrong 295 * @throws OsmTransferCancelledException if the upload was cancelled by the user 296 */ 297 public Collection<OsmPrimitive> uploadDiff(final Collection<OsmPrimitive> list) throws OsmTransferException { 298 295 299 if (changeset == null) { 296 300 throw new OsmTransferException(tr("No changeset present for diff upload")); 297 301 } 298 299 CreateOsmChangeVisitor duv = new CreateOsmChangeVisitor(changeset, this); 300 301 ArrayList<OsmPrimitive> processed = new ArrayList<OsmPrimitive>(); 302 303 for (OsmPrimitive osm : list) { 304 int progress = Main.pleaseWaitDlg.progress.getValue(); 305 Main.pleaseWaitDlg.currentAction.setText(tr("Preparing...")); 306 if (cancel) throw new OsmTransferCancelledException(); 307 osm.visit(duv); 308 Main.pleaseWaitDlg.progress.setValue(progress+1); 309 } 310 311 Main.pleaseWaitDlg.currentAction.setText(tr("Uploading...")); 312 if (cancel) throw new OsmTransferCancelledException(); 313 314 String diff = duv.getDocument(); 315 String diffresult = sendRequest("POST", "changeset/" + changeset.id + "/upload", diff); 302 303 304 final ArrayList<OsmPrimitive> processed = new ArrayList<OsmPrimitive>(); 305 306 // this is the asynchronous update task 307 // 308 class UploadDiffTask extends PleaseWaitRunnable { 309 310 private boolean uploadCancelled = false; 311 private boolean uploadFailed = false; 312 private Throwable lastThrowable = null; 313 314 public UploadDiffTask(String title) { 315 super(title,false /* don't ignore exceptions */); 316 } 317 318 @Override protected void realRun() throws SAXException, IOException { 319 CreateOsmChangeVisitor duv = new CreateOsmChangeVisitor(changeset, OsmApi.this); 320 321 for (OsmPrimitive osm : list) { 322 int progress = Main.pleaseWaitDlg.progress.getValue(); 323 Main.pleaseWaitDlg.currentAction.setText(tr("Preparing...")); 324 osm.visit(duv); 325 Main.pleaseWaitDlg.progress.setValue(progress+1); 326 } 327 328 Main.pleaseWaitDlg.currentAction.setText(tr("Uploading...")); 329 330 String diff = duv.getDocument(); 331 try { 332 String diffresult = sendRequest("POST", "changeset/" + changeset.id + "/upload", diff); 333 DiffResultReader.parseDiffResult(diffresult, list, processed, duv.getNewIdMap(), Main.pleaseWaitDlg); 334 } catch (Exception sxe) { 335 if (isUploadCancelled()) { 336 // ignore exceptions thrown because the connection is aborted, 337 // i.e. IOExceptions or SocketExceptions 338 // 339 System.out.println("Ignoring exception caught because upload is cancelled. Exception is: " + sxe.toString()); 340 return; 341 } 342 uploadFailed = true; 343 // remember last exception and don't throw it. If it was thrown again it would 344 // have to be encapsulated in a RuntimeException which would be nested in yet 345 // another RuntimeException by parent classes. 346 // Rather check isUploadFailed() and retrieve getLastThrowable() after the task 347 // is completed 348 // 349 lastThrowable = sxe; 350 } 351 } 352 353 @Override protected void finish() { 354 // do nothing 355 } 356 357 @Override protected void cancel() { 358 activeConnection.disconnect(); 359 uploadCancelled = true; 360 } 361 362 public boolean isUploadCancelled() { 363 return uploadCancelled; 364 } 365 366 public boolean isUploadFailed() { 367 return uploadFailed; 368 } 369 370 public Throwable getLastThrowable() { 371 return lastThrowable; 372 } 373 } 374 375 UploadDiffTask uploadTask = new UploadDiffTask(tr("Uploading data")); 376 377 // run data upload as asynchronous task 378 // 316 379 try { 317 DiffResultReader.parseDiffResult(diffresult, list, processed, duv.getNewIdMap(), Main.pleaseWaitDlg); 318 } catch (Exception sxe) { 319 throw new OsmTransferException(tr("Error processing changeset upload response"), sxe); 320 } 380 Void result = null; 381 FutureTask<Void> task = new FutureTask<Void>(uploadTask, result); 382 task.run(); 383 task.get(); // wait for the task to complete, no return value expected, though 384 } catch(Throwable e) { 385 if (uploadTask.isUploadCancelled()) { 386 throw new OsmTransferCancelledException(); 387 } 388 throw new OsmTransferException(e); 389 } 390 391 // handle failed upload 392 // 393 if (uploadTask.isUploadFailed()) { 394 if (uploadTask.getLastThrowable() != null && uploadTask.getLastThrowable() instanceof OsmTransferException) { 395 OsmTransferException e = (OsmTransferException)uploadTask.getLastThrowable(); 396 throw e; 397 } 398 // shouldn't happen, but just in case 399 // 400 throw new OsmTransferException(tr("Data upload failed for unknown reason")); 401 } 402 403 // handle cancelled upload 404 // 405 if (uploadTask.isUploadCancelled()) { 406 throw new OsmTransferCancelledException(); 407 } 408 321 409 return processed; 322 410 } 411 412 323 413 324 414 private void sleepAndListen() throws OsmTransferCancelledException { … … 339 429 * This method will automatically re-try any requests that are answered with a 5xx 340 430 * error code, or that resulted in a timeout exception from the TCP layer. 341 * 431 * 342 432 * @param requestMethod The http method used when talking with the server. 343 433 * @param urlSuffix The suffix to add at the server url, not including the version number, 344 434 * but including any object ids (e.g. "/way/1234/history"). 345 435 * @param requestBody the body of the HTTP request, if any. 346 * 436 * 347 437 * @return the body of the HTTP response, if and only if the response code was "200 OK". 348 * @exception OsmTransferException if the HTTP return code was not 200 (and retries have 349 * been exhausted), or rewrapping a Java exception. 438 * @exception OsmTransferException if the HTTP return code was not 200 (and retries have 439 * been exhausted), or rewrapping a Java exception. 350 440 */ 351 441 private String sendRequest(String requestMethod, String urlSuffix, … … 353 443 354 444 if (!initialized) throw new OsmTransferException(tr("Not initialized")); 355 445 356 446 StringBuffer responseBody = new StringBuffer(); 357 447 StringBuffer statusMessage = new StringBuffer(); 358 448 359 int retries = 5; // configurable? 360 449 int retries = 5; // configurable? 450 361 451 while(true) { // the retry loop 362 452 try { … … 386 476 out.close(); 387 477 } 388 478 389 479 activeConnection.connect(); 390 480 System.out.println(activeConnection.getResponseMessage()); 391 481 int retCode = activeConnection.getResponseCode(); 392 482 393 483 if (retCode >= 500) { 394 484 if (retries-- > 0) { … … 400 490 // populate return fields. 401 491 responseBody.setLength(0); 402 492 403 493 // If the API returned an error code like 403 forbidden, getInputStream 404 494 // will fail with an IOException. … … 410 500 } 411 501 BufferedReader in = new BufferedReader(new InputStreamReader(i)); 412 502 413 503 String s; 414 504 while((s = in.readLine()) != null) { … … 430 520 } 431 521 activeConnection.disconnect(); 432 522 433 523 if (retCode != 200) { 434 524 throw new OsmTransferException(statusMessage.toString()); -
trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java
r1575 r1581 138 138 139 139 private void dealWithTransferException (OsmTransferException e) { 140 if (e instanceof OsmTransferCancelledException) { 141 // ignore - don't bother the user with yet another message that he 142 // has successfully cancelled the data upload 143 // 144 return; 145 } 146 140 147 JOptionPane.showMessageDialog(Main.parent, 141 148 /* tr("Error during upload: ") + */ e.getMessage());
Note:
See TracChangeset
for help on using the changeset viewer.