Changeset 17330 in josm for trunk/src/org


Ignore:
Timestamp:
2020-11-22T22:54:01+01:00 (3 years ago)
Author:
Don-vip
Message:

fix #20131 - remote control: report errors in case of OSM API error (load_and_zoom) or no valid identifier (load_object)

Location:
trunk/src/org/openstreetmap/josm
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadTask.java

    r13927 r17330  
    44import java.net.URL;
    55import java.util.List;
     6import java.util.Objects;
    67import java.util.concurrent.Future;
     8import java.util.stream.Collectors;
    79
    810import org.openstreetmap.josm.data.Bounds;
    911import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
    1012import org.openstreetmap.josm.gui.progress.ProgressMonitor;
     13import org.openstreetmap.josm.tools.ExceptionUtil;
    1114
    1215/**
     
    116119
    117120    /**
     121     * Replies the error messages of the task. Empty list, if no error messages are available.
     122     *
     123     * @return the list of error messages
     124     * @since 17330
     125     */
     126    default List<String> getErrorMessages() {
     127        return getErrorObjects().stream().map(o -> {
     128            if (o instanceof String) {
     129                return (String) o;
     130            } else if (o instanceof Exception) {
     131                return ExceptionUtil.explainException((Exception) o).replace("<html>", "").replace("</html>", "");
     132            } else {
     133                return (String) null;
     134            }
     135        }).filter(Objects::nonNull).collect(Collectors.toList());
     136    }
     137
     138    /**
    118139     * Cancels the asynchronous download task.
    119140     *
  • trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadTaskList.java

    r16770 r17330  
    99import java.awt.geom.Area;
    1010import java.awt.geom.Rectangle2D;
    11 import java.util.ArrayList;
    1211import java.util.Collection;
    1312import java.util.LinkedHashSet;
     
    3534import org.openstreetmap.josm.gui.progress.ProgressMonitor;
    3635import org.openstreetmap.josm.gui.util.GuiHelper;
    37 import org.openstreetmap.josm.tools.ExceptionUtil;
    3836import org.openstreetmap.josm.tools.ImageProvider;
    3937import org.openstreetmap.josm.tools.Logging;
     
    247245                }
    248246            }
    249             Set<Object> errors = tasks.stream().flatMap(t -> t.getErrorObjects().stream()).collect(Collectors.toSet());
     247            Set<String> errors = tasks.stream().flatMap(t -> t.getErrorMessages().stream()).collect(Collectors.toSet());
    250248            if (!errors.isEmpty()) {
    251                 final Collection<String> items = new ArrayList<>();
    252                 for (Object error : errors) {
    253                     if (error instanceof String) {
    254                         items.add((String) error);
    255                     } else if (error instanceof Exception) {
    256                         items.add(ExceptionUtil.explainException((Exception) error));
    257                     }
    258                 }
    259 
    260249                GuiHelper.runInEDT(() -> {
    261                     if (items.size() == 1 && PostDownloadHandler.isNoDataErrorMessage(items.iterator().next())) {
    262                         new Notification(items.iterator().next()).setIcon(JOptionPane.WARNING_MESSAGE).show();
     250                    if (errors.size() == 1 && PostDownloadHandler.isNoDataErrorMessage(errors.iterator().next())) {
     251                        new Notification(errors.iterator().next()).setIcon(JOptionPane.WARNING_MESSAGE).show();
    263252                    } else {
    264253                        JOptionPane.showMessageDialog(MainApplication.getMainFrame(), "<html>"
    265254                                + tr("The following errors occurred during mass download: {0}",
    266                                         Utils.joinAsHtmlUnorderedList(items)) + "</html>",
     255                                        Utils.joinAsHtmlUnorderedList(errors)) + "</html>",
    267256                                tr("Errors during download"), JOptionPane.ERROR_MESSAGE);
    268257                        return;
  • trunk/src/org/openstreetmap/josm/actions/downloadtasks/PostDownloadHandler.java

    r15358 r17330  
    55
    66import java.awt.GraphicsEnvironment;
    7 import java.util.ArrayList;
    87import java.util.Collection;
    98import java.util.HashSet;
     
    2221import org.openstreetmap.josm.gui.Notification;
    2322import org.openstreetmap.josm.gui.util.GuiHelper;
    24 import org.openstreetmap.josm.tools.ExceptionUtil;
    2523import org.openstreetmap.josm.tools.Logging;
    2624import org.openstreetmap.josm.tools.Utils;
     
    126124        // multiple error object? prepare a HTML list
    127125        //
    128         if (!errors.isEmpty()) {
    129             final Collection<String> items = new ArrayList<>();
    130             for (Object error : errors) {
    131                 if (error instanceof String) {
    132                     items.add((String) error);
    133                 } else if (error instanceof Exception) {
    134                     items.add(ExceptionUtil.explainException((Exception) error));
    135                 }
    136             }
    137 
    138             if (!GraphicsEnvironment.isHeadless()) {
    139                 SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(
    140                         MainApplication.getMainFrame(),
    141                         "<html>"+Utils.joinAsHtmlUnorderedList(items)+"</html>",
    142                         tr("Errors during download"),
    143                         JOptionPane.ERROR_MESSAGE));
    144             }
     126        if (!errors.isEmpty() && !GraphicsEnvironment.isHeadless()) {
     127            SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(
     128                    MainApplication.getMainFrame(),
     129                    "<html>"+Utils.joinAsHtmlUnorderedList(task.getErrorMessages())+"</html>",
     130                    tr("Errors during download"),
     131                    JOptionPane.ERROR_MESSAGE));
    145132        }
    146133    }
  • trunk/src/org/openstreetmap/josm/io/remotecontrol/RequestProcessor.java

    r16913 r17330  
    4343import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerErrorException;
    4444import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerForbiddenException;
     45import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerOsmApiException;
    4546import org.openstreetmap.josm.io.remotecontrol.handler.VersionHandler;
    4647import org.openstreetmap.josm.tools.Logging;
     
    185186            String get = in.readLine();
    186187            if (get == null) {
    187                 sendError(out);
     188                sendInternalError(out, null);
    188189                return;
    189190            }
     
    192193            StringTokenizer st = new StringTokenizer(get);
    193194            if (!st.hasMoreTokens()) {
    194                 sendError(out);
     195                sendInternalError(out, null);
    195196                return;
    196197            }
    197198            String method = st.nextToken();
    198199            if (!st.hasMoreTokens()) {
    199                 sendError(out);
     200                sendInternalError(out, null);
    200201                return;
    201202            }
     
    252253                String help = "No command specified! The following commands are available:<ul>" + usage
    253254                        + "</ul>" + "See <a href=\""+websiteDoc+"\">"+websiteDoc+"</a> for complete documentation.";
    254                 sendHeader(out, "400 Bad Request", "text/html", true);
    255                 out.write(String.format(
    256                         RESPONSE_TEMPLATE,
    257                         "<title>Bad Request</title>",
    258                         "<h1>HTTP Error 400: Bad Request</h1>" +
    259                         "<p>" + help + "</p>"));
    260                 out.flush();
     255                sendBadRequest(out, help);
    261256            } else {
    262257                // create handler object
     
    273268                    out.write(handler.getContent());
    274269                    out.flush();
     270                } catch (RequestHandlerOsmApiException ex) {
     271                    Logging.debug(ex);
     272                    sendBadGateway(out, ex.getMessage());
    275273                } catch (RequestHandlerErrorException ex) {
    276274                    Logging.debug(ex);
    277                     sendError(out);
     275                    sendInternalError(out, ex.getMessage());
    278276                } catch (RequestHandlerBadRequestException ex) {
    279277                    Logging.debug(ex);
     
    289287            Logging.error(e);
    290288            try {
    291                 sendError(out);
     289                sendInternalError(out, e.getMessage());
    292290            } catch (IOException e1) {
    293291                Logging.warn(e1);
     
    302300    }
    303301
    304     /**
    305      * Sends a 500 error: server error
    306      *
    307      * @param out
    308      *            The writer where the error is written
    309      * @throws IOException
    310      *             If the error can not be written
    311      */
    312     private static void sendError(Writer out) throws IOException {
    313         sendHeader(out, "500 Internal Server Error", "text/html", true);
     302    private static void sendError(Writer out, int errorCode, String errorName, String help) throws IOException {
     303        sendHeader(out, errorCode + " " + errorName, "text/html", true);
    314304        out.write(String.format(
    315305                RESPONSE_TEMPLATE,
    316                 "<title>Internal Error</title>",
    317                 "<h1>HTTP Error 500: Internal Server Error</h1>"
     306                "<title>" + errorName + "</title>",
     307                "<h1>HTTP Error " + errorCode + ": " + errorName + "</h1>" +
     308                (help == null ? "" : "<p>"+Utils.escapeReservedCharactersHTML(help) + "</p>")
    318309        ));
    319310        out.flush();
     
    321312
    322313    /**
    323      * Sends a 501 error: not implemented
    324      *
    325      * @param out
    326      *            The writer where the error is written
    327      * @throws IOException
    328      *             If the error can not be written
    329      */
    330     private static void sendNotImplemented(Writer out) throws IOException {
    331         sendHeader(out, "501 Not Implemented", "text/html", true);
    332         out.write(String.format(
    333                 RESPONSE_TEMPLATE,
    334                 "<title>Not Implemented</title>",
    335                 "<h1>HTTP Error 501: Not Implemented</h1>"
    336         ));
    337         out.flush();
    338     }
    339 
    340     /**
    341      * Sends a 403 error: forbidden
     314     * Sends a 500 error: internal server error
    342315     *
    343316     * @param out
     
    348321     *             If the error can not be written
    349322     */
     323    private static void sendInternalError(Writer out, String help) throws IOException {
     324        sendError(out, 500, "Internal Server Error", help);
     325    }
     326
     327    /**
     328     * Sends a 501 error: not implemented
     329     *
     330     * @param out
     331     *            The writer where the error is written
     332     * @throws IOException
     333     *             If the error can not be written
     334     */
     335    private static void sendNotImplemented(Writer out) throws IOException {
     336        sendError(out, 501, "Not Implemented", null);
     337    }
     338
     339    /**
     340     * Sends a 502 error: bad gateway
     341     *
     342     * @param out
     343     *            The writer where the error is written
     344     * @param help
     345     *            Optional HTML help content to display, can be null
     346     * @throws IOException
     347     *             If the error can not be written
     348     */
     349    private static void sendBadGateway(Writer out, String help) throws IOException {
     350        sendError(out, 502, "Bad Gateway", help);
     351    }
     352
     353    /**
     354     * Sends a 403 error: forbidden
     355     *
     356     * @param out
     357     *            The writer where the error is written
     358     * @param help
     359     *            Optional HTML help content to display, can be null
     360     * @throws IOException
     361     *             If the error can not be written
     362     */
    350363    private static void sendForbidden(Writer out, String help) throws IOException {
    351         sendHeader(out, "403 Forbidden", "text/html", true);
    352         out.write(String.format(
    353                 RESPONSE_TEMPLATE,
    354                 "<title>Forbidden</title>",
    355                 "<h1>HTTP Error 403: Forbidden</h1>" +
    356                 (help == null ? "" : "<p>"+Utils.escapeReservedCharactersHTML(help) + "</p>")
    357         ));
    358         out.flush();
     364        sendError(out, 403, "Forbidden", help);
    359365    }
    360366
     
    367373     */
    368374    private static void sendBadRequest(Writer out, String help) throws IOException {
    369         sendHeader(out, "400 Bad Request", "text/html", true);
    370         out.write(String.format(
    371                 RESPONSE_TEMPLATE,
    372                 "<title>Bad Request</title>",
    373                 "<h1>HTTP Error 400: Bad Request</h1>" +
    374                 (help == null ? "" : ("<p>" + Utils.escapeReservedCharactersHTML(help) + "</p>"))
    375         ));
    376         out.flush();
     375        sendError(out, 400, "Bad Request", help);
    377376    }
    378377
  • trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandler.java

    r16643 r17330  
    1212import java.util.Map;
    1313import java.util.Set;
     14import java.util.concurrent.ExecutionException;
    1415import java.util.concurrent.Future;
     16import java.util.concurrent.TimeUnit;
     17import java.util.concurrent.TimeoutException;
    1518
    1619import javax.swing.JOptionPane;
     
    2023import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
    2124import org.openstreetmap.josm.actions.downloadtasks.DownloadParams;
    22 import org.openstreetmap.josm.actions.downloadtasks.DownloadTask;
    2325import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
    2426import org.openstreetmap.josm.data.Bounds;
     
    3638import org.openstreetmap.josm.gui.Notification;
    3739import org.openstreetmap.josm.gui.util.GuiHelper;
     40import org.openstreetmap.josm.io.OsmApiException;
    3841import org.openstreetmap.josm.io.remotecontrol.AddTagsDialog;
    3942import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
     
    120123    @Override
    121124    protected void handleRequest() throws RequestHandlerErrorException {
    122         DownloadTask osmTask = new DownloadOsmTask();
     125        DownloadOsmTask osmTask = new DownloadOsmTask();
    123126        try {
    124127            DownloadParams settings = getDownloadParams();
     
    154157                        Future<?> future = osmTask.download(settings, new Bounds(minlat, minlon, maxlat, maxlon),
    155158                                null /* let the task manage the progress monitor */);
    156                         MainApplication.worker.submit(new PostDownloadHandler(osmTask, future));
     159                        MainApplication.worker.submit(new PostDownloadHandler(osmTask, future))
     160                            .get(OSM_DOWNLOAD_TIMEOUT.get(), TimeUnit.SECONDS);
     161                        if (osmTask.isFailed()) {
     162                            Object error = osmTask.getErrorObjects().get(0);
     163                            throw error instanceof OsmApiException
     164                                ? new RequestHandlerOsmApiException((OsmApiException) error)
     165                                : new RequestHandlerErrorException(String.join(", ", osmTask.getErrorMessages()));
     166                        }
    157167                    }
    158168                }
    159169            }
    160         } catch (RuntimeException ex) { // NOPMD
     170        } catch (RuntimeException | InterruptedException | ExecutionException | TimeoutException ex) { // NOPMD
    161171            Logging.warn("RemoteControl: Error parsing load_and_zoom remote control request:");
    162172            Logging.error(ex);
  • trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadObjectHandler.java

    r15152 r17330  
    103103            }
    104104        }
     105        if (ps.isEmpty()) {
     106            throw new RequestHandlerBadRequestException(tr("No valid object identifier has been provided"));
     107        }
    105108    }
    106109}
  • trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/RequestHandler.java

    r16825 r17330  
    2525import org.openstreetmap.josm.data.osm.UploadPolicy;
    2626import org.openstreetmap.josm.data.preferences.BooleanProperty;
     27import org.openstreetmap.josm.data.preferences.IntegerProperty;
    2728import org.openstreetmap.josm.gui.MainApplication;
     29import org.openstreetmap.josm.io.OsmApiException;
    2830import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
    2931import org.openstreetmap.josm.spi.preferences.Config;
     
    4345    /** preference to determine if remote control loads data in a new layer */
    4446    public static final BooleanProperty LOAD_IN_NEW_LAYER = new BooleanProperty("remotecontrol.new-layer", false);
     47    /** preference to define OSM download timeout in seconds */
     48    public static final IntegerProperty OSM_DOWNLOAD_TIMEOUT = new IntegerProperty("remotecontrol.osm.download.timeout", 5*60);
    4549
    4650    protected static final Pattern SPLITTER_COMMA = Pattern.compile(",\\s*");
     
    416420        /**
    417421         * Constructs a new {@code RequestHandlerErrorException}.
     422         * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method.
     423         * @since 17330
     424         */
     425        public RequestHandlerErrorException(String message) {
     426            super(message);
     427        }
     428
     429        /**
     430         * Constructs a new {@code RequestHandlerErrorException}.
    418431         * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method).
    419432         */
    420433        public RequestHandlerErrorException(Throwable cause) {
     434            super(cause);
     435        }
     436    }
     437
     438    /**
     439     * Error raised for OSM API errors.
     440     * @since 17330
     441     */
     442    public static class RequestHandlerOsmApiException extends RequestHandlerErrorException {
     443
     444        /**
     445         * Constructs a new {@code RequestHandlerOsmApiException}.
     446         * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method).
     447         */
     448        public RequestHandlerOsmApiException(OsmApiException cause) {
    421449            super(cause);
    422450        }
Note: See TracChangeset for help on using the changeset viewer.