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