001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io.remotecontrol.handler; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.io.ByteArrayInputStream; 007import java.nio.charset.StandardCharsets; 008 009import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask; 010import org.openstreetmap.josm.actions.downloadtasks.DownloadParams; 011import org.openstreetmap.josm.data.osm.DataSet; 012import org.openstreetmap.josm.gui.MainApplication; 013import org.openstreetmap.josm.io.IllegalDataException; 014import org.openstreetmap.josm.io.OsmReader; 015import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 016import org.openstreetmap.josm.tools.Utils; 017 018/** 019 * Handler to load data directly from the URL. 020 * @since 7636 021 */ 022public class LoadDataHandler extends RequestHandler { 023 024 private static final String OSM_MIME_TYPE = "application/x-osm+xml"; 025 026 /** 027 * The remote control command name used to import data. 028 */ 029 public static final String command = "load_data"; 030 031 /** 032 * Holds the data input string 033 */ 034 private String data; 035 036 /** 037 * Holds the parsed data set 038 */ 039 private DataSet dataSet; 040 041 @Override 042 protected void handleRequest() throws RequestHandlerErrorException { 043 MainApplication.worker.submit(new LoadDataTask(getDownloadParams(), dataSet, args.get("layer_name"))); 044 } 045 046 @Override 047 public String[] getMandatoryParams() { 048 return new String[]{"data"}; 049 } 050 051 @Override 052 public String[] getOptionalParams() { 053 return new String[] {"new_layer", "mime_type", "layer_name", "layer_locked", "download_policy", "upload_policy"}; 054 } 055 056 @Override 057 public String getUsage() { 058 return "Reads data encoded directly in the URL and adds it to the current data set"; 059 } 060 061 @Override 062 public String[] getUsageExamples() { 063 return new String[]{ 064 "/load_data?layer_name=extra_layer&new_layer=true&data=" + 065 Utils.encodeUrl("<osm version='0.6'><node id='-1' lat='1' lon='2' /></osm>")}; 066 } 067 068 @Override 069 public String getPermissionMessage() { 070 return tr("Remote Control has been asked to load the following data:") 071 + "<br>" + data; 072 } 073 074 @Override 075 public PermissionPrefWithDefault getPermissionPref() { 076 // Same permission as the import data, as the difference from a user pov is minimal 077 return PermissionPrefWithDefault.IMPORT_DATA; 078 } 079 080 @Override 081 protected void validateRequest() throws RequestHandlerBadRequestException { 082 validateDownloadParams(); 083 this.data = args.get("data"); 084 /** 085 * Holds the mime type. Currently only OSM_MIME_TYPE is supported 086 * But it could be extended to text/csv, application/gpx+xml, ... or even binary encoded data 087 */ 088 final String mimeType = Utils.firstNonNull(args.get("mime_type"), OSM_MIME_TYPE); 089 try { 090 if (OSM_MIME_TYPE.equals(mimeType)) { 091 final ByteArrayInputStream in = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)); 092 dataSet = OsmReader.parseDataSet(in, null); 093 } else { 094 dataSet = new DataSet(); 095 } 096 } catch (IllegalDataException e) { 097 throw new RequestHandlerBadRequestException("Failed to parse " + data + ": " + e.getMessage(), e); 098 } 099 } 100 101 protected static class LoadDataTask extends DownloadOsmTask.AbstractInternalTask { 102 103 protected final String layerName; 104 105 /** 106 * Constructs a new {@code LoadDataTask}. 107 * @param settings download settings 108 * @param dataSet data set 109 * @param layerName layer name 110 * @since 13927 111 */ 112 public LoadDataTask(DownloadParams settings, DataSet dataSet, String layerName) { 113 super(settings, tr("Loading data"), false, true); 114 this.dataSet = dataSet; 115 this.layerName = layerName; 116 } 117 118 @Override 119 public void realRun() { 120 // No real run, the data is already loaded 121 } 122 123 @Override 124 protected void cancel() { 125 // No Cancel, would be hard without a real run 126 } 127 128 @Override 129 protected void finish() { 130 loadData(layerName, null); 131 } 132 } 133}