Changeset 1581 in josm


Ignore:
Timestamp:
May 7, 2009 5:55:45 PM (4 years ago)
Author:
stoecker
Message:

fix #2429 - patch by Gubaer - fix upload cancel

Location:
trunk/src/org/openstreetmap/josm/io
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/io/OsmApi.java

    r1578 r1581  
    2323import java.util.Properties; 
    2424import java.util.StringTokenizer; 
     25import java.util.concurrent.FutureTask; 
    2526 
    2627import javax.xml.parsers.SAXParserFactory; 
     
    3334import org.openstreetmap.josm.data.osm.Way; 
    3435import org.openstreetmap.josm.data.osm.visitor.CreateOsmChangeVisitor; 
     36import org.openstreetmap.josm.gui.PleaseWaitRunnable; 
    3537import org.xml.sax.Attributes; 
    3638import org.xml.sax.InputSource; 
     
    3941 
    4042/** 
    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. 
    4446 * 
    4547 * It is conceivable to extract this into an interface later and create various 
    4648 * classes implementing the interface, to be able to talk to various kinds of servers. 
    47  *  
     49 * 
    4850 */ 
    4951public class OsmApi extends OsmConnection { 
     
    6365     */ 
    6466    private String minVersion = null; 
    65      
     67 
    6668    /** 
    6769     * Maximum API version accepted by server, from capabilities response 
    6870     */ 
    6971    private String maxVersion = null; 
    70      
     72 
    7173    /** 
    7274     * Maximum downloadable area from server (degrees squared), from capabilities response 
     
    7476     */ 
    7577    private String maxArea = null; 
    76      
     78 
    7779    /** 
    7880     * true if successfully initialized 
    7981     */ 
    8082    private boolean initialized = false; 
    81      
     83 
    8284    private StringWriter swriter = new StringWriter(); 
    8385    private OsmWriter osmWriter = new OsmWriter(new PrintWriter(swriter), true, null); 
     
    108110        return ""; 
    109111    } 
    110      
    111     /**  
     112 
     113    /** 
    112114     * Returns the OSM protocol version we use to talk to the server. 
    113115     * @return protocol version, or null if not yet negotiated. 
     
    116118        return version; 
    117119    } 
    118      
     120 
    119121    /** 
    120122     * Returns true if the negotiated version supports changesets. 
     
    124126        return ((version != null) && (version.compareTo("0.6")>=0)); 
    125127    } 
    126      
     128 
    127129    /** 
    128130     * Initializes this component by negotiating a protocol version with the server. 
     
    141143            } else { 
    142144                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}.", 
    144146                    minVersion, maxVersion)); 
    145147                initialized = false; 
    146148            } 
    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"), 
    149151                version)); 
    150152            osmWriter.setVersion(version); 
     
    154156        } 
    155157    } 
    156      
     158 
    157159    /** 
    158160     * Makes an XML string from an OSM primitive. Uses the OsmWriter class. 
     
    171173        return swriter.toString(); 
    172174    } 
    173      
     175 
    174176    /** 
    175177     * Helper that makes an int from the first whitespace separated token in a string. 
     
    183185            return Integer.parseInt(t.nextToken()); 
    184186        } catch (Exception x) { 
    185             throw new OsmTransferException("Cannot read numeric value from response"); 
     187            throw new OsmTransferException(tr("Cannot read numeric value from response")); 
    186188        } 
    187189    } 
     
    198200            return Long.parseLong(t.nextToken()); 
    199201        } 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 
    204206    /** 
    205207     * Returns the base URL for API requests, including the negotiated version number. 
     
    213215        } 
    214216        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 
    216218        // an URL will cause a "404 not found" response. 
    217219        int p; while ((p = rv.indexOf("//", 6)) > -1) { rv.delete(p, p + 1); } 
     
    219221    } 
    220222 
    221     /**  
     223    /** 
    222224     * Creates an OSM primitive on the server. The OsmPrimitive object passed in 
    223225     * is modified by giving it the server-assigned id. 
    224      *  
     226     * 
    225227     * @param osm the primitive 
    226228     * @throws OsmTransferException if something goes wrong 
     
    230232        osm.version = 1; 
    231233    } 
    232      
     234 
    233235    /** 
    234236     * 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 
    236238     * version. 
    237      *  
     239     * 
    238240     * @param osm the primitive 
    239241     * @throws OsmTransferException if something goes wrong 
     
    247249            osm.version = parseInt(sendRequest("PUT", which(osm)+"/" + osm.id, toXml(osm, true))); 
    248250        } 
    249     }     
    250      
     251    } 
     252 
    251253    /** 
    252254     * Deletes an OSM primitive on the server. 
     
    257259        // legacy mode does not require payload. normal mode (0.6 and up) requires payload for version matching. 
    258260        sendRequest("DELETE", which(osm)+"/" + osm.id, version.equals("0.5") ? null : toXml(osm, false)); 
    259     }    
    260      
     261    } 
     262 
    261263    /** 
    262264     * Creates a new changeset on the server to use for subsequent calls. 
     
    276278    /** 
    277279     * Closes a changeset on the server. 
    278      *  
     280     * 
    279281     * @throws OsmTransferException if something goes wrong. 
    280282     */ 
     
    286288 
    287289    /** 
    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     * 
    289292     * @param list the list of changed OSM Primitives 
    290293     * @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 
    295299        if (changeset == null) { 
    296300            throw new OsmTransferException(tr("No changeset present for diff upload")); 
    297301        } 
    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        // 
    316379        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 
    321409        return processed; 
    322410    } 
     411 
     412 
    323413 
    324414    private void sleepAndListen() throws OsmTransferCancelledException { 
     
    339429     * This method will automatically re-try any requests that are answered with a 5xx 
    340430     * error code, or that resulted in a timeout exception from the TCP layer. 
    341      *  
     431     * 
    342432     * @param requestMethod The http method used when talking with the server. 
    343433     * @param urlSuffix The suffix to add at the server url, not including the version number, 
    344434     *    but including any object ids (e.g. "/way/1234/history"). 
    345435     * @param requestBody the body of the HTTP request, if any. 
    346      *  
     436     * 
    347437     * @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. 
    350440     */ 
    351441    private String sendRequest(String requestMethod, String urlSuffix, 
     
    353443 
    354444        if (!initialized) throw new OsmTransferException(tr("Not initialized")); 
    355          
     445 
    356446        StringBuffer responseBody = new StringBuffer(); 
    357447        StringBuffer statusMessage = new StringBuffer(); 
    358448 
    359         int retries = 5; // configurable?  
    360          
     449        int retries = 5; // configurable? 
     450 
    361451        while(true) { // the retry loop 
    362452            try { 
     
    386476                    out.close(); 
    387477                } 
    388                  
     478 
    389479                activeConnection.connect(); 
    390480                System.out.println(activeConnection.getResponseMessage()); 
    391481                int retCode = activeConnection.getResponseCode(); 
    392                  
     482 
    393483                if (retCode >= 500) { 
    394484                    if (retries-- > 0) { 
     
    400490                // populate return fields. 
    401491                responseBody.setLength(0); 
    402                  
     492 
    403493                // If the API returned an error code like 403 forbidden, getInputStream 
    404494                // will fail with an IOException. 
     
    410500                } 
    411501                BufferedReader in = new BufferedReader(new InputStreamReader(i)); 
    412                  
     502 
    413503                String s; 
    414504                while((s = in.readLine()) != null) { 
     
    430520                } 
    431521                activeConnection.disconnect(); 
    432                  
     522 
    433523                if (retCode != 200) { 
    434524                    throw new OsmTransferException(statusMessage.toString()); 
  • trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java

    r1575 r1581  
    138138 
    139139    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         
    140147        JOptionPane.showMessageDialog(Main.parent,  
    141148            /* tr("Error during upload: ") + */ e.getMessage()); 
Note: See TracChangeset for help on using the changeset viewer.