Ticket #22034: remote-control.patch
| File remote-control.patch, 58.6 KB (added by , 4 years ago) |
|---|
-
src/org/openstreetmap/josm/io/remotecontrol/RemoteControlHttpServer.java
8 8 import java.net.Socket; 9 9 import java.net.SocketException; 10 10 11 import org.openstreetmap.josm.data.preferences.IntegerProperty; 11 12 import org.openstreetmap.josm.spi.preferences.Config; 12 13 import org.openstreetmap.josm.tools.Logging; 13 14 … … 19 20 */ 20 21 public class RemoteControlHttpServer extends Thread { 21 22 23 /** 24 * preference to define remote control port 25 */ 26 public static final IntegerProperty PORT = new IntegerProperty("remote.control.port", 8111); 27 22 28 /** The server socket */ 23 29 private final ServerSocket server; 24 30 … … 32 38 */ 33 39 public static void restartRemoteControlHttpServer() { 34 40 stopRemoteControlHttpServer(); 35 int port = Config.getPref().getInt("remote.control.port", 8111);41 int port = PORT.get(); 36 42 try { 37 43 instance4 = new RemoteControlHttpServer(port, false); 38 44 instance4.start(); -
src/org/openstreetmap/josm/io/remotecontrol/RequestProcessor.java
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>"); -
src/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandler.java
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, "number"); 39 private final RequestParameter<Double> lonParameter = RequestParameter.mandatory("lon", Double::parseDouble, "number"); 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"}; 50 public List<RequestParameter<?>> getParameters() { 51 return Arrays.asList( 52 latParameter, 53 lonParameter, 54 addTagsParameter 55 ); 46 56 } 47 57 48 58 @Override 49 public String[] getOptionalParams() {50 return new String[] {"addtags"};51 }52 53 @Override54 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
29 29 import org.openstreetmap.josm.gui.util.GuiHelper; 30 30 import org.openstreetmap.josm.io.remotecontrol.AddTagsDialog; 31 31 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 32 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 32 33 import org.openstreetmap.josm.spi.preferences.Config; 33 34 34 35 /** … … 41 42 */ 42 43 public static final String command = "add_way"; 43 44 45 private final RequestParameter<String> wayParameter = RequestParameter.mandatory("way"); 46 44 47 private final List<LatLon> allCoordinates = new ArrayList<>(); 45 48 46 49 /** … … 49 52 private Map<LatLon, Node> addedNodes; 50 53 51 54 @Override 52 public String[] getMandatoryParams() { 53 return new String[]{"way"}; 55 public List<RequestParameter<?>> getParameters() { 56 return Arrays.asList( 57 wayParameter, 58 addTagsParameter 59 ); 54 60 } 55 61 56 62 @Override 57 public String[] getOptionalParams() {58 return new String[] {"addtags"};59 }60 61 @Override62 63 public String getUsage() { 63 return " adds a way (given by a semicolon separated sequence of lat,lon pairs) to the current dataset";64 return "Adds a way (given by a semicolon separated sequence of lat,lon pairs) to the current dataset"; 64 65 } 65 66 66 67 @Override … … 91 92 @Override 92 93 protected void validateRequest() throws RequestHandlerBadRequestException { 93 94 allCoordinates.clear(); 94 for (String coordinatesString : splitArg("way", SPLITTER_SEMIC)) {95 for (String coordinatesString : SPLITTER_SEMIC.split(wayParameter.read(args), -1)) { 95 96 String[] coordinates = coordinatesString.split(",\\s*", 2); 96 97 if (coordinates.length < 2) { 97 98 throw new RequestHandlerBadRequestException( -
src/org/openstreetmap/josm/io/remotecontrol/handler/FeaturesHandler.java
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]; 84 public List<RequestParameter<?>> getParameters() { 85 return Arrays.asList( 86 jsonpParameter, 87 queryParameter 88 ); 80 89 } 81 90 82 91 @Override 83 public String[] getOptionalParams() {84 return new String[]{"jsonp", "q"};85 }86 87 @Override88 92 protected void validateRequest() throws RequestHandlerBadRequestException { 89 93 // Nothing to do 90 94 } … … 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
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 }50 public List<RequestParameter<?>> getParameters() { 51 Map<String, String> struct = StructUtils.serializeStruct(new ImageryPreferenceEntry(), ImageryPreferenceEntry.class, 52 StructUtils.SerializeOptions.INCLUDE_NULL, StructUtils.SerializeOptions.INCLUDE_DEFAULT); 46 53 47 @Override 48 public String[] getOptionalParams() { 49 Set<String> params = new LinkedHashSet<>(); 50 params.add("url"); 51 params.add("id"); 52 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]); 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://a.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
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"}; 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 ); 62 77 } 63 78 64 79 @Override 65 public String[] getOptionalParams() {66 return new String[] {"new_layer", "layer_name", "layer_locked", "download_policy", "upload_policy", "changeset_tags"};67 }68 69 @Override70 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
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, "number"); 69 private final RequestParameter<Double> topParameter = RequestParameter.mandatory("top", Double::parseDouble, "number"); 70 private final RequestParameter<Double> leftParameter = RequestParameter.mandatory("left", Double::parseDouble, "number"); 71 private final RequestParameter<Double> rightParameter = RequestParameter.mandatory("right", Double::parseDouble, "number"); 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"}; 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 ); 90 122 } 91 123 92 124 @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"};97 }98 99 @Override100 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)); 265 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)); 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
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"}; 54 public List<RequestParameter<?>> getParameters() { 55 return Arrays.asList( 56 dataParameter, 57 mimeTypeParameter, 58 layerNameParameter, 59 layerLockedParameter, 60 downloadPolicyParameter, 61 uploadPolicyParameter 62 ); 49 63 } 50 64 51 65 @Override 52 public String[] getOptionalParams() {53 return new String[] {"new_layer", "mime_type", "layer_name", "layer_locked", "download_policy", "upload_policy"};54 }55 56 @Override57 66 public String getUsage() { 58 67 return "Reads data encoded directly in the URL and adds it to the current data set"; 59 68 } … … 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
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 37 @Override 38 public String[] getMandatoryParams() { 39 return new String[]{"objects"}; 40 } 39 private final RequestParameter<String> objectsParameter = RequestParameter.mandatory("objects"); 40 private final RequestParameter<Boolean> relationMembersParameter = RequestParameter.optional("relation_members", Boolean::parseBoolean, () -> false, "boolean"); 41 private final RequestParameter<Boolean> referrersParameter = RequestParameter.optional("referrers", Boolean::parseBoolean, () -> false, "boolean"); 41 42 42 43 @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
6 6 7 7 import java.io.StringWriter; 8 8 import java.util.Arrays; 9 import java.util.stream.Stream; 9 import java.util.Collections; 10 import java.util.List; 10 11 11 12 import javax.json.Json; 12 13 import javax.json.JsonArrayBuilder; … … 15 16 import org.openstreetmap.josm.data.preferences.JosmUrls; 16 17 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 17 18 import org.openstreetmap.josm.io.remotecontrol.RemoteControl; 19 import org.openstreetmap.josm.io.remotecontrol.RemoteControlHttpServer; 18 20 import org.openstreetmap.josm.io.remotecontrol.RequestProcessor; 21 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 19 22 import org.openstreetmap.josm.tools.Utils; 20 23 21 24 /** … … 39 42 40 43 private JsonObjectBuilder getOpenApi() { 41 44 return Json.createObjectBuilder() 42 .add("openapi", "3.0. 0")45 .add("openapi", "3.0.3") 43 46 .add("info", Json.createObjectBuilder() 44 47 .add("title", RequestProcessor.JOSM_REMOTE_CONTROL) 45 48 .add("version", RemoteControl.getVersion()) … … 47 50 .add("name", "JOSM") 48 51 .add("url", JosmUrls.getInstance().getJOSMWebsite()))) 49 52 .add("servers", Json.createArrayBuilder() 50 .add(Json.createObjectBuilder().add("url", "http://localhost:8111/")))53 .add(Json.createObjectBuilder().add("url", String.format("http://localhost:%s/", RemoteControlHttpServer.PORT.get())))) 51 54 .add("paths", getHandlers()); 52 55 } 53 56 … … 60 63 61 64 private JsonObjectBuilder getHandler(RequestHandler handler) { 62 65 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)68 .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);66 handler.getParameters() 67 .stream() 68 .map(param -> Json.createObjectBuilder() 69 .add("name", param.getName()) 70 .add("in", "query") 71 .add("required", param.isMandatory()) 72 .add("schema", Json.createObjectBuilder().add("type", param.getOpenapiType())) 73 ) 74 .forEach(parameters::add); 72 75 return Json.createObjectBuilder().add("get", Json.createObjectBuilder() 73 76 .add("description", getDescription(handler)) 74 77 .add("operationId", handler.getCommand()) 75 78 .add("parameters", parameters) 76 79 .add("responses", Json.createObjectBuilder() 77 .add("200", Json.createObjectBuilder().add("description", "successful operation"))) 80 .add("200", Json.createObjectBuilder().add("description", "Successful operation")) 81 .add("400", Json.createObjectBuilder().add("description", "Missing required parameters or bad request format")) 82 .add("403", Json.createObjectBuilder().add("description", "Action is not permitted")) 83 .add("500", Json.createObjectBuilder().add("description", "Internal server error")) 84 .add("502", Json.createObjectBuilder().add("description", "Bad gateway (upstream)")) 85 ) 78 86 ); 79 87 } 80 88 … … 90 98 91 99 @Override 92 100 public String[] getUsageExamples() { 93 return new String[]{"https://petstore.swagger.io/?url=http://localhost:8111/openapi.json", "https://swagger.io/specification/"}; 101 return new String[]{ 102 "https://petstore.swagger.io/?url=http://localhost:8111/openapi.json", 103 "https://swagger.io/specification/" 104 }; 94 105 } 95 106 96 107 @Override … … 104 115 } 105 116 106 117 @Override 107 public String[] getMandatoryParams() {108 return new String[0];118 public List<RequestParameter<?>> getParameters() { 119 return Collections.emptyList(); 109 120 } 110 121 111 122 @Override -
src/org/openstreetmap/josm/io/remotecontrol/handler/OpenFileHandler.java
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, "string"); 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
6 6 import java.net.URI; 7 7 import java.net.URISyntaxException; 8 8 import java.text.MessageFormat; 9 import java.util.Arrays; 9 10 import java.util.Collections; 10 11 import java.util.HashMap; 11 12 import java.util.HashSet; … … 16 17 import java.util.function.Function; 17 18 import java.util.function.Supplier; 18 19 import java.util.regex.Pattern; 20 import java.util.stream.Collectors; 21 import java.util.stream.Stream; 19 22 20 23 import javax.swing.JLabel; 21 24 import javax.swing.JOptionPane; … … 28 31 import org.openstreetmap.josm.gui.MainApplication; 29 32 import org.openstreetmap.josm.io.OsmApiException; 30 33 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 34 import org.openstreetmap.josm.io.remotecontrol.parameter.RequestParameter; 31 35 import org.openstreetmap.josm.spi.preferences.Config; 32 36 import org.openstreetmap.josm.tools.Logging; 33 37 import org.openstreetmap.josm.tools.Pair; … … 53 57 /** past confirmations */ 54 58 protected static final PermissionCache PERMISSIONS = new PermissionCache(); 55 59 60 protected final RequestParameter<String> layerNameParameter = RequestParameter.optional("layer_name"); 61 protected final RequestParameter<Boolean> newLayerParameter = RequestParameter.optional("new_layer", Boolean::parseBoolean, LOAD_IN_NEW_LAYER::get, "boolean"); 62 protected final RequestParameter<Boolean> layerLockedParameter = RequestParameter.optional("layer_locked", Boolean::parseBoolean, () -> false, "boolean"); 63 protected final RequestParameter<DownloadPolicy> downloadPolicyParameter = RequestParameter.optional("download_policy", DownloadPolicy::of, () -> DownloadPolicy.NORMAL, "string"); 64 protected final RequestParameter<UploadPolicy> uploadPolicyParameter = RequestParameter.optional("upload_policy", UploadPolicy::of, () -> UploadPolicy.NORMAL, "string"); 65 protected final RequestParameter<String> addTagsParameter = RequestParameter.optional("addtags"); 66 56 67 /** The GET request arguments */ 57 68 protected Map<String, String> args; 58 69 … … 129 140 public abstract PermissionPrefWithDefault getPermissionPref(); 130 141 131 142 /** 143 * Returns the request parameters. Both used in runtime and for documentation. 144 * 145 * @return the request parameters 146 */ 147 public List<RequestParameter<?>> getParameters() { 148 // Default implementation for backwards compatibility 149 return Stream.concat( 150 Arrays.stream(getMandatoryParams()).map(RequestParameter::mandatory), 151 Arrays.stream(getOptionalParams()).map(RequestParameter::optional) 152 ).collect(Collectors.toList()); 153 } 154 155 /** 132 156 * Returns the mandatory parameters. Both used to enforce their presence at runtime and for documentation. 157 * @deprecated implement `getParameters` instead. 133 158 * @return the mandatory parameters 134 159 */ 135 public abstract String[] getMandatoryParams(); 160 @Deprecated 161 public String[] getMandatoryParams() { 162 return new String[0]; 163 } 136 164 137 165 /** 138 166 * Returns the optional parameters. Both used to enforce their presence at runtime and for documentation. 167 * @deprecated implement `getParameters` instead. 139 168 * @return the optional parameters 140 169 */ 170 @Deprecated 141 171 public String[] getOptionalParams() { 142 172 return new String[0]; 143 173 } … … 247 277 this.args = getRequestParameter(new URI(this.request)); 248 278 } 249 279 250 protected final String[] splitArg(String arg, Pattern splitter) {251 return splitter.split(args != null ? args.get(arg) : "", -1);252 }253 254 280 /** 255 281 * Returns the request parameters. 256 282 * @param uri URI as string … … 271 297 } 272 298 273 299 void checkMandatoryParams() throws RequestHandlerBadRequestException { 274 String[] mandatory = getMandatoryParams(); 275 String[] optional = getOptionalParams(); 300 List<RequestParameter<?>> mandatory = getParameters().stream().filter(RequestParameter::isMandatory).collect(Collectors.toList()); 276 301 List<String> missingKeys = new LinkedList<>(); 277 302 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)) {303 if (args != null) { 304 for (RequestParameter<?> parameter : mandatory) { 305 String value = args.get(parameter.getName()); 306 if (Utils.isStripEmpty(value)) { 282 307 error = true; 283 Logging.warn('\'' + myCommand + "' remote control request must have '" + key+ "' parameter");284 missingKeys.add( key);308 Logging.warn('\'' + myCommand + "' remote control request must have '" + parameter.getName() + "' parameter"); 309 missingKeys.add(parameter.getName()); 285 310 } 286 311 } 287 312 } 288 Set<String> knownParams = new HashSet<>(); 289 if (mandatory != null) 290 Collections.addAll(knownParams, mandatory); 291 if (optional != null) 292 Collections.addAll(knownParams, optional); 313 Set<String> knownParams = getParameters().stream().map(RequestParameter::getName).collect(Collectors.toSet()); 293 314 if (args != null) { 294 315 for (String par: args.keySet()) { 295 316 if (!knownParams.contains(par)) { … … 340 361 return contentType; 341 362 } 342 363 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 364 protected DownloadParams getDownloadParams() { 357 365 DownloadParams result = new DownloadParams(); 358 366 if (args != null) { 359 367 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));368 .withNewLayer(newLayerParameter.read(args)) 369 .withLayerName(layerNameParameter.read(args)) 370 .withLocked(layerLockedParameter.read(args)) 371 .withDownloadPolicy(downloadPolicyParameter.read(args)) 372 .withUploadPolicy(uploadPolicyParameter.read(args)); 365 373 } 366 374 return result; 367 375 } … … 501 509 */ 502 510 public abstract static class RawURLParseRequestHandler extends RequestHandler { 503 511 @Override 504 protected void parseArgs() throws URISyntaxException{512 protected void parseArgs() { 505 513 Map<String, String> args = new HashMap<>(); 506 514 if (request.indexOf('?') != -1) { 507 515 String query = request.substring(request.indexOf('?') + 1); -
src/org/openstreetmap/josm/io/remotecontrol/handler/VersionHandler.java
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; 8 9 10 import java.util.Arrays; 11 import java.util.Collections; 12 import java.util.List; 13 9 14 /** 10 15 * Handler for version request. 11 16 */ … … 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]; 47 public List<RequestParameter<?>> getParameters() { 48 return Collections.singletonList( 49 jsonpParameter 50 ); 42 51 } 43 52 44 53 @Override 45 public String[] getOptionalParams() {46 return new String[]{"jsonp"};47 }48 49 @Override50 54 protected void validateRequest() throws RequestHandlerBadRequestException { 51 55 // Nothing to do 52 56 } … … 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 }
