Ticket #22034: 22034.patch
| File 22034.patch, 73.8 KB (added by , 4 years ago) |
|---|
-
src/org/openstreetmap/josm/data/osm/DownloadPolicy.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/osm/DownloadPolicy.java b/src/org/openstreetmap/josm/data/osm/DownloadPolicy.java
a b 1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.osm; 3 3 4 import java.util.Locale; 5 4 6 /** 5 7 * Download policy. 6 8 * … … 48 50 } 49 51 throw new IllegalArgumentException(xmlFlag); 50 52 } 53 54 @Override 55 public String toString() { 56 return this.name().toLowerCase(Locale.ROOT); 57 } 51 58 } -
src/org/openstreetmap/josm/data/osm/UploadPolicy.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/osm/UploadPolicy.java b/src/org/openstreetmap/josm/data/osm/UploadPolicy.java
a b 1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.osm; 3 3 4 import java.util.Locale; 5 4 6 /** 5 7 * Upload policy. 6 8 * … … 55 57 } 56 58 throw new IllegalArgumentException(xmlFlag); 57 59 } 60 61 62 @Override 63 public String toString() { 64 return this.name().toLowerCase(Locale.ROOT); 65 } 58 66 } -
src/org/openstreetmap/josm/gui/preferences/remotecontrol/RemoteControlPreference.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/gui/preferences/remotecontrol/RemoteControlPreference.java b/src/org/openstreetmap/josm/gui/preferences/remotecontrol/RemoteControlPreference.java
a b 27 27 import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel; 28 28 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 29 29 import org.openstreetmap.josm.io.remotecontrol.RemoteControl; 30 import org.openstreetmap.josm.io.remotecontrol.RemoteControlHttpServer; 30 31 import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler; 31 32 import org.openstreetmap.josm.spi.preferences.Config; 32 33 import org.openstreetmap.josm.tools.GBC; … … 78 79 final JLabel portLabel = new JLabel("<html>" 79 80 + tr("JOSM will always listen at <b>port {0}</b> (http) on localhost." 80 81 + "<br>This port is not configurable because it is referenced by external applications talking to JOSM.", 81 Config.getPref().get("remote.control.port", "8111")) + "</html>");82 RemoteControlHttpServer.PORT.get()) + "</html>"); 82 83 portLabel.setFont(portLabel.getFont().deriveFont(Font.PLAIN)); 83 84 remote.add(portLabel, GBC.eol().insets(5, 5, 0, 10).fill(GBC.HORIZONTAL)); 84 85 -
src/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandler.java
a b 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 6 import java.awt.Point; 7 import java.util.Arrays; 7 8 import java.util.Collections; 9 import java.util.List; 8 10 9 11 import org.openstreetmap.josm.actions.AutoScaleAction; 10 12 import org.openstreetmap.josm.actions.AutoScaleAction.AutoScaleMode; … … 19 21 import org.openstreetmap.josm.gui.util.GuiHelper; 20 22 import org.openstreetmap.josm.io.remotecontrol.AddTagsDialog; 21 23 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 24 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 22 25 import org.openstreetmap.josm.spi.preferences.Config; 23 26 import org.openstreetmap.josm.tools.Logging; 24 27 … … 32 35 */ 33 36 public static final String command = "add_node"; 34 37 38 private final RequestParameter<Double> latParameter = RequestParameter.mandatory("lat", Double::parseDouble, Double.class); 39 private final RequestParameter<Double> lonParameter = RequestParameter.mandatory("lon", Double::parseDouble, Double.class); 40 35 41 private double lat; 36 42 private double lon; 37 43 … … 41 47 } 42 48 43 49 @Override 44 public String[] getMandatoryParams() { 45 return new String[] {"lat", "lon"}; 46 } 47 48 @Override 49 public String[] getOptionalParams() { 50 return new String[] {"addtags"}; 50 public List<RequestParameter<?>> getParameters() { 51 return Arrays.asList( 52 latParameter, 53 lonParameter, 54 addTagsParameter 55 ); 51 56 } 52 57 53 58 @Override 54 59 public String getUsage() { 55 return " adds a node (given by its latitude and longitude) to the current dataset";60 return "Adds a node (given by its latitude and longitude) to the current dataset"; 56 61 } 57 62 58 63 @Override … … 66 71 @Override 67 72 public String getPermissionMessage() { 68 73 return tr("Remote Control has been asked to create a new node.") + 69 "<br>" + tr("Coordinates: ") + args.get("lat") + ", " + args.get("lon");74 "<br>" + tr("Coordinates: ") + latParameter.read(args) + ", " + lonParameter.read(args); 70 75 } 71 76 72 77 @Override … … 116 121 @Override 117 122 protected void validateRequest() throws RequestHandlerBadRequestException { 118 123 try { 119 lat = Double.parseDouble(args != null ? args.get("lat") : "");120 lon = Double.parseDouble(args != null ? args.get("lon") : "");124 lat = latParameter.read(args); 125 lon = lonParameter.read(args); 121 126 } catch (NumberFormatException e) { 122 127 throw new RequestHandlerBadRequestException("NumberFormatException ("+e.getMessage()+')', e); 123 128 } 129 124 130 if (MainApplication.getLayerManager().getEditLayer() == null) { 125 131 throw new RequestHandlerBadRequestException(tr("There is no layer opened to add node")); 126 132 } -
src/org/openstreetmap/josm/io/remotecontrol/handler/AddWayHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/AddWayHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/AddWayHandler.java
a b 30 30 import org.openstreetmap.josm.gui.util.GuiHelper; 31 31 import org.openstreetmap.josm.io.remotecontrol.AddTagsDialog; 32 32 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 33 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 33 34 import org.openstreetmap.josm.spi.preferences.Config; 34 35 35 36 /** … … 42 43 */ 43 44 public static final String command = "add_way"; 44 45 46 private final RequestParameter<String> wayParameter = RequestParameter.mandatory("way"); 47 45 48 private final List<LatLon> allCoordinates = new ArrayList<>(); 46 49 47 50 /** … … 50 53 private Map<LatLon, Node> addedNodes; 51 54 52 55 @Override 53 public String[] getMandatoryParams() { 54 return new String[]{"way"}; 55 } 56 57 @Override 58 public String[] getOptionalParams() { 59 return new String[] {"addtags"}; 56 public List<RequestParameter<?>> getParameters() { 57 return Arrays.asList( 58 wayParameter, 59 addTagsParameter 60 ); 60 61 } 61 62 62 63 @Override 63 64 public String getUsage() { 64 return " adds a way (given by a semicolon separated sequence of lat,lon pairs) to the current dataset";65 return "Adds a way (given by a semicolon separated sequence of lat,lon pairs) to the current dataset"; 65 66 } 66 67 67 68 @Override … … 92 93 @Override 93 94 protected void validateRequest() throws RequestHandlerBadRequestException { 94 95 allCoordinates.clear(); 95 for (String coordinatesString : splitArg("way", SPLITTER_SEMIC)) {96 for (String coordinatesString : SPLITTER_SEMIC.split(wayParameter.read(args), -1)) { 96 97 String[] coordinates = coordinatesString.split(",\\s*", 2); 97 98 if (coordinates.length < 2) { 98 99 throw new RequestHandlerBadRequestException( -
src/org/openstreetmap/josm/io/remotecontrol/handler/FeaturesHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/FeaturesHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/FeaturesHandler.java
a b 5 5 6 6 import java.util.Arrays; 7 7 import java.util.Collection; 8 import java.util.List; 8 9 import java.util.stream.Collectors; 10 import java.util.stream.Stream; 9 11 10 12 import javax.json.Json; 11 13 import javax.json.JsonArray; … … 15 17 16 18 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 17 19 import org.openstreetmap.josm.io.remotecontrol.RequestProcessor; 20 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 18 21 19 22 /** 20 23 * Reports available commands, their parameters and examples … … 27 30 */ 28 31 public static final String command = "features"; 29 32 33 private static final RequestParameter<String> jsonpParameter = RequestParameter.optional("jsonp"); 34 private static final RequestParameter<String> queryParameter = RequestParameter.optional("q"); 35 30 36 @Override 31 37 protected void handleRequest() throws RequestHandlerErrorException, RequestHandlerBadRequestException { 32 String q = args.get("q");38 String q = queryParameter.read(args); 33 39 Collection<String> handlers = q == null ? null : Arrays.asList(q.split("[,\\s]+", -1)); 34 40 content = getHandlersInfoAsJSON(handlers).toString(); 35 41 contentType = "application/json"; 36 if ( args.containsKey("jsonp")) {37 content = args.get("jsonp") + " && " + args.get("jsonp") + '(' + content + ')';42 if (jsonpParameter.isPresent(args)) { 43 content = jsonpParameter.read(args) + " && " + jsonpParameter.read(args) + '(' + content + ')'; 38 44 } 39 45 } 40 46 … … 52 58 if (handler.getUsage() != null) { 53 59 json.add("usage", handler.getUsage()); 54 60 } 55 json.add("parameters", toJsonArray(handler.get MandatoryParams()));56 json.add("optional", toJsonArray(handler.get OptionalParams()));57 json.add("examples", toJsonArray( handler.getUsageExamples(handler.getCommand())));61 json.add("parameters", toJsonArray(handler.getParameters().stream().filter(RequestParameter::isMandatory).map(RequestParameter::getName))); 62 json.add("optional", toJsonArray(handler.getParameters().stream().filter(RequestParameter::isOptional).map(RequestParameter::getName))); 63 json.add("examples", toJsonArray(Arrays.stream(handler.getUsageExamples(handler.getCommand())))); 58 64 return json.build(); 59 65 } 60 66 61 private static JsonArray toJsonArray(Str ing[]strings) {62 return Arrays.stream(strings)67 private static JsonArray toJsonArray(Stream<String> strings) { 68 return strings 63 69 .collect(Collectors.collectingAndThen(Collectors.toList(), Json::createArrayBuilder)) 64 70 .build(); 65 71 } … … 75 81 } 76 82 77 83 @Override 78 public String[] getMandatoryParams() { 79 return new String[0]; 80 } 81 82 @Override 83 public String[] getOptionalParams() { 84 return new String[]{"jsonp", "q"}; 84 public List<RequestParameter<?>> getParameters() { 85 return Arrays.asList( 86 jsonpParameter, 87 queryParameter 88 ); 85 89 } 86 90 87 91 @Override … … 91 95 92 96 @Override 93 97 public String getUsage() { 94 return " reports available commands, their parameters and examples";98 return "Reports available commands, their parameters and examples"; 95 99 } 96 100 97 101 @Override 98 102 public String[] getUsageExamples() { 99 return new String[] {"/features", "/features?q=import,add_node"}; 103 return new String[] { 104 "/features", 105 "/features?q=import,add_node" 106 }; 100 107 } 101 108 } -
src/org/openstreetmap/josm/io/remotecontrol/handler/ImageryHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/ImageryHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/ImageryHandler.java
a b 3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.util.ArrayList; 6 7 import java.util.Arrays; 7 8 import java.util.LinkedHashSet; 9 import java.util.List; 8 10 import java.util.Map; 9 11 import java.util.Objects; 10 12 import java.util.Set; 13 import java.util.stream.Collectors; 11 14 12 15 import org.openstreetmap.josm.data.StructUtils; 13 16 import org.openstreetmap.josm.data.imagery.ImageryInfo; … … 18 21 import org.openstreetmap.josm.gui.layer.ImageryLayer; 19 22 import org.openstreetmap.josm.gui.util.GuiHelper; 20 23 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 24 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 21 25 import org.openstreetmap.josm.tools.CheckParameterUtil; 22 26 import org.openstreetmap.josm.tools.Logging; 23 27 import org.openstreetmap.josm.tools.Utils; … … 33 37 */ 34 38 public static final String command = "imagery"; 35 39 40 private final RequestParameter<String> urlParameter = RequestParameter.optional("url"); 41 private final RequestParameter<String> idParameters = RequestParameter.optional("id"); 42 36 43 @Override 37 44 public String getPermissionMessage() { 38 45 return tr("Remote Control has been asked to load an imagery layer from the following URL:") … … 40 47 } 41 48 42 49 @Override 43 public String[] getMandatoryParams() { 44 return new String[0]; 45 } 46 47 @Override 48 public String[] getOptionalParams() { 49 Set<String> params = new LinkedHashSet<>(); 50 params.add("url"); 51 params.add("id"); 50 public List<RequestParameter<?>> getParameters() { 52 51 Map<String, String> struct = StructUtils.serializeStruct(new ImageryPreferenceEntry(), ImageryPreferenceEntry.class, 53 StructUtils.SerializeOptions.INCLUDE_NULL, StructUtils.SerializeOptions.INCLUDE_DEFAULT); 54 params.addAll(struct.keySet()); 55 return params.toArray(new String[0]); 52 StructUtils.SerializeOptions.INCLUDE_NULL, StructUtils.SerializeOptions.INCLUDE_DEFAULT); 53 54 List<RequestParameter<?>> imageryPreferenceParameters = struct.keySet().stream() 55 .map(RequestParameter::optional) 56 .filter(param -> !param.getName().equals("url") && !param.getName().equals("id")) 57 .collect(Collectors.toList()); 58 59 List<RequestParameter<?>> parameters = new ArrayList<>(); 60 parameters.add(urlParameter); 61 parameters.add(idParameters); 62 parameters.addAll(imageryPreferenceParameters); 63 return parameters; 56 64 } 57 65 58 66 @Override … … 61 69 } 62 70 63 71 protected ImageryInfo buildImageryInfo() { 64 String id = args.get("id");72 String id = idParameters.read(args); 65 73 if (id != null) { 66 74 return ImageryLayerInfo.instance.getAllDefaultLayers().stream() 67 75 .filter(l -> Objects.equals(l.getId(), id)) … … 108 116 109 117 @Override 110 118 public String getUsage() { 111 return " adds an imagery layer (e.g. WMS, TMS)";119 return "Adds an imagery layer (e.g. WMS, TMS)"; 112 120 } 113 121 114 122 @Override … … 119 127 "/imagery?id=Bing", 120 128 "/imagery?title=osm&type=tms&url=https://tile.openstreetmap.org/%7Bzoom%7D/%7Bx%7D/%7By%7D.png", 121 129 "/imagery?title=landsat&type=wms&url=http://irs.gis-lab.info/?" + 122 "layers=landsat&SRS=%7Bproj%7D&WIDTH=%7Bwidth%7D&HEIGHT=%7Bheight%7D&BBOX=%7Bbbox%7D",123 "/imagery?title=...&type={" +types+"}&url=....[&cookies=...][&min_zoom=...][&max_zoom=...]"124 };130 "layers=landsat&SRS=%7Bproj%7D&WIDTH=%7Bwidth%7D&HEIGHT=%7Bheight%7D&BBOX=%7Bbbox%7D", 131 "/imagery?title=...&type={" + types + "}&url=....[&cookies=...][&min_zoom=...][&max_zoom=...]" 132 }; 125 133 } 126 134 } -
src/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandler.java
a b 3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.lang.reflect.Array; 6 7 import java.net.MalformedURLException; 7 8 import java.net.URL; 9 import java.util.Arrays; 8 10 import java.util.Collection; 11 import java.util.Collections; 9 12 import java.util.LinkedHashSet; 13 import java.util.List; 10 14 import java.util.Set; 11 15 12 16 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask; 13 17 import org.openstreetmap.josm.actions.downloadtasks.DownloadTask; 14 18 import org.openstreetmap.josm.gui.MainApplication; 15 19 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 20 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 16 21 import org.openstreetmap.josm.spi.preferences.Config; 17 22 import org.openstreetmap.josm.tools.Logging; 18 23 import org.openstreetmap.josm.tools.Utils; … … 27 32 */ 28 33 public static final String command = "import"; 29 34 35 private final RequestParameter<String> urlParameter = RequestParameter.mandatory("url"); 36 30 37 private URL url; 31 38 private Collection<DownloadTask> suitableDownloadTasks; 32 39 … … 48 55 task.loadUrl(getDownloadParams(), url.toExternalForm(), null); 49 56 } 50 57 } 51 LoadAndZoomHandler.parseChangesetTags( args);58 LoadAndZoomHandler.parseChangesetTags(LoadAndZoomHandler.changesetTagsParameter, args); 52 59 } catch (RuntimeException ex) { // NOPMD 53 60 Logging.warn("RemoteControl: Error parsing import remote control request:"); 54 61 Logging.error(ex); … … 57 64 } 58 65 59 66 @Override 60 public String[] getMandatoryParams() { 61 return new String[]{"url"}; 62 } 63 64 @Override 65 public String[] getOptionalParams() { 66 return new String[] {"new_layer", "layer_name", "layer_locked", "download_policy", "upload_policy", "changeset_tags"}; 67 public List<RequestParameter<?>> getParameters() { 68 return Arrays.asList( 69 urlParameter, 70 newLayerParameter, 71 layerNameParameter, 72 layerLockedParameter, 73 downloadPolicyParameter, 74 uploadPolicyParameter, 75 LoadAndZoomHandler.changesetTagsParameter 76 ); 67 77 } 68 78 69 79 @Override 70 80 public String getUsage() { 71 return " downloads the specified OSM file and adds it to the current data set";81 return "Downloads the specified OSM file and adds it to the current data set"; 72 82 } 73 83 74 84 @Override 75 85 public String[] getUsageExamples() { 76 return new String[] {"/import?url=" + Utils.encodeUrl( 77 Config.getUrls().getJOSMWebsite()+"/browser/josm/trunk/nodist/data/direction-arrows.osm?format=txt")}; 86 return new String[] { 87 "/import?url=" + Utils.encodeUrl( 88 Config.getUrls().getJOSMWebsite()+"/browser/josm/trunk/nodist/data/direction-arrows.osm?format=txt") 89 }; 78 90 } 79 91 80 92 @Override … … 102 114 @Override 103 115 protected void validateRequest() throws RequestHandlerBadRequestException { 104 116 validateDownloadParams(); 105 String urlString = args != null ? args.get("url") : null;117 String urlString = urlParameter.read(args); 106 118 if (Config.getPref().getBoolean("remotecontrol.importhandler.fix_url_query", true)) { 107 119 urlString = Utils.fixURLQuery(urlString); 108 120 } -
src/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandler.java
a b 9 9 import java.util.Collection; 10 10 import java.util.Collections; 11 11 import java.util.LinkedHashSet; 12 import java.util.List; 12 13 import java.util.Map; 13 14 import java.util.Set; 14 15 import java.util.concurrent.ExecutionException; … … 42 43 import org.openstreetmap.josm.io.OsmTransferException; 43 44 import org.openstreetmap.josm.io.remotecontrol.AddTagsDialog; 44 45 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 46 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 45 47 import org.openstreetmap.josm.tools.Logging; 46 48 import org.openstreetmap.josm.tools.SubclassFilteredCollection; 47 49 import org.openstreetmap.josm.tools.Utils; … … 63 65 public static final String command2 = "zoom"; 64 66 private static final String CURRENT_SELECTION = "currentselection"; 65 67 68 private final RequestParameter<Double> bottomParameter = RequestParameter.mandatory("bottom", Double::parseDouble, Double.class); 69 private final RequestParameter<Double> topParameter = RequestParameter.mandatory("top", Double::parseDouble, Double.class); 70 private final RequestParameter<Double> leftParameter = RequestParameter.mandatory("left", Double::parseDouble, Double.class); 71 private final RequestParameter<Double> rightParameter = RequestParameter.mandatory("right", Double::parseDouble, Double.class); 72 private final RequestParameter<String> selectParameter = RequestParameter.optional("select"); 73 private final RequestParameter<String> searchParameter = RequestParameter.optional("search"); 74 private final RequestParameter<String> zoomModeParameter = RequestParameter.optional("zoom_mode"); 75 private final RequestParameter<String> changesetCommentParameter = RequestParameter.optional("changeset_comment"); 76 private final RequestParameter<String> changesetSourceParameter = RequestParameter.optional("changeset_source"); 77 private final RequestParameter<String> changesetHashtagsParameter = RequestParameter.optional("changeset_hashtags"); 78 public static final RequestParameter<String> changesetTagsParameter = RequestParameter.optional("changeset_tags"); 79 66 80 // Mandatory arguments 67 81 private double minlat; 68 82 private double maxlat; … … 78 92 public String getPermissionMessage() { 79 93 String msg = tr("Remote Control has been asked to load data from the API.") + 80 94 "<br>" + tr("Bounding box: ") + new BBox(minlon, minlat, maxlon, maxlat).toStringCSV(", "); 81 if ( args.containsKey("select") && !toSelect.isEmpty()) {95 if (selectParameter.isPresent(args) && !toSelect.isEmpty()) { 82 96 msg += "<br>" + tr("Selection: {0}", toSelect.size()); 83 97 } 84 98 return msg; 85 99 } 86 100 87 101 @Override 88 public String[] getMandatoryParams() { 89 return new String[] {"bottom", "top", "left", "right"}; 90 } 91 92 @Override 93 public String[] getOptionalParams() { 94 return new String[] {"new_layer", "layer_name", "addtags", "select", "zoom_mode", 95 "changeset_comment", "changeset_source", "changeset_hashtags", "changeset_tags", 96 "search", "layer_locked", "download_policy", "upload_policy"}; 102 public List<RequestParameter<?>> getParameters() { 103 return Arrays.asList( 104 bottomParameter, 105 topParameter, 106 leftParameter, 107 rightParameter, 108 newLayerParameter, 109 layerNameParameter, 110 addTagsParameter, 111 selectParameter, 112 zoomModeParameter, 113 changesetCommentParameter, 114 changesetSourceParameter, 115 changesetHashtagsParameter, 116 changesetTagsParameter, 117 searchParameter, 118 layerLockedParameter, 119 downloadPolicyParameter, 120 uploadPolicyParameter 121 ); 97 122 } 98 123 99 124 @Override 100 125 public String getUsage() { 101 return " download a bounding box from the API, zoom to the downloaded area and optionally select one or more objects";126 return "Download a bounding box from the API, zoom to the downloaded area and optionally select one or more objects"; 102 127 } 103 128 104 129 @Override … … 110 135 public String[] getUsageExamples(String cmd) { 111 136 if (command.equals(cmd)) { 112 137 return new String[] { 113 "/load_and_zoom?addtags=wikipedia:de=Wei%C3%9Fe_Gasse|maxspeed=5&select=way23071688,way23076176,way23076177," + 114 "&left=13.740&right=13.741&top=51.05&bottom=51.049", 115 "/load_and_zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&select=node413602999&new_layer=true"}; 138 "/load_and_zoom?addtags=wikipedia:de=Wei%C3%9Fe_Gasse|maxspeed=5&select=way23071688,way23076176,way23076177," + 139 "&left=13.740&right=13.741&top=51.05&bottom=51.049", 140 "/load_and_zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&select=node413602999&new_layer=true" 141 }; 116 142 } else { 117 143 return new String[] { 118 "/zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&select=node413602999",119 "/zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&search=highway+OR+railway",120 "/zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&search=" + CURRENT_SELECTION + "&addtags=foo=bar",144 "/zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&select=node413602999", 145 "/zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&search=highway+OR+railway", 146 "/zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&search=" + CURRENT_SELECTION + "&addtags=foo=bar" 121 147 }; 122 148 } 123 149 } … … 185 211 /** 186 212 * deselect objects if parameter addtags given 187 213 */ 188 if (a rgs.containsKey("addtags") && !isKeepingCurrentSelection) {214 if (addTagsParameter.isPresent(args) && !isKeepingCurrentSelection) { 189 215 GuiHelper.executeByMainWorkerInEDT(() -> { 190 216 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 191 217 if (ds == null) // e.g. download failed … … 196 222 197 223 final Collection<OsmPrimitive> forTagAdd = new LinkedHashSet<>(); 198 224 final Bounds bbox = new Bounds(minlat, minlon, maxlat, maxlon); 199 if ( args.containsKey("select") && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) {225 if (selectParameter.isPresent(args) && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) { 200 226 // select objects after downloading, zoom to selection. 201 227 GuiHelper.executeByMainWorkerInEDT(() -> { 202 228 Set<OsmPrimitive> newSel = new LinkedHashSet<>(); … … 225 251 map.relationListDialog.selectRelations(Utils.filteredCollection(newSel, Relation.class)); 226 252 } 227 253 }); 228 } else if ( args.containsKey("search") && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) {254 } else if (selectParameter.isPresent(args) && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) { 229 255 try { 230 final SearchCompiler.Match search = SearchCompiler.compile( args.get("search"));256 final SearchCompiler.Match search = SearchCompiler.compile(selectParameter.read(args)); 231 257 MainApplication.worker.submit(() -> { 232 258 final DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 233 259 final Collection<OsmPrimitive> filteredPrimitives = SubclassFilteredCollection.filter(ds.allPrimitives(), search); … … 245 271 } 246 272 247 273 // This comes before the other changeset tags, so that they can be overridden 248 parseChangesetTags( args);274 parseChangesetTags(changesetTagsParameter, args); 249 275 250 276 // add changeset tags after download if necessary 251 if ( args.containsKey("changeset_comment") || args.containsKey("changeset_source") || args.containsKey("changeset_hashtags")) {277 if (changesetCommentParameter.isPresent(args) || changesetSourceParameter.isPresent(args) || changesetHashtagsParameter.isPresent(args)) { 252 278 MainApplication.worker.submit(() -> { 253 279 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 254 280 if (ds != null) { 255 for (String tag : Arrays.asList("changeset_comment", "changeset_source", "changeset_hashtags")) { 256 if (args.containsKey(tag)) { 257 final String tagKey = tag.substring("changeset_".length()); 258 final String value = args.get(tag); 259 if (!Utils.isStripEmpty(value)) { 260 ds.addChangeSetTag(tagKey, value); 261 } else { 262 ds.addChangeSetTag(tagKey, null); 263 } 264 } 281 if (changesetCommentParameter.isPresent(args)) { 282 ds.addChangeSetTag("comment", changesetCommentParameter.read(args)); 283 } 284 if (changesetSourceParameter.isPresent(args)) { 285 ds.addChangeSetTag("source", changesetSourceParameter.read(args)); 286 } 287 if (changesetHashtagsParameter.isPresent(args)) { 288 ds.addChangeSetTag("hashtags", changesetHashtagsParameter.read(args)); 265 289 } 266 290 } 267 291 }); 268 292 } 269 293 270 294 // add tags to objects 271 if (a rgs.containsKey("addtags")) {295 if (addTagsParameter.isPresent(args)) { 272 296 // needs to run in EDT since forTagAdd is updated in EDT as well 273 297 GuiHelper.executeByMainWorkerInEDT(() -> { 274 298 if (!forTagAdd.isEmpty()) { … … 288 312 } 289 313 } 290 314 291 static void parseChangesetTags( Map<String, String> args) {292 if ( args.containsKey("changeset_tags")) {315 static void parseChangesetTags(RequestParameter<String> changesetTagsParameter, Map<String, String> args) { 316 if (changesetTagsParameter.isPresent(args)) { 293 317 MainApplication.worker.submit(() -> { 294 318 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 295 319 if (ds != null) { 296 AddTagsDialog.parseUrlTagsToKeyValues( args.get("changeset_tags")).forEach(ds::addChangeSetTag);320 AddTagsDialog.parseUrlTagsToKeyValues(changesetTagsParameter.read(args)).forEach(ds::addChangeSetTag); 297 321 } 298 322 }); 299 323 } … … 304 328 return; 305 329 } 306 330 // zoom_mode=(download|selection), defaults to selection 307 if (!"download".equals( args.get("zoom_mode")) && !primitives.isEmpty()) {331 if (!"download".equals(zoomModeParameter.read(args)) && !primitives.isEmpty()) { 308 332 AutoScaleAction.autoScale(AutoScaleMode.SELECTION); 309 333 } else if (MainApplication.isDisplayingMapView()) { 310 334 // make sure this isn't called unless there *is* a MapView … … 330 354 minlon = 0; 331 355 maxlon = 0; 332 356 try { 333 minlat = LatLon.roundToOsmPrecision( Double.parseDouble(args != null ? args.get("bottom") : ""));334 maxlat = LatLon.roundToOsmPrecision( Double.parseDouble(args != null ? args.get("top") : ""));335 minlon = LatLon.roundToOsmPrecision( Double.parseDouble(args != null ? args.get("left") : ""));336 maxlon = LatLon.roundToOsmPrecision( Double.parseDouble(args != null ? args.get("right") : ""));357 minlat = LatLon.roundToOsmPrecision(bottomParameter.read(args)); 358 maxlat = LatLon.roundToOsmPrecision(topParameter.read(args)); 359 minlon = LatLon.roundToOsmPrecision(leftParameter.read(args)); 360 maxlon = LatLon.roundToOsmPrecision(rightParameter.read(args)); 337 361 } catch (NumberFormatException e) { 338 362 throw new RequestHandlerBadRequestException("NumberFormatException ("+e.getMessage()+')', e); 339 363 } … … 352 376 } 353 377 354 378 // Process optional argument 'select' 355 if (args != null && args.containsKey("select")) {379 if (args != null && selectParameter.isPresent(args)) { 356 380 toSelect.clear(); 357 for (String item : args.get("select").split(",", -1)) {381 for (String item : selectParameter.read(args).split(",", -1)) { 358 382 if (!item.isEmpty()) { 359 383 if (CURRENT_SELECTION.equalsIgnoreCase(item)) { 360 384 isKeepingCurrentSelection = true; -
src/org/openstreetmap/josm/io/remotecontrol/handler/LoadDataHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadDataHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadDataHandler.java
a b 1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.io.remotecontrol.handler; 3 3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 6 import java.io.ByteArrayInputStream;7 import java.nio.charset.StandardCharsets;8 9 4 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask; 10 5 import org.openstreetmap.josm.actions.downloadtasks.DownloadParams; 11 6 import org.openstreetmap.josm.data.osm.DataSet; … … 13 8 import org.openstreetmap.josm.io.IllegalDataException; 14 9 import org.openstreetmap.josm.io.OsmReader; 15 10 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 11 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 16 12 import org.openstreetmap.josm.tools.Utils; 17 13 14 import java.io.ByteArrayInputStream; 15 import java.nio.charset.StandardCharsets; 16 import java.util.Arrays; 17 import java.util.Collections; 18 import java.util.List; 19 20 import static org.openstreetmap.josm.tools.I18n.tr; 21 18 22 /** 19 23 * Handler to load data directly from the URL. 20 24 * @since 7636 … … 28 32 */ 29 33 public static final String command = "load_data"; 30 34 35 private final RequestParameter<String> dataParameter = RequestParameter.mandatory("data"); 36 private final RequestParameter<String> mimeTypeParameter = RequestParameter.optional("mime_type", () -> OSM_MIME_TYPE); 37 31 38 /** 32 39 * Holds the data input string 33 40 */ … … 40 47 41 48 @Override 42 49 protected void handleRequest() throws RequestHandlerErrorException { 43 MainApplication.worker.submit(new LoadDataTask(getDownloadParams(), dataSet, args.get("layer_name")));50 MainApplication.worker.submit(new LoadDataTask(getDownloadParams(), dataSet, layerNameParameter.read(args))); 44 51 } 45 52 46 53 @Override 47 public String[] getMandatoryParams() { 48 return new String[]{"data"}; 49 } 50 51 @Override 52 public String[] getOptionalParams() { 53 return new String[] {"new_layer", "mime_type", "layer_name", "layer_locked", "download_policy", "upload_policy"}; 54 public List<RequestParameter<?>> getParameters() { 55 return Arrays.asList( 56 dataParameter, 57 mimeTypeParameter, 58 layerNameParameter, 59 layerLockedParameter, 60 downloadPolicyParameter, 61 uploadPolicyParameter 62 ); 54 63 } 55 64 56 65 @Override … … 60 69 61 70 @Override 62 71 public String[] getUsageExamples() { 63 return new String[]{ 64 "/load_data?layer_name=extra_layer&new_layer=true&data=" + 65 Utils.encodeUrl("<osm version='0.6'><node id='-1' lat='1' lon='2' /></osm>")}; 72 return new String[] { 73 "/load_data?layer_name=extra_layer&new_layer=true&data=" + 74 Utils.encodeUrl("<osm version='0.6'><node id='-1' lat='1' lon='2' /></osm>") 75 }; 66 76 } 67 77 68 78 @Override … … 80 90 @Override 81 91 protected void validateRequest() throws RequestHandlerBadRequestException { 82 92 validateDownloadParams(); 83 this.data = args.get("data");93 this.data = dataParameter.read(args); 84 94 /** 85 95 * Holds the mime type. Currently only OSM_MIME_TYPE is supported 86 96 * But it could be extended to text/csv, application/gpx+xml, ... or even binary encoded data 87 97 */ 88 final String mimeType = Utils.firstNonNull(args.get("mime_type"), OSM_MIME_TYPE);98 final String mimeType = mimeTypeParameter.read(args); 89 99 try { 90 100 if (OSM_MIME_TYPE.equals(mimeType)) { 91 101 final ByteArrayInputStream in = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)); -
src/org/openstreetmap/josm/io/remotecontrol/handler/LoadObjectHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadObjectHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadObjectHandler.java
a b 3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.util.Arrays; 6 7 import java.util.LinkedList; 7 8 import java.util.List; 8 9 import java.util.concurrent.ExecutionException; … … 18 19 import org.openstreetmap.josm.gui.util.GuiHelper; 19 20 import org.openstreetmap.josm.io.remotecontrol.AddTagsDialog; 20 21 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 22 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 21 23 import org.openstreetmap.josm.tools.Logging; 22 24 23 25 /** … … 34 36 35 37 private final List<PrimitiveId> ps = new LinkedList<>(); 36 38 39 private final RequestParameter<String> objectsParameter = RequestParameter.mandatory("objects"); 40 private final RequestParameter<Boolean> relationMembersParameter = RequestParameter.optional("relation_members", Boolean::parseBoolean, () -> false, Boolean.class); 41 private final RequestParameter<Boolean> referrersParameter = RequestParameter.optional("referrers", Boolean::parseBoolean, () -> false, Boolean.class); 42 37 43 @Override 38 public String[] getMandatoryParams() { 39 return new String[]{"objects"}; 40 } 41 42 @Override 43 public String[] getOptionalParams() { 44 return new String[] {"new_layer", "layer_name", "layer_locked", "download_policy", "upload_policy", 45 "addtags", "relation_members", "referrers"}; 44 public List<RequestParameter<?>> getParameters() { 45 return Arrays.asList( 46 objectsParameter, 47 layerNameParameter, 48 layerLockedParameter, 49 downloadPolicyParameter, 50 uploadPolicyParameter, 51 addTagsParameter, 52 relationMembersParameter, 53 referrersParameter 54 ); 46 55 } 47 56 48 57 @Override 49 58 public String getUsage() { 50 return " downloads the specified objects from the server";59 return "Downloads the specified objects from the server"; 51 60 } 52 61 53 62 @Override 54 63 public String[] getUsageExamples() { 55 return new String[] {"/load_object?new_layer=true&objects=w106159509", 64 return new String[]{ 65 "/load_object?new_layer=true&objects=w106159509", 56 66 "/load_object?new_layer=true&objects=r2263653&relation_members=true", 57 67 "/load_object?objects=n100000&referrers=false" 58 68 }; … … 64 74 Logging.info("RemoteControl: download forbidden by preferences"); 65 75 } 66 76 if (!ps.isEmpty()) { 67 final boolean newLayer = getDownloadParams().isNewLayer();68 final boolean relationMembers = Boolean.parseBoolean(args.get("relation_members"));69 final boolean referrers = Boolean.parseBoolean(args.get("referrers"));77 final boolean newLayer = newLayerParameter.read(args); 78 final boolean relationMembers = relationMembersParameter.read(args); 79 final boolean referrers = referrersParameter.read(args); 70 80 final DownloadPrimitivesWithReferrersTask task = new DownloadPrimitivesWithReferrersTask( 71 newLayer, ps, referrers, relationMembers, args.get("layer_name"), null);81 newLayer, ps, referrers, relationMembers, layerNameParameter.read(args), null); 72 82 try { 73 83 MainApplication.worker.submit(task).get(OSM_DOWNLOAD_TIMEOUT.get(), TimeUnit.SECONDS); 74 84 } catch (InterruptedException | ExecutionException | TimeoutException e) { … … 100 110 protected void validateRequest() throws RequestHandlerBadRequestException { 101 111 validateDownloadParams(); 102 112 ps.clear(); 103 for (String i : splitArg("objects", SPLITTER_COMMA)) {113 for (String i : SPLITTER_COMMA.split(objectsParameter.read(args), -1)) { 104 114 if (!i.isEmpty()) { 105 115 try { 106 116 ps.add(SimplePrimitiveId.fromString(i)); -
src/org/openstreetmap/josm/io/remotecontrol/handler/OpenApiHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/OpenApiHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/OpenApiHandler.java
a b 5 5 import static org.openstreetmap.josm.tools.I18n.tr; 6 6 7 7 import java.io.StringWriter; 8 import java.util. Arrays;9 import java.util. stream.Stream;8 import java.util.Collections; 9 import java.util.List; 10 10 11 11 import javax.json.Json; 12 12 import javax.json.JsonArrayBuilder; … … 15 15 import org.openstreetmap.josm.data.preferences.JosmUrls; 16 16 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 17 17 import org.openstreetmap.josm.io.remotecontrol.RemoteControl; 18 import org.openstreetmap.josm.io.remotecontrol.RemoteControlHttpServer; 18 19 import org.openstreetmap.josm.io.remotecontrol.RequestProcessor; 20 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 19 21 import org.openstreetmap.josm.tools.Utils; 20 22 21 23 /** … … 28 30 */ 29 31 public static final String command = "openapi.json"; 30 32 33 /** 34 * OpenAPI description. 35 */ 36 public static final String DESCRIPTION = "The Remote control API for JOSM.\n\nAllows using GET HTTP requests with query parameters to invoke actions in JOSM."; 37 31 38 @Override 32 39 protected void handleRequest() { 33 40 JsonObjectBuilder openapi = getOpenApi(); … … 39 46 40 47 private JsonObjectBuilder getOpenApi() { 41 48 return Json.createObjectBuilder() 42 .add("openapi", "3.0.0") 43 .add("info", Json.createObjectBuilder() 44 .add("title", RequestProcessor.JOSM_REMOTE_CONTROL) 45 .add("version", RemoteControl.getVersion()) 46 .add("contact", Json.createObjectBuilder() 47 .add("name", "JOSM") 48 .add("url", JosmUrls.getInstance().getJOSMWebsite()))) 49 .add("servers", Json.createArrayBuilder() 50 .add(Json.createObjectBuilder().add("url", "http://localhost:8111/"))) 51 .add("paths", getHandlers()); 49 .add("openapi", "3.0.3") 50 .add("info", getInfo()) 51 .add("servers", getServers()) 52 .add("paths", getHandlers()); 53 } 54 55 private JsonObjectBuilder getInfo() { 56 return Json.createObjectBuilder() 57 .add("title", RequestProcessor.JOSM_REMOTE_CONTROL) 58 .add("description", DESCRIPTION) 59 .add("version", RemoteControl.getVersion()) 60 .add("contact", getContact()); 61 } 62 63 private JsonObjectBuilder getContact() { 64 return Json.createObjectBuilder() 65 .add("name", "JOSM") 66 .add("url", JosmUrls.getInstance().getJOSMWebsite()); 67 } 68 69 private JsonArrayBuilder getServers() { 70 return Json.createArrayBuilder() 71 .add(Json.createObjectBuilder().add("url", String.format("http://localhost:%s/", RemoteControlHttpServer.PORT.get()))); 52 72 } 53 73 54 74 private JsonObjectBuilder getHandlers() { … … 59 79 } 60 80 61 81 private JsonObjectBuilder getHandler(RequestHandler handler) { 82 return Json.createObjectBuilder() 83 .add("get", getOperation(handler)); 84 } 85 86 private JsonObjectBuilder getOperation(RequestHandler handler) { 87 return Json.createObjectBuilder() 88 .add("summary", getSummary(handler)) 89 .add("description", getDescription(handler)) 90 .add("operationId", handler.getCommand()) 91 .add("parameters", getParameters(handler)) 92 .add("responses", operationResponses()); 93 } 94 95 private JsonObjectBuilder operationResponses() { 96 return Json.createObjectBuilder() 97 .add("200", Json.createObjectBuilder().add("description", "Successful operation")) 98 .add("400", Json.createObjectBuilder().add("description", "Missing required parameters or bad request format")) 99 .add("403", Json.createObjectBuilder().add("description", "Action is not permitted")) 100 .add("500", Json.createObjectBuilder().add("description", "Internal server error")) 101 .add("502", Json.createObjectBuilder().add("description", "Bad gateway (upstream)")); 102 } 103 104 private JsonArrayBuilder getParameters(RequestHandler handler) { 62 105 JsonArrayBuilder parameters = Json.createArrayBuilder(); 63 Stream.concat( 64 Arrays.stream(handler.getMandatoryParams()),65 Arrays.stream(handler.getOptionalParams())66 ).distinct().map(param -> Json.createObjectBuilder()67 .add("name", param )106 107 handler.getParameters() 108 .stream() 109 .map(param -> Json.createObjectBuilder() 110 .add("name", param.getName()) 68 111 .add("in", "query") 69 .add("required", Arrays.asList(handler.getMandatoryParams()).contains(param))70 .add("schema", Json.createObjectBuilder().add("type", "string")) // TODO fix type71 ).forEach(parameters::add);72 return Json.createObjectBuilder().add("get", Json.createObjectBuilder()73 .add("description", getDescription(handler)) 74 .add("operationId", handler.getCommand())75 .add("parameters", parameters)76 .add("responses", Json.createObjectBuilder() 77 .add("200", Json.createObjectBuilder().add("description", "successful operation")))78 );112 .add("required", param.isMandatory()) 113 .add("schema", param.getOpenapiType()) 114 ) 115 .forEach(parameters::add); 116 117 return parameters; 118 } 119 120 private String getSummary(RequestHandler handler) { 121 return Utils.firstNonNull(handler.getUsage(), String.format("Command %s", handler.getCommand())); 79 122 } 80 123 81 124 private String getDescription(RequestHandler handler) { … … 90 133 91 134 @Override 92 135 public String[] getUsageExamples() { 93 return new String[]{"https://petstore.swagger.io/?url=http://localhost:8111/openapi.json", "https://swagger.io/specification/"}; 136 return new String[]{ 137 "https://petstore.swagger.io/?url=http://localhost:8111/openapi.json", 138 "https://swagger.io/specification/" 139 }; 94 140 } 95 141 96 142 @Override … … 104 150 } 105 151 106 152 @Override 107 public String[] getMandatoryParams() {108 return new String[0];153 public List<RequestParameter<?>> getParameters() { 154 return Collections.emptyList(); 109 155 } 110 156 111 157 @Override -
src/org/openstreetmap/josm/io/remotecontrol/handler/OpenFileHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/OpenFileHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/OpenFileHandler.java
a b 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 6 import java.io.File; 7 import java.util. Arrays;7 import java.util.Collections; 8 8 import java.util.EnumSet; 9 import java.util.List; 9 10 10 11 import org.openstreetmap.josm.actions.OpenFileAction; 11 12 import org.openstreetmap.josm.gui.io.importexport.Options; 12 13 import org.openstreetmap.josm.gui.util.GuiHelper; 13 14 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 15 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 14 16 15 17 /** 16 18 * Opens a local file … … 22 24 */ 23 25 public static final String command = "open_file"; 24 26 27 private final RequestParameter<File> filenameParameter = RequestParameter.mandatory("filename", File::new, File.class); 28 25 29 @Override 26 public String[] getMandatoryParams() {27 return new String[]{"filename"};30 public List<RequestParameter<?>> getParameters() { 31 return Collections.singletonList(filenameParameter); 28 32 } 29 33 30 34 @Override 31 35 public String getUsage() { 32 return " opens a local file in JOSM";36 return "Opens a local file in JOSM"; 33 37 } 34 38 35 39 @Override 36 40 public String[] getUsageExamples() { 37 return new String[] {"/open_file?filename=/tmp/test.osm"}; 41 return new String[]{ 42 "/open_file?filename=/tmp/test.osm" 43 }; 38 44 } 39 45 40 46 @Override … … 49 55 options.add(Options.ALLOW_WEB_RESOURCES); 50 56 } 51 57 GuiHelper.runInEDT(() -> 52 OpenFileAction.openFiles( Arrays.asList(new File(args.get("filename"))), options.toArray(new Options[0])));58 OpenFileAction.openFiles(Collections.singletonList(filenameParameter.read(args)), options.toArray(new Options[0]))); 53 59 } 54 60 55 61 @Override -
src/org/openstreetmap/josm/io/remotecontrol/handler/RequestHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/RequestHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/RequestHandler.java
a b 6 6 import java.net.URI; 7 7 import java.net.URISyntaxException; 8 8 import java.text.MessageFormat; 9 import java.util. Collections;9 import java.util.Arrays; 10 10 import java.util.HashMap; 11 11 import java.util.HashSet; 12 12 import java.util.LinkedList; 13 13 import java.util.List; 14 14 import java.util.Map; 15 15 import java.util.Set; 16 import java.util.function.Function;17 import java.util.function.Supplier;18 16 import java.util.regex.Pattern; 19 17 import java.util.stream.Collectors; 18 import java.util.stream.Stream; 20 19 import javax.swing.JLabel; 21 20 import javax.swing.JOptionPane; 22 21 … … 28 27 import org.openstreetmap.josm.gui.MainApplication; 29 28 import org.openstreetmap.josm.io.OsmApiException; 30 29 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 30 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 31 31 import org.openstreetmap.josm.spi.preferences.Config; 32 32 import org.openstreetmap.josm.tools.Logging; 33 33 import org.openstreetmap.josm.tools.Pair; … … 53 53 /** past confirmations */ 54 54 protected static final PermissionCache PERMISSIONS = new PermissionCache(); 55 55 56 protected final RequestParameter<String> layerNameParameter = RequestParameter.optional("layer_name"); 57 protected final RequestParameter<Boolean> newLayerParameter = RequestParameter.optional("new_layer", Boolean::parseBoolean, LOAD_IN_NEW_LAYER::get, Boolean.class); 58 protected final RequestParameter<Boolean> layerLockedParameter = RequestParameter.optional("layer_locked", Boolean::parseBoolean, () -> false, Boolean.class); 59 protected final RequestParameter<DownloadPolicy> downloadPolicyParameter = RequestParameter.optional("download_policy", DownloadPolicy::of, () -> DownloadPolicy.NORMAL, DownloadPolicy.class); 60 protected final RequestParameter<UploadPolicy> uploadPolicyParameter = RequestParameter.optional("upload_policy", UploadPolicy::of, () -> UploadPolicy.NORMAL, UploadPolicy.class); 61 protected final RequestParameter<String> addTagsParameter = RequestParameter.optional("addtags"); 62 56 63 /** The GET request arguments */ 57 64 protected Map<String, String> args; 58 65 … … 128 135 */ 129 136 public abstract PermissionPrefWithDefault getPermissionPref(); 130 137 138 /** 139 * Returns the request parameters. Both used in runtime and for documentation. 140 * @since xxx 141 * @return the request parameters 142 */ 143 public List<RequestParameter<?>> getParameters() { 144 // Default implementation for backwards compatibility 145 return Stream.concat( 146 Arrays.stream(getMandatoryParams()).map(RequestParameter::mandatory), 147 Arrays.stream(getOptionalParams()).map(RequestParameter::optional) 148 ).collect(Collectors.toList()); 149 } 150 131 151 /** 132 152 * Returns the mandatory parameters. Both used to enforce their presence at runtime and for documentation. 153 * @deprecated implement `getParameters` instead. 133 154 * @return the mandatory parameters 134 155 */ 135 public abstract String[] getMandatoryParams(); 156 @Deprecated 157 public String[] getMandatoryParams() { 158 return new String[0]; 159 } 136 160 137 161 /** 138 162 * Returns the optional parameters. Both used to enforce their presence at runtime and for documentation. 163 * @deprecated implement `getParameters` instead. 139 164 * @return the optional parameters 140 165 */ 166 @Deprecated 141 167 public String[] getOptionalParams() { 142 168 return new String[0]; 143 169 } … … 247 273 this.args = getRequestParameter(new URI(this.request)); 248 274 } 249 275 250 protected final String[] splitArg(String arg, Pattern splitter) {251 return splitter.split(args != null ? args.get(arg) : "", -1);252 }253 254 276 /** 255 277 * Returns the request parameters. 256 278 * @param uri URI as string … … 271 293 } 272 294 273 295 void checkMandatoryParams() throws RequestHandlerBadRequestException { 274 String[] mandatory = getMandatoryParams(); 275 String[] optional = getOptionalParams(); 296 List<RequestParameter<?>> mandatory = getParameters().stream().filter(RequestParameter::isMandatory).collect(Collectors.toList()); 276 297 List<String> missingKeys = new LinkedList<>(); 277 298 boolean error = false; 278 if ( mandatory != null &&args != null) {279 for ( String key: mandatory) {280 String value = args.get( key);281 if (Utils.is Empty(value)) {299 if (args != null) { 300 for (RequestParameter<?> parameter : mandatory) { 301 String value = args.get(parameter.getName()); 302 if (Utils.isStripEmpty(value)) { 282 303 error = true; 283 Logging.warn('\'' + myCommand + "' remote control request must have '" + key+ "' parameter");284 missingKeys.add( key);304 Logging.warn('\'' + myCommand + "' remote control request must have '" + parameter.getName() + "' parameter"); 305 missingKeys.add(parameter.getName()); 285 306 } 286 307 } 287 308 } 288 Set<String> knownParams = new HashSet<>(); 289 if (mandatory != null) 290 Collections.addAll(knownParams, mandatory); 291 if (optional != null) 292 Collections.addAll(knownParams, optional); 309 Set<String> knownParams = getParameters().stream().map(RequestParameter::getName).collect(Collectors.toSet()); 293 310 if (args != null) { 294 311 for (String par: args.keySet()) { 295 312 if (!knownParams.contains(par)) { … … 340 357 return contentType; 341 358 } 342 359 343 private <T> T get(String key, Function<String, T> parser, Supplier<T> defaultSupplier) {344 String val = args.get(key);345 return !Utils.isEmpty(val) ? parser.apply(val) : defaultSupplier.get();346 }347 348 private boolean get(String key) {349 return get(key, Boolean::parseBoolean, () -> Boolean.FALSE);350 }351 352 private boolean isLoadInNewLayer() {353 return get("new_layer", Boolean::parseBoolean, LOAD_IN_NEW_LAYER::get);354 }355 356 360 protected DownloadParams getDownloadParams() { 357 361 DownloadParams result = new DownloadParams(); 358 362 if (args != null) { 359 363 result = result 360 .withNewLayer( isLoadInNewLayer())361 .withLayerName( args.get("layer_name"))362 .withLocked( get("layer_locked"))363 .withDownloadPolicy( get("download_policy", DownloadPolicy::of, () -> DownloadPolicy.NORMAL))364 .withUploadPolicy( get("upload_policy", UploadPolicy::of, () -> UploadPolicy.NORMAL));364 .withNewLayer(newLayerParameter.read(args)) 365 .withLayerName(layerNameParameter.read(args)) 366 .withLocked(layerLockedParameter.read(args)) 367 .withDownloadPolicy(downloadPolicyParameter.read(args)) 368 .withUploadPolicy(uploadPolicyParameter.read(args)); 365 369 } 366 370 return result; 367 371 } … … 501 505 */ 502 506 public abstract static class RawURLParseRequestHandler extends RequestHandler { 503 507 @Override 504 protected void parseArgs() throws URISyntaxException{508 protected void parseArgs() { 505 509 Map<String, String> args = new HashMap<>(); 506 510 if (request.indexOf('?') != -1) { 507 511 String query = request.substring(request.indexOf('?') + 1); -
src/org/openstreetmap/josm/io/remotecontrol/handler/VersionHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/VersionHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/VersionHandler.java
a b 5 5 6 6 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 7 7 import org.openstreetmap.josm.io.remotecontrol.RequestProcessor; 8 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 9 10 import java.util.Arrays; 11 import java.util.Collections; 12 import java.util.List; 8 13 9 14 /** 10 15 * Handler for version request. … … 16 21 */ 17 22 public static final String command = "version"; 18 23 24 private final RequestParameter<String> jsonpParameter = RequestParameter.optional("jsonp"); 25 19 26 @Override 20 27 protected void handleRequest() throws RequestHandlerErrorException, 21 28 RequestHandlerBadRequestException { 22 29 content = RequestProcessor.PROTOCOLVERSION; 23 30 contentType = "application/json"; 24 if ( args.containsKey("jsonp")) {25 content = args.get("jsonp") + " && " + args.get("jsonp") + '(' + content + ')';31 if (jsonpParameter.isPresent(args)) { 32 content = jsonpParameter.read(args) + " && " + jsonpParameter.read(args) + '(' + content + ')'; 26 33 } 27 34 } 28 35 … … 37 44 } 38 45 39 46 @Override 40 public String[] getMandatoryParams() { 41 return new String[0]; 42 } 43 44 @Override 45 public String[] getOptionalParams() { 46 return new String[]{"jsonp"}; 47 public List<RequestParameter<?>> getParameters() { 48 return Collections.singletonList( 49 jsonpParameter 50 ); 47 51 } 48 52 49 53 @Override … … 53 57 54 58 @Override 55 59 public String getUsage() { 56 return " returns the current protocol version of the installed JOSM RemoteControl";60 return "Returns the current protocol version of the installed JOSM RemoteControl"; 57 61 } 58 62 59 63 @Override 60 64 public String[] getUsageExamples() { 61 return new String[] {"/version", "/version?jsonp=test"}; 65 return new String[]{ 66 "/version", 67 "/version?jsonp=test" 68 }; 62 69 } 63 70 } -
new file src/org/openstreetmap/josm/io/remotecontrol/parameter/RequestParameter.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/parameter/RequestParameter.java b/src/org/openstreetmap/josm/io/remotecontrol/parameter/RequestParameter.java new file mode 100644
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.io.remotecontrol.parameter; 3 4 import org.openstreetmap.josm.tools.Utils; 5 6 import javax.json.Json; 7 import javax.json.JsonArrayBuilder; 8 import javax.json.JsonObject; 9 import javax.json.JsonObjectBuilder; 10 import java.util.Arrays; 11 import java.util.List; 12 import java.util.Map; 13 import java.util.Objects; 14 import java.util.function.Function; 15 import java.util.function.Supplier; 16 17 /** 18 * Logic for parsing a mandatory or optional request parameter with a name, a default value and an OpenAPI type. 19 * @param <T> The parameter type -- at this time, it is recommended to stay with arrays, {@link String}, 20 * {@link Boolean}, {@link Number}, and {@link Enum} classes. 21 * @since xxx 22 */ 23 public final class RequestParameter<T> { 24 private static final String TYPE = "type"; 25 26 private final String name; 27 private final Function<String, T> parser; 28 private final boolean mandatory; 29 private final Supplier<T> defaultValue; 30 private final Class<T> openApiType; 31 32 private RequestParameter(String name, Function<String, T> parser, boolean mandatory, Supplier<T> defaultValue, Class<T> openApiType) { 33 this.name = Objects.requireNonNull(name, "name"); 34 this.parser = Objects.requireNonNull(parser, "parser"); 35 this.mandatory = mandatory; 36 this.defaultValue = defaultValue; 37 this.openApiType = openApiType; 38 } 39 40 public static <T> RequestParameter<T> mandatory(String name, Function<String, T> parser, Class<T> openapiType) { 41 return new RequestParameter<>(name, parser, true, () -> null, openapiType); 42 } 43 44 public static RequestParameter<String> mandatory(String name) { 45 return new RequestParameter<>(name, Function.identity(), true, () -> null, String.class); 46 } 47 48 public static <T> RequestParameter<T> optional(String name, Function<String, T> parser, Class<T> openapiType) { 49 return new RequestParameter<>(name, parser, false, () -> null, openapiType); 50 } 51 52 public static <T> RequestParameter<T> optional(String name, Function<String, T> parser, Supplier<T> defaultValue, Class<T> openapiType) { 53 return new RequestParameter<>(name, parser, false, defaultValue, openapiType); 54 } 55 56 public static RequestParameter<String> optional(String name) { 57 return new RequestParameter<>(name, Function.identity(), false, () -> null, String.class); 58 } 59 60 public static RequestParameter<String> optional(String name, Supplier<String> defaultValue) { 61 return new RequestParameter<>(name, Function.identity(), false, defaultValue, String.class); 62 } 63 64 public String getName() { 65 return name; 66 } 67 68 public boolean isMandatory() { 69 return mandatory; 70 } 71 72 public boolean isOptional() { 73 return !mandatory; 74 } 75 76 /** 77 * Is the parameter present in the request 78 * @param arguments the request parameters 79 */ 80 public boolean isPresent(Map<String, String> arguments) { 81 return arguments.containsKey(name); 82 } 83 84 /** 85 * Read the parameter from the request 86 * @param arguments the request parameters 87 * @return The parameter, or the default value if the parameter is missing. 88 * @throws IllegalArgumentException when a mandatory parameter is missing. 89 */ 90 public T read(Map<String, String> arguments) { 91 String value = arguments.get(name); 92 if (Utils.isStripEmpty(value)) { 93 if (mandatory) { 94 throw new IllegalArgumentException("Empty value supplied for mandatory parameter"); 95 } 96 return defaultValue.get(); 97 } 98 99 return parser.apply(value); 100 } 101 102 /** 103 * For use in the OpenAPI documentation of the JOSM API. 104 * @see <a href="https://swagger.io/docs/specification/data-models/data-types/">OpenAPI data types</a> 105 */ 106 public JsonObject getOpenapiType() { 107 JsonObjectBuilder builder = Json.createObjectBuilder(); 108 addDataType(builder, this.openApiType); 109 return builder.build(); 110 } 111 112 private JsonObjectBuilder addDataType(JsonObjectBuilder builder, Class<?> clazz) { 113 if (clazz.isArray() || List.class.isAssignableFrom(clazz)) { 114 builder.add(TYPE, "array"); 115 if (clazz.isArray()) { 116 builder.add("items", addDataType(Json.createObjectBuilder(), clazz.getComponentType())); 117 } 118 } else if (clazz == Integer.class) { 119 builder.add(TYPE, "integer"); 120 } else if (Number.class.isAssignableFrom(clazz)) { 121 builder.add(TYPE, "number"); 122 } else if (clazz == Boolean.class) { 123 builder.add(TYPE, "boolean"); 124 } else if (clazz == Map.class) { 125 // This should eventually do a recursive call 126 builder.add(TYPE, "object"); 127 } else { 128 builder.add(TYPE, "string"); 129 if (clazz.isEnum()) { 130 JsonArrayBuilder array = Json.createArrayBuilder(); 131 Arrays.stream(clazz.getEnumConstants()).map(Object::toString).forEach(array::add); 132 builder.add("enum", array); 133 } 134 } 135 return builder; 136 } 137 } -
src/org/openstreetmap/josm/io/remotecontrol/RemoteControlHttpServer.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/RemoteControlHttpServer.java b/src/org/openstreetmap/josm/io/remotecontrol/RemoteControlHttpServer.java
a b 8 8 import java.net.Socket; 9 9 import java.net.SocketException; 10 10 11 import org.openstreetmap.josm. spi.preferences.Config;11 import org.openstreetmap.josm.data.preferences.IntegerProperty; 12 12 import org.openstreetmap.josm.tools.Logging; 13 13 14 14 /** … … 19 19 */ 20 20 public class RemoteControlHttpServer extends Thread { 21 21 22 /** 23 * preference to define remote control port 24 */ 25 public static final IntegerProperty PORT = new IntegerProperty("remote.control.port", 8111); 26 22 27 /** The server socket */ 23 28 private final ServerSocket server; 24 29 … … 32 37 */ 33 38 public static void restartRemoteControlHttpServer() { 34 39 stopRemoteControlHttpServer(); 35 int port = Config.getPref().getInt("remote.control.port", 8111);40 int port = PORT.get(); 36 41 try { 37 42 instance4 = new RemoteControlHttpServer(port, false); 38 43 instance4.start(); -
src/org/openstreetmap/josm/io/remotecontrol/RequestProcessor.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/remotecontrol/RequestProcessor.java b/src/org/openstreetmap/josm/io/remotecontrol/RequestProcessor.java
a b 13 13 import java.util.Collection; 14 14 import java.util.Date; 15 15 import java.util.HashMap; 16 import java.util.List; 16 17 import java.util.Locale; 17 18 import java.util.Map; 18 19 import java.util.Map.Entry; … … 22 23 import java.util.TreeMap; 23 24 import java.util.regex.Matcher; 24 25 import java.util.regex.Pattern; 26 import java.util.stream.Collectors; 25 27 import java.util.stream.Stream; 26 28 27 29 import javax.json.Json; … … 44 46 import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerForbiddenException; 45 47 import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerOsmApiException; 46 48 import org.openstreetmap.josm.io.remotecontrol.handler.VersionHandler; 49 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 47 50 import org.openstreetmap.josm.tools.Logging; 48 51 import org.openstreetmap.josm.tools.Utils; 49 52 … … 450 453 StringBuilder usage = new StringBuilder(1024); 451 454 for (Entry<String, Class<? extends RequestHandler>> handler : handlers.entrySet()) { 452 455 RequestHandler sample = handler.getValue().getConstructor().newInstance(); 453 String[] mandatory = sample.getMandatoryParams();454 String[] optional = sample.getOptionalParams();456 List<String> mandatory = sample.getParameters().stream().filter(RequestParameter::isMandatory).map(RequestParameter::getName).sorted().collect(Collectors.toList()); 457 List<String> optional = sample.getParameters().stream().filter(RequestParameter::isOptional).map(RequestParameter::getName).sorted().collect(Collectors.toList()); 455 458 String[] examples = sample.getUsageExamples(handler.getKey().substring(1)); 456 459 usage.append("<li>") 457 460 .append(handler.getKey()); 458 461 if (!Utils.isEmpty(sample.getUsage())) { 459 462 usage.append(" — <i>").append(sample.getUsage()).append("</i>"); 460 463 } 461 if ( mandatory != null && mandatory.length > 0) {464 if (!mandatory.isEmpty()) { 462 465 usage.append("<br/>mandatory parameters: ").append(String.join(", ", mandatory)); 463 466 } 464 if ( optional != null && optional.length > 0) {467 if (!optional.isEmpty()) { 465 468 usage.append("<br/>optional parameters: ").append(String.join(", ", optional)); 466 469 } 467 470 if (examples != null && examples.length > 0) { 468 471 usage.append("<br/>examples: "); 469 472 for (String ex: examples) { 470 usage.append("<br/> <a href=\"http://localhost: 8111").append(ex).append("\">").append(ex).append("</a>");473 usage.append("<br/> <a href=\"http://localhost:" + RemoteControlHttpServer.PORT.get()).append(ex).append("\">").append(ex).append("</a>"); 471 474 } 472 475 } 473 476 usage.append("</li>"); -
test/unit/org/openstreetmap/josm/io/remotecontrol/RemoteControlTest.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/test/unit/org/openstreetmap/josm/io/remotecontrol/RemoteControlTest.java b/test/unit/org/openstreetmap/josm/io/remotecontrol/RemoteControlTest.java
a b 41 41 @BeforeEach 42 42 public void setUp() throws GeneralSecurityException { 43 43 RemoteControl.start(); 44 httpBase = "http://127.0.0.1:"+Config.getPref().getInt("remote.control.port", 8111);44 httpBase = String.format("http://127.0.0.1:%s", RemoteControlHttpServer.PORT.get()); 45 45 } 46 46 47 47 /**
