source: josm/trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/RequestHandler.java@ 5691

Last change on this file since 5691 was 5691, checked in by Don-vip, 11 years ago

see #8148 - Remote control: URL validation in import handler + find suitable download tasks + dynamic width of confirmation dialog box

  • Property svn:eol-style set to native
File size: 9.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.remotecontrol.handler;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.UnsupportedEncodingException;
7import java.net.URLDecoder;
8import java.text.MessageFormat;
9import java.util.HashMap;
10import java.util.LinkedList;
11import java.util.List;
12
13import javax.swing.JLabel;
14import javax.swing.JOptionPane;
15
16import org.openstreetmap.josm.Main;
17import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
18import org.openstreetmap.josm.tools.Utils;
19
20/**
21 * This is the parent of all classes that handle a specific remote control command
22 *
23 * @author Bodo Meissner
24 */
25public abstract class RequestHandler {
26
27 public static final String globalConfirmationKey = "remotecontrol.always-confirm";
28 public static final boolean globalConfirmationDefault = false;
29 public static final String loadInNewLayerKey = "remotecontrol.new-layer";
30 public static final boolean loadInNewLayerDefault = false;
31
32 /** The GET request arguments */
33 protected HashMap<String,String> args;
34
35 /** The request URL without "GET". */
36 protected String request;
37
38 /** default response */
39 protected String content = "OK\r\n";
40 /** default content type */
41 protected String contentType = "text/plain";
42
43 /** will be filled with the command assigned to the subclass */
44 protected String myCommand;
45
46 /**
47 * Check permission and parameters and handle request.
48 *
49 * @throws RequestHandlerForbiddenException
50 * @throws RequestHandlerBadRequestException
51 * @throws RequestHandlerErrorException
52 */
53 public final void handle() throws RequestHandlerForbiddenException, RequestHandlerBadRequestException, RequestHandlerErrorException
54 {
55 checkMandatoryParams();
56 validateRequest();
57 checkPermission();
58 handleRequest();
59 }
60
61 /**
62 * Validates the request before attempting to perform it.
63 * @throws RequestHandlerBadRequestException
64 * @since 5678
65 */
66 protected abstract void validateRequest() throws RequestHandlerBadRequestException;
67
68 /**
69 * Handle a specific command sent as remote control.
70 *
71 * This method of the subclass will do the real work.
72 *
73 * @throws RequestHandlerErrorException
74 * @throws RequestHandlerBadRequestException
75 */
76 protected abstract void handleRequest() throws RequestHandlerErrorException, RequestHandlerBadRequestException;
77
78 /**
79 * Get a specific message to ask the user for permission for the operation
80 * requested via remote control.
81 *
82 * This message will be displayed to the user if the preference
83 * remotecontrol.always-confirm is true.
84 *
85 * @return the message
86 */
87 abstract public String getPermissionMessage();
88
89 /**
90 * Get a PermissionPref object containing the name of a special permission
91 * preference to individually allow the requested operation and an error
92 * message to be displayed when a disabled operation is requested.
93 *
94 * Default is not to check any special preference. Override this in a
95 * subclass to define permission preference and error message.
96 *
97 * @return the preference name and error message or null
98 */
99 abstract public PermissionPrefWithDefault getPermissionPref();
100
101 abstract public String[] getMandatoryParams();
102
103 /**
104 * Check permissions in preferences and display error message
105 * or ask for permission.
106 *
107 * @throws RequestHandlerForbiddenException
108 */
109 final public void checkPermission() throws RequestHandlerForbiddenException
110 {
111 /*
112 * If the subclass defines a specific preference and if this is set
113 * to false, abort with an error message.
114 *
115 * Note: we use the deprecated class here for compatibility with
116 * older versions of WMSPlugin.
117 */
118 PermissionPrefWithDefault permissionPref = getPermissionPref();
119 if((permissionPref != null) && (permissionPref.pref != null))
120 {
121 if (!Main.pref.getBoolean(permissionPref.pref, permissionPref.defaultVal)) {
122 String err = MessageFormat.format("RemoteControl: ''{0}'' forbidden by preferences", myCommand);
123 System.out.println(err);
124 throw new RequestHandlerForbiddenException(err);
125 }
126 }
127
128 /* Does the user want to confirm everything?
129 * If yes, display specific confirmation message.
130 */
131 if (Main.pref.getBoolean(globalConfirmationKey, globalConfirmationDefault)) {
132 // Ensure dialog box does not exceed main window size
133 Integer maxWidth = (int) Math.max(200, Main.parent.getWidth()*0.6);
134 String message = "<html><div>" + getPermissionMessage() +
135 "<br/>" + tr("Do you want to allow this?") + "</div></html>";
136 JLabel label = new JLabel(message);
137 if (label.getPreferredSize().width > maxWidth) {
138 label.setText(message.replaceFirst("<div>", "<div style=\"width:" + maxWidth + "px;\">"));
139 }
140 if (JOptionPane.showConfirmDialog(Main.parent, label,
141 tr("Confirm Remote Control action"),
142 JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
143 String err = MessageFormat.format("RemoteControl: ''{0}'' forbidden by user''s choice", myCommand);
144 throw new RequestHandlerForbiddenException(err);
145 }
146 }
147 }
148
149 /**
150 * Set request URL and parse args.
151 *
152 * @param url The request URL.
153 */
154 public void setUrl(String url) {
155 this.request = url;
156 parseArgs();
157 }
158
159 /**
160 * Parse the request parameters as key=value pairs.
161 * The result will be stored in {@code this.args}.
162 *
163 * Can be overridden by subclass.
164 */
165 protected void parseArgs() {
166 try {
167 String req = URLDecoder.decode(this.request, "UTF-8");
168 HashMap<String, String> args = new HashMap<String, String>();
169 if (req.indexOf('?') != -1) {
170 String query = req.substring(req.indexOf('?') + 1);
171 if (query.indexOf('#') != -1) {
172 query = query.substring(0, query.indexOf('#'));
173 }
174 String[] params = query.split("&", -1);
175 for (String param : params) {
176 int eq = param.indexOf('=');
177 if (eq != -1) {
178 args.put(param.substring(0, eq), param.substring(eq + 1));
179 }
180 }
181 }
182 this.args = args;
183 } catch (UnsupportedEncodingException ex) {
184 throw new IllegalStateException(ex);
185 }
186 }
187
188 void checkMandatoryParams() throws RequestHandlerBadRequestException {
189 String[] mandatory = getMandatoryParams();
190 if(mandatory == null) return;
191
192 List<String> missingKeys = new LinkedList<String>();
193 boolean error = false;
194 for (String key : mandatory) {
195 String value = args.get(key);
196 if ((value == null) || (value.length() == 0)) {
197 error = true;
198 System.out.println("'" + myCommand + "' remote control request must have '" + key + "' parameter");
199 missingKeys.add(key);
200 }
201 }
202 if (error) {
203 throw new RequestHandlerBadRequestException(
204 "The following keys are mandatory, but have not been provided: "
205 + Utils.join(", ", missingKeys));
206 }
207 }
208
209 /**
210 * Save command associated with this handler.
211 *
212 * @param command The command.
213 */
214 public void setCommand(String command)
215 {
216 if (command.charAt(0) == '/') {
217 command = command.substring(1);
218 }
219 myCommand = command;
220 }
221
222 public String getContent() {
223 return content;
224 }
225
226 public String getContentType() {
227 return contentType;
228 }
229
230 protected boolean isLoadInNewLayer() {
231 return args.get("new_layer") != null && !args.get("new_layer").isEmpty()
232 ? Boolean.parseBoolean(args.get("new_layer"))
233 : Main.pref.getBoolean(loadInNewLayerKey, loadInNewLayerDefault);
234 }
235
236 protected final String decodeParam(String param) {
237 try {
238 return URLDecoder.decode(param, "UTF-8");
239 } catch (UnsupportedEncodingException e) {
240 throw new RuntimeException();
241 }
242 }
243
244 public static class RequestHandlerException extends Exception {
245
246 public RequestHandlerException(String message) {
247 super(message);
248 }
249
250 public RequestHandlerException() {
251 }
252 }
253
254 public static class RequestHandlerErrorException extends RequestHandlerException {
255 }
256
257 public static class RequestHandlerBadRequestException extends RequestHandlerException {
258
259 public RequestHandlerBadRequestException(String message) {
260 super(message);
261 }
262 }
263
264 public static class RequestHandlerForbiddenException extends RequestHandlerException {
265 private static final long serialVersionUID = 2263904699747115423L;
266
267 public RequestHandlerForbiddenException(String message) {
268 super(message);
269 }
270 }
271}
Note: See TracBrowser for help on using the repository browser.