001 package com.thetransactioncompany.jsonrpc2; 002 003 004 import java.util.List; 005 import java.util.Map; 006 007 import net.minidev.json.JSONObject; 008 009 010 /** 011 * Represents a JSON-RPC 2.0 notification. 012 * 013 * <p>Notifications provide a mean for calling a remote procedure without 014 * generating a response. Note that notifications are inherently unreliable 015 * as no confirmation is sent back to the caller. 016 * 017 * <p>Notifications have the same JSON structure as requests, except that they 018 * lack an identifier: 019 * <ul> 020 * <li>{@code method} The name of the remote method to call. 021 * <li>{@code params} The required method parameters (if any), which can 022 * be packed into a JSON array or object. 023 * <li>{@code jsonrpc} A string indicating the JSON-RPC protocol version 024 * set to "2.0". 025 * </ul> 026 * 027 * <p>Here is a sample JSON-RPC 2.0 notification string: 028 * 029 * <pre> 030 * { 031 * "method" : "progressNotify", 032 * "params" : ["75%"], 033 * "jsonrpc" : "2.0" 034 * } 035 * </pre> 036 * 037 * <p>This class provides two methods to obtain a request object: 038 * <ul> 039 * <li>Pass a JSON-RPC 2.0 notification string to the static 040 * {@link #parse} method, or 041 * <li>Invoke one of the constructors with the appropriate arguments. 042 * </ul> 043 * 044 * <p>Example 1: Parsing a notification string: 045 * 046 * <pre> 047 * String jsonString = "{\"method\":\"progressNotify\",\"params\":[\"75%\"],\"jsonrpc\":\"2.0\"}"; 048 * 049 * JSONRPC2Notification notification = null; 050 * 051 * try { 052 * notification = JSONRPC2Notification.parse(jsonString); 053 * 054 * } catch (JSONRPC2ParseException e) { 055 * // handle exception 056 * } 057 * </pre> 058 * 059 * <p>Example 2: Recreating the above request: 060 * 061 * <pre> 062 * String method = "progressNotify"; 063 * List<Object> params = new Vector<Object>(); 064 * params.add("75%"); 065 * 066 * JSONRPC2Notification notification = new JSONRPC2Notification(method, params); 067 * 068 * System.out.println(notification); 069 * </pre> 070 * 071 * <p id="map">The mapping between JSON and Java entities (as defined by the 072 * underlying JSON Smart library): 073 * 074 * <pre> 075 * true|false <---> java.lang.Boolean 076 * number <---> java.lang.Number 077 * string <---> java.lang.String 078 * array <---> java.util.List 079 * object <---> java.util.Map 080 * null <---> null 081 * </pre> 082 * 083 * <p>The JSON-RPC 2.0 specification and user group forum can be found 084 * <a href="http://groups.google.com/group/json-rpc">here</a>. 085 * 086 * @author Vladimir Dzhuvinov 087 */ 088 public class JSONRPC2Notification extends JSONRPC2Message { 089 090 091 /** 092 * The requested method name. 093 */ 094 private String method; 095 096 097 /** 098 * The positional parameters, {@code null} if none. 099 */ 100 private List<Object> positionalParams; 101 102 103 /** 104 * The named parameters, {@code null} if none. 105 */ 106 private Map<String,Object> namedParams; 107 108 109 /** 110 * Parses a JSON-RPC 2.0 notification string. This method is 111 * thread-safe. 112 * 113 * @param jsonString The JSON-RPC 2.0 notification string, UTF-8 114 * encoded. Must not be {@code null}. 115 * 116 * @return The corresponding JSON-RPC 2.0 notification object. 117 * 118 * @throws JSONRPC2ParseException With detailed message if parsing 119 * failed. 120 */ 121 public static JSONRPC2Notification parse(final String jsonString) 122 throws JSONRPC2ParseException { 123 124 return parse(jsonString, false, false, false); 125 } 126 127 128 /** 129 * Parses a JSON-RPC 2.0 notification string. This method is 130 * thread-safe. 131 * 132 * @param jsonString The JSON-RPC 2.0 notification string, UTF-8 133 * encoded. Must not be {@code null}. 134 * @param preserveOrder {@code true} to preserve the order of JSON 135 * object members in parameters. 136 * 137 * @return The corresponding JSON-RPC 2.0 notification object. 138 * 139 * @throws JSONRPC2ParseException With detailed message if parsing 140 * failed. 141 */ 142 public static JSONRPC2Notification parse(final String jsonString, 143 final boolean preserveOrder) 144 throws JSONRPC2ParseException { 145 146 return parse(jsonString, preserveOrder, false, false); 147 } 148 149 150 /** 151 * Parses a JSON-RPC 2.0 notification string. This method is 152 * thread-safe. 153 * 154 * @param jsonString The JSON-RPC 2.0 notification string, UTF-8 155 * encoded. Must not be {@code null}. 156 * @param preserveOrder {@code true} to preserve the order of JSON 157 * object members in parameters. 158 * @param ignoreVersion {@code true} to skip a check of the 159 * {@code "jsonrpc":"2.0"} version attribute in the 160 * JSON-RPC 2.0 message. 161 * 162 * @return The corresponding JSON-RPC 2.0 notification object. 163 * 164 * @throws JSONRPC2ParseException With detailed message if parsing 165 * failed. 166 */ 167 public static JSONRPC2Notification parse(final String jsonString, 168 final boolean preserveOrder, 169 final boolean ignoreVersion) 170 throws JSONRPC2ParseException { 171 172 return parse(jsonString, preserveOrder, ignoreVersion, false); 173 } 174 175 176 /** 177 * Parses a JSON-RPC 2.0 notification string. This method is 178 * thread-safe. 179 * 180 * @param jsonString The JSON-RPC 2.0 notification string, 181 * UTF-8 encoded. Must not be {@code null}. 182 * @param preserveOrder {@code true} to preserve the order of 183 * JSON object members in parameters. 184 * @param ignoreVersion {@code true} to skip a check of the 185 * {@code "jsonrpc":"2.0"} version 186 * attribute in the JSON-RPC 2.0 message. 187 * @param parseNonStdAttributes {@code true} to parse non-standard 188 * attributes found in the JSON-RPC 2.0 189 * message. 190 * 191 * @return The corresponding JSON-RPC 2.0 notification object. 192 * 193 * @throws JSONRPC2ParseException With detailed message if parsing 194 * failed. 195 */ 196 public static JSONRPC2Notification parse(final String jsonString, 197 final boolean preserveOrder, 198 final boolean ignoreVersion, 199 final boolean parseNonStdAttributes) 200 throws JSONRPC2ParseException { 201 202 JSONRPC2Parser parser = new JSONRPC2Parser(preserveOrder, ignoreVersion, parseNonStdAttributes); 203 204 return parser.parseJSONRPC2Notification(jsonString); 205 } 206 207 208 /** 209 * Constructs a new JSON-RPC 2.0 notification with no parameters. 210 * 211 * @param method The name of the requested method. Must not be 212 * {@code null}. 213 */ 214 public JSONRPC2Notification(final String method) { 215 216 setMethod(method); 217 setParams(null); 218 } 219 220 221 /** 222 * Constructs a new JSON-RPC 2.0 notification with positional (JSON 223 * array) parameters. 224 * 225 * @param method The name of the requested method. Must not 226 * be {@code null}. 227 * @param positionalParams The positional (JSON array) parameters, 228 * {@code null} if none. 229 */ 230 public JSONRPC2Notification(final String method, 231 final List<Object> positionalParams) { 232 233 setMethod(method); 234 setPositionalParams(positionalParams); 235 } 236 237 238 /** 239 * Constructs a new JSON-RPC 2.0 notification with named (JSON object) 240 * parameters. 241 * 242 * @param method The name of the requested method. 243 * @param namedParams The named (JSON object) parameters, {@code null} 244 * if none. 245 */ 246 public JSONRPC2Notification(final String method, 247 final Map <String,Object> namedParams) { 248 249 setMethod(method); 250 setNamedParams(namedParams); 251 } 252 253 254 /** 255 * Gets the name of the requested method. 256 * 257 * @return The method name. 258 */ 259 public String getMethod() { 260 261 return method; 262 } 263 264 265 /** 266 * Sets the name of the requested method. 267 * 268 * @param method The method name. Must not be {@code null}. 269 */ 270 public void setMethod(final String method) { 271 272 // The method name is mandatory 273 if (method == null) 274 throw new IllegalArgumentException("The method name must not be null"); 275 276 this.method = method; 277 } 278 279 280 /** 281 * Gets the parameters type ({@link JSONRPC2ParamsType#ARRAY positional}, 282 * {@link JSONRPC2ParamsType#OBJECT named} or 283 * {@link JSONRPC2ParamsType#NO_PARAMS none}). 284 * 285 * @return The parameters type. 286 */ 287 public JSONRPC2ParamsType getParamsType() { 288 289 if (positionalParams == null && namedParams == null) 290 return JSONRPC2ParamsType.NO_PARAMS; 291 292 if (positionalParams != null) 293 return JSONRPC2ParamsType.ARRAY; 294 295 if (namedParams != null) 296 return JSONRPC2ParamsType.OBJECT; 297 298 else 299 return JSONRPC2ParamsType.NO_PARAMS; 300 } 301 302 /** 303 * Gets the notification parameters. 304 * 305 * <p>This method was deprecated in version 1.30. Use 306 * {@link #getPositionalParams} or {@link #getNamedParams} instead. 307 * 308 * @return The parameters as {@code List<Object>} for positional (JSON 309 * array), {@code Map<String,Object>} for named (JSON object), 310 * or {@code null} if none. 311 */ 312 @Deprecated 313 public Object getParams() { 314 315 switch (getParamsType()) { 316 317 case ARRAY: 318 return positionalParams; 319 320 case OBJECT: 321 return namedParams; 322 323 default: 324 return null; 325 } 326 } 327 328 329 /** 330 * Gets the positional (JSON array) parameters. 331 * 332 * @since 1.30 333 * 334 * @return The positional (JSON array) parameters, {@code null} if none 335 * or named. 336 */ 337 public List<Object> getPositionalParams() { 338 339 return positionalParams; 340 } 341 342 343 /** 344 * Gets the named parameters. 345 * 346 * @since 1.30 347 * 348 * @return The named (JSON object) parameters, {@code null} if none or 349 * positional. 350 */ 351 public Map<String,Object> getNamedParams() { 352 353 return namedParams; 354 } 355 356 357 /** 358 * Sets the notification parameters. 359 * 360 * <p>This method was deprecated in version 1.30. Use 361 * {@link #setPositionalParams} or {@link #setNamedParams} instead. 362 * 363 * @param params The parameters. For positional (JSON array) pass a 364 * {@code List<Object>}. For named (JSON object) pass a 365 * {@code Map<String,Object>}. If there are no 366 * parameters pass {@code null}. 367 */ 368 @Deprecated 369 @SuppressWarnings("unchecked") 370 public void setParams(final Object params) { 371 372 if (params == null) 373 return; 374 375 else if (params instanceof List) 376 positionalParams = (List<Object>)params; 377 378 else if (params instanceof Map) 379 namedParams = (Map<String,Object>)params; 380 381 else 382 throw new IllegalArgumentException("The notification parameters must be of type List, Map or null"); 383 } 384 385 386 /** 387 * Sets the positional (JSON array) request parameters. 388 * 389 * @since 1.30 390 * 391 * @param positionalParams The positional (JSON array) request 392 * parameters, {@code null} if none. 393 */ 394 public void setPositionalParams(final List<Object> positionalParams) { 395 396 if (positionalParams == null) 397 return; 398 399 this.positionalParams = positionalParams; 400 } 401 402 403 /** 404 * Sets the named (JSON object) request parameters. 405 * 406 * @since 1.30 407 * 408 * @param namedParams The named (JSON object) request parameters, 409 * {@code null} if none. 410 */ 411 public void setNamedParams(final Map<String,Object> namedParams) { 412 413 if (namedParams == null) 414 return; 415 416 this.namedParams = namedParams; 417 } 418 419 420 @Override 421 public JSONObject toJSONObject() { 422 423 JSONObject notf = new JSONObject(); 424 425 notf.put("method", method); 426 427 // The params can be omitted if none 428 switch (getParamsType()) { 429 430 case ARRAY: 431 notf.put("params", positionalParams); 432 break; 433 434 case OBJECT: 435 notf.put("params", namedParams); 436 break; 437 } 438 439 notf.put("jsonrpc", "2.0"); 440 441 442 Map <String,Object> nonStdAttributes = getNonStdAttributes(); 443 444 if (nonStdAttributes != null) { 445 446 for (final Map.Entry<String,Object> attr: nonStdAttributes.entrySet()) 447 notf.put(attr.getKey(), attr.getValue()); 448 } 449 450 return notf; 451 } 452 }