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}&lt;String, {@link JsonObject},
488     * {@link Ret0}&gt;</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}&lt;String, {@link JsonObject},
532     * {@link Ret0}&gt;</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}&lt;String, {@link JsonObject},
578     * {@link Ret0}&gt;</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}&lt;String, {@link JsonObject},
623     * {@link Ret0}&gt;</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}