001package com.thetransactioncompany.jsonrpc2; 002 003 004import java.util.List; 005import java.util.Map; 006 007import 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 */ 088public 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 309 * (JSON array), {@code Map<String,Object>} for named 310 * (JSON object), 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) 365 * pass a {@code Map<String,Object>}. If there are 366 * no parameters pass {@code null}. 367 */ 368 @Deprecated 369 @SuppressWarnings("unchecked") 370 public void setParams(final Object params) { 371 372 if (params == null) { 373 positionalParams = null; 374 namedParams = null; 375 } else if (params instanceof List) { 376 positionalParams = (List<Object>) params; 377 } else if (params instanceof Map) { 378 namedParams = (Map<String, Object>) params; 379 } else { 380 throw new IllegalArgumentException("The notification parameters must be of type List, Map or null"); 381 } 382 } 383 384 385 /** 386 * Sets the positional (JSON array) request parameters. 387 * 388 * @since 1.30 389 * 390 * @param positionalParams The positional (JSON array) request 391 * parameters, {@code null} if none. 392 */ 393 public void setPositionalParams(final List<Object> positionalParams) { 394 395 if (positionalParams == null) 396 return; 397 398 this.positionalParams = positionalParams; 399 } 400 401 402 /** 403 * Sets the named (JSON object) request parameters. 404 * 405 * @since 1.30 406 * 407 * @param namedParams The named (JSON object) request parameters, 408 * {@code null} if none. 409 */ 410 public void setNamedParams(final Map<String,Object> namedParams) { 411 412 if (namedParams == null) 413 return; 414 415 this.namedParams = namedParams; 416 } 417 418 419 @Override 420 public JSONObject toJSONObject() { 421 422 JSONObject notf = new JSONObject(); 423 424 notf.put("method", method); 425 426 // The params can be omitted if none 427 switch (getParamsType()) { 428 429 case ARRAY: 430 notf.put("params", positionalParams); 431 break; 432 433 case OBJECT: 434 notf.put("params", namedParams); 435 break; 436 } 437 438 notf.put("jsonrpc", "2.0"); 439 440 441 Map <String,Object> nonStdAttributes = getNonStdAttributes(); 442 443 if (nonStdAttributes != null) { 444 445 for (final Map.Entry<String,Object> attr: nonStdAttributes.entrySet()) 446 notf.put(attr.getKey(), attr.getValue()); 447 } 448 449 return notf; 450 } 451}