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