001package Torello.Browser.BrowserAPI; 002 003import java.util.*; 004import javax.json.*; 005import javax.json.stream.*; 006import java.io.*; 007 008import java.lang.reflect.Method; 009import java.lang.reflect.Parameter; 010import java.util.function.Function; 011 012import Torello.Browser.BrowserEvent; 013import Torello.Browser.JavaScriptAPI.*; 014import Torello.Browser.helper.*; 015 016import Torello.Java.Additional.*; 017import Torello.Java.JSON.*; 018 019import static Torello.Java.JSON.JFlag.*; 020 021import Torello.Java.StrCmpr; 022import Torello.JavaDoc.StaticFunctional; 023import Torello.JavaDoc.JDHeaderBackgroundImg; 024import Torello.JavaDoc.Excuse; 025 026/** 027 * <SPAN CLASS=COPIEDJDK><B>Defines events for background web platform features.</B></SPAN> 028 * 029 * <EMBED CLASS='external-html' DATA-FILE-ID=CODE_GEN_NOTE> 030 */ 031@StaticFunctional(Excused={"counter"}, Excuses={Excuse.CONFIGURATION}) 032@JDHeaderBackgroundImg(EmbedTagFileID="WOOD_PLANK_NOTE") 033public class BackgroundService 034{ 035 // ******************************************************************************************** 036 // ******************************************************************************************** 037 // Class Header Stuff 038 // ******************************************************************************************** 039 // ******************************************************************************************** 040 041 042 // No Pubic Constructors 043 private BackgroundService () { } 044 045 // These two Vector's are used by all the "Methods" exported by this class. java.lang.reflect 046 // is used to generate the JSON String's. It saves thousands of lines of Auto-Generated Code. 047 private static final Map<String, Vector<String>> parameterNames = new HashMap<>(); 048 private static final Map<String, Vector<Class<?>>> parameterTypes = new HashMap<>(); 049 050 // Some Methods do not take any parameters - for instance all the "enable()" and "disable()" 051 // I simply could not get ride of RAW-TYPES and UNCHECKED warnings... so there are now, 052 // offically, two empty-vectors. One for String's, and the other for Classes. 053 054 private static final Vector<String> EMPTY_VEC_STR = new Vector<>(); 055 private static final Vector<Class<?>> EMPTY_VEC_CLASS = new Vector<>(); 056 057 static 058 { 059 for (Method m : BackgroundService.class.getMethods()) 060 { 061 // This doesn't work! The parameter names are all "arg0" ... "argN" 062 // It works for java.lang.reflect.Field, BUT NOT java.lang.reflect.Parameter! 063 // 064 // Vector<String> parameterNamesList = new Vector<>(); -- NOPE! 065 066 Vector<Class<?>> parameterTypesList = new Vector<>(); 067 068 for (Parameter p : m.getParameters()) parameterTypesList.add(p.getType()); 069 070 parameterTypes.put( 071 m.getName(), 072 (parameterTypesList.size() > 0) ? parameterTypesList : EMPTY_VEC_CLASS 073 ); 074 } 075 } 076 077 static 078 { 079 Vector<String> v = null; 080 081 v = new Vector<String>(1); 082 parameterNames.put("startObserving", v); 083 Collections.addAll(v, new String[] 084 { "service", }); 085 086 v = new Vector<String>(1); 087 parameterNames.put("stopObserving", v); 088 Collections.addAll(v, new String[] 089 { "service", }); 090 091 v = new Vector<String>(2); 092 parameterNames.put("setRecording", v); 093 Collections.addAll(v, new String[] 094 { "shouldRecord", "service", }); 095 096 v = new Vector<String>(1); 097 parameterNames.put("clearEvents", v); 098 Collections.addAll(v, new String[] 099 { "service", }); 100 } 101 102 103 // ******************************************************************************************** 104 // ******************************************************************************************** 105 // Types - Static Inner Classes 106 // ******************************************************************************************** 107 // ******************************************************************************************** 108 109 /** 110 * The Background Service that will be associated with the commands/events. 111 * Every Background Service operates independently, but they share the same 112 * API. 113 */ 114 public static final String[] ServiceName = 115 { 116 "backgroundFetch", "backgroundSync", "pushMessaging", "notifications", "paymentHandler", 117 "periodicBackgroundSync", 118 }; 119 120 /** A key-value pair for additional event information to pass along. */ 121 public static class EventMetadata 122 extends BaseType 123 implements java.io.Serializable 124 { 125 /** For Object Serialization. java.io.Serializable */ 126 protected static final long serialVersionUID = 1; 127 128 public boolean[] optionals() 129 { return new boolean[] { false, false, }; } 130 131 /** <CODE>[No Description Provided by Google]</CODE> */ 132 public final String key; 133 134 /** <CODE>[No Description Provided by Google]</CODE> */ 135 public final String value; 136 137 /** 138 * Constructor 139 * 140 * @param key - 141 * 142 * @param value - 143 */ 144 public EventMetadata(String key, String value) 145 { 146 // Exception-Check(s) to ensure that if any parameters which are not declared as 147 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 148 149 if (key == null) THROWS.throwNPE("key"); 150 if (value == null) THROWS.throwNPE("value"); 151 152 this.key = key; 153 this.value = value; 154 } 155 156 /** 157 * JSON Object Constructor 158 * @param jo A Json-Object having data about an instance of {@code 'EventMetadata'}. 159 */ 160 public EventMetadata (JsonObject jo) 161 { 162 this.key = ReadJSON.getString(jo, "key", false, true); 163 this.value = ReadJSON.getString(jo, "value", false, true); 164 } 165 166 167 /** Checks whether {@code 'this'} equals an input Java-{@code Object} */ 168 public boolean equals(Object other) 169 { 170 if (this == other) return true; 171 if (other == null) return false; 172 if (other.getClass() != this.getClass()) return false; 173 174 EventMetadata o = (EventMetadata) other; 175 176 return 177 Objects.equals(this.key, o.key) 178 && Objects.equals(this.value, o.value); 179 } 180 181 /** Generates a Hash-Code for {@code 'this'} instance */ 182 public int hashCode() 183 { 184 return 185 Objects.hashCode(this.key) 186 + Objects.hashCode(this.value); 187 } 188 } 189 190 /** <CODE>[No Description Provided by Google]</CODE> */ 191 public static class BackgroundServiceEvent 192 extends BaseType 193 implements java.io.Serializable 194 { 195 /** For Object Serialization. java.io.Serializable */ 196 protected static final long serialVersionUID = 1; 197 198 public boolean[] optionals() 199 { return new boolean[] { false, false, false, false, false, false, false, false, }; } 200 201 /** Timestamp of the event (in seconds). */ 202 public final Number timestamp; 203 204 /** The origin this event belongs to. */ 205 public final String origin; 206 207 /** The Service Worker ID that initiated the event. */ 208 public final String serviceWorkerRegistrationId; 209 210 /** The Background Service this event belongs to. */ 211 public final String service; 212 213 /** A description of the event. */ 214 public final String eventName; 215 216 /** An identifier that groups related events together. */ 217 public final String instanceId; 218 219 /** A list of event-specific information. */ 220 public final BackgroundService.EventMetadata[] eventMetadata; 221 222 /** Storage key this event belongs to. */ 223 public final String storageKey; 224 225 /** 226 * Constructor 227 * 228 * @param timestamp Timestamp of the event (in seconds). 229 * 230 * @param origin The origin this event belongs to. 231 * 232 * @param serviceWorkerRegistrationId The Service Worker ID that initiated the event. 233 * 234 * @param service The Background Service this event belongs to. 235 * 236 * @param eventName A description of the event. 237 * 238 * @param instanceId An identifier that groups related events together. 239 * 240 * @param eventMetadata A list of event-specific information. 241 * 242 * @param storageKey Storage key this event belongs to. 243 */ 244 public BackgroundServiceEvent( 245 Number timestamp, String origin, String serviceWorkerRegistrationId, String service, 246 String eventName, String instanceId, 247 BackgroundService.EventMetadata[] eventMetadata, String storageKey 248 ) 249 { 250 // Exception-Check(s) to ensure that if any parameters which are not declared as 251 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 252 253 if (timestamp == null) THROWS.throwNPE("timestamp"); 254 if (origin == null) THROWS.throwNPE("origin"); 255 if (serviceWorkerRegistrationId == null) THROWS.throwNPE("serviceWorkerRegistrationId"); 256 if (service == null) THROWS.throwNPE("service"); 257 if (eventName == null) THROWS.throwNPE("eventName"); 258 if (instanceId == null) THROWS.throwNPE("instanceId"); 259 if (eventMetadata == null) THROWS.throwNPE("eventMetadata"); 260 if (storageKey == null) THROWS.throwNPE("storageKey"); 261 262 // Exception-Check(s) to ensure that if any parameters which must adhere to a 263 // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw. 264 265 THROWS.checkIAE("service", service, "BackgroundService.ServiceName", BackgroundService.ServiceName); 266 267 this.timestamp = timestamp; 268 this.origin = origin; 269 this.serviceWorkerRegistrationId = serviceWorkerRegistrationId; 270 this.service = service; 271 this.eventName = eventName; 272 this.instanceId = instanceId; 273 this.eventMetadata = eventMetadata; 274 this.storageKey = storageKey; 275 } 276 277 /** 278 * JSON Object Constructor 279 * @param jo A Json-Object having data about an instance of {@code 'BackgroundServiceEvent'}. 280 */ 281 public BackgroundServiceEvent (JsonObject jo) 282 { 283 this.timestamp = ReadNumberJSON.get(jo, "timestamp", false, true); 284 this.origin = ReadJSON.getString(jo, "origin", false, true); 285 this.serviceWorkerRegistrationId = ReadJSON.getString(jo, "serviceWorkerRegistrationId", false, true); 286 this.service = ReadJSON.getString(jo, "service", false, true); 287 this.eventName = ReadJSON.getString(jo, "eventName", false, true); 288 this.instanceId = ReadJSON.getString(jo, "instanceId", false, true); 289 this.eventMetadata = (jo.getJsonArray("eventMetadata") == null) 290 ? null 291 : RJArrIntoStream.objArr(jo.getJsonArray("eventMetadata"), null, 0, BackgroundService.EventMetadata.class).toArray(BackgroundService.EventMetadata[]::new); 292 293 this.storageKey = ReadJSON.getString(jo, "storageKey", false, true); 294 } 295 296 297 /** Checks whether {@code 'this'} equals an input Java-{@code Object} */ 298 public boolean equals(Object other) 299 { 300 if (this == other) return true; 301 if (other == null) return false; 302 if (other.getClass() != this.getClass()) return false; 303 304 BackgroundServiceEvent o = (BackgroundServiceEvent) other; 305 306 return 307 Objects.equals(this.timestamp, o.timestamp) 308 && Objects.equals(this.origin, o.origin) 309 && Objects.equals(this.serviceWorkerRegistrationId, o.serviceWorkerRegistrationId) 310 && Objects.equals(this.service, o.service) 311 && Objects.equals(this.eventName, o.eventName) 312 && Objects.equals(this.instanceId, o.instanceId) 313 && Arrays.deepEquals(this.eventMetadata, o.eventMetadata) 314 && Objects.equals(this.storageKey, o.storageKey); 315 } 316 317 /** Generates a Hash-Code for {@code 'this'} instance */ 318 public int hashCode() 319 { 320 return 321 Objects.hashCode(this.timestamp) 322 + Objects.hashCode(this.origin) 323 + Objects.hashCode(this.serviceWorkerRegistrationId) 324 + Objects.hashCode(this.service) 325 + Objects.hashCode(this.eventName) 326 + Objects.hashCode(this.instanceId) 327 + Arrays.deepHashCode(this.eventMetadata) 328 + Objects.hashCode(this.storageKey); 329 } 330 } 331 332 /** Called when the recording state for the service has been updated. */ 333 public static class recordingStateChanged 334 extends BrowserEvent 335 implements java.io.Serializable 336 { 337 /** For Object Serialization. java.io.Serializable */ 338 protected static final long serialVersionUID = 1; 339 340 public boolean[] optionals() 341 { return new boolean[] { false, false, }; } 342 343 /** <CODE>[No Description Provided by Google]</CODE> */ 344 public final boolean isRecording; 345 346 /** <CODE>[No Description Provided by Google]</CODE> */ 347 public final String service; 348 349 /** 350 * Constructor 351 * 352 * @param isRecording - 353 * 354 * @param service - 355 */ 356 public recordingStateChanged(boolean isRecording, String service) 357 { 358 super("BackgroundService", "recordingStateChanged", 2); 359 360 // Exception-Check(s) to ensure that if any parameters which are not declared as 361 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 362 363 if (service == null) THROWS.throwNPE("service"); 364 365 // Exception-Check(s) to ensure that if any parameters which must adhere to a 366 // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw. 367 368 THROWS.checkIAE("service", service, "BackgroundService.ServiceName", BackgroundService.ServiceName); 369 370 this.isRecording = isRecording; 371 this.service = service; 372 } 373 374 /** 375 * JSON Object Constructor 376 * @param jo A Json-Object having data about an instance of {@code 'recordingStateChanged'}. 377 */ 378 public recordingStateChanged (JsonObject jo) 379 { 380 super("BackgroundService", "recordingStateChanged", 2); 381 382 this.isRecording = ReadPrimJSON.getBoolean(jo, "isRecording"); 383 this.service = ReadJSON.getString(jo, "service", false, true); 384 } 385 386 387 /** Checks whether {@code 'this'} equals an input Java-{@code Object} */ 388 public boolean equals(Object other) 389 { 390 if (this == other) return true; 391 if (other == null) return false; 392 if (other.getClass() != this.getClass()) return false; 393 394 recordingStateChanged o = (recordingStateChanged) other; 395 396 return 397 (this.isRecording == o.isRecording) 398 && Objects.equals(this.service, o.service); 399 } 400 401 /** Generates a Hash-Code for {@code 'this'} instance */ 402 public int hashCode() 403 { 404 return 405 (this.isRecording ? 1 : 0) 406 + Objects.hashCode(this.service); 407 } 408 } 409 410 /** 411 * Called with all existing backgroundServiceEvents when enabled, and all new 412 * events afterwards if enabled and recording. 413 */ 414 public static class backgroundServiceEventReceived 415 extends BrowserEvent 416 implements java.io.Serializable 417 { 418 /** For Object Serialization. java.io.Serializable */ 419 protected static final long serialVersionUID = 1; 420 421 public boolean[] optionals() 422 { return new boolean[] { false, }; } 423 424 /** <CODE>[No Description Provided by Google]</CODE> */ 425 public final BackgroundService.BackgroundServiceEvent backgroundServiceEvent; 426 427 /** 428 * Constructor 429 * 430 * @param backgroundServiceEvent - 431 */ 432 public backgroundServiceEventReceived 433 (BackgroundService.BackgroundServiceEvent backgroundServiceEvent) 434 { 435 super("BackgroundService", "backgroundServiceEventReceived", 1); 436 437 // Exception-Check(s) to ensure that if any parameters which are not declared as 438 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 439 440 if (backgroundServiceEvent == null) THROWS.throwNPE("backgroundServiceEvent"); 441 442 this.backgroundServiceEvent = backgroundServiceEvent; 443 } 444 445 /** 446 * JSON Object Constructor 447 * @param jo A Json-Object having data about an instance of {@code 'backgroundServiceEventReceived'}. 448 */ 449 public backgroundServiceEventReceived (JsonObject jo) 450 { 451 super("BackgroundService", "backgroundServiceEventReceived", 1); 452 453 this.backgroundServiceEvent = ReadJSON.getObject(jo, "backgroundServiceEvent", BackgroundService.BackgroundServiceEvent.class, false, true); 454 } 455 456 457 /** Checks whether {@code 'this'} equals an input Java-{@code Object} */ 458 public boolean equals(Object other) 459 { 460 if (this == other) return true; 461 if (other == null) return false; 462 if (other.getClass() != this.getClass()) return false; 463 464 backgroundServiceEventReceived o = (backgroundServiceEventReceived) other; 465 466 return 467 Objects.equals(this.backgroundServiceEvent, o.backgroundServiceEvent); 468 } 469 470 /** Generates a Hash-Code for {@code 'this'} instance */ 471 public int hashCode() 472 { 473 return 474 this.backgroundServiceEvent.hashCode(); 475 } 476 } 477 478 479 // Counter for keeping the WebSocket Request ID's distinct. 480 private static int counter = 1; 481 482 /** 483 * Enables event updates for the service. 484 * 485 * @param service - 486 * 487 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 488 * {@link Ret0}></CODE> 489 * 490 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 491 * browser receives the invocation-request. 492 * 493 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 494 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 495 * {@code >} to ensure the Browser Function has run to completion. 496 */ 497 public static Script<String, JsonObject, Ret0> startObserving(String service) 498 { 499 // Exception-Check(s) to ensure that if any parameters which are not declared as 500 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 501 502 if (service == null) THROWS.throwNPE("service"); 503 504 // Exception-Check(s) to ensure that if any parameters which must adhere to a 505 // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw. 506 507 THROWS.checkIAE("service", service, "BackgroundService.ServiceName", BackgroundService.ServiceName); 508 509 final int webSocketID = 12000000 + counter++; 510 final boolean[] optionals = { false, }; 511 512 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 513 String requestJSON = WriteJSON.get( 514 parameterTypes.get("startObserving"), 515 parameterNames.get("startObserving"), 516 optionals, webSocketID, 517 "BackgroundService.startObserving", 518 service 519 ); 520 521 // This Remote Command does not have a Return-Value. 522 return new Script<> 523 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 524 } 525 526 /** 527 * Disables event updates for the service. 528 * 529 * @param service - 530 * 531 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 532 * {@link Ret0}></CODE> 533 * 534 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 535 * browser receives the invocation-request. 536 * 537 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 538 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 539 * {@code >} to ensure the Browser Function has run to completion. 540 */ 541 public static Script<String, JsonObject, Ret0> stopObserving(String service) 542 { 543 // Exception-Check(s) to ensure that if any parameters which are not declared as 544 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 545 546 if (service == null) THROWS.throwNPE("service"); 547 548 // Exception-Check(s) to ensure that if any parameters which must adhere to a 549 // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw. 550 551 THROWS.checkIAE("service", service, "BackgroundService.ServiceName", BackgroundService.ServiceName); 552 553 final int webSocketID = 12001000 + counter++; 554 final boolean[] optionals = { false, }; 555 556 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 557 String requestJSON = WriteJSON.get( 558 parameterTypes.get("stopObserving"), 559 parameterNames.get("stopObserving"), 560 optionals, webSocketID, 561 "BackgroundService.stopObserving", 562 service 563 ); 564 565 // This Remote Command does not have a Return-Value. 566 return new Script<> 567 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 568 } 569 570 /** 571 * Set the recording state for the service. 572 * 573 * @param shouldRecord - 574 * 575 * @param service - 576 * 577 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 578 * {@link Ret0}></CODE> 579 * 580 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 581 * browser receives the invocation-request. 582 * 583 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 584 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 585 * {@code >} to ensure the Browser Function has run to completion. 586 */ 587 public static Script<String, JsonObject, Ret0> setRecording 588 (boolean shouldRecord, String service) 589 { 590 // Exception-Check(s) to ensure that if any parameters which are not declared as 591 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 592 593 if (service == null) THROWS.throwNPE("service"); 594 595 // Exception-Check(s) to ensure that if any parameters which must adhere to a 596 // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw. 597 598 THROWS.checkIAE("service", service, "BackgroundService.ServiceName", BackgroundService.ServiceName); 599 600 final int webSocketID = 12002000 + counter++; 601 final boolean[] optionals = { false, false, }; 602 603 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 604 String requestJSON = WriteJSON.get( 605 parameterTypes.get("setRecording"), 606 parameterNames.get("setRecording"), 607 optionals, webSocketID, 608 "BackgroundService.setRecording", 609 shouldRecord, service 610 ); 611 612 // This Remote Command does not have a Return-Value. 613 return new Script<> 614 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 615 } 616 617 /** 618 * Clears all stored data for the service. 619 * 620 * @param service - 621 * 622 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 623 * {@link Ret0}></CODE> 624 * 625 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 626 * browser receives the invocation-request. 627 * 628 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 629 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 630 * {@code >} to ensure the Browser Function has run to completion. 631 */ 632 public static Script<String, JsonObject, Ret0> clearEvents(String service) 633 { 634 // Exception-Check(s) to ensure that if any parameters which are not declared as 635 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 636 637 if (service == null) THROWS.throwNPE("service"); 638 639 // Exception-Check(s) to ensure that if any parameters which must adhere to a 640 // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw. 641 642 THROWS.checkIAE("service", service, "BackgroundService.ServiceName", BackgroundService.ServiceName); 643 644 final int webSocketID = 12003000 + counter++; 645 final boolean[] optionals = { false, }; 646 647 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 648 String requestJSON = WriteJSON.get( 649 parameterTypes.get("clearEvents"), 650 parameterNames.get("clearEvents"), 651 optionals, webSocketID, 652 "BackgroundService.clearEvents", 653 service 654 ); 655 656 // This Remote Command does not have a Return-Value. 657 return new Script<> 658 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 659 } 660 661}